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];
1045 std::size_t ntot = 0;
1046 for (std::size_t r = 0; r < n.size(); ++r) ntot += n[r];
1051 std::size_t rrw = 0;
1052 if (ind <=
sn.nvars.size())
1053 for (std::size_t r = 0; r < R && R + r <
sn.nvars[ind - 1].size(); ++r)
1054 rrw +=
sn.nvars[ind - 1][R + r];
1055 std::vector<std::vector<T>> ptrsets(1, std::vector<T>());
1056 for (std::size_t r = 1; r <= R; ++r) {
1057 if (
sn.rr_var_slot(ind, r) == 0)
continue;
1058 std::vector<T> vals;
1059 if (
sn.nodes[ind - 1].routing[r - 1] == RoutingStrategy::RROBIN) {
1060 const std::vector<std::size_t> ol =
sn.rr_outlinks(ind, r);
1061 for (std::size_t d = 0; d < ol.size(); ++d)
1064 const std::vector<std::size_t> cy =
sn.rr_weighted_outlinks(ind, r);
1065 for (std::size_t d = 0; d < cy.size(); ++d)
1068 if (vals.empty()) vals.push_back(zero);
1069 std::vector<std::vector<T>> grown;
1070 for (std::size_t g = 0; g < ptrsets.size(); ++g)
1071 for (std::size_t v = 0; v < vals.size(); ++v) {
1072 std::vector<T> row = ptrsets[g];
1073 row.push_back(vals[v]);
1074 grown.push_back(row);
1076 ptrsets.swap(grown);
1079 std::vector<std::vector<T>> out;
1080 for (std::size_t i = 0; i < rows.size(); ++i) {
1083 std::vector<std::size_t> nbuf(R, 0);
1084 std::size_t srvclass = 0;
1086 std::size_t srvw = 0;
1087 for (std::size_t r = 0; r < R; ++r) srvw += phases[r];
1088 const std::size_t srv0 = rows[i].size() - srvw;
1089 std::size_t off = 0;
1090 for (std::size_t r = 0; r < R; ++r) {
1092 for (std::size_t k = 0; k < phases[r]; ++k)
1093 c +=
static_cast<std::size_t
>(
1096 if (c > 0 && srvclass == 0) srvclass = r + 1;
1099 if (srv0 >= R) nbuf[r] =
static_cast<std::size_t
>(
1103 const std::vector<std::vector<T>> blocks =
1105 : std::vector<std::vector<T>>(1, std::vector<T>());
1113 const std::size_t head = pi.
valid ? pi.
off : width - pw;
1114 for (std::size_t b = 0; b < blocks.size(); ++b) {
1115 for (std::size_t g = 0; g < ptrsets.size(); ++g) {
1116 std::vector<T> row = rows[i];
1117 row.insert(row.end(), head - rrw, zero);
1118 row.insert(row.end(), ptrsets[g].begin(), ptrsets[g].end());
1119 row.insert(row.end(), blocks[b].begin(), blocks[b].end());
1120 row.insert(row.end(), width - head - pw, zero);
1129 for (std::size_t v = 0; v <= (ntot > 0 ? 1u : 0u); ++v) {
1130 std::vector<T> r2 = row;
1142 const std::vector<std::size_t>& n,
1143 const std::vector<std::size_t>& phases) {
1144 const std::size_t jnd0 =
sn.node_of_station(ist);
1148 if (
sn.isfjaugmented && jnd0 != 0 &&
sn.nodes[jnd0 - 1].nodetype == NodeType::Join) {
1150 for (std::size_t r = 0; r <
sn.nclasses && r < n.size(); ++r)
1152 return std::vector<std::vector<T>>(1, row);
1165 if (jnd0 != 0 &&
sn.replyblock.size() >= jnd0) {
1166 std::vector<std::size_t> rclasses;
1167 for (std::size_t r = 0; r <
sn.replyblock[jnd0 - 1].size(); ++r)
1168 if (
sn.replyblock[jnd0 - 1][r]) rclasses.push_back(r + 1);
1169 if (!rclasses.empty()) {
1170 const double Sd =
sn.stations[ist - 1].nservers;
1171 const std::size_t S =
1172 std::isfinite(Sd) ?
static_cast<std::size_t
>(Sd) :
static_cast<std::size_t
>(0);
1177 if (snb.
nvars.size() >= jnd0)
1178 for (std::size_t r = 1; r <=
sn.nclasses && 2 *
sn.nclasses + r < snb.
nvars[jnd0 - 1].size();
1180 snb.
nvars[jnd0 - 1][2 *
sn.nclasses + r] = 0;
1181 std::vector<std::vector<std::size_t>> bspace(1, std::vector<std::size_t>());
1182 for (std::size_t i = 0; i < rclasses.size(); ++i) {
1183 std::vector<std::vector<std::size_t>> next;
1184 for (std::size_t j = 0; j < bspace.size(); ++j)
1185 for (std::size_t v = 0; v <= S; ++v) {
1186 std::vector<std::size_t> row = bspace[j];
1188 next.push_back(row);
1192 std::vector<std::vector<std::vector<T>>> subs(bspace.size());
1193 std::size_t maxw = 0;
1194 for (std::size_t bi = 0; bi < bspace.size(); ++bi) {
1195 std::size_t tot = 0;
1196 for (std::size_t i = 0; i < bspace[bi].size(); ++i) tot += bspace[bi][i];
1197 if (tot > S)
continue;
1198 snb.
stations[ist - 1].nservers =
static_cast<double>(S - tot);
1200 for (std::size_t i = 0; i < subs[bi].size(); ++i)
1201 maxw = std::max(maxw, subs[bi][i].size());
1206 std::vector<std::vector<T>> out;
1207 for (std::size_t bi = 0; bi < bspace.size(); ++bi) {
1208 for (std::size_t i = 0; i < subs[bi].size(); ++i) {
1210 row.reserve(maxw + bspace[bi].size());
1211 if (subs[bi][i].size() < maxw)
1213 row.insert(row.end(), subs[bi][i].begin(), subs[bi][i].end());
1214 for (std::size_t j = 0; j < bspace[bi].size(); ++j)
1219 std::sort(out.begin(), out.end(), [](
const std::vector<T>& a,
const std::vector<T>& b) {
1220 for (std::size_t i = 0; i < a.size() && i < b.size(); ++i) {
1221 const double av = num_traits<T>::to_double(a[i]);
1222 const double bv = num_traits<T>::to_double(b[i]);
1223 if (av != bv) return av < bv;
1225 return a.size() < b.size();
1227 out.erase(std::unique(out.begin(), out.end(),
1228 [](
const std::vector<T>& a,
const std::vector<T>& b) {
1229 if (a.size() != b.size()) return false;
1230 for (std::size_t i = 0; i < a.size(); ++i)
1231 if (num_traits<T>::to_double(a[i]) !=
1232 num_traits<T>::to_double(b[i]))
1284 const std::vector<std::size_t>& n,
1285 const std::vector<std::size_t>& s,
1286 const std::vector<std::size_t>& phases) {
1287 const std::size_t R =
sn.nclasses;
1288 if (ist == 0 || ist >
sn.stations.size())
1289 throw InputError(
"from_marginal_and_started: station index " + std::to_string(ist) +
1290 " is out of range");
1291 if (n.size() != R || s.size() != R || phases.size() != R)
1292 throw InputError(
"from_marginal_and_started: n, s and phases must have one entry per class");
1296 std::vector<std::vector<T>> out;
1298 std::size_t ntot = 0, stot = 0;
1299 for (std::size_t r = 0; r < R; ++r) {
1300 if (s[r] > n[r])
return out;
1307 if (ist <=
sn.classcap.size())
1308 for (std::size_t r = 0; r < R && r <
sn.classcap[ist - 1].size(); ++r)
1309 if (
static_cast<double>(n[r]) >
sn.classcap[ist - 1][r])
return out;
1311 if (S > 0.0 && std::isfinite(S) &&
static_cast<double>(stot) > S)
return out;
1314 if (sched == SchedStrategy::PAS || sched == SchedStrategy::OI)
1320 if (sched == SchedStrategy::EXT || st.
nodetype == NodeType::Source) {
1327 std::vector<std::vector<T>> srv;
1328 for (std::size_t r = 0; r < R; ++r) {
1329 if (phases[r] == 0)
continue;
1331 if (r <
sn.classes.size() && std::isinf(
sn.classes[r].population) &&
1332 !
sn.disabled[ist - 1][r])
1334 srv =
cartesian(srv, std::vector<std::vector<T>>(1, init));
1336 if (srv.empty()) srv.push_back(std::vector<T>());
1337 for (std::size_t i = 0; i < srv.size(); ++i) {
1339 std::numeric_limits<double>::infinity()));
1340 row.insert(row.end(), srv[i].begin(), srv[i].end());
1347 const auto phase_one_block = [&](
const std::vector<std::size_t>& cnt,
1348 bool* ok) -> std::vector<T> {
1351 for (std::size_t r = 0; r < R; ++r) {
1356 if (
sn.phases_of(ist, r + 1) == 0 && cnt[r] > 0) *ok =
false;
1357 if (phases[r] == 0)
continue;
1363 std::size_t srvw = 0;
1364 for (std::size_t r = 0; r < R; ++r) srvw += phases[r];
1366 if (state_detail::buffer_is_per_class_count(sched)) {
1370 const bool all_in_service = std::isfinite(S) &&
static_cast<double>(ntot) <= S;
1371 std::vector<std::size_t> insrv(R, 0), wait(R, 0);
1372 for (std::size_t r = 0; r < R; ++r) {
1373 insrv[r] = all_in_service ? n[r] : s[r];
1374 wait[r] = n[r] - insrv[r];
1377 const std::vector<T> blk = phase_one_block(insrv, &ok);
1378 if (!ok)
return out;
1380 for (std::size_t r = 0; r < R; ++r)
1382 row.insert(row.end(), blk.begin(), blk.end());
1387 const bool paired = state_detail::buffer_is_tag_phase_pairs(sched);
1388 if (state_detail::buffer_is_class_tag(sched) || paired) {
1394 const std::size_t bw = paired ? 2u : 1u;
1400 std::vector<std::size_t> inbuf;
1401 for (std::size_t r = 0; r < R; ++r)
1402 for (std::size_t j = 0; j < n[r] - s[r]; ++j) inbuf.push_back(r + 1);
1405 std::sort(inbuf.begin(), inbuf.end(),
1406 [](std::size_t a, std::size_t b) { return a > b; });
1409 const std::vector<T> blk = phase_one_block(s, &ok);
1410 if (!ok)
return out;
1413 if (inbuf.empty()) {
1416 for (std::size_t j = 0; j < inbuf.size(); ++j) {
1422 static_cast<long>(phases[inbuf[j] - 1])));
1425 row.insert(row.end(), blk.begin(), blk.end());
1433 const std::vector<T> blk = phase_one_block(n, &ok);
1434 if (!ok)
return out;
1447 const std::vector<std::size_t>& n,
1448 const std::vector<std::size_t>& s,
1449 const std::vector<std::size_t>& phases) {
1450 const std::size_t jnd0 =
sn.node_of_station(ist);
1451 if (
sn.isfjaugmented && jnd0 != 0 &&
sn.nodes[jnd0 - 1].nodetype == NodeType::Join) {
1453 for (std::size_t r = 0; r <
sn.nclasses && r < n.size(); ++r)
1455 return std::vector<std::vector<T>>(1, row);
1474 const std::vector<std::size_t>& n,
1475 const std::vector<std::size_t>& phases) {
1476 if (ind == 0 || ind >
sn.nodes.size())
1477 throw InputError(
"from_marginal_node: node index " + std::to_string(ind) +
1478 " is out of range");
1481 if (!nd.
stateful)
return std::vector<std::vector<T>>();
1483 const std::size_t R =
sn.nclasses;
1485 throw InputError(
"from_marginal_node: n must have one entry per class");
1487 if (nd.
nodetype == NodeType::Transition) {
1493 const typename std::map<std::size_t, TransitionParam<T> >::const_iterator it =
1494 sn.transparam.find(ind);
1495 if (it ==
sn.transparam.end())
1497 "from_marginal_node: transition node has no TransitionParam; build it with "
1501 for (std::size_t mm = 0; mm < tp.
nmodes; ++mm) {
1506 std::size_t fph = 0;
1507 for (std::size_t mm = 0; mm < tp.
nmodes; ++mm)
1511 return std::vector<std::vector<T> >{row};
1524 if (nd.
nodetype == NodeType::Cache) {
1525 const typename std::map<std::size_t, CacheParam<T> >::const_iterator cc =
1526 sn.nodeparam.find(ind);
1527 if (cc !=
sn.nodeparam.end()) {
1528 const std::size_t pend =
1529 cc->second.retrieval_capacity > 0 && cc->second.max_pending_retrieval > 0
1530 ?
static_cast<std::size_t
>(cc->second.max_pending_retrieval)
1532 std::size_t tot = 0;
1533 for (std::size_t r = 0; r < R; ++r) {
1534 bool is_hit =
false;
1535 for (std::size_t u = 0; u < cc->second.hitclass.size(); ++u)
1536 if (cc->second.hitclass[u] == r + 1) is_hit =
true;
1537 if (n[r] > (is_hit ? 1 + pend : 1))
return std::vector<std::vector<T> >();
1540 if (tot > 1 + pend)
return std::vector<std::vector<T> >();
1547 std::vector<std::vector<T> > acc;
1548 for (std::size_t r = 0; r < R; ++r) {
1550 if (sr.empty() && n[r] > 0)
return std::vector<std::vector<T> >();
1563 std::vector<std::vector<T> > ptrsets(1, std::vector<T>());
1565 for (std::size_t r = 1; r <= R; ++r) {
1566 if (
sn.rr_var_slot(ind, r) == 0)
continue;
1568 std::vector<T> vals;
1569 if (
sn.nodes[ind - 1].routing[r - 1] == RoutingStrategy::RROBIN) {
1570 const std::vector<std::size_t> ol =
sn.rr_outlinks(ind, r);
1571 for (std::size_t u = 0; u < ol.size(); ++u)
1574 const std::vector<std::size_t> cy =
sn.rr_weighted_outlinks(ind, r);
1575 for (std::size_t u = 0; u < cy.size(); ++u)
1579 std::vector<std::vector<T> > grown;
1580 for (std::size_t g = 0; g < ptrsets.size(); ++g)
1581 for (std::size_t v = 0; v < vals.size(); ++v) {
1582 std::vector<T> row = ptrsets[g];
1583 row.push_back(vals[v]);
1584 grown.push_back(row);
1586 ptrsets.swap(grown);
1611 if (nd.
nodetype == NodeType::Cache) {
1612 const typename std::map<std::size_t, CacheParam<T> >::const_iterator ci =
1613 sn.nodeparam.find(ind);
1614 if (ci ==
sn.nodeparam.end())
return acc;
1616 std::size_t tcc = 0;
1617 for (std::size_t u = 0; u < cp.
itemcap.size(); ++u)
1618 if (cp.
itemcap[u] > 0) tcc +=
static_cast<std::size_t
>(cp.
itemcap[u]);
1620 const std::size_t first_item = tcc <= cp.
nitems ? 1 : 0;
1621 std::vector<std::vector<T> > contents(1, std::vector<T>());
1622 for (std::size_t slot = 0; slot < tcc; ++slot) {
1623 std::vector<std::vector<T> > grown;
1624 for (std::size_t c = 0; c < contents.size(); ++c)
1625 for (std::size_t item = first_item; item <= cp.
nitems; ++item) {
1628 for (std::size_t j = 0; j < contents[c].size(); ++j)
1630 static_cast<double>(item)) { dup =
true;
break; }
1632 std::vector<T> row = contents[c];
1634 grown.push_back(row);
1636 contents.swap(grown);
1641 for (std::size_t i = 0; i < cp.
nitems; ++i) {
1642 std::vector<std::vector<T> > grown;
1643 for (std::size_t c = 0; c < contents.size(); ++c)
1644 for (
int b = 0; b <= 1; ++b) {
1645 std::vector<T> row = contents[c];
1647 grown.push_back(row);
1649 contents.swap(grown);
1657 std::vector<std::size_t> rcl, rci, rco;
1660 const long maxpend =
1662 std::vector<std::vector<T> > grown;
1663 for (std::size_t c = 0; c < contents.size(); ++c) {
1666 std::vector<std::size_t> active;
1667 for (std::size_t j = 0; j < rcl.size(); ++j)
1669 active.push_back(j);
1670 std::vector<std::vector<long> > pend(1, std::vector<long>(rcl.size(), 0));
1671 for (std::size_t a = 0; a < active.size(); ++a) {
1672 std::vector<std::vector<long> > next;
1673 for (std::size_t q = 0; q < pend.size(); ++q) {
1675 for (std::size_t j = 0; j < rcl.size(); ++j) used += pend[q][j];
1676 for (
long v = 0; v + used <= maxpend; ++v) {
1677 std::vector<long> row = pend[q];
1679 next.push_back(row);
1684 for (std::size_t q = 0; q < pend.size(); ++q) {
1685 std::vector<T> row = contents[c];
1686 for (std::size_t j = 0; j < rcl.size(); ++j)
1688 grown.push_back(row);
1691 contents.swap(grown);
1694 std::vector<std::vector<T> > joint =
cartesian(acc, contents);
1706 std::vector<bool> is_hit(R,
false), is_miss(R,
false);
1707 for (std::size_t u = 0; u < cp.
hitclass.size(); ++u)
1709 for (std::size_t u = 0; u < cp.
missclass.size(); ++u)
1712 std::vector<std::vector<T> > kept;
1713 for (std::size_t row = 0; row < joint.size(); ++row) {
1714 const std::vector<T>& st = joint[row];
1715 double tot = 0, other = 0, miss = 0;
1716 for (std::size_t r = 0; r < R; ++r) {
1719 if (is_miss[r]) miss += v;
1720 else if (!is_hit[r]) other += v;
1725 if (!(tot <= 1 || (other == 0 && miss <= 1 && tot <= 1 + maxpend)))
continue;
1728 for (std::size_t i = 0; i < cp.
nitems && ok; ++i) {
1732 for (std::size_t c = 0; c < tcc; ++c)
1756 const std::vector<std::size_t>& s,
const std::vector<std::size_t>& phases) {
1757 if (ind == 0 || ind >
sn.nodes.size())
1758 throw InputError(
"from_marginal_node_and_started: node index " + std::to_string(ind) +
1759 " is out of range");
1763 "from_marginal_node_and_started cannot be used on Petri net elements");
1765 if (!nd.
stateful)
return std::vector<std::vector<T>>();
1800 const std::vector<std::size_t>& phases) {
1801 if (ind == 0 || ind >
sn.nodes.size())
1802 throw InputError(
"from_marg_node: node index " + std::to_string(ind) +
" is out of range");
1804 const std::size_t R =
sn.nclasses;
1807 std::vector<double> ccap(R, std::numeric_limits<double>::infinity());
1809 const std::vector<double>& row =
sn.classcap[nd.
station - 1];
1810 for (std::size_t r = 0; r < R && r < row.size(); ++r) ccap[r] = row[r];
1813 std::vector<std::vector<int>> nset;
1815 nset.push_back(std::vector<int>(R, 0));
1817 const std::vector<std::vector<int>> all =
1819 for (std::size_t j = 0; j < all.size(); ++j) {
1821 for (std::size_t r = 0; r < R && ok; ++r)
1822 if (
static_cast<double>(all[j][r]) > ccap[r]) ok =
false;
1823 if (ok) nset.push_back(all[j]);
1827 std::vector<std::vector<T>> space;
1828 std::size_t maxw = 0;
1829 std::vector<std::vector<std::vector<T>>> subspaces;
1830 for (std::size_t j = 0; j < nset.size(); ++j) {
1831 std::vector<std::size_t> nj(R, 0);
1832 for (std::size_t r = 0; r < R; ++r) nj[r] = static_cast<std::size_t>(nset[j][r]);
1834 if (sj.empty())
continue;
1835 for (std::size_t a = 0; a < sj.size(); ++a) maxw = std::max(maxw, sj[a].size());
1836 subspaces.push_back(sj);
1838 for (std::size_t j = 0; j < subspaces.size(); ++j)
1839 for (std::size_t a = 0; a < subspaces[j].size(); ++a) {
1840 std::vector<T> row = subspaces[j][a];
1841 if (row.size() < maxw)
1843 space.push_back(row);
1845 if (space.empty())
return space;
1847 std::sort(space.begin(), space.end());
1848 space.erase(std::unique(space.begin(), space.end()), space.end());
1849 std::reverse(space.begin(), space.end());
1853namespace state_detail {
1864inline std::vector<std::vector<std::size_t> > multichoosecon(
const std::vector<std::size_t>& n,
1866 const std::size_t R = n.size();
1867 std::vector<std::vector<std::size_t> > out;
1868 if (R == 0)
return out;
1870 out.push_back(std::vector<std::size_t>(R, 0));
1874 for (std::size_t i = 0; i < R; ++i)
1876 std::vector<std::size_t> row(R, 0);
1882 for (std::size_t i = 0; i < R; ++i) {
1883 if (n[i] == 0)
continue;
1884 std::vector<std::size_t> n1 = n;
1886 const std::vector<std::vector<std::size_t> > tail = multichoosecon(n1, S - 1);
1887 for (std::size_t k = 0; k < tail.size(); ++k) {
1888 std::vector<std::size_t> row = tail[k];
1920 std::size_t ntot, std::size_t stot,
1921 const std::vector<std::size_t>& phases) {
1922 if (ind == 0 || ind >
sn.nodes.size())
1923 throw InputError(
"from_marg_node_started: node index " + std::to_string(ind) +
1924 " is out of range");
1925 std::vector<std::vector<T>> space;
1926 if (stot > ntot)
return space;
1929 const std::size_t R =
sn.nclasses;
1931 std::vector<double> ccap(R, std::numeric_limits<double>::infinity());
1933 const std::vector<double>& row =
sn.classcap[nd.
station - 1];
1934 for (std::size_t r = 0; r < R && r < row.size(); ++r) ccap[r] = row[r];
1937 std::vector<std::vector<int>> nset;
1939 nset.push_back(std::vector<int>(R, 0));
1941 const std::vector<std::vector<int>> all =
1943 for (std::size_t j = 0; j < all.size(); ++j) {
1945 for (std::size_t r = 0; r < R && ok; ++r)
1946 if (
static_cast<double>(all[j][r]) > ccap[r]) ok =
false;
1947 if (ok) nset.push_back(all[j]);
1951 std::size_t maxw = 0;
1952 std::vector<std::vector<std::vector<T>>> subspaces;
1953 for (std::size_t j = 0; j < nset.size(); ++j) {
1954 std::vector<std::size_t> nj(R, 0);
1955 for (std::size_t r = 0; r < R; ++r) nj[r] = static_cast<std::size_t>(nset[j][r]);
1956 const std::vector<std::vector<std::size_t> > sset =
1957 state_detail::multichoosecon(nj, stot);
1958 for (std::size_t k = 0; k < sset.size(); ++k) {
1959 const std::vector<std::vector<T>> sjk =
1961 if (sjk.empty())
continue;
1962 for (std::size_t a = 0; a < sjk.size(); ++a) maxw = std::max(maxw, sjk[a].size());
1963 subspaces.push_back(sjk);
1966 for (std::size_t j = 0; j < subspaces.size(); ++j)
1967 for (std::size_t a = 0; a < subspaces[j].size(); ++a) {
1968 std::vector<T> row = subspaces[j][a];
1969 if (row.size() < maxw)
1971 space.push_back(row);
1973 if (space.empty())
return space;
1975 std::sort(space.begin(), space.end());
1976 space.erase(std::unique(space.begin(), space.end()), space.end());
1977 std::reverse(space.begin(), space.end());
2006 const std::vector<std::size_t>& n,
2007 const std::vector<std::size_t>& phases, std::vector<T>& out) {
2008 if (ind == 0 || ind >
sn.nodes.size())
2009 throw InputError(
"from_marginal_node_first: node index " + std::to_string(ind) +
2010 " is out of range");
2014 if (rows.empty())
return false;
2019 const std::size_t R =
sn.nclasses;
2021 throw InputError(
"from_marginal_node_first: n must have one entry per class");
2023 for (std::size_t r = 0; r < R; ++r) {
2027 if (n[r] > 0)
return false;
2030 out.insert(out.end(), sr[0].begin(), sr[0].end());
2033 const typename std::map<std::size_t, CacheParam<T> >::const_iterator ci =
2034 sn.nodeparam.find(ind);
2035 if (ci ==
sn.nodeparam.end())
return true;
2037 std::size_t tcc = 0;
2038 for (std::size_t u = 0; u < cp.
itemcap.size(); ++u)
2039 if (cp.
itemcap[u] > 0) tcc +=
static_cast<std::size_t
>(cp.
itemcap[u]);
2040 for (std::size_t slot = 0; slot < tcc; ++slot)
2042 tcc <= cp.
nitems ?
static_cast<long>(slot + 1) : 0L));
2045 std::vector<std::size_t> rcl, rci, rco;
2059 std::size_t M,
const std::vector<std::size_t>& N,
2060 const std::vector<std::vector<long>>& caps = std::vector<std::vector<long>>()) {
2061 std::vector<std::vector<T>> ss;
2062 for (std::size_t r = 0; r < N.size(); ++r) {
2063 const std::vector<std::vector<T>> sr =
2066 if (sr.empty())
return std::vector<std::vector<T>>();
2086 std::size_t M,
const std::vector<std::size_t>& N,
2087 const std::vector<std::vector<bool>>& chains,
2088 const std::vector<std::vector<long>>& caps = std::vector<std::vector<long>>()) {
2089 const std::size_t C = chains.size();
2090 const std::size_t R = N.size();
2092 std::vector<std::vector<std::vector<int>>> chainInitPos(C);
2093 std::vector<std::size_t> inchain_sz(C, 0);
2094 for (std::size_t c = 0; c < C; ++c) {
2095 std::size_t tot = 0, k = 0;
2096 for (std::size_t r = 0; r < R; ++r)
2097 if (chains[c][r]) { tot += N[r]; ++k; }
2099 chainInitPos[c] = k == 0 ? std::vector<std::vector<int>>{std::vector<int>()}
2102 std::vector<std::vector<T>> ss;
2103 std::vector<std::size_t> v(C, 0);
2105 std::vector<std::size_t> subN;
2107 for (std::size_t c = 0; c < C; ++c) {
2108 const std::vector<int>& row = chainInitPos[c][v[c]];
2109 for (std::size_t j = 0; j < row.size(); ++j)
2110 subN.push_back(
static_cast<std::size_t
>(row[j]));
2116 std::vector<std::size_t> subNg(R, 0);
2119 for (std::size_t c = 0; c < C; ++c)
2120 for (std::size_t r = 0; r < R; ++r)
2121 if (chains[c][r]) subNg[r] = subN[k++];
2123 const std::vector<std::vector<T>> blk =
2126 ss.insert(ss.end(), blk.begin(), blk.end());
2129 for (; c < C; ++c) {
2130 if (++v[c] < chainInitPos[c].size())
break;
2155 if (ind == 0 || ind >
sn.nodes.size())
return 0;
2156 if (
sn.nodes[ind - 1].nodetype != NodeType::Place)
return 0;
2157 const typename std::map<std::size_t, std::vector<T>>::const_iterator it =
2158 sn.initmarking.find(ind);
2159 if (it ==
sn.initmarking.end() || r >= it->second.size())
return 0;
2161 return v > 0 ?
static_cast<std::size_t
>(v) : 0;
2192 const std::vector<std::vector<std::size_t>>& cutoff_mat =
2193 std::vector<std::vector<std::size_t>>()) {
2194 const std::size_t R =
sn.nclasses, N =
sn.nodes.size();
2195 std::vector<std::vector<std::size_t>> cap(N, std::vector<std::size_t>(R, 0));
2196 const std::vector<double> njobs =
sn.njobs();
2200 std::size_t maxpend = 0;
2201 for (std::size_t r = 0; r < R; ++r)
2202 if (!std::isfinite(njobs[r])) maxpend = std::max(maxpend, cutoff[r]);
2203 if (maxpend > 0) --maxpend;
2205 for (std::size_t ind = 1; ind <= N; ++ind) {
2208 const std::size_t ist = nd.
station;
2209 const std::size_t isf =
sn.stateful_index(ind);
2210 if (ist != 0 && nd.
nodetype != NodeType::Source) {
2211 for (std::size_t r = 0; r < R; ++r) {
2213 for (std::size_t cc = 0; cc <
sn.chains.size(); ++cc)
2214 if (r <
sn.chains[cc].size() &&
sn.chains[cc][r]) { c = cc;
break; }
2215 const bool novisit = c <
sn.visits.size() &&
sn.visits[c].rows() != 0 &&
2216 isf != 0 && isf - 1 <
sn.visits[c].rows() &&
2222 if (nd.
nodetype != NodeType::Place && ist - 1 <
sn.disabled.size() &&
2223 r <
sn.disabled[ist - 1].size() &&
sn.disabled[ist - 1][r]) {
2224 cap[ind - 1][r] = 0;
2228 if (!std::isfinite(njobs[r])) {
2233 b =
static_cast<double>(
2234 (!cutoff_mat.empty() && ist - 1 < cutoff_mat.size() &&
2235 r < cutoff_mat[ist - 1].size())
2236 ? cutoff_mat[ist - 1][r]
2240 for (std::size_t k = 0; k < R; ++k)
2241 if (c <
sn.chains.size() && k <
sn.chains[c].size() &&
sn.chains[c][k] &&
2242 std::isfinite(njobs[k]))
2245 if (ist - 1 <
sn.classcap.size() && r <
sn.classcap[ist - 1].size())
2246 b = std::min(b,
sn.classcap[ist - 1][r]);
2248 for (std::size_t f = 0; f <
sn.regions.size(); ++f) {
2250 if (ist - 1 >= rg.
cap.size())
continue;
2251 if (r < rg.
cap[ist - 1].size() && rg.
cap[ist - 1][r] >= 0)
2252 b = std::min(b, rg.
cap[ist - 1][r]);
2253 if (R < rg.
cap[ist - 1].size() && rg.
cap[ist - 1][R] >= 0)
2254 b = std::min(b, rg.
cap[ist - 1][R]);
2256 if (!(b > 0)) b = 0;
2257 cap[ind - 1][r] = std::isfinite(b) ?
static_cast<std::size_t
>(b)
2258 :
static_cast<std::size_t
>(-1);
2263 case NodeType::Cache: {
2264 for (std::size_t r = 0; r < R; ++r) cap[ind - 1][r] = 1;
2265 const typename std::map<std::size_t, CacheParam<T>>::const_iterator ci =
2266 sn.nodeparam.find(ind);
2267 if (ci !=
sn.nodeparam.end() && ci->second.retrieval_capacity > 0)
2268 for (std::size_t r = 0; r < R; ++r)
2269 for (std::size_t k = 0; k < ci->second.hitclass.size(); ++k)
2270 if (ci->second.hitclass[k] == r + 1) cap[ind - 1][r] = 1 + maxpend;
2273 case NodeType::Router:
2274 for (std::size_t r = 0; r < R; ++r) {
2276 for (std::size_t cc = 0; cc <
sn.chains.size(); ++cc)
2277 if (r <
sn.chains[cc].size() &&
sn.chains[cc][r]) { c = cc;
break; }
2279 (c <
sn.nodevisits.size() &&
sn.nodevisits[c].rows() != 0 &&
2280 ind - 1 <
sn.nodevisits[c].rows() &&
2289 for (std::size_t r = 0; r < R; ++r)
2290 cap[ind - 1][r] =
static_cast<std::size_t
>(-1);
2315 std::size_t maxst = 3000000,
2316 const std::vector<std::vector<std::size_t>>& cutoff_mat =
2317 std::vector<std::vector<std::size_t>>()) {
2318 const std::size_t R =
sn.nclasses;
2319 if (cutoff.size() != R)
2320 throw InputError(
"space_generator: cutoff must have one entry per class");
2330 const std::vector<double> njobs =
sn.njobs();
2331 std::vector<std::size_t> Np(R, 0);
2332 for (std::size_t r = 0; r < R; ++r) {
2333 const double nj = njobs[r];
2334 if (std::isfinite(nj)) {
2335 Np[r] =
static_cast<std::size_t
>(nj);
2339 "space_generator: class " + std::to_string(r) +
2340 " is open, so its population is unbounded; supply a cutoff for it");
2348 const std::vector<std::vector<std::size_t>> capc =
space_capacity_c(
sn, cutoff, cutoff_mat);
2349 const std::size_t unbounded =
static_cast<std::size_t
>(-1);
2350 for (std::size_t r = 0; r < R; ++r) {
2351 if (std::isfinite(njobs[r]))
continue;
2353 bool any_unbounded =
false;
2354 for (std::size_t ind = 1; ind <=
sn.nodes.size(); ++ind) {
2355 if (!
sn.nodes[ind - 1].stateful ||
sn.nodes[ind - 1].nodetype == NodeType::Source)
2357 if (capc[ind - 1][r] == unbounded) any_unbounded =
true;
2358 else hi = std::max(hi, capc[ind - 1][r]);
2360 if (!any_unbounded) Np[r] = std::min(Np[r], hi);
2363 std::vector<std::vector<bool>> chains =
sn.chains;
2364 if (chains.empty()) {
2365 chains.assign(R, std::vector<bool>(R,
false));
2366 for (std::size_t r = 0; r < R; ++r) chains[r][r] =
true;
2372 const std::vector<std::size_t>& sfn =
sn.stateful_nodes;
2373 const std::size_t NF = sfn.size();
2374 std::vector<std::size_t> lat_col(NF,
static_cast<std::size_t
>(-1));
2376 for (std::size_t k = 0; k < NF; ++k)
2377 if (
sn.nodes[sfn[k] - 1].nodetype != NodeType::Source) lat_col[k] = Mp++;
2385 std::vector<bool> is_open(R,
false);
2386 for (std::size_t r = 0; r < R; ++r)
2387 is_open[r] = !std::isfinite(njobs[r]);
2397 std::vector<std::vector<long>> lat_caps(R, std::vector<long>(Mp, -1));
2400 for (std::size_t k = 0; k < NF && ok; ++k) {
2401 if (lat_col[k] ==
static_cast<std::size_t
>(-1))
continue;
2402 const std::size_t ind = sfn[k];
2403 for (std::size_t r = 0; r < R; ++r) {
2404 const std::size_t cap = capc[ind - 1][r];
2405 lat_caps[r][lat_col[k]] =
2406 cap == unbounded ? -1 :
static_cast<long>(cap);
2409 if (!ok) lat_caps.clear();
2411 std::vector<std::vector<T>> pos;
2412 std::vector<std::size_t> nlev(R, 0);
2414 bool admissible =
true;
2415 for (std::size_t r = 0; r < R; ++r)
2416 if (!is_open[r] && nlev[r] != Np[r]) { admissible =
false;
break; }
2418 const std::vector<std::vector<T>> part =
2420 pos.insert(pos.end(), part.begin(), part.end());
2421 if (pos.size() > maxst)
2423 "space_generator: the population lattice exceeds the cap of " +
2424 std::to_string(maxst) +
" states; raise it or use another solver");
2428 for (; r < R; ++r) {
2429 if (nlev[r] < Np[r]) { ++nlev[r];
break; }
2436 std::sort(pos.begin(), pos.end());
2437 pos.erase(std::unique(pos.begin(), pos.end()), pos.end());
2445 std::vector<std::vector<std::vector<std::vector<T>>>> allper(pos.size());
2446 std::vector<bool> row_ok(pos.size(),
true);
2447 std::vector<std::size_t> maxw(NF, 0);
2448 std::vector<NetState<T>> out;
2449 for (std::size_t j = 0; j < pos.size(); ++j) {
2450 std::vector<std::vector<std::vector<T>>> per(NF);
2452 for (std::size_t k = 0; k < NF && ok; ++k) {
2453 const std::size_t ind = sfn[k];
2454 const std::size_t ist =
sn.nodes[ind - 1].station;
2455 std::vector<std::size_t> ph(R, 1), nmarg(R, 0);
2458 for (std::size_t r = 0; r < R; ++r) ph[r] =
sn.phasessz_of(ist, r + 1);
2459 if (lat_col[k] ==
static_cast<std::size_t
>(-1)) {
2469 for (std::size_t r = 0; r < R; ++r)
2470 if (!
sn.disabled[ist - 1][r]) nmarg[r] = 1;
2472 for (std::size_t r = 0; r < R; ++r)
2473 nmarg[r] =
static_cast<std::size_t
>(
2478 for (std::size_t r = 0; r < R && ok; ++r)
2479 if (capc[ind - 1][r] !=
static_cast<std::size_t
>(-1) &&
2480 nmarg[r] > capc[ind - 1][r])
2485 if (per[k].empty()) ok =
false;
2486 for (std::size_t b = 0; b < per[k].size(); ++b)
2487 maxw[k] = std::max(maxw[k], per[k][b].size());
2490 allper[j].swap(per);
2493 for (std::size_t j = 0; j < pos.size(); ++j) {
2494 if (!row_ok[j])
continue;
2495 std::vector<std::vector<std::vector<T>>>& per = allper[j];
2497 for (std::size_t k = 0; k < NF; ++k)
2498 for (std::size_t b = 0; b < per[k].size(); ++b)
2499 if (per[k][b].size() < maxw[k])
2500 per[k][b].insert(per[k][b].begin(), maxw[k] - per[k][b].size(),
2503 std::vector<NetState<T>> acc(1);
2504 for (std::size_t i = 0; i < NF; ++i) {
2505 std::vector<NetState<T>> next;
2506 for (std::size_t a = 0; a < acc.size(); ++a)
2507 for (std::size_t b = 0; b < per[i].size(); ++b) {
2509 ns.
local.push_back(per[i][b]);
2513 if (out.size() + acc.size() > maxst)
2515 "space_generator: the state space exceeds the cap of " +
2516 std::to_string(maxst) +
" states; raise it or use another solver");
2518 out.insert(out.end(), acc.begin(), acc.end());
2522 std::vector<std::vector<std::vector<T>>> seen;
2523 std::vector<NetState<T>> uniq;
2524 for (std::size_t i = 0; i < out.size(); ++i) {
2526 for (std::size_t p = 0; p < seen.size() && !dup; ++p)
2527 if (seen[p] == out[i].local) dup =
true;
2529 seen.push_back(out[i].local);
2530 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,...
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