5#ifndef LINE_LANG_QN_STATE_H
6#define LINE_LANG_QN_STATE_H
56 std::vector<std::vector<T>>
kir;
59namespace state_detail {
64 case SchedStrategy::SIRO:
65 case SchedStrategy::POLLING:
66 case SchedStrategy::SEPT:
67 case SchedStrategy::LEPT:
68 case SchedStrategy::SRPT:
69 case SchedStrategy::SRPTPRIO:
82 case SchedStrategy::FCFS:
83 case SchedStrategy::HOL:
84 case SchedStrategy::LCFS:
85 case SchedStrategy::LCFSPRIO:
103 case SchedStrategy::FCFSPI:
104 case SchedStrategy::FCFSPIPRIO:
105 case SchedStrategy::FCFSPR:
106 case SchedStrategy::FCFSPRPRIO:
107 case SchedStrategy::LCFSPI:
108 case SchedStrategy::LCFSPIPRIO:
109 case SchedStrategy::LCFSPR:
110 case SchedStrategy::LCFSPRPRIO:
132 const std::vector<T>& state_i,
const std::vector<std::size_t>& phasesz,
133 const std::vector<std::size_t>& phaseshift, std::size_t nvar = 0) {
134 const std::size_t R =
sn.nclasses;
135 if (ist == 0 || ist >
sn.stations.size())
136 throw InputError(
"to_marginal: station index " + std::to_string(ist) +
" is out of range");
140 m.
nir.assign(R, zero);
141 m.
sir.assign(R, zero);
142 std::size_t maxph = 1;
143 for (std::size_t r = 0; r < R; ++r) maxph = std::max(maxph, phasesz[r]);
144 m.
kir.assign(R, std::vector<T>(maxph, zero));
149 const std::size_t jnd =
sn.node_of_station(ist);
150 if (
sn.isfjaugmented && jnd != 0 &&
sn.nodes[jnd - 1].nodetype == NodeType::Join &&
151 state_i.size() >= R) {
152 for (std::size_t r = 0; r < R; ++r) m.
nir[r] = state_i[state_i.size() - R + r];
166 const bool ordered_list = (sched == SchedStrategy::PAS || sched == SchedStrategy::OI);
170 std::size_t srvw = 0;
171 for (std::size_t r = 0; r < R; ++r) srvw += phasesz[r];
172 if (!ordered_list && state_i.size() < nvar + srvw)
173 throw InputError(
"to_marginal: state row is narrower than the server block it declares");
174 const std::size_t srv0 = ordered_list ? 0 : state_i.size() - nvar - srvw;
175 const std::size_t bufw = srv0;
178 for (std::size_t r = 0; r < R; ++r) {
179 for (std::size_t k = 0; k < phasesz[r]; ++k) {
180 const T v = state_i[srv0 + phaseshift[r] + k];
187 if (sched == SchedStrategy::EXT) {
206 std::numeric_limits<double>::infinity());
207 for (std::size_t r = 0; r < R; ++r) m.
nir[r] = ext;
208 }
else if (sched == SchedStrategy::PAS || sched == SchedStrategy::OI) {
221 for (std::size_t r = 0; r < R; ++r) {
224 for (std::size_t k = 0; k < maxph; ++k) m.
kir[r][k] = zero;
226 const std::size_t w = state_i.size() > nvar ? state_i.size() - nvar : 0;
227 std::vector<std::size_t> clist;
228 for (std::size_t b = 0; b < w; ++b) {
230 if (tag >= 1 &&
static_cast<std::size_t
>(tag) <= R) {
232 clist.push_back(
static_cast<std::size_t
>(tag));
235 const typename std::map<std::size_t,
237 sn.pasparam.find(ist);
238 if (pit !=
sn.pasparam.end() && pit->second.svc_rate_fun) {
240 for (std::size_t p = 0; p < clist.size(); ++p) {
241 const std::vector<std::size_t> prefix(clist.begin(), clist.begin() + p + 1);
242 const T mucur = pit->second.svc_rate_fun(prefix);
254 for (std::size_t r = 0; r < R; ++r) m.
kir[r][0] = m.
nir[r];
256 }
else if (state_detail::buffer_is_class_tag(sched)) {
257 for (std::size_t r = 0; r < R; ++r) {
259 for (std::size_t b = 0; b < bufw; ++b)
261 m.
nir[r] = T(m.
sir[r] + waiting);
263 }
else if (state_detail::buffer_is_tag_phase_pairs(sched)) {
265 for (std::size_t r = 0; r < R; ++r) {
267 for (std::size_t b = 0; b < bufw; b += 2)
269 m.
nir[r] = T(m.
sir[r] + waiting);
274 }
else if (state_detail::buffer_is_per_class_count(sched)) {
275 for (std::size_t r = 0; r < R; ++r)
276 m.
nir[r] = bufw >= R ? T(m.
sir[r] + state_i[r]) : m.
sir[r];
287 if (
sn.stations[ist - 1].nodetype == NodeType::Place) {
289 case SchedStrategy::INF:
290 case SchedStrategy::PS:
291 case SchedStrategy::PSPRIO:
292 case SchedStrategy::DPS:
293 case SchedStrategy::DPSPRIO:
294 case SchedStrategy::GPS:
295 case SchedStrategy::GPSPRIO:
296 case SchedStrategy::LPS:
298 for (std::size_t r = 0; r < R; ++r) m.
nir[r] = T(m.
sir[r] + state_i[r]);
303 for (std::size_t r = 0; r < R; ++r)
304 if (
sn.disabled[ist - 1][r]) {
305 for (std::size_t k = 0; k < phasesz[r]; ++k) m.
kir[r][k] = zero;
309 for (std::size_t r = 0; r < R; ++r)
310 if (
sn.disabled[ist - 1][r]) {
312 for (std::size_t k = 0; k < phasesz[r]; ++k) m.
kir[r][k] = zero;
318 for (std::size_t r = 0; r < R; ++r) m.
ni += m.
nir[r];
332 const std::vector<std::vector<T>>& local) {
333 const std::size_t M =
sn.stations.size(), K =
sn.nclasses;
334 std::vector<double> n(M, 0.0);
335 for (std::size_t ist = 1; ist <= M; ++ist) {
336 const std::size_t isf =
sn.stateful_of_station(ist);
337 if (isf == 0 || isf > local.size())
continue;
338 if (
sn.stations[ist - 1].nodetype == NodeType::Source)
continue;
339 std::vector<std::size_t> ph(K, 1), shift(K, 0);
341 for (std::size_t k = 0; k < K; ++k) {
342 ph[k] =
sn.phasessz_of(ist, k + 1);
347 to_marginal(
sn, ist, local[isf - 1], ph, shift,
sn.nvars_of(
sn.node_of_station(ist)));
385 const std::size_t K =
sn.nclasses, I =
sn.nodes.size();
387 if (full.
rows() != I * K)
388 throw InputError(
"rt_state: the node-level routing has not been refreshed");
389 if (!
sn.has_rtfun_routing())
return sn.stoch_comp_stateful(full, K);
392 for (std::size_t ind = 1; ind <= I; ++ind) {
394 for (std::size_t r = 1; r <= K && r <= nd.
routing.size(); ++r) {
396 if (rs != RoutingStrategy::JSQ && rs != RoutingStrategy::SQ)
continue;
397 const std::size_t row = (ind - 1) * K + (r - 1);
398 std::vector<std::size_t> cand;
399 std::vector<double> n;
400 for (std::size_t jnd = 1; jnd <= I; ++jnd) {
402 const std::size_t ist =
sn.nodes[jnd - 1].station;
405 "node '" + nd.
name +
"' dispatches class '" +
sn.classes[r - 1].name +
"' by " +
407 "', which is not a station and so has no queue length to compare");
409 n.push_back(nst[ist - 1]);
411 for (std::size_t c = 0; c < I * K; ++c) full(row, c) = zero;
412 if (cand.empty())
continue;
413 const std::size_t m = cand.size();
414 std::vector<long> hits(m, 0);
416 if (rs == RoutingStrategy::JSQ) {
417 const double best = *std::min_element(n.begin(), n.end());
418 for (std::size_t i = 0; i < m; ++i)
425 const std::size_t d = std::max<std::size_t>(1, std::min<std::size_t>(dp > 0 ? dp : 2, m));
426 std::vector<std::size_t> tup(d, 0);
428 std::size_t win = tup[0];
429 for (std::size_t c = 1; c < d; ++c)
430 if (n[tup[c]] < n[win]) win = tup[c];
434 while (c < d && ++tup[c] == m) tup[c++] = 0;
438 for (std::size_t i = 0; i < m; ++i)
439 full(row, (cand[i] - 1) * K + (r - 1)) =
443 if (
sn.sdr.empty())
return sn.stoch_comp_stateful(full, K);
451 std::vector<double> p(I, 0.0);
452 for (std::size_t b = 1; b <
sn.sdr_nodes.branch.size(); ++b)
453 p[
sn.sdr_nodes.entryOf[b]] += Pb[b];
454 p[
sn.sdr_nodes.departure] += Ped;
456 for (std::size_t ind = 1; ind <= I; ++ind) {
458 for (std::size_t r = 1; r <= K && r <= nd.
routing.size(); ++r) {
459 if (nd.
routing[r - 1] != RoutingStrategy::SDR)
continue;
460 for (std::size_t jnd = 1; jnd <= I; ++jnd)
461 for (std::size_t s = 1; s <= K; ++s)
462 full((ind - 1) * K + (r - 1), (jnd - 1) * K + (s - 1)) =
466 return sn.stoch_comp_stateful(full, K);
477std::vector<std::vector<T>>
cartesian(
const std::vector<std::vector<T>>& a,
478 const std::vector<std::vector<T>>& b) {
479 if (a.empty())
return b;
480 if (b.empty())
return a;
481 std::vector<std::vector<T>> out;
482 out.reserve(a.size() * b.size());
483 for (std::size_t i = 0; i < a.size(); ++i)
484 for (std::size_t j = 0; j < b.size(); ++j) {
485 std::vector<T> row = a[i];
486 row.insert(row.end(), b[j].begin(), b[j].end());
500 std::vector<std::vector<T>> out;
501 if (m == 0)
return out;
502 const std::vector<std::vector<int>> rows =
504 out.reserve(rows.size());
505 for (std::size_t i = 0; i < rows.size(); ++i) {
507 r.reserve(rows[i].size());
508 for (std::size_t j = 0; j < rows[i].size(); ++j)
529 std::size_t off, std::vector<T>& row,
530 std::vector<std::vector<T>>& out) {
532 if (n == 0) out.push_back(row);
536 bool unbounded =
false;
537 for (std::size_t k = off; k < off + m && k < caps.size(); ++k) {
538 if (caps[k] < 0) { unbounded =
true;
break; }
541 if (!unbounded && n > room)
return;
542 const long here = off < caps.size() ? caps[off] : -1;
543 const long hi = here < 0 ? n : std::min<long>(n, here);
544 for (
long i = 0; i <= hi; ++i) {
554 const std::vector<long>& caps) {
555 std::vector<std::vector<T>> out;
556 if (m == 0)
return out;
582 const std::vector<std::size_t>& vec) {
583 std::vector<std::vector<std::size_t> > pu;
584 if (vec.empty())
return pu;
585 std::vector<std::size_t> uvec = vec;
586 std::sort(uvec.begin(), uvec.end());
587 uvec.erase(std::unique(uvec.begin(), uvec.end()), uvec.end());
588 if (uvec.size() == 1) {
592 if (uvec.size() == vec.size()) {
593 std::vector<std::size_t> p(vec.rbegin(), vec.rend());
596 }
while (std::prev_permutation(p.begin(), p.end()));
599 for (std::size_t i = 0; i < uvec.size(); ++i) {
600 std::vector<std::size_t> v = vec;
601 for (std::size_t j = 0; j < v.size(); ++j)
602 if (v[j] == uvec[i]) {
603 v.erase(v.begin() +
static_cast<std::ptrdiff_t
>(j));
607 for (std::size_t t = 0; t < tmp.size(); ++t) {
608 std::vector<std::size_t> row(1, uvec[i]);
609 row.insert(row.end(), tmp[t].begin(), tmp[t].end());
637 const std::vector<std::size_t>& n,
638 const std::vector<std::size_t>& phases) {
639 const std::size_t R =
sn.nclasses;
640 if (ist == 0 || ist >
sn.stations.size())
641 throw InputError(
"from_marginal: station index " + std::to_string(ist) +
" is out of range");
642 if (n.size() != R || phases.size() != R)
643 throw InputError(
"from_marginal: n and phases must have one entry per class");
653 for (std::size_t r = 0; r < R; ++r) {
655 if ((pt == ProcessType::MAP || pt == ProcessType::MMPP2) &&
656 sched != SchedStrategy::FCFS && st.
nodetype != NodeType::Source)
658 "from_marginal: a MAP/MMPP2 process at a non-FCFS station is not supported; "
659 "only the FCFS encoding carries the modulating phase");
670 bool is_retrial =
false;
672 const typename std::map<std::size_t, RetrialParam<T> >::const_iterator rit =
673 sn.retrialparam.find(ist);
674 if (rit !=
sn.retrialparam.end())
675 for (std::size_t r = 0; r < rit->second.retrial_proc.size(); ++r)
676 if (!rit->second.retrial_proc[r].disabled) { is_retrial =
true;
break; }
680 for (std::size_t r = 0; r < R; ++r)
681 if (n[r] > 0) { rr = r;
break; }
684 for (std::size_t r = 0; r < R; ++r) w += phases[r];
688 const std::size_t maxsrv =
689 std::isfinite(S) ? std::min(n[rr],
static_cast<std::size_t
>(S)) : n[rr];
690 const std::size_t maxorbit = n[rr];
691 std::vector<std::vector<T>> res3;
692 for (std::size_t csrv = 0; csrv <= maxsrv; ++csrv) {
693 const std::size_t orbit = n[rr] - csrv;
696 std::vector<std::vector<T>> srv3;
698 for (std::size_t cls = 0; cls < R; ++cls) {
699 const std::size_t want = cls == rr ? csrv : 0;
701 if (sc.empty() && want > 0) { ok3 =
false;
break; }
705 for (std::size_t i3 = 0; i3 < srv3.size(); ++i3) {
706 std::vector<T> row = buf;
707 row.insert(row.end(), srv3[i3].begin(), srv3[i3].end());
717 std::vector<std::vector<T>> out;
718 if (sched != SchedStrategy::EXT)
719 for (std::size_t r = 0; r < R; ++r)
723 if (
sn.classcap.size() >= ist && r <
sn.classcap[ist - 1].size() &&
724 static_cast<double>(n[r]) >
sn.classcap[ist - 1][r])
727 if (sched == SchedStrategy::PAS || sched == SchedStrategy::OI) {
746 const double W = ist <=
sn.cap.size() ?
sn.cap[ist - 1]
747 : std::numeric_limits<double>::infinity();
748 if (!std::isfinite(W))
750 "from_marginal: PAS stations require finite capacity for state-space generation");
751 const std::size_t w =
static_cast<std::size_t
>(W);
753 for (std::size_t r = 0; r < R; ++r) tot += n[r];
755 return std::vector<std::vector<T> >(
757 if (tot > w)
return out;
758 std::vector<std::size_t> vi;
759 for (std::size_t r = 0; r < R; ++r)
760 for (std::size_t j = 0; j < n[r]; ++j) vi.push_back(r + 1);
762 out.reserve(mi.size());
763 for (std::size_t i = 0; i < mi.size(); ++i) {
766 for (std::size_t j = 0; j < mi[i].size(); ++j)
788 for (std::size_t r = 0; r < R; ++r)
789 if (
sn.phases_of(ist, r + 1) == 0 && n[r] > 0)
792 if (state_detail::buffer_is_class_tag(sched) || state_detail::buffer_is_tag_phase_pairs(sched)) {
803 const bool paired = state_detail::buffer_is_tag_phase_pairs(sched);
804 std::vector<std::size_t> vi;
805 for (std::size_t r = 0; r < R; ++r)
806 for (std::size_t j = 0; j < n[r]; ++j) vi.push_back(r + 1);
808 const std::size_t nsrv =
809 std::isfinite(S) ?
static_cast<std::size_t
>(S) : vi.size();
814 const std::size_t bw = state_detail::buffer_is_tag_phase_pairs(sched) ? 2u : 1u;
816 std::size_t srvw2 = 0;
817 for (std::size_t r = 0; r < R; ++r) srvw2 += phases[r];
819 return std::vector<std::vector<T>>{row};
827 std::sort(vi.begin(), vi.end(), [](std::size_t a, std::size_t b) { return a > b; });
828 std::vector<std::vector<T>> res2;
829 const std::size_t insrv = std::min(nsrv, vi.size());
831 const auto emit_split = [&](
const std::vector<std::size_t>& wait,
const std::vector<std::size_t>& si) {
832 std::vector<std::vector<T>> kst;
833 for (std::size_t r = 0; r < R; ++r) {
835 if (sr.empty() && si[r] > 0)
return;
838 std::vector<std::vector<T>> bufs;
841 for (std::size_t j = 0; j < wait.size(); ++j)
845 }
else if (wait.empty()) {
850 bufs.push_back(std::vector<T>());
851 for (std::size_t j = 0; j < wait.size(); ++j) {
852 std::vector<std::vector<T>> next;
853 for (std::size_t b = 0; b < bufs.size(); ++b)
854 for (std::size_t p = 0; p < phases[wait[j] - 1]; ++p) {
855 std::vector<T> row = bufs[b];
863 for (std::size_t bi = 0; bi < bufs.size(); ++bi)
864 for (std::size_t i2 = 0; i2 < kst.size(); ++i2) {
865 std::vector<T> row = bufs[bi];
866 row.insert(row.end(), kst[i2].begin(), kst[i2].end());
870 if (sched == SchedStrategy::LCFSPRIO) {
878 std::vector<std::vector<std::size_t>> splits;
879 std::vector<std::size_t> cur(R, 0);
880 std::function<void(std::size_t, std::size_t)> rec = [&](std::size_t r, std::size_t left) {
882 if (left == 0) splits.push_back(cur);
885 for (std::size_t v = std::min(n[r], left) + 1; v-- > 0;) {
887 rec(r + 1, left - v);
892 std::vector<int> levels;
893 for (std::size_t r = 0; r < R; ++r)
894 if (n[r] > 0) levels.push_back(
sn.classes[r].prio);
895 std::sort(levels.begin(), levels.end(), std::greater<int>());
896 levels.erase(std::unique(levels.begin(), levels.end()), levels.end());
897 for (
const std::vector<std::size_t>& si : splits) {
898 std::vector<std::vector<std::size_t>> waits(1);
899 for (
int lev : levels) {
900 std::vector<std::size_t> grp;
901 for (std::size_t r = R; r-- > 0;)
902 if (
sn.classes[r].prio == lev)
903 for (std::size_t j = 0; j < n[r] - si[r]; ++j) grp.push_back(r + 1);
904 if (grp.empty())
continue;
905 std::vector<std::vector<std::size_t>> next;
907 for (
const std::vector<std::size_t>& w : waits) {
908 std::vector<std::size_t> w2 = w;
909 w2.insert(w2.end(), grp.begin(), grp.end());
912 }
while (std::prev_permutation(grp.begin(), grp.end()));
915 for (
const std::vector<std::size_t>& w : waits) emit_split(w, si);
923 if (!std::is_sorted(vi.end() -
static_cast<std::ptrdiff_t
>(insrv), vi.end(),
924 std::greater<std::size_t>()))
926 std::vector<std::size_t> si(R, 0);
927 for (std::size_t j = vi.size() - insrv; j < vi.size(); ++j) si[vi[j] - 1] += 1;
928 std::vector<std::size_t> wait;
929 for (std::size_t j = 0; j + insrv < vi.size(); ++j) wait.push_back(vi[j]);
930 emit_split(wait, si);
931 }
while (std::prev_permutation(vi.begin(), vi.end()));
935 if (!state_detail::buffer_is_per_class_count(sched)) {
938 std::vector<std::vector<T>> srv;
939 for (std::size_t r = 0; r < R; ++r)
983 if (sched == SchedStrategy::POLLING && S != 1.0)
985 "from_marginal: a polling station must have exactly one server; the controller "
986 "encoding pins the visit to a single class at a time, so a multi-server polling "
987 "station cannot be represented (the reference refuses it the same way)");
988 const std::size_t nsrv =
989 std::isfinite(S) ?
static_cast<std::size_t
>(S) :
static_cast<std::size_t
>(-1);
990 std::size_t ntot = 0;
991 for (std::size_t r = 0; r < R; ++r) ntot += n[r];
992 const std::size_t maxsrv = std::min(nsrv, ntot);
993 const std::size_t minsrv = sched == SchedStrategy::POLLING ? 0 : maxsrv;
995 std::vector<std::vector<T>> res;
996 std::vector<std::size_t> sv(R, 0);
998 std::size_t stot = 0;
999 for (std::size_t r = 0; r < R; ++r) stot += sv[r];
1000 if (stot >= minsrv && stot <= maxsrv) {
1001 std::vector<std::vector<T>> srv_s;
1003 for (std::size_t r = 0; r < R && ok; ++r) {
1005 if (sr.empty() && sv[r] > 0) ok =
false;
1010 for (std::size_t r = 0; r < R; ++r)
1012 for (std::size_t i = 0; i < srv_s.size(); ++i) {
1013 std::vector<T> row = buf;
1014 row.insert(row.end(), srv_s[i].begin(), srv_s[i].end());
1021 for (; r < R; ++r) {
1022 if (sv[r] < n[r]) { ++sv[r];
break; }
1052 const std::vector<std::size_t>& nbuf) {
1053 const std::size_t R = pi.
polled.size();
1054 std::vector<std::vector<long>> trips;
1057 if (!pi.
polled[srvclass - 1])
return std::vector<std::vector<T>>();
1058 std::vector<long> ctrset;
1061 ctrset.push_back(0);
1067 for (
long c = 1; c <= static_cast<long>(nbuf[srvclass - 1]) + 1; ++c)
1068 ctrset.push_back(c);
1071 for (
long c = 1; c <= static_cast<long>(pi.
pk); ++c) ctrset.push_back(c);
1075 for (
long c = 0; c <= static_cast<long>(nbuf[srvclass - 1]); ++c)
1076 ctrset.push_back(c);
1079 for (std::size_t i = 0; i < ctrset.size(); ++i)
1080 trips.push_back(std::vector<long>{static_cast<long>(srvclass), 0, ctrset[i]});
1083 for (std::size_t q = 1; q <= R; ++q) {
1084 if (!pi.
has_sw[q - 1])
continue;
1089 for (std::size_t k = 1; k <= pi.
ksw[q - 1]; ++k)
1090 trips.push_back(std::vector<long>{static_cast<long>(q), static_cast<long>(k), 0});
1092 std::size_t total = 0;
1093 for (std::size_t r = 0; r < nbuf.size(); ++r) total += nbuf[r];
1094 if (!anysw && total == 0) {
1095 std::size_t first = 0;
1096 for (std::size_t r = 1; r <= R; ++r)
1097 if (pi.
polled[r - 1]) { first = r;
break; }
1098 trips.push_back(std::vector<long>{
static_cast<long>(first), 0, 0});
1102 const std::size_t npos =
static_cast<std::size_t
>(-1);
1103 std::vector<std::vector<T>> out;
1104 for (std::size_t i = 0; i < trips.size(); ++i) {
1141 std::vector<std::vector<T>> rows,
1142 const std::vector<std::size_t>& n,
1143 const std::vector<std::size_t>& phases) {
1144 if (rows.empty())
return rows;
1145 const std::size_t ind =
sn.node_of_station(ist);
1148 if (ind == 0)
return rows;
1149 const std::size_t width =
sn.nvars_of(ind);
1150 if (width == 0)
return rows;
1152 const std::size_t R =
sn.nclasses;
1154 const std::size_t pw = pi.
valid ? pi.
width : 0;
1162 const bool bas = ind <=
sn.isbasblocking.size() &&
sn.isbasblocking[ind - 1];
1168 const bool brk =
sn.has_breakdown_node(ind);
1169 std::size_t ntot = 0;
1170 for (std::size_t r = 0; r < n.size(); ++r) ntot += n[r];
1175 std::size_t rrw = 0;
1176 if (ind <=
sn.nvars.size())
1177 for (std::size_t r = 0; r < R && R + r <
sn.nvars[ind - 1].size(); ++r)
1178 rrw +=
sn.nvars[ind - 1][R + r];
1179 std::vector<std::vector<T>> ptrsets(1, std::vector<T>());
1180 for (std::size_t r = 1; r <= R; ++r) {
1181 if (
sn.rr_var_slot(ind, r) == 0)
continue;
1182 std::vector<T> vals;
1183 if (
sn.nodes[ind - 1].routing[r - 1] == RoutingStrategy::RROBIN) {
1184 const std::vector<std::size_t> ol =
sn.rr_outlinks(ind, r);
1185 for (std::size_t d = 0; d < ol.size(); ++d)
1188 const std::vector<std::size_t> cy =
sn.rr_weighted_outlinks(ind, r);
1189 for (std::size_t d = 0; d < cy.size(); ++d)
1192 if (vals.empty()) vals.push_back(zero);
1193 std::vector<std::vector<T>> grown;
1194 for (std::size_t g = 0; g < ptrsets.size(); ++g)
1195 for (std::size_t v = 0; v < vals.size(); ++v) {
1196 std::vector<T> row = ptrsets[g];
1197 row.push_back(vals[v]);
1198 grown.push_back(row);
1200 ptrsets.swap(grown);
1203 std::vector<std::vector<T>> out;
1204 for (std::size_t i = 0; i < rows.size(); ++i) {
1207 std::vector<std::size_t> nbuf(R, 0);
1208 std::size_t srvclass = 0;
1210 std::size_t srvw = 0;
1211 for (std::size_t r = 0; r < R; ++r) srvw += phases[r];
1212 const std::size_t srv0 = rows[i].size() - srvw;
1213 std::size_t off = 0;
1214 for (std::size_t r = 0; r < R; ++r) {
1216 for (std::size_t k = 0; k < phases[r]; ++k)
1217 c +=
static_cast<std::size_t
>(
1220 if (c > 0 && srvclass == 0) srvclass = r + 1;
1223 if (srv0 >= R) nbuf[r] =
static_cast<std::size_t
>(
1227 const std::vector<std::vector<T>> blocks =
1229 : std::vector<std::vector<T>>(1, std::vector<T>());
1237 const std::size_t head = pi.
valid ? pi.
off : width - pw;
1238 for (std::size_t b = 0; b < blocks.size(); ++b) {
1239 for (std::size_t g = 0; g < ptrsets.size(); ++g) {
1240 std::vector<T> row = rows[i];
1241 row.insert(row.end(), head - rrw, zero);
1242 row.insert(row.end(), ptrsets[g].begin(), ptrsets[g].end());
1243 row.insert(row.end(), blocks[b].begin(), blocks[b].end());
1244 row.insert(row.end(), width - head - pw, zero);
1246 for (
long v = 1; v >= 0; --v) {
1247 std::vector<T> r2 = row;
1261 for (std::size_t v = 0; v <= (ntot > 0 ? 1u : 0u); ++v) {
1262 std::vector<T> r2 = row;
1273 std::size_t srvw = 0;
1274 for (std::size_t r = 0; r < R && r < phases.size(); ++r) srvw += phases[r];
1275 for (std::size_t r = 1; r <= R; ++r) {
1277 if (
mc ==
nullptr ||
sn.nvars[ind - 1][r - 1] == 0)
continue;
1278 const std::size_t slot =
sn.map_var_slot(ind, r);
1279 std::size_t off = 0;
1280 for (std::size_t j = 0; j + 1 < r; ++j) off += phases[j];
1281 std::vector<std::vector<T>> grown;
1282 grown.reserve(out.size() *
mc->p);
1283 for (std::size_t i = 0; i < out.size(); ++i) {
1284 const std::size_t srv0 = out[i].size() - width - srvw;
1285 std::size_t busy = 0;
1286 for (std::size_t k = 0;
mc->single && k < phases[r - 1] && busy == 0; ++k)
1288 for (std::size_t h = 1; h <=
mc->p; ++h) {
1289 if (busy != 0 && h != busy)
continue;
1290 std::vector<T> row = out[i];
1292 grown.push_back(row);
1300namespace state_detail {
1308void pool_allocations(
const CtmcPool<T>& pool,
const std::vector<std::size_t>& n, std::size_t r,
1309 std::size_t k, std::vector<std::vector<std::size_t>>& x,
1310 std::vector<double>& load,
1311 std::vector<std::vector<std::vector<std::size_t>>>& out) {
1312 const std::size_t R = n.size();
1314 for (std::size_t s = 0; s < R; ++s) {
1315 if (pool.pools[s].empty())
continue;
1316 std::size_t ins = 0;
1317 for (std::size_t j = 0; j < x[s].size(); ++j) ins += x[s][j];
1318 if (n[s] <= ins)
continue;
1319 for (std::size_t j = 0; j < pool.pools[s].size(); ++j) {
1320 const std::size_t t = pool.pools[s][j];
1321 if (load[t - 1] < pool.count[t - 1])
return;
1327 if (pool.pools[r].empty() || k == pool.pools[r].size()) {
1328 pool_allocations(pool, n, r + 1, 0, x, load, out);
1331 const std::size_t t = pool.pools[r][k];
1332 std::size_t used = 0;
1333 for (std::size_t j = 0; j < k; ++j) used += x[r][j];
1334 const double room = pool.count[t - 1] - load[t - 1];
1335 const std::size_t cmax = std::min<std::size_t>(
1336 n[r] - used, room > 0 ?
static_cast<std::size_t
>(room + 0.5) : 0);
1337 for (std::size_t c = 0; c <= cmax; ++c) {
1339 load[t - 1] +=
static_cast<double>(c);
1340 pool_allocations(pool, n, r, k + 1, x, load, out);
1341 load[t - 1] -=
static_cast<double>(c);
1359 const std::vector<std::size_t>& n) {
1360 const std::size_t R =
sn.nclasses;
1361 const std::size_t ind =
sn.node_of_station(ist);
1364 std::vector<std::vector<T>> space;
1365 if (
sn.nvars_of(ind) != (pool.
rotate ? 1u : 0u))
1367 "' carries local variables that a heterogeneous server pool "
1369 std::size_t ntot = 0;
1370 for (std::size_t r = 0; r < R; ++r) {
1372 if (
sn.classcap.size() >= ist && r <
sn.classcap[ist - 1].size() &&
1373 static_cast<double>(n[r]) >
sn.classcap[ist - 1][r])
1375 if (pool.
pools[r].empty() && n[r] > 0)
return space;
1377 const double cap =
sn.cap[ist - 1];
1378 if (
static_cast<double>(ntot) > cap)
return space;
1379 const bool siro =
sn.stations[ist - 1].sched == SchedStrategy::SIRO;
1380 const std::size_t W =
1382 : std::max<std::size_t>(1, std::isfinite(cap) ? std::min<std::size_t>(
1383 ntot,
static_cast<std::size_t
>(cap))
1385 std::vector<std::vector<std::size_t>> x(R);
1386 for (std::size_t r = 0; r < R; ++r) x[r].assign(pool.
pools[r].size(), 0);
1387 std::vector<double> load(pool.
ntypes, 0.0);
1388 std::vector<std::vector<std::vector<std::size_t>>> alloc;
1389 state_detail::pool_allocations(pool, n, 0, 0, x, load, alloc);
1390 for (std::size_t a = 0; a < alloc.size(); ++a) {
1391 std::vector<std::size_t> w = n;
1392 for (std::size_t r = 0; r < R; ++r)
1393 for (std::size_t k = 0; k < alloc[a][r].size(); ++k) w[r] -= alloc[a][r][k];
1395 std::vector<std::vector<T>> srvset;
1397 for (std::size_t r = 0; r < R && ok; ++r) {
1398 const std::size_t Kr =
sn.phasessz_of(ist, r + 1);
1399 std::vector<std::vector<T>> blk;
1400 if (pool.
pools[r].empty()) {
1401 blk.push_back(std::vector<T>(Kr, zero));
1403 for (std::size_t k = 0; k < pool.
pools[r].size(); ++k) {
1404 const std::vector<std::vector<T>> sc =
1406 if (sc.empty()) { ok =
false;
break; }
1409 for (std::size_t b = 0; b < blk.
size(); ++b)
1410 if (blk[b].size() < Kr) blk[b].resize(Kr, zero);
1416 std::vector<std::vector<T>> bufset;
1418 std::vector<T> b(R, zero);
1419 for (std::size_t r = 0; r < R; ++r) b[r] = num_traits<T>::from_int(
static_cast<long>(w[r]));
1420 bufset.push_back(b);
1422 std::vector<std::size_t> vi;
1423 for (std::size_t r = 0; r < R; ++r) vi.insert(vi.end(), w[r], r + 1);
1424 if (vi.size() > W)
continue;
1426 std::vector<T> b(W - vi.size(), zero);
1427 for (std::size_t j = 0; j < vi.size(); ++j)
1429 bufset.push_back(b);
1430 }
while (std::next_permutation(vi.begin(), vi.end()));
1432 const std::vector<std::vector<T>> part =
cartesian(bufset, srvset);
1433 space.insert(space.end(), part.begin(), part.end());
1436 std::vector<std::vector<T>> ords;
1437 for (std::size_t p = 1; p <= pool.
perms.size(); ++p)
1441 const auto less = [](
const std::vector<T>& a,
const std::vector<T>& b) {
1442 for (std::size_t i = 0; i < a.size() && i < b.size(); ++i) {
1444 if (av != bv)
return av > bv;
1446 return a.size() < b.size();
1448 const auto same = [](
const std::vector<T>& a,
const std::vector<T>& b) {
1449 if (a.size() != b.size())
return false;
1450 for (std::size_t i = 0; i < a.size(); ++i)
1454 std::sort(space.begin(), space.end(), less);
1455 space.erase(std::unique(space.begin(), space.end(), same), space.end());
1461 const std::vector<std::size_t>& n,
1462 const std::vector<std::size_t>& phases) {
1463 const std::size_t jnd0 =
sn.node_of_station(ist);
1465 if (jnd0 != 0 && !
sn.ctmcpool.empty() &&
sn.ctmcpool.count(jnd0))
1470 if (
sn.isfjaugmented && jnd0 != 0 &&
sn.nodes[jnd0 - 1].nodetype == NodeType::Join) {
1472 for (std::size_t r = 0; r <
sn.nclasses && r < n.size(); ++r)
1474 return std::vector<std::vector<T>>(1, row);
1487 if (jnd0 != 0 &&
sn.replyblock.size() >= jnd0) {
1488 std::vector<std::size_t> rclasses;
1489 for (std::size_t r = 0; r <
sn.replyblock[jnd0 - 1].size(); ++r)
1490 if (
sn.replyblock[jnd0 - 1][r]) rclasses.push_back(r + 1);
1491 if (!rclasses.empty()) {
1492 const double Sd =
sn.stations[ist - 1].nservers;
1493 const std::size_t S =
1494 std::isfinite(Sd) ?
static_cast<std::size_t
>(Sd) :
static_cast<std::size_t
>(0);
1499 if (snb.
nvars.size() >= jnd0)
1500 for (std::size_t r = 1; r <=
sn.nclasses && 2 *
sn.nclasses + r < snb.
nvars[jnd0 - 1].size();
1502 snb.
nvars[jnd0 - 1][2 *
sn.nclasses + r] = 0;
1503 std::vector<std::vector<std::size_t>> bspace(1, std::vector<std::size_t>());
1504 for (std::size_t i = 0; i < rclasses.size(); ++i) {
1505 std::vector<std::vector<std::size_t>> next;
1506 for (std::size_t j = 0; j < bspace.size(); ++j)
1507 for (std::size_t v = 0; v <= S; ++v) {
1508 std::vector<std::size_t> row = bspace[j];
1510 next.push_back(row);
1514 std::vector<std::vector<std::vector<T>>> subs(bspace.size());
1515 std::size_t maxw = 0;
1516 for (std::size_t bi = 0; bi < bspace.size(); ++bi) {
1517 std::size_t tot = 0;
1518 for (std::size_t i = 0; i < bspace[bi].size(); ++i) tot += bspace[bi][i];
1519 if (tot > S)
continue;
1520 snb.
stations[ist - 1].nservers =
static_cast<double>(S - tot);
1522 for (std::size_t i = 0; i < subs[bi].size(); ++i)
1523 maxw = std::max(maxw, subs[bi][i].size());
1528 std::vector<std::vector<T>> out;
1529 for (std::size_t bi = 0; bi < bspace.size(); ++bi) {
1530 for (std::size_t i = 0; i < subs[bi].size(); ++i) {
1532 row.reserve(maxw + bspace[bi].size());
1533 if (subs[bi][i].size() < maxw)
1535 row.insert(row.end(), subs[bi][i].begin(), subs[bi][i].end());
1536 for (std::size_t j = 0; j < bspace[bi].size(); ++j)
1541 std::sort(out.begin(), out.end(), [](
const std::vector<T>& a,
const std::vector<T>& b) {
1542 for (std::size_t i = 0; i < a.size() && i < b.size(); ++i) {
1543 const double av = num_traits<T>::to_double(a[i]);
1544 const double bv = num_traits<T>::to_double(b[i]);
1545 if (av != bv) return av < bv;
1547 return a.size() < b.size();
1549 out.erase(std::unique(out.begin(), out.end(),
1550 [](
const std::vector<T>& a,
const std::vector<T>& b) {
1551 if (a.size() != b.size()) return false;
1552 for (std::size_t i = 0; i < a.size(); ++i)
1553 if (num_traits<T>::to_double(a[i]) !=
1554 num_traits<T>::to_double(b[i]))
1606 const std::vector<std::size_t>& n,
1607 const std::vector<std::size_t>& s,
1608 const std::vector<std::size_t>& phases) {
1609 const std::size_t R =
sn.nclasses;
1610 if (ist == 0 || ist >
sn.stations.size())
1611 throw InputError(
"from_marginal_and_started: station index " + std::to_string(ist) +
1612 " is out of range");
1613 if (n.size() != R || s.size() != R || phases.size() != R)
1614 throw InputError(
"from_marginal_and_started: n, s and phases must have one entry per class");
1618 std::vector<std::vector<T>> out;
1620 std::size_t ntot = 0, stot = 0;
1621 for (std::size_t r = 0; r < R; ++r) {
1622 if (s[r] > n[r])
return out;
1629 if (ist <=
sn.classcap.size())
1630 for (std::size_t r = 0; r < R && r <
sn.classcap[ist - 1].size(); ++r)
1631 if (
static_cast<double>(n[r]) >
sn.classcap[ist - 1][r])
return out;
1633 if (S > 0.0 && std::isfinite(S) &&
static_cast<double>(stot) > S)
return out;
1636 if (sched == SchedStrategy::PAS || sched == SchedStrategy::OI)
1642 if (sched == SchedStrategy::EXT || st.
nodetype == NodeType::Source) {
1649 std::vector<std::vector<T>> srv;
1650 for (std::size_t r = 0; r < R; ++r) {
1651 if (phases[r] == 0)
continue;
1656 if (r <
sn.classes.size() && std::isinf(
sn.classes[r].population) &&
1657 !
sn.disabled[ist - 1][r] &&
sn.markidx_of(ist, r + 1) <= 1)
1659 srv =
cartesian(srv, std::vector<std::vector<T>>(1, init));
1661 if (srv.empty()) srv.push_back(std::vector<T>());
1662 for (std::size_t i = 0; i < srv.size(); ++i) {
1664 std::numeric_limits<double>::infinity()));
1665 row.insert(row.end(), srv[i].begin(), srv[i].end());
1672 const auto phase_one_block = [&](
const std::vector<std::size_t>& cnt,
1673 bool* ok) -> std::vector<T> {
1676 for (std::size_t r = 0; r < R; ++r) {
1681 if (
sn.phases_of(ist, r + 1) == 0 && cnt[r] > 0) *ok =
false;
1682 if (phases[r] == 0)
continue;
1688 std::size_t srvw = 0;
1689 for (std::size_t r = 0; r < R; ++r) srvw += phases[r];
1691 if (state_detail::buffer_is_per_class_count(sched)) {
1695 const bool all_in_service = std::isfinite(S) &&
static_cast<double>(ntot) <= S;
1696 std::vector<std::size_t> insrv(R, 0), wait(R, 0);
1697 for (std::size_t r = 0; r < R; ++r) {
1698 insrv[r] = all_in_service ? n[r] : s[r];
1699 wait[r] = n[r] - insrv[r];
1702 const std::vector<T> blk = phase_one_block(insrv, &ok);
1703 if (!ok)
return out;
1705 for (std::size_t r = 0; r < R; ++r)
1707 row.insert(row.end(), blk.begin(), blk.end());
1712 const bool paired = state_detail::buffer_is_tag_phase_pairs(sched);
1713 if (state_detail::buffer_is_class_tag(sched) || paired) {
1719 const std::size_t bw = paired ? 2u : 1u;
1725 std::vector<std::size_t> inbuf;
1726 for (std::size_t r = 0; r < R; ++r)
1727 for (std::size_t j = 0; j < n[r] - s[r]; ++j) inbuf.push_back(r + 1);
1730 std::sort(inbuf.begin(), inbuf.end(),
1731 [](std::size_t a, std::size_t b) { return a > b; });
1732 if (sched == SchedStrategy::LCFSPRIO) {
1735 std::stable_sort(inbuf.begin(), inbuf.end(), [&](std::size_t a, std::size_t b) {
1736 return sn.classes[a - 1].prio > sn.classes[b - 1].prio;
1741 const std::vector<T> blk = phase_one_block(s, &ok);
1742 if (!ok)
return out;
1745 if (inbuf.empty()) {
1748 for (std::size_t j = 0; j < inbuf.size(); ++j) {
1754 static_cast<long>(phases[inbuf[j] - 1])));
1757 row.insert(row.end(), blk.begin(), blk.end());
1765 const std::vector<T> blk = phase_one_block(n, &ok);
1766 if (!ok)
return out;
1779 const std::vector<std::size_t>& n,
1780 const std::vector<std::size_t>& s,
1781 const std::vector<std::size_t>& phases) {
1782 const std::size_t jnd0 =
sn.node_of_station(ist);
1783 if (
sn.isfjaugmented && jnd0 != 0 &&
sn.nodes[jnd0 - 1].nodetype == NodeType::Join) {
1785 for (std::size_t r = 0; r <
sn.nclasses && r < n.size(); ++r)
1787 return std::vector<std::vector<T>>(1, row);
1833 const std::vector<std::size_t>& n,
1834 const std::vector<std::size_t>& s,
1835 const std::vector<std::size_t>& phases) {
1836 const std::size_t R =
sn.nclasses;
1837 if (ist == 0 || ist >
sn.stations.size())
1838 throw InputError(
"from_marginal_and_running: station index " + std::to_string(ist) +
1839 " is out of range");
1840 if (n.size() != R || s.size() != R || phases.size() != R)
1841 throw InputError(
"from_marginal_and_running: n, s and phases must have one entry per class");
1845 std::vector<std::vector<T>> out;
1847 std::size_t ntot = 0, stot = 0, srvw = 0;
1848 for (std::size_t r = 0; r < R; ++r) {
1849 if (s[r] > n[r])
return out;
1854 if (ist <=
sn.classcap.size())
1855 for (std::size_t r = 0; r < R && r <
sn.classcap[ist - 1].size(); ++r)
1856 if (
static_cast<double>(n[r]) >
sn.classcap[ist - 1][r])
return out;
1858 if (S > 0.0 &&
static_cast<double>(stot) > S)
return out;
1863 const auto server_block = [&](
const std::vector<std::size_t>& cnt,
1864 std::vector<std::vector<T>>* blk) ->
bool {
1866 for (std::size_t r = 0; r < R; ++r) {
1869 if (cnt[r] > 0)
return false;
1876 const auto finish = [](std::vector<std::vector<T>> rows) {
1877 const auto greater = [](
const std::vector<T>& a,
const std::vector<T>& b) {
1878 for (std::size_t i = 0; i < a.size() && i < b.size(); ++i) {
1881 if (av != bv)
return av > bv;
1883 return a.size() > b.size();
1885 const auto same = [](
const std::vector<T>& a,
const std::vector<T>& b) {
1886 if (a.size() != b.size())
return false;
1887 for (std::size_t i = 0; i < a.size(); ++i)
1891 std::sort(rows.begin(), rows.end(), greater);
1892 rows.erase(std::unique(rows.begin(), rows.end(), same), rows.end());
1898 if (sched == SchedStrategy::EXT || st.
nodetype == NodeType::Source) {
1900 for (std::size_t r = 0; r < R; ++r) {
1901 if (phases[r] == 0)
continue;
1902 std::vector<T> init(phases[r], zero);
1903 if (r <
sn.classes.size() && std::isinf(
sn.classes[r].population) &&
1904 !
sn.disabled[ist - 1][r] &&
sn.markidx_of(ist, r + 1) <= 1)
1906 row.insert(row.end(), init.begin(), init.end());
1913 case SchedStrategy::INF:
1914 case SchedStrategy::PS:
1915 case SchedStrategy::DPS:
1916 case SchedStrategy::GPS:
1917 case SchedStrategy::PSPRIO:
1918 case SchedStrategy::DPSPRIO:
1919 case SchedStrategy::GPSPRIO:
1920 case SchedStrategy::LPS: {
1921 std::vector<std::vector<T>> blk;
1922 if (!server_block(n, &blk))
return out;
1925 case SchedStrategy::SIRO:
1926 case SchedStrategy::SEPT:
1927 case SchedStrategy::LEPT:
1928 case SchedStrategy::SRPT:
1929 case SchedStrategy::SRPTPRIO:
1930 case SchedStrategy::SETF:
1931 case SchedStrategy::FSP: {
1933 const bool all_in_service =
static_cast<double>(ntot) <= S;
1934 std::vector<std::vector<T>> blk;
1935 if (!server_block(all_in_service ? n : s, &blk))
return out;
1936 std::vector<T> buf(R, zero);
1937 if (!all_in_service)
1938 for (std::size_t r = 0; r < R; ++r)
1940 for (std::size_t i = 0; i < blk.
size(); ++i) {
1941 std::vector<T> row = buf;
1942 row.insert(row.end(), blk[i].begin(), blk[i].end());
1951 const bool paired = state_detail::buffer_is_tag_phase_pairs(sched) || sched == SchedStrategy::EDF;
1952 if (!(paired || state_detail::buffer_is_class_tag(sched) || sched == SchedStrategy::EDD))
1958 out.push_back(std::vector<T>((paired ? 2u : 1u) + srvw, zero));
1961 std::vector<std::vector<T>> kstate;
1962 if (!server_block(s, &kstate))
return out;
1964 std::vector<std::size_t> w(R, 0), inbuf;
1965 for (std::size_t r = 0; r < R; ++r) {
1967 inbuf.insert(inbuf.end(), w[r], r + 1);
1973 std::vector<std::vector<std::size_t>> bufs;
1974 if (inbuf.empty()) {
1975 bufs.push_back(std::vector<std::size_t>(1, 0));
1976 }
else if (sched == SchedStrategy::LCFSPRIO) {
1977 std::vector<int> levels;
1978 for (std::size_t r = 0; r < R; ++r)
1979 if (w[r] > 0) levels.push_back(
sn.classes[r].prio);
1980 std::sort(levels.begin(), levels.end(), std::greater<int>());
1981 levels.erase(std::unique(levels.begin(), levels.end()), levels.end());
1982 bufs.push_back(std::vector<std::size_t>());
1983 for (
int lev : levels) {
1984 std::vector<std::size_t> grp;
1985 for (std::size_t r = 0; r < R; ++r)
1986 if (
sn.classes[r].prio == lev) grp.insert(grp.end(), w[r], r + 1);
1987 std::vector<std::vector<std::size_t>> next;
1989 for (
const std::vector<std::size_t>& b : bufs) {
1990 std::vector<std::size_t> b2 = b;
1991 b2.insert(b2.end(), grp.begin(), grp.end());
1994 }
while (std::next_permutation(grp.begin(), grp.end()));
1998 std::vector<std::size_t> p = inbuf;
2001 }
while (std::next_permutation(p.begin(), p.end()));
2004 for (
const std::vector<std::size_t>& b : bufs) {
2005 std::vector<std::vector<T>> brows(1, std::vector<T>());
2006 for (std::size_t j = 0; j < b.size(); ++j) {
2007 std::vector<std::vector<T>> next;
2008 const std::size_t np = (paired && b[j] > 0) ? phases[b[j] - 1] : 1;
2009 for (
const std::vector<T>& br : brows)
2010 for (std::size_t p = 1; p <= np; ++p) {
2011 std::vector<T> row = br;
2017 next.push_back(row);
2021 for (
const std::vector<T>& br : brows) {
2022 if (kstate.empty()) out.push_back(br);
2023 for (
const std::vector<T>& ks : kstate) {
2024 std::vector<T> row = br;
2025 row.insert(row.end(), ks.begin(), ks.end());
2045 const std::vector<std::size_t>& n,
2046 const std::vector<std::size_t>& phases) {
2047 if (ind == 0 || ind >
sn.nodes.size())
2048 throw InputError(
"from_marginal_node: node index " + std::to_string(ind) +
2049 " is out of range");
2052 if (!nd.
stateful)
return std::vector<std::vector<T>>();
2054 const std::size_t R =
sn.nclasses;
2056 throw InputError(
"from_marginal_node: n must have one entry per class");
2058 if (nd.
nodetype == NodeType::Transition) {
2064 const typename std::map<std::size_t, TransitionParam<T> >::const_iterator it =
2065 sn.transparam.find(ind);
2066 if (it ==
sn.transparam.end())
2068 "from_marginal_node: transition node has no TransitionParam; build it with "
2072 for (std::size_t mm = 0; mm < tp.
nmodes; ++mm) {
2077 std::size_t fph = 0;
2078 for (std::size_t mm = 0; mm < tp.
nmodes; ++mm)
2082 return std::vector<std::vector<T> >{row};
2095 if (nd.
nodetype == NodeType::Cache) {
2096 const typename std::map<std::size_t, CacheParam<T> >::const_iterator cc =
2097 sn.nodeparam.find(ind);
2098 if (cc !=
sn.nodeparam.end()) {
2099 const std::size_t pend =
2100 cc->second.retrieval_capacity > 0 && cc->second.max_pending_retrieval > 0
2101 ?
static_cast<std::size_t
>(cc->second.max_pending_retrieval)
2103 std::size_t tot = 0;
2104 for (std::size_t r = 0; r < R; ++r) {
2105 bool is_hit =
false;
2106 for (std::size_t u = 0; u < cc->second.hitclass.size(); ++u)
2107 if (cc->second.hitclass[u] == r + 1) is_hit =
true;
2108 if (n[r] > (is_hit ? 1 + pend : 1))
return std::vector<std::vector<T> >();
2111 if (tot > 1 + pend)
return std::vector<std::vector<T> >();
2118 std::vector<std::vector<T> > acc;
2119 for (std::size_t r = 0; r < R; ++r) {
2121 if (sr.empty() && n[r] > 0)
return std::vector<std::vector<T> >();
2134 std::vector<std::vector<T> > ptrsets(1, std::vector<T>());
2136 for (std::size_t r = 1; r <= R; ++r) {
2137 if (
sn.rr_var_slot(ind, r) == 0)
continue;
2139 std::vector<T> vals;
2140 if (
sn.nodes[ind - 1].routing[r - 1] == RoutingStrategy::RROBIN) {
2141 const std::vector<std::size_t> ol =
sn.rr_outlinks(ind, r);
2142 for (std::size_t u = 0; u < ol.size(); ++u)
2145 const std::vector<std::size_t> cy =
sn.rr_weighted_outlinks(ind, r);
2146 for (std::size_t u = 0; u < cy.size(); ++u)
2150 std::vector<std::vector<T> > grown;
2151 for (std::size_t g = 0; g < ptrsets.size(); ++g)
2152 for (std::size_t v = 0; v < vals.size(); ++v) {
2153 std::vector<T> row = ptrsets[g];
2154 row.push_back(vals[v]);
2155 grown.push_back(row);
2157 ptrsets.swap(grown);
2182 if (nd.
nodetype == NodeType::Cache) {
2183 const typename std::map<std::size_t, CacheParam<T> >::const_iterator ci =
2184 sn.nodeparam.find(ind);
2185 if (ci ==
sn.nodeparam.end())
return acc;
2187 std::size_t tcc = 0;
2188 for (std::size_t u = 0; u < cp.
itemcap.size(); ++u)
2189 if (cp.
itemcap[u] > 0) tcc +=
static_cast<std::size_t
>(cp.
itemcap[u]);
2191 const std::size_t first_item = tcc <= cp.
nitems ? 1 : 0;
2192 std::vector<std::vector<T> > contents(1, std::vector<T>());
2193 for (std::size_t slot = 0; slot < tcc; ++slot) {
2194 std::vector<std::vector<T> > grown;
2195 for (std::size_t c = 0; c < contents.size(); ++c)
2196 for (std::size_t item = first_item; item <= cp.
nitems; ++item) {
2199 for (std::size_t j = 0; j < contents[c].size(); ++j)
2201 static_cast<double>(item)) { dup =
true;
break; }
2203 std::vector<T> row = contents[c];
2205 grown.push_back(row);
2207 contents.swap(grown);
2212 for (std::size_t i = 0; i < cp.
nitems; ++i) {
2213 std::vector<std::vector<T> > grown;
2214 for (std::size_t c = 0; c < contents.size(); ++c)
2215 for (
int b = 0; b <= 1; ++b) {
2216 std::vector<T> row = contents[c];
2218 grown.push_back(row);
2220 contents.swap(grown);
2228 std::vector<std::size_t> rcl, rci, rco;
2231 const long maxpend =
2233 std::vector<std::vector<T> > grown;
2234 for (std::size_t c = 0; c < contents.size(); ++c) {
2237 std::vector<std::size_t> active;
2238 for (std::size_t j = 0; j < rcl.size(); ++j)
2240 active.push_back(j);
2241 std::vector<std::vector<long> > pend(1, std::vector<long>(rcl.size(), 0));
2242 for (std::size_t a = 0; a < active.size(); ++a) {
2243 std::vector<std::vector<long> > next;
2244 for (std::size_t q = 0; q < pend.size(); ++q) {
2246 for (std::size_t j = 0; j < rcl.size(); ++j) used += pend[q][j];
2247 for (
long v = 0; v + used <= maxpend; ++v) {
2248 std::vector<long> row = pend[q];
2250 next.push_back(row);
2255 for (std::size_t q = 0; q < pend.size(); ++q) {
2256 std::vector<T> row = contents[c];
2257 for (std::size_t j = 0; j < rcl.size(); ++j)
2259 grown.push_back(row);
2262 contents.swap(grown);
2265 std::vector<std::vector<T> > joint =
cartesian(acc, contents);
2277 std::vector<bool> is_hit(R,
false), is_miss(R,
false);
2278 for (std::size_t u = 0; u < cp.
hitclass.size(); ++u)
2280 for (std::size_t u = 0; u < cp.
missclass.size(); ++u)
2283 std::vector<std::vector<T> > kept;
2284 for (std::size_t row = 0; row < joint.size(); ++row) {
2285 const std::vector<T>& st = joint[row];
2286 double tot = 0, other = 0, miss = 0;
2287 for (std::size_t r = 0; r < R; ++r) {
2290 if (is_miss[r]) miss += v;
2291 else if (!is_hit[r]) other += v;
2296 if (!(tot <= 1 || (other == 0 && miss <= 1 && tot <= 1 + maxpend)))
continue;
2299 for (std::size_t i = 0; i < cp.
nitems && ok; ++i) {
2303 for (std::size_t c = 0; c < tcc; ++c)
2327 const std::vector<std::size_t>& s,
const std::vector<std::size_t>& phases) {
2328 if (ind == 0 || ind >
sn.nodes.size())
2329 throw InputError(
"from_marginal_node_and_started: node index " + std::to_string(ind) +
2330 " is out of range");
2334 "from_marginal_node_and_started cannot be used on Petri net elements");
2336 if (!nd.
stateful)
return std::vector<std::vector<T>>();
2352 const std::vector<std::size_t>& s,
const std::vector<std::size_t>& phases) {
2353 if (ind == 0 || ind >
sn.nodes.size())
2354 throw InputError(
"from_marginal_node_and_running: node index " + std::to_string(ind) +
2355 " is out of range");
2359 "from_marginal_node_and_running cannot be used on Petri net elements");
2361 throw InputError(
"from_marginal_node_and_running: node " + std::to_string(ind) +
2362 " is not a station");
2394 const std::vector<std::size_t>& phases) {
2395 if (ind == 0 || ind >
sn.nodes.size())
2396 throw InputError(
"from_marg_node: node index " + std::to_string(ind) +
" is out of range");
2398 const std::size_t R =
sn.nclasses;
2401 std::vector<double> ccap(R, std::numeric_limits<double>::infinity());
2403 const std::vector<double>& row =
sn.classcap[nd.
station - 1];
2404 for (std::size_t r = 0; r < R && r < row.size(); ++r) ccap[r] = row[r];
2407 std::vector<std::vector<int>> nset;
2409 nset.push_back(std::vector<int>(R, 0));
2411 const std::vector<std::vector<int>> all =
2413 for (std::size_t j = 0; j < all.size(); ++j) {
2415 for (std::size_t r = 0; r < R && ok; ++r)
2416 if (
static_cast<double>(all[j][r]) > ccap[r]) ok =
false;
2417 if (ok) nset.push_back(all[j]);
2421 std::vector<std::vector<T>> space;
2422 std::size_t maxw = 0;
2423 std::vector<std::vector<std::vector<T>>> subspaces;
2424 for (std::size_t j = 0; j < nset.size(); ++j) {
2425 std::vector<std::size_t> nj(R, 0);
2426 for (std::size_t r = 0; r < R; ++r) nj[r] = static_cast<std::size_t>(nset[j][r]);
2428 if (sj.empty())
continue;
2429 for (std::size_t a = 0; a < sj.size(); ++a) maxw = std::max(maxw, sj[a].size());
2430 subspaces.push_back(sj);
2432 for (std::size_t j = 0; j < subspaces.size(); ++j)
2433 for (std::size_t a = 0; a < subspaces[j].size(); ++a) {
2434 std::vector<T> row = subspaces[j][a];
2435 if (row.size() < maxw)
2437 space.push_back(row);
2439 if (space.empty())
return space;
2441 std::sort(space.begin(), space.end());
2442 space.erase(std::unique(space.begin(), space.end()), space.end());
2443 std::reverse(space.begin(), space.end());
2447namespace state_detail {
2458inline std::vector<std::vector<std::size_t> > multichoosecon(
const std::vector<std::size_t>& n,
2460 const std::size_t R = n.size();
2461 std::vector<std::vector<std::size_t> > out;
2462 if (R == 0)
return out;
2464 out.push_back(std::vector<std::size_t>(R, 0));
2468 for (std::size_t i = 0; i < R; ++i)
2470 std::vector<std::size_t> row(R, 0);
2476 for (std::size_t i = 0; i < R; ++i) {
2477 if (n[i] == 0)
continue;
2478 std::vector<std::size_t> n1 = n;
2480 const std::vector<std::vector<std::size_t> > tail = multichoosecon(n1, S - 1);
2481 for (std::size_t k = 0; k < tail.size(); ++k) {
2482 std::vector<std::size_t> row = tail[k];
2514 std::size_t ntot, std::size_t stot,
2515 const std::vector<std::size_t>& phases) {
2516 if (ind == 0 || ind >
sn.nodes.size())
2517 throw InputError(
"from_marg_node_started: node index " + std::to_string(ind) +
2518 " is out of range");
2519 std::vector<std::vector<T>> space;
2520 if (stot > ntot)
return space;
2523 const std::size_t R =
sn.nclasses;
2525 std::vector<double> ccap(R, std::numeric_limits<double>::infinity());
2527 const std::vector<double>& row =
sn.classcap[nd.
station - 1];
2528 for (std::size_t r = 0; r < R && r < row.size(); ++r) ccap[r] = row[r];
2531 std::vector<std::vector<int>> nset;
2533 nset.push_back(std::vector<int>(R, 0));
2535 const std::vector<std::vector<int>> all =
2537 for (std::size_t j = 0; j < all.size(); ++j) {
2539 for (std::size_t r = 0; r < R && ok; ++r)
2540 if (
static_cast<double>(all[j][r]) > ccap[r]) ok =
false;
2541 if (ok) nset.push_back(all[j]);
2545 std::size_t maxw = 0;
2546 std::vector<std::vector<std::vector<T>>> subspaces;
2547 for (std::size_t j = 0; j < nset.size(); ++j) {
2548 std::vector<std::size_t> nj(R, 0);
2549 for (std::size_t r = 0; r < R; ++r) nj[r] = static_cast<std::size_t>(nset[j][r]);
2550 const std::vector<std::vector<std::size_t> > sset =
2551 state_detail::multichoosecon(nj, stot);
2552 for (std::size_t k = 0; k < sset.size(); ++k) {
2553 const std::vector<std::vector<T>> sjk =
2555 if (sjk.empty())
continue;
2556 for (std::size_t a = 0; a < sjk.size(); ++a) maxw = std::max(maxw, sjk[a].size());
2557 subspaces.push_back(sjk);
2560 for (std::size_t j = 0; j < subspaces.size(); ++j)
2561 for (std::size_t a = 0; a < subspaces[j].size(); ++a) {
2562 std::vector<T> row = subspaces[j][a];
2563 if (row.size() < maxw)
2565 space.push_back(row);
2567 if (space.empty())
return space;
2569 std::sort(space.begin(), space.end());
2570 space.erase(std::unique(space.begin(), space.end()), space.end());
2571 std::reverse(space.begin(), space.end());
2600 const std::vector<std::size_t>& n,
2601 const std::vector<std::size_t>& phases, std::vector<T>& out) {
2602 if (ind == 0 || ind >
sn.nodes.size())
2603 throw InputError(
"from_marginal_node_first: node index " + std::to_string(ind) +
2604 " is out of range");
2608 if (rows.empty())
return false;
2613 const std::size_t R =
sn.nclasses;
2615 throw InputError(
"from_marginal_node_first: n must have one entry per class");
2617 for (std::size_t r = 0; r < R; ++r) {
2621 if (n[r] > 0)
return false;
2624 out.insert(out.end(), sr[0].begin(), sr[0].end());
2627 const typename std::map<std::size_t, CacheParam<T> >::const_iterator ci =
2628 sn.nodeparam.find(ind);
2629 if (ci ==
sn.nodeparam.end())
return true;
2631 std::size_t tcc = 0;
2632 for (std::size_t u = 0; u < cp.
itemcap.size(); ++u)
2633 if (cp.
itemcap[u] > 0) tcc +=
static_cast<std::size_t
>(cp.
itemcap[u]);
2634 for (std::size_t slot = 0; slot < tcc; ++slot)
2636 tcc <= cp.
nitems ?
static_cast<long>(slot + 1) : 0L));
2639 std::vector<std::size_t> rcl, rci, rco;
2653 std::size_t M,
const std::vector<std::size_t>& N,
2654 const std::vector<std::vector<long>>& caps = std::vector<std::vector<long>>()) {
2655 std::vector<std::vector<T>> ss;
2656 for (std::size_t r = 0; r < N.size(); ++r) {
2657 const std::vector<std::vector<T>> sr =
2660 if (sr.empty())
return std::vector<std::vector<T>>();
2680 std::size_t M,
const std::vector<std::size_t>& N,
2681 const std::vector<std::vector<bool>>& chains,
2682 const std::vector<std::vector<long>>& caps = std::vector<std::vector<long>>()) {
2683 const std::size_t C = chains.size();
2684 const std::size_t R = N.size();
2686 std::vector<std::vector<std::vector<int>>> chainInitPos(C);
2687 std::vector<std::size_t> inchain_sz(C, 0);
2688 for (std::size_t c = 0; c < C; ++c) {
2689 std::size_t tot = 0, k = 0;
2690 for (std::size_t r = 0; r < R; ++r)
2691 if (chains[c][r]) { tot += N[r]; ++k; }
2693 chainInitPos[c] = k == 0 ? std::vector<std::vector<int>>{std::vector<int>()}
2696 std::vector<std::vector<T>> ss;
2697 std::vector<std::size_t> v(C, 0);
2699 std::vector<std::size_t> subN;
2701 for (std::size_t c = 0; c < C; ++c) {
2702 const std::vector<int>& row = chainInitPos[c][v[c]];
2703 for (std::size_t j = 0; j < row.size(); ++j)
2704 subN.push_back(
static_cast<std::size_t
>(row[j]));
2710 std::vector<std::size_t> subNg(R, 0);
2713 for (std::size_t c = 0; c < C; ++c)
2714 for (std::size_t r = 0; r < R; ++r)
2715 if (chains[c][r]) subNg[r] = subN[k++];
2717 const std::vector<std::vector<T>> blk =
2720 ss.insert(ss.end(), blk.begin(), blk.end());
2723 for (; c < C; ++c) {
2724 if (++v[c] < chainInitPos[c].size())
break;
2749 if (ind == 0 || ind >
sn.nodes.size())
return 0;
2750 if (
sn.nodes[ind - 1].nodetype != NodeType::Place)
return 0;
2751 const typename std::map<std::size_t, std::vector<T>>::const_iterator it =
2752 sn.initmarking.find(ind);
2753 if (it ==
sn.initmarking.end() || r >= it->second.size())
return 0;
2755 return v > 0 ?
static_cast<std::size_t
>(v) : 0;
2786 const std::vector<std::vector<std::size_t>>& cutoff_mat =
2787 std::vector<std::vector<std::size_t>>()) {
2788 const std::size_t R =
sn.nclasses, N =
sn.nodes.size();
2789 std::vector<std::vector<std::size_t>> cap(N, std::vector<std::size_t>(R, 0));
2790 const std::vector<double> njobs =
sn.njobs();
2794 std::size_t maxpend = 0;
2795 for (std::size_t r = 0; r < R; ++r)
2796 if (!std::isfinite(njobs[r])) maxpend = std::max(maxpend, cutoff[r]);
2797 if (maxpend > 0) --maxpend;
2799 for (std::size_t ind = 1; ind <= N; ++ind) {
2802 const std::size_t ist = nd.
station;
2803 const std::size_t isf =
sn.stateful_index(ind);
2804 if (ist != 0 && nd.
nodetype != NodeType::Source) {
2805 for (std::size_t r = 0; r < R; ++r) {
2807 for (std::size_t cc = 0; cc <
sn.chains.size(); ++cc)
2808 if (r <
sn.chains[cc].size() &&
sn.chains[cc][r]) { c = cc;
break; }
2809 const bool novisit = c <
sn.visits.size() &&
sn.visits[c].rows() != 0 &&
2810 isf != 0 && isf - 1 <
sn.visits[c].rows() &&
2816 if (nd.
nodetype != NodeType::Place && ist - 1 <
sn.disabled.size() &&
2817 r <
sn.disabled[ist - 1].size() &&
sn.disabled[ist - 1][r]) {
2818 cap[ind - 1][r] = 0;
2822 if (!std::isfinite(njobs[r])) {
2827 b =
static_cast<double>(
2828 (!cutoff_mat.empty() && ist - 1 < cutoff_mat.size() &&
2829 r < cutoff_mat[ist - 1].size())
2830 ? cutoff_mat[ist - 1][r]
2834 for (std::size_t k = 0; k < R; ++k)
2835 if (c <
sn.chains.size() && k <
sn.chains[c].size() &&
sn.chains[c][k] &&
2836 std::isfinite(njobs[k]))
2839 if (ist - 1 <
sn.classcap.size() && r <
sn.classcap[ist - 1].size())
2840 b = std::min(b,
sn.classcap[ist - 1][r]);
2842 for (std::size_t f = 0; f <
sn.regions.size(); ++f) {
2844 if (ist - 1 >= rg.
cap.size())
continue;
2845 if (r < rg.
cap[ist - 1].size() && rg.
cap[ist - 1][r] >= 0)
2846 b = std::min(b, rg.
cap[ist - 1][r]);
2847 if (R < rg.
cap[ist - 1].size() && rg.
cap[ist - 1][R] >= 0)
2848 b = std::min(b, rg.
cap[ist - 1][R]);
2850 if (!(b > 0)) b = 0;
2851 cap[ind - 1][r] = std::isfinite(b) ?
static_cast<std::size_t
>(b)
2852 :
static_cast<std::size_t
>(-1);
2857 case NodeType::Cache: {
2858 for (std::size_t r = 0; r < R; ++r) cap[ind - 1][r] = 1;
2859 const typename std::map<std::size_t, CacheParam<T>>::const_iterator ci =
2860 sn.nodeparam.find(ind);
2861 if (ci !=
sn.nodeparam.end() && ci->second.retrieval_capacity > 0)
2862 for (std::size_t r = 0; r < R; ++r)
2863 for (std::size_t k = 0; k < ci->second.hitclass.size(); ++k)
2864 if (ci->second.hitclass[k] == r + 1) cap[ind - 1][r] = 1 + maxpend;
2867 case NodeType::Router:
2868 for (std::size_t r = 0; r < R; ++r) {
2870 for (std::size_t cc = 0; cc <
sn.chains.size(); ++cc)
2871 if (r <
sn.chains[cc].size() &&
sn.chains[cc][r]) { c = cc;
break; }
2873 (c <
sn.nodevisits.size() &&
sn.nodevisits[c].rows() != 0 &&
2874 ind - 1 <
sn.nodevisits[c].rows() &&
2883 for (std::size_t r = 0; r < R; ++r)
2884 cap[ind - 1][r] =
static_cast<std::size_t
>(-1);
2909 std::size_t maxst = 3000000,
2910 const std::vector<std::vector<std::size_t>>& cutoff_mat =
2911 std::vector<std::vector<std::size_t>>()) {
2912 const std::size_t R =
sn.nclasses;
2913 if (cutoff.size() != R)
2914 throw InputError(
"space_generator: cutoff must have one entry per class");
2924 const std::vector<double> njobs =
sn.njobs();
2925 std::vector<std::size_t> Np(R, 0);
2926 for (std::size_t r = 0; r < R; ++r) {
2927 const double nj = njobs[r];
2928 if (std::isfinite(nj)) {
2929 Np[r] =
static_cast<std::size_t
>(nj);
2933 "space_generator: class " + std::to_string(r) +
2934 " is open, so its population is unbounded; supply a cutoff for it");
2942 const std::vector<std::vector<std::size_t>> capc =
space_capacity_c(
sn, cutoff, cutoff_mat);
2943 const std::size_t unbounded =
static_cast<std::size_t
>(-1);
2944 for (std::size_t r = 0; r < R; ++r) {
2945 if (std::isfinite(njobs[r]))
continue;
2947 bool any_unbounded =
false;
2948 for (std::size_t ind = 1; ind <=
sn.nodes.size(); ++ind) {
2949 if (!
sn.nodes[ind - 1].stateful ||
sn.nodes[ind - 1].nodetype == NodeType::Source)
2951 if (capc[ind - 1][r] == unbounded) any_unbounded =
true;
2952 else hi = std::max(hi, capc[ind - 1][r]);
2954 if (!any_unbounded) Np[r] = std::min(Np[r], hi);
2957 std::vector<std::vector<bool>> chains =
sn.chains;
2958 if (chains.empty()) {
2959 chains.assign(R, std::vector<bool>(R,
false));
2960 for (std::size_t r = 0; r < R; ++r) chains[r][r] =
true;
2966 const std::vector<std::size_t>& sfn =
sn.stateful_nodes;
2967 const std::size_t NF = sfn.size();
2968 std::vector<std::size_t> lat_col(NF,
static_cast<std::size_t
>(-1));
2970 for (std::size_t k = 0; k < NF; ++k)
2971 if (
sn.nodes[sfn[k] - 1].nodetype != NodeType::Source) lat_col[k] = Mp++;
2979 std::vector<bool> is_open(R,
false);
2980 for (std::size_t r = 0; r < R; ++r)
2981 is_open[r] = !std::isfinite(njobs[r]);
2991 std::vector<std::vector<long>> lat_caps(R, std::vector<long>(Mp, -1));
2994 for (std::size_t k = 0; k < NF && ok; ++k) {
2995 if (lat_col[k] ==
static_cast<std::size_t
>(-1))
continue;
2996 const std::size_t ind = sfn[k];
2997 for (std::size_t r = 0; r < R; ++r) {
2998 const std::size_t cap = capc[ind - 1][r];
2999 lat_caps[r][lat_col[k]] =
3000 cap == unbounded ? -1 :
static_cast<long>(cap);
3003 if (!ok) lat_caps.clear();
3005 std::vector<std::vector<T>> pos;
3006 std::vector<std::size_t> nlev(R, 0);
3008 bool admissible =
true;
3009 for (std::size_t r = 0; r < R; ++r)
3010 if (!is_open[r] && nlev[r] != Np[r]) { admissible =
false;
break; }
3012 const std::vector<std::vector<T>> part =
3014 pos.insert(pos.end(), part.begin(), part.end());
3015 if (pos.size() > maxst)
3017 "space_generator: the population lattice exceeds the cap of " +
3018 std::to_string(maxst) +
" states; raise it or use another solver");
3022 for (; r < R; ++r) {
3023 if (nlev[r] < Np[r]) { ++nlev[r];
break; }
3030 std::sort(pos.begin(), pos.end());
3031 pos.erase(std::unique(pos.begin(), pos.end()), pos.end());
3039 std::vector<std::vector<std::vector<std::vector<T>>>> allper(pos.size());
3040 std::vector<bool> row_ok(pos.size(),
true);
3041 std::vector<std::size_t> maxw(NF, 0);
3042 std::vector<NetState<T>> out;
3043 for (std::size_t j = 0; j < pos.size(); ++j) {
3044 std::vector<std::vector<std::vector<T>>> per(NF);
3046 for (std::size_t k = 0; k < NF && ok; ++k) {
3047 const std::size_t ind = sfn[k];
3048 const std::size_t ist =
sn.nodes[ind - 1].station;
3049 std::vector<std::size_t> ph(R, 1), nmarg(R, 0);
3052 for (std::size_t r = 0; r < R; ++r) ph[r] =
sn.phasessz_of(ist, r + 1);
3053 if (lat_col[k] ==
static_cast<std::size_t
>(-1)) {
3063 for (std::size_t r = 0; r < R; ++r)
3064 if (!
sn.disabled[ist - 1][r]) nmarg[r] = 1;
3066 for (std::size_t r = 0; r < R; ++r)
3067 nmarg[r] =
static_cast<std::size_t
>(
3072 for (std::size_t r = 0; r < R && ok; ++r)
3073 if (capc[ind - 1][r] !=
static_cast<std::size_t
>(-1) &&
3074 nmarg[r] > capc[ind - 1][r])
3079 if (per[k].empty()) ok =
false;
3080 for (std::size_t b = 0; b < per[k].size(); ++b)
3081 maxw[k] = std::max(maxw[k], per[k][b].size());
3084 allper[j].swap(per);
3087 for (std::size_t j = 0; j < pos.size(); ++j) {
3088 if (!row_ok[j])
continue;
3089 std::vector<std::vector<std::vector<T>>>& per = allper[j];
3091 for (std::size_t k = 0; k < NF; ++k)
3092 for (std::size_t b = 0; b < per[k].size(); ++b)
3093 if (per[k][b].size() < maxw[k])
3094 per[k][b].insert(per[k][b].begin(), maxw[k] - per[k][b].size(),
3097 std::vector<NetState<T>> acc(1);
3098 for (std::size_t i = 0; i < NF; ++i) {
3099 std::vector<NetState<T>> next;
3100 for (std::size_t a = 0; a < acc.size(); ++a)
3101 for (std::size_t b = 0; b < per[i].size(); ++b) {
3103 ns.
local.push_back(per[i][b]);
3107 if (out.size() + acc.size() > maxst)
3109 "space_generator: the state space exceeds the cap of " +
3110 std::to_string(maxst) +
" states; raise it or use another solver");
3112 out.insert(out.end(), acc.begin(), acc.end());
3116 std::vector<std::vector<std::vector<T>>> seen;
3117 std::vector<NetState<T>> uniq;
3118 for (std::size_t i = 0; i < out.size(); ++i) {
3120 for (std::size_t p = 0; p < seen.size() && !dup; ++p)
3121 if (seen[p] == out[i].local) dup =
true;
3123 seen.push_back(out[i].local);
3124 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.
RoutingStrategy
Routing strategies, with the values of MATLAB RoutingStrategy.
@ 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_and_running(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.fromMarginalAndRunning: EVERY local state of station ist holding n[r] class-r jobs of w...
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< T > > from_marginal_node_and_running(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.fromMarginalAndRunning at its OWN signature, which indexes by NODE, as from_marginal_no...
const char * routing_to_text(RoutingStrategy r)
std::vector< std::vector< std::size_t > > space_capacity_c(const NetworkStruct< T > &sn, const std::vector< std::size_t > &cutoff, const std::vector< std::vector< std::size_t > > &cutoff_mat=std::vector< std::vector< std::size_t > >())
Port of the capacityc table of State.spaceGeneratorNodes: the largest class-r marginal node ind may h...
PollingInfo< T > polling_info(const NetworkStruct< T > &sn, std::size_t ind)
Matrix< T > rt_state(const NetworkStruct< T > &sn, const std::vector< std::vector< T > > &local)
Port of sn.rtfun: the routing over the stateful nodes AT ONE STATE.
std::vector< std::vector< std::size_t > > pas_multiset_perms(const std::vector< std::size_t > &vec)
Port of matlab/util/multiset_perms.m on an ASCENDING multiset, ROW ORDER INCLUDED.
std::vector< std::vector< T > > from_marginal_and_started(const NetworkStruct< T > &sn, std::size_t ist, const std::vector< std::size_t > &n, const std::vector< std::size_t > &s, const std::vector< std::size_t > &phases)
State.fromMarginalAndStarted with the trailing local-variable block appended, i.e.
std::vector< std::vector< T > > space_closed_multi_cs(std::size_t M, const std::vector< std::size_t > &N, const std::vector< std::vector< bool > > &chains, const std::vector< std::vector< long > > &caps=std::vector< std::vector< long > >())
Port of State.spaceClosedMultiCS: the same, but a CHAIN's population is shared among its classes,...
std::vector< std::vector< T > > append_local_vars(const NetworkStruct< T > &sn, std::size_t ist, std::vector< std::vector< T > > rows, const std::vector< std::size_t > &n, const std::vector< std::size_t > &phases)
Append the trailing local-variable block to every row the core builders produce, which is what makes ...
std::vector< std::vector< T > > space_closed_single_capped(std::size_t m, std::size_t n, const std::vector< long > &caps)
std::vector< std::vector< T > > space_closed_multi(std::size_t M, const std::vector< std::size_t > &N, const std::vector< std::vector< long > > &caps=std::vector< std::vector< long > >())
Port of State.spaceClosedMulti: how N[r] class-r jobs distribute over M stateful nodes,...
std::vector< std::vector< T > > from_marginal_pool(const NetworkStruct< T > &sn, std::size_t ist, const std::vector< std::size_t > &n)
Port of State.fromMarginalPool: the local states with marginal n at a station rewritten by ctmc::ctmc...
Conservation laws of a layered queueing network, enumerated from its structure.
A queueing network and its refreshed NetworkStruct.
Integer-composition enumeration shared by the CoMoM and MVAC ports.
State.pollingInfo and the controller description it returns.
The <kind> part of a LINE:<category>:<kind> identifier (see _kb/17-error-vocabulary....
Derived coefficients of an SDR structure, eqs.
The parameters of a Cache node, MATLAB's sn.nodeparam{ind} for a Cache.
int retrieval_capacity
Delayed-hit retrieval system (Cache.setRetrievalSystem).
long max_pending_retrieval
Truncation level of block B: how many secondary requests may be merged onto the in-flight fetches of ...
std::vector< int > itemcap
std::vector< std::size_t > missclass
std::vector< std::size_t > hitclass
CTMC pair form of a MAP service at an FCFS station, written by ctmc::ctmc_mapc on the solver's privat...
CTMC bookkeeping of a heterogeneous-server station, written by ctmc::ctmc_pools on the solver's priva...
std::vector< std::vector< std::size_t > > len
offset and length of block k of class r
std::vector< std::vector< std::size_t > > pools
pools[r-1]: compatible pools of r, ascending
bool rotate
ALIS/FAIRNESS order is part of the state.
std::vector< std::vector< std::size_t > > perms
every pool order, identity first
static constexpr double MaxInt
Stand-in for an unbounded COUNT, MATLAB GlobalConstants.MaxInt.
What State.toMarginal returns for one station and one state row.
std::vector< std::vector< T > > kir
jobs in service per class and phase
T ni
total jobs in the station
std::vector< T > nir
jobs per class
std::vector< T > sir
jobs in service per class
One network state: the per-stateful-node local rows it is composed of.
std::vector< std::vector< T > > local
local[isf] is that node's state row
The pass-and-swap / order-independent parameters of a PAS station, keyed by station index (Dorsman an...
FINITE CAPACITY REGIONS, MATLAB's refreshRegions output.
std::vector< std::vector< double > > cap
(nstations x nclasses+1), -1 = unbounded
std::vector< int > routing_param
The scalar parameter of a parameterized dispatcher, per class: the d of a power-of-d (SQ) choice.
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 Transition node: MATLAB sn.nodeparam{ind} for an SPN transition,...
std::vector< double > nmodeservers
servers per mode, may be infinite
std::vector< std::size_t > firingphases
phase count per mode, 0 when non-Markovian