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;
1156 const std::vector<std::size_t>& n,
1157 const std::vector<std::size_t>& phases) {
1158 const std::size_t jnd0 =
sn.node_of_station(ist);
1162 if (
sn.isfjaugmented && jnd0 != 0 &&
sn.nodes[jnd0 - 1].nodetype == NodeType::Join) {
1164 for (std::size_t r = 0; r <
sn.nclasses && r < n.size(); ++r)
1166 return std::vector<std::vector<T>>(1, row);
1179 if (jnd0 != 0 &&
sn.replyblock.size() >= jnd0) {
1180 std::vector<std::size_t> rclasses;
1181 for (std::size_t r = 0; r <
sn.replyblock[jnd0 - 1].size(); ++r)
1182 if (
sn.replyblock[jnd0 - 1][r]) rclasses.push_back(r + 1);
1183 if (!rclasses.empty()) {
1184 const double Sd =
sn.stations[ist - 1].nservers;
1185 const std::size_t S =
1186 std::isfinite(Sd) ?
static_cast<std::size_t
>(Sd) :
static_cast<std::size_t
>(0);
1191 if (snb.
nvars.size() >= jnd0)
1192 for (std::size_t r = 1; r <=
sn.nclasses && 2 *
sn.nclasses + r < snb.
nvars[jnd0 - 1].size();
1194 snb.
nvars[jnd0 - 1][2 *
sn.nclasses + r] = 0;
1195 std::vector<std::vector<std::size_t>> bspace(1, std::vector<std::size_t>());
1196 for (std::size_t i = 0; i < rclasses.size(); ++i) {
1197 std::vector<std::vector<std::size_t>> next;
1198 for (std::size_t j = 0; j < bspace.size(); ++j)
1199 for (std::size_t v = 0; v <= S; ++v) {
1200 std::vector<std::size_t> row = bspace[j];
1202 next.push_back(row);
1206 std::vector<std::vector<std::vector<T>>> subs(bspace.size());
1207 std::size_t maxw = 0;
1208 for (std::size_t bi = 0; bi < bspace.size(); ++bi) {
1209 std::size_t tot = 0;
1210 for (std::size_t i = 0; i < bspace[bi].size(); ++i) tot += bspace[bi][i];
1211 if (tot > S)
continue;
1212 snb.
stations[ist - 1].nservers =
static_cast<double>(S - tot);
1214 for (std::size_t i = 0; i < subs[bi].size(); ++i)
1215 maxw = std::max(maxw, subs[bi][i].size());
1220 std::vector<std::vector<T>> out;
1221 for (std::size_t bi = 0; bi < bspace.size(); ++bi) {
1222 for (std::size_t i = 0; i < subs[bi].size(); ++i) {
1224 row.reserve(maxw + bspace[bi].size());
1225 if (subs[bi][i].size() < maxw)
1227 row.insert(row.end(), subs[bi][i].begin(), subs[bi][i].end());
1228 for (std::size_t j = 0; j < bspace[bi].size(); ++j)
1233 std::sort(out.begin(), out.end(), [](
const std::vector<T>& a,
const std::vector<T>& b) {
1234 for (std::size_t i = 0; i < a.size() && i < b.size(); ++i) {
1235 const double av = num_traits<T>::to_double(a[i]);
1236 const double bv = num_traits<T>::to_double(b[i]);
1237 if (av != bv) return av < bv;
1239 return a.size() < b.size();
1241 out.erase(std::unique(out.begin(), out.end(),
1242 [](
const std::vector<T>& a,
const std::vector<T>& b) {
1243 if (a.size() != b.size()) return false;
1244 for (std::size_t i = 0; i < a.size(); ++i)
1245 if (num_traits<T>::to_double(a[i]) !=
1246 num_traits<T>::to_double(b[i]))
1298 const std::vector<std::size_t>& n,
1299 const std::vector<std::size_t>& s,
1300 const std::vector<std::size_t>& phases) {
1301 const std::size_t R =
sn.nclasses;
1302 if (ist == 0 || ist >
sn.stations.size())
1303 throw InputError(
"from_marginal_and_started: station index " + std::to_string(ist) +
1304 " is out of range");
1305 if (n.size() != R || s.size() != R || phases.size() != R)
1306 throw InputError(
"from_marginal_and_started: n, s and phases must have one entry per class");
1310 std::vector<std::vector<T>> out;
1312 std::size_t ntot = 0, stot = 0;
1313 for (std::size_t r = 0; r < R; ++r) {
1314 if (s[r] > n[r])
return out;
1321 if (ist <=
sn.classcap.size())
1322 for (std::size_t r = 0; r < R && r <
sn.classcap[ist - 1].size(); ++r)
1323 if (
static_cast<double>(n[r]) >
sn.classcap[ist - 1][r])
return out;
1325 if (S > 0.0 && std::isfinite(S) &&
static_cast<double>(stot) > S)
return out;
1328 if (sched == SchedStrategy::PAS || sched == SchedStrategy::OI)
1334 if (sched == SchedStrategy::EXT || st.
nodetype == NodeType::Source) {
1341 std::vector<std::vector<T>> srv;
1342 for (std::size_t r = 0; r < R; ++r) {
1343 if (phases[r] == 0)
continue;
1348 if (r <
sn.classes.size() && std::isinf(
sn.classes[r].population) &&
1349 !
sn.disabled[ist - 1][r] &&
sn.markidx_of(ist, r + 1) <= 1)
1351 srv =
cartesian(srv, std::vector<std::vector<T>>(1, init));
1353 if (srv.empty()) srv.push_back(std::vector<T>());
1354 for (std::size_t i = 0; i < srv.size(); ++i) {
1356 std::numeric_limits<double>::infinity()));
1357 row.insert(row.end(), srv[i].begin(), srv[i].end());
1364 const auto phase_one_block = [&](
const std::vector<std::size_t>& cnt,
1365 bool* ok) -> std::vector<T> {
1368 for (std::size_t r = 0; r < R; ++r) {
1373 if (
sn.phases_of(ist, r + 1) == 0 && cnt[r] > 0) *ok =
false;
1374 if (phases[r] == 0)
continue;
1380 std::size_t srvw = 0;
1381 for (std::size_t r = 0; r < R; ++r) srvw += phases[r];
1383 if (state_detail::buffer_is_per_class_count(sched)) {
1387 const bool all_in_service = std::isfinite(S) &&
static_cast<double>(ntot) <= S;
1388 std::vector<std::size_t> insrv(R, 0), wait(R, 0);
1389 for (std::size_t r = 0; r < R; ++r) {
1390 insrv[r] = all_in_service ? n[r] : s[r];
1391 wait[r] = n[r] - insrv[r];
1394 const std::vector<T> blk = phase_one_block(insrv, &ok);
1395 if (!ok)
return out;
1397 for (std::size_t r = 0; r < R; ++r)
1399 row.insert(row.end(), blk.begin(), blk.end());
1404 const bool paired = state_detail::buffer_is_tag_phase_pairs(sched);
1405 if (state_detail::buffer_is_class_tag(sched) || paired) {
1411 const std::size_t bw = paired ? 2u : 1u;
1417 std::vector<std::size_t> inbuf;
1418 for (std::size_t r = 0; r < R; ++r)
1419 for (std::size_t j = 0; j < n[r] - s[r]; ++j) inbuf.push_back(r + 1);
1422 std::sort(inbuf.begin(), inbuf.end(),
1423 [](std::size_t a, std::size_t b) { return a > b; });
1426 const std::vector<T> blk = phase_one_block(s, &ok);
1427 if (!ok)
return out;
1430 if (inbuf.empty()) {
1433 for (std::size_t j = 0; j < inbuf.size(); ++j) {
1439 static_cast<long>(phases[inbuf[j] - 1])));
1442 row.insert(row.end(), blk.begin(), blk.end());
1450 const std::vector<T> blk = phase_one_block(n, &ok);
1451 if (!ok)
return out;
1464 const std::vector<std::size_t>& n,
1465 const std::vector<std::size_t>& s,
1466 const std::vector<std::size_t>& phases) {
1467 const std::size_t jnd0 =
sn.node_of_station(ist);
1468 if (
sn.isfjaugmented && jnd0 != 0 &&
sn.nodes[jnd0 - 1].nodetype == NodeType::Join) {
1470 for (std::size_t r = 0; r <
sn.nclasses && r < n.size(); ++r)
1472 return std::vector<std::vector<T>>(1, row);
1491 const std::vector<std::size_t>& n,
1492 const std::vector<std::size_t>& phases) {
1493 if (ind == 0 || ind >
sn.nodes.size())
1494 throw InputError(
"from_marginal_node: node index " + std::to_string(ind) +
1495 " is out of range");
1498 if (!nd.
stateful)
return std::vector<std::vector<T>>();
1500 const std::size_t R =
sn.nclasses;
1502 throw InputError(
"from_marginal_node: n must have one entry per class");
1504 if (nd.
nodetype == NodeType::Transition) {
1510 const typename std::map<std::size_t, TransitionParam<T> >::const_iterator it =
1511 sn.transparam.find(ind);
1512 if (it ==
sn.transparam.end())
1514 "from_marginal_node: transition node has no TransitionParam; build it with "
1518 for (std::size_t mm = 0; mm < tp.
nmodes; ++mm) {
1523 std::size_t fph = 0;
1524 for (std::size_t mm = 0; mm < tp.
nmodes; ++mm)
1528 return std::vector<std::vector<T> >{row};
1541 if (nd.
nodetype == NodeType::Cache) {
1542 const typename std::map<std::size_t, CacheParam<T> >::const_iterator cc =
1543 sn.nodeparam.find(ind);
1544 if (cc !=
sn.nodeparam.end()) {
1545 const std::size_t pend =
1546 cc->second.retrieval_capacity > 0 && cc->second.max_pending_retrieval > 0
1547 ?
static_cast<std::size_t
>(cc->second.max_pending_retrieval)
1549 std::size_t tot = 0;
1550 for (std::size_t r = 0; r < R; ++r) {
1551 bool is_hit =
false;
1552 for (std::size_t u = 0; u < cc->second.hitclass.size(); ++u)
1553 if (cc->second.hitclass[u] == r + 1) is_hit =
true;
1554 if (n[r] > (is_hit ? 1 + pend : 1))
return std::vector<std::vector<T> >();
1557 if (tot > 1 + pend)
return std::vector<std::vector<T> >();
1564 std::vector<std::vector<T> > acc;
1565 for (std::size_t r = 0; r < R; ++r) {
1567 if (sr.empty() && n[r] > 0)
return std::vector<std::vector<T> >();
1580 std::vector<std::vector<T> > ptrsets(1, std::vector<T>());
1582 for (std::size_t r = 1; r <= R; ++r) {
1583 if (
sn.rr_var_slot(ind, r) == 0)
continue;
1585 std::vector<T> vals;
1586 if (
sn.nodes[ind - 1].routing[r - 1] == RoutingStrategy::RROBIN) {
1587 const std::vector<std::size_t> ol =
sn.rr_outlinks(ind, r);
1588 for (std::size_t u = 0; u < ol.size(); ++u)
1591 const std::vector<std::size_t> cy =
sn.rr_weighted_outlinks(ind, r);
1592 for (std::size_t u = 0; u < cy.size(); ++u)
1596 std::vector<std::vector<T> > grown;
1597 for (std::size_t g = 0; g < ptrsets.size(); ++g)
1598 for (std::size_t v = 0; v < vals.size(); ++v) {
1599 std::vector<T> row = ptrsets[g];
1600 row.push_back(vals[v]);
1601 grown.push_back(row);
1603 ptrsets.swap(grown);
1628 if (nd.
nodetype == NodeType::Cache) {
1629 const typename std::map<std::size_t, CacheParam<T> >::const_iterator ci =
1630 sn.nodeparam.find(ind);
1631 if (ci ==
sn.nodeparam.end())
return acc;
1633 std::size_t tcc = 0;
1634 for (std::size_t u = 0; u < cp.
itemcap.size(); ++u)
1635 if (cp.
itemcap[u] > 0) tcc +=
static_cast<std::size_t
>(cp.
itemcap[u]);
1637 const std::size_t first_item = tcc <= cp.
nitems ? 1 : 0;
1638 std::vector<std::vector<T> > contents(1, std::vector<T>());
1639 for (std::size_t slot = 0; slot < tcc; ++slot) {
1640 std::vector<std::vector<T> > grown;
1641 for (std::size_t c = 0; c < contents.size(); ++c)
1642 for (std::size_t item = first_item; item <= cp.
nitems; ++item) {
1645 for (std::size_t j = 0; j < contents[c].size(); ++j)
1647 static_cast<double>(item)) { dup =
true;
break; }
1649 std::vector<T> row = contents[c];
1651 grown.push_back(row);
1653 contents.swap(grown);
1658 for (std::size_t i = 0; i < cp.
nitems; ++i) {
1659 std::vector<std::vector<T> > grown;
1660 for (std::size_t c = 0; c < contents.size(); ++c)
1661 for (
int b = 0; b <= 1; ++b) {
1662 std::vector<T> row = contents[c];
1664 grown.push_back(row);
1666 contents.swap(grown);
1674 std::vector<std::size_t> rcl, rci, rco;
1677 const long maxpend =
1679 std::vector<std::vector<T> > grown;
1680 for (std::size_t c = 0; c < contents.size(); ++c) {
1683 std::vector<std::size_t> active;
1684 for (std::size_t j = 0; j < rcl.size(); ++j)
1686 active.push_back(j);
1687 std::vector<std::vector<long> > pend(1, std::vector<long>(rcl.size(), 0));
1688 for (std::size_t a = 0; a < active.size(); ++a) {
1689 std::vector<std::vector<long> > next;
1690 for (std::size_t q = 0; q < pend.size(); ++q) {
1692 for (std::size_t j = 0; j < rcl.size(); ++j) used += pend[q][j];
1693 for (
long v = 0; v + used <= maxpend; ++v) {
1694 std::vector<long> row = pend[q];
1696 next.push_back(row);
1701 for (std::size_t q = 0; q < pend.size(); ++q) {
1702 std::vector<T> row = contents[c];
1703 for (std::size_t j = 0; j < rcl.size(); ++j)
1705 grown.push_back(row);
1708 contents.swap(grown);
1711 std::vector<std::vector<T> > joint =
cartesian(acc, contents);
1723 std::vector<bool> is_hit(R,
false), is_miss(R,
false);
1724 for (std::size_t u = 0; u < cp.
hitclass.size(); ++u)
1726 for (std::size_t u = 0; u < cp.
missclass.size(); ++u)
1729 std::vector<std::vector<T> > kept;
1730 for (std::size_t row = 0; row < joint.size(); ++row) {
1731 const std::vector<T>& st = joint[row];
1732 double tot = 0, other = 0, miss = 0;
1733 for (std::size_t r = 0; r < R; ++r) {
1736 if (is_miss[r]) miss += v;
1737 else if (!is_hit[r]) other += v;
1742 if (!(tot <= 1 || (other == 0 && miss <= 1 && tot <= 1 + maxpend)))
continue;
1745 for (std::size_t i = 0; i < cp.
nitems && ok; ++i) {
1749 for (std::size_t c = 0; c < tcc; ++c)
1773 const std::vector<std::size_t>& s,
const std::vector<std::size_t>& phases) {
1774 if (ind == 0 || ind >
sn.nodes.size())
1775 throw InputError(
"from_marginal_node_and_started: node index " + std::to_string(ind) +
1776 " is out of range");
1780 "from_marginal_node_and_started cannot be used on Petri net elements");
1782 if (!nd.
stateful)
return std::vector<std::vector<T>>();
1817 const std::vector<std::size_t>& phases) {
1818 if (ind == 0 || ind >
sn.nodes.size())
1819 throw InputError(
"from_marg_node: node index " + std::to_string(ind) +
" is out of range");
1821 const std::size_t R =
sn.nclasses;
1824 std::vector<double> ccap(R, std::numeric_limits<double>::infinity());
1826 const std::vector<double>& row =
sn.classcap[nd.
station - 1];
1827 for (std::size_t r = 0; r < R && r < row.size(); ++r) ccap[r] = row[r];
1830 std::vector<std::vector<int>> nset;
1832 nset.push_back(std::vector<int>(R, 0));
1834 const std::vector<std::vector<int>> all =
1836 for (std::size_t j = 0; j < all.size(); ++j) {
1838 for (std::size_t r = 0; r < R && ok; ++r)
1839 if (
static_cast<double>(all[j][r]) > ccap[r]) ok =
false;
1840 if (ok) nset.push_back(all[j]);
1844 std::vector<std::vector<T>> space;
1845 std::size_t maxw = 0;
1846 std::vector<std::vector<std::vector<T>>> subspaces;
1847 for (std::size_t j = 0; j < nset.size(); ++j) {
1848 std::vector<std::size_t> nj(R, 0);
1849 for (std::size_t r = 0; r < R; ++r) nj[r] = static_cast<std::size_t>(nset[j][r]);
1851 if (sj.empty())
continue;
1852 for (std::size_t a = 0; a < sj.size(); ++a) maxw = std::max(maxw, sj[a].size());
1853 subspaces.push_back(sj);
1855 for (std::size_t j = 0; j < subspaces.size(); ++j)
1856 for (std::size_t a = 0; a < subspaces[j].size(); ++a) {
1857 std::vector<T> row = subspaces[j][a];
1858 if (row.size() < maxw)
1860 space.push_back(row);
1862 if (space.empty())
return space;
1864 std::sort(space.begin(), space.end());
1865 space.erase(std::unique(space.begin(), space.end()), space.end());
1866 std::reverse(space.begin(), space.end());
1870namespace state_detail {
1881inline std::vector<std::vector<std::size_t> > multichoosecon(
const std::vector<std::size_t>& n,
1883 const std::size_t R = n.size();
1884 std::vector<std::vector<std::size_t> > out;
1885 if (R == 0)
return out;
1887 out.push_back(std::vector<std::size_t>(R, 0));
1891 for (std::size_t i = 0; i < R; ++i)
1893 std::vector<std::size_t> row(R, 0);
1899 for (std::size_t i = 0; i < R; ++i) {
1900 if (n[i] == 0)
continue;
1901 std::vector<std::size_t> n1 = n;
1903 const std::vector<std::vector<std::size_t> > tail = multichoosecon(n1, S - 1);
1904 for (std::size_t k = 0; k < tail.size(); ++k) {
1905 std::vector<std::size_t> row = tail[k];
1937 std::size_t ntot, std::size_t stot,
1938 const std::vector<std::size_t>& phases) {
1939 if (ind == 0 || ind >
sn.nodes.size())
1940 throw InputError(
"from_marg_node_started: node index " + std::to_string(ind) +
1941 " is out of range");
1942 std::vector<std::vector<T>> space;
1943 if (stot > ntot)
return space;
1946 const std::size_t R =
sn.nclasses;
1948 std::vector<double> ccap(R, std::numeric_limits<double>::infinity());
1950 const std::vector<double>& row =
sn.classcap[nd.
station - 1];
1951 for (std::size_t r = 0; r < R && r < row.size(); ++r) ccap[r] = row[r];
1954 std::vector<std::vector<int>> nset;
1956 nset.push_back(std::vector<int>(R, 0));
1958 const std::vector<std::vector<int>> all =
1960 for (std::size_t j = 0; j < all.size(); ++j) {
1962 for (std::size_t r = 0; r < R && ok; ++r)
1963 if (
static_cast<double>(all[j][r]) > ccap[r]) ok =
false;
1964 if (ok) nset.push_back(all[j]);
1968 std::size_t maxw = 0;
1969 std::vector<std::vector<std::vector<T>>> subspaces;
1970 for (std::size_t j = 0; j < nset.size(); ++j) {
1971 std::vector<std::size_t> nj(R, 0);
1972 for (std::size_t r = 0; r < R; ++r) nj[r] = static_cast<std::size_t>(nset[j][r]);
1973 const std::vector<std::vector<std::size_t> > sset =
1974 state_detail::multichoosecon(nj, stot);
1975 for (std::size_t k = 0; k < sset.size(); ++k) {
1976 const std::vector<std::vector<T>> sjk =
1978 if (sjk.empty())
continue;
1979 for (std::size_t a = 0; a < sjk.size(); ++a) maxw = std::max(maxw, sjk[a].size());
1980 subspaces.push_back(sjk);
1983 for (std::size_t j = 0; j < subspaces.size(); ++j)
1984 for (std::size_t a = 0; a < subspaces[j].size(); ++a) {
1985 std::vector<T> row = subspaces[j][a];
1986 if (row.size() < maxw)
1988 space.push_back(row);
1990 if (space.empty())
return space;
1992 std::sort(space.begin(), space.end());
1993 space.erase(std::unique(space.begin(), space.end()), space.end());
1994 std::reverse(space.begin(), space.end());
2023 const std::vector<std::size_t>& n,
2024 const std::vector<std::size_t>& phases, std::vector<T>& out) {
2025 if (ind == 0 || ind >
sn.nodes.size())
2026 throw InputError(
"from_marginal_node_first: node index " + std::to_string(ind) +
2027 " is out of range");
2031 if (rows.empty())
return false;
2036 const std::size_t R =
sn.nclasses;
2038 throw InputError(
"from_marginal_node_first: n must have one entry per class");
2040 for (std::size_t r = 0; r < R; ++r) {
2044 if (n[r] > 0)
return false;
2047 out.insert(out.end(), sr[0].begin(), sr[0].end());
2050 const typename std::map<std::size_t, CacheParam<T> >::const_iterator ci =
2051 sn.nodeparam.find(ind);
2052 if (ci ==
sn.nodeparam.end())
return true;
2054 std::size_t tcc = 0;
2055 for (std::size_t u = 0; u < cp.
itemcap.size(); ++u)
2056 if (cp.
itemcap[u] > 0) tcc +=
static_cast<std::size_t
>(cp.
itemcap[u]);
2057 for (std::size_t slot = 0; slot < tcc; ++slot)
2059 tcc <= cp.
nitems ?
static_cast<long>(slot + 1) : 0L));
2062 std::vector<std::size_t> rcl, rci, rco;
2076 std::size_t M,
const std::vector<std::size_t>& N,
2077 const std::vector<std::vector<long>>& caps = std::vector<std::vector<long>>()) {
2078 std::vector<std::vector<T>> ss;
2079 for (std::size_t r = 0; r < N.size(); ++r) {
2080 const std::vector<std::vector<T>> sr =
2083 if (sr.empty())
return std::vector<std::vector<T>>();
2103 std::size_t M,
const std::vector<std::size_t>& N,
2104 const std::vector<std::vector<bool>>& chains,
2105 const std::vector<std::vector<long>>& caps = std::vector<std::vector<long>>()) {
2106 const std::size_t C = chains.size();
2107 const std::size_t R = N.size();
2109 std::vector<std::vector<std::vector<int>>> chainInitPos(C);
2110 std::vector<std::size_t> inchain_sz(C, 0);
2111 for (std::size_t c = 0; c < C; ++c) {
2112 std::size_t tot = 0, k = 0;
2113 for (std::size_t r = 0; r < R; ++r)
2114 if (chains[c][r]) { tot += N[r]; ++k; }
2116 chainInitPos[c] = k == 0 ? std::vector<std::vector<int>>{std::vector<int>()}
2119 std::vector<std::vector<T>> ss;
2120 std::vector<std::size_t> v(C, 0);
2122 std::vector<std::size_t> subN;
2124 for (std::size_t c = 0; c < C; ++c) {
2125 const std::vector<int>& row = chainInitPos[c][v[c]];
2126 for (std::size_t j = 0; j < row.size(); ++j)
2127 subN.push_back(
static_cast<std::size_t
>(row[j]));
2133 std::vector<std::size_t> subNg(R, 0);
2136 for (std::size_t c = 0; c < C; ++c)
2137 for (std::size_t r = 0; r < R; ++r)
2138 if (chains[c][r]) subNg[r] = subN[k++];
2140 const std::vector<std::vector<T>> blk =
2143 ss.insert(ss.end(), blk.begin(), blk.end());
2146 for (; c < C; ++c) {
2147 if (++v[c] < chainInitPos[c].size())
break;
2172 if (ind == 0 || ind >
sn.nodes.size())
return 0;
2173 if (
sn.nodes[ind - 1].nodetype != NodeType::Place)
return 0;
2174 const typename std::map<std::size_t, std::vector<T>>::const_iterator it =
2175 sn.initmarking.find(ind);
2176 if (it ==
sn.initmarking.end() || r >= it->second.size())
return 0;
2178 return v > 0 ?
static_cast<std::size_t
>(v) : 0;
2209 const std::vector<std::vector<std::size_t>>& cutoff_mat =
2210 std::vector<std::vector<std::size_t>>()) {
2211 const std::size_t R =
sn.nclasses, N =
sn.nodes.size();
2212 std::vector<std::vector<std::size_t>> cap(N, std::vector<std::size_t>(R, 0));
2213 const std::vector<double> njobs =
sn.njobs();
2217 std::size_t maxpend = 0;
2218 for (std::size_t r = 0; r < R; ++r)
2219 if (!std::isfinite(njobs[r])) maxpend = std::max(maxpend, cutoff[r]);
2220 if (maxpend > 0) --maxpend;
2222 for (std::size_t ind = 1; ind <= N; ++ind) {
2225 const std::size_t ist = nd.
station;
2226 const std::size_t isf =
sn.stateful_index(ind);
2227 if (ist != 0 && nd.
nodetype != NodeType::Source) {
2228 for (std::size_t r = 0; r < R; ++r) {
2230 for (std::size_t cc = 0; cc <
sn.chains.size(); ++cc)
2231 if (r <
sn.chains[cc].size() &&
sn.chains[cc][r]) { c = cc;
break; }
2232 const bool novisit = c <
sn.visits.size() &&
sn.visits[c].rows() != 0 &&
2233 isf != 0 && isf - 1 <
sn.visits[c].rows() &&
2239 if (nd.
nodetype != NodeType::Place && ist - 1 <
sn.disabled.size() &&
2240 r <
sn.disabled[ist - 1].size() &&
sn.disabled[ist - 1][r]) {
2241 cap[ind - 1][r] = 0;
2245 if (!std::isfinite(njobs[r])) {
2250 b =
static_cast<double>(
2251 (!cutoff_mat.empty() && ist - 1 < cutoff_mat.size() &&
2252 r < cutoff_mat[ist - 1].size())
2253 ? cutoff_mat[ist - 1][r]
2257 for (std::size_t k = 0; k < R; ++k)
2258 if (c <
sn.chains.size() && k <
sn.chains[c].size() &&
sn.chains[c][k] &&
2259 std::isfinite(njobs[k]))
2262 if (ist - 1 <
sn.classcap.size() && r <
sn.classcap[ist - 1].size())
2263 b = std::min(b,
sn.classcap[ist - 1][r]);
2265 for (std::size_t f = 0; f <
sn.regions.size(); ++f) {
2267 if (ist - 1 >= rg.
cap.size())
continue;
2268 if (r < rg.
cap[ist - 1].size() && rg.
cap[ist - 1][r] >= 0)
2269 b = std::min(b, rg.
cap[ist - 1][r]);
2270 if (R < rg.
cap[ist - 1].size() && rg.
cap[ist - 1][R] >= 0)
2271 b = std::min(b, rg.
cap[ist - 1][R]);
2273 if (!(b > 0)) b = 0;
2274 cap[ind - 1][r] = std::isfinite(b) ?
static_cast<std::size_t
>(b)
2275 :
static_cast<std::size_t
>(-1);
2280 case NodeType::Cache: {
2281 for (std::size_t r = 0; r < R; ++r) cap[ind - 1][r] = 1;
2282 const typename std::map<std::size_t, CacheParam<T>>::const_iterator ci =
2283 sn.nodeparam.find(ind);
2284 if (ci !=
sn.nodeparam.end() && ci->second.retrieval_capacity > 0)
2285 for (std::size_t r = 0; r < R; ++r)
2286 for (std::size_t k = 0; k < ci->second.hitclass.size(); ++k)
2287 if (ci->second.hitclass[k] == r + 1) cap[ind - 1][r] = 1 + maxpend;
2290 case NodeType::Router:
2291 for (std::size_t r = 0; r < R; ++r) {
2293 for (std::size_t cc = 0; cc <
sn.chains.size(); ++cc)
2294 if (r <
sn.chains[cc].size() &&
sn.chains[cc][r]) { c = cc;
break; }
2296 (c <
sn.nodevisits.size() &&
sn.nodevisits[c].rows() != 0 &&
2297 ind - 1 <
sn.nodevisits[c].rows() &&
2306 for (std::size_t r = 0; r < R; ++r)
2307 cap[ind - 1][r] =
static_cast<std::size_t
>(-1);
2332 std::size_t maxst = 3000000,
2333 const std::vector<std::vector<std::size_t>>& cutoff_mat =
2334 std::vector<std::vector<std::size_t>>()) {
2335 const std::size_t R =
sn.nclasses;
2336 if (cutoff.size() != R)
2337 throw InputError(
"space_generator: cutoff must have one entry per class");
2347 const std::vector<double> njobs =
sn.njobs();
2348 std::vector<std::size_t> Np(R, 0);
2349 for (std::size_t r = 0; r < R; ++r) {
2350 const double nj = njobs[r];
2351 if (std::isfinite(nj)) {
2352 Np[r] =
static_cast<std::size_t
>(nj);
2356 "space_generator: class " + std::to_string(r) +
2357 " is open, so its population is unbounded; supply a cutoff for it");
2365 const std::vector<std::vector<std::size_t>> capc =
space_capacity_c(
sn, cutoff, cutoff_mat);
2366 const std::size_t unbounded =
static_cast<std::size_t
>(-1);
2367 for (std::size_t r = 0; r < R; ++r) {
2368 if (std::isfinite(njobs[r]))
continue;
2370 bool any_unbounded =
false;
2371 for (std::size_t ind = 1; ind <=
sn.nodes.size(); ++ind) {
2372 if (!
sn.nodes[ind - 1].stateful ||
sn.nodes[ind - 1].nodetype == NodeType::Source)
2374 if (capc[ind - 1][r] == unbounded) any_unbounded =
true;
2375 else hi = std::max(hi, capc[ind - 1][r]);
2377 if (!any_unbounded) Np[r] = std::min(Np[r], hi);
2380 std::vector<std::vector<bool>> chains =
sn.chains;
2381 if (chains.empty()) {
2382 chains.assign(R, std::vector<bool>(R,
false));
2383 for (std::size_t r = 0; r < R; ++r) chains[r][r] =
true;
2389 const std::vector<std::size_t>& sfn =
sn.stateful_nodes;
2390 const std::size_t NF = sfn.size();
2391 std::vector<std::size_t> lat_col(NF,
static_cast<std::size_t
>(-1));
2393 for (std::size_t k = 0; k < NF; ++k)
2394 if (
sn.nodes[sfn[k] - 1].nodetype != NodeType::Source) lat_col[k] = Mp++;
2402 std::vector<bool> is_open(R,
false);
2403 for (std::size_t r = 0; r < R; ++r)
2404 is_open[r] = !std::isfinite(njobs[r]);
2414 std::vector<std::vector<long>> lat_caps(R, std::vector<long>(Mp, -1));
2417 for (std::size_t k = 0; k < NF && ok; ++k) {
2418 if (lat_col[k] ==
static_cast<std::size_t
>(-1))
continue;
2419 const std::size_t ind = sfn[k];
2420 for (std::size_t r = 0; r < R; ++r) {
2421 const std::size_t cap = capc[ind - 1][r];
2422 lat_caps[r][lat_col[k]] =
2423 cap == unbounded ? -1 :
static_cast<long>(cap);
2426 if (!ok) lat_caps.clear();
2428 std::vector<std::vector<T>> pos;
2429 std::vector<std::size_t> nlev(R, 0);
2431 bool admissible =
true;
2432 for (std::size_t r = 0; r < R; ++r)
2433 if (!is_open[r] && nlev[r] != Np[r]) { admissible =
false;
break; }
2435 const std::vector<std::vector<T>> part =
2437 pos.insert(pos.end(), part.begin(), part.end());
2438 if (pos.size() > maxst)
2440 "space_generator: the population lattice exceeds the cap of " +
2441 std::to_string(maxst) +
" states; raise it or use another solver");
2445 for (; r < R; ++r) {
2446 if (nlev[r] < Np[r]) { ++nlev[r];
break; }
2453 std::sort(pos.begin(), pos.end());
2454 pos.erase(std::unique(pos.begin(), pos.end()), pos.end());
2462 std::vector<std::vector<std::vector<std::vector<T>>>> allper(pos.size());
2463 std::vector<bool> row_ok(pos.size(),
true);
2464 std::vector<std::size_t> maxw(NF, 0);
2465 std::vector<NetState<T>> out;
2466 for (std::size_t j = 0; j < pos.size(); ++j) {
2467 std::vector<std::vector<std::vector<T>>> per(NF);
2469 for (std::size_t k = 0; k < NF && ok; ++k) {
2470 const std::size_t ind = sfn[k];
2471 const std::size_t ist =
sn.nodes[ind - 1].station;
2472 std::vector<std::size_t> ph(R, 1), nmarg(R, 0);
2475 for (std::size_t r = 0; r < R; ++r) ph[r] =
sn.phasessz_of(ist, r + 1);
2476 if (lat_col[k] ==
static_cast<std::size_t
>(-1)) {
2486 for (std::size_t r = 0; r < R; ++r)
2487 if (!
sn.disabled[ist - 1][r]) nmarg[r] = 1;
2489 for (std::size_t r = 0; r < R; ++r)
2490 nmarg[r] =
static_cast<std::size_t
>(
2495 for (std::size_t r = 0; r < R && ok; ++r)
2496 if (capc[ind - 1][r] !=
static_cast<std::size_t
>(-1) &&
2497 nmarg[r] > capc[ind - 1][r])
2502 if (per[k].empty()) ok =
false;
2503 for (std::size_t b = 0; b < per[k].size(); ++b)
2504 maxw[k] = std::max(maxw[k], per[k][b].size());
2507 allper[j].swap(per);
2510 for (std::size_t j = 0; j < pos.size(); ++j) {
2511 if (!row_ok[j])
continue;
2512 std::vector<std::vector<std::vector<T>>>& per = allper[j];
2514 for (std::size_t k = 0; k < NF; ++k)
2515 for (std::size_t b = 0; b < per[k].size(); ++b)
2516 if (per[k][b].size() < maxw[k])
2517 per[k][b].insert(per[k][b].begin(), maxw[k] - per[k][b].size(),
2520 std::vector<NetState<T>> acc(1);
2521 for (std::size_t i = 0; i < NF; ++i) {
2522 std::vector<NetState<T>> next;
2523 for (std::size_t a = 0; a < acc.size(); ++a)
2524 for (std::size_t b = 0; b < per[i].size(); ++b) {
2526 ns.
local.push_back(per[i][b]);
2530 if (out.size() + acc.size() > maxst)
2532 "space_generator: the state space exceeds the cap of " +
2533 std::to_string(maxst) +
" states; raise it or use another solver");
2535 out.insert(out.end(), acc.begin(), acc.end());
2539 std::vector<std::vector<std::vector<T>>> seen;
2540 std::vector<NetState<T>> uniq;
2541 for (std::size_t i = 0; i < out.size(); ++i) {
2543 for (std::size_t p = 0; p < seen.size() && !dup; ++p)
2544 if (seen[p] == out[i].local) dup =
true;
2546 seen.push_back(out[i].local);
2547 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,...
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
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