5#ifndef LINE_LANG_QN_STATE_EVENTS_H
6#define LINE_LANG_QN_STATE_EVENTS_H
54 std::vector<std::vector<T>>
space;
62 std::vector<std::vector<std::size_t>>
start;
64 std::vector<std::vector<std::size_t>>
preempt;
76 if (out.
space.empty())
return;
79 if (start_cls) out.
start.back().push_back(start_cls);
80 if (preempt_cls) out.
preempt.back().push_back(preempt_cls);
111 const std::vector<T>& state_i) {
112 const std::size_t R =
sn.nclasses;
114 std::vector<T> nir(R, zero);
115 if (ind == 0 || ind >
sn.nodes.size())
116 throw InputError(
"to_marginal_aggr: node index is out of range");
118 const std::size_t ist = nd.
station;
119 const std::size_t nvar =
sn.nvars_of(ind);
125 if (
sn.isfjaugmented && nd.
nodetype == NodeType::Join && state_i.size() >= R) {
127 for (std::size_t r = 0; r < R; ++r) {
128 nir[r] = state_i[state_i.size() - R + r];
131 return std::make_pair(ni, nir);
138 const std::size_t bufw = state_i.size() > nvar ? state_i.size() - nvar : 0;
139 for (std::size_t r = 0; r < R && r < bufw; ++r) nir[r] = state_i[r];
141 for (std::size_t r = 0; r < R; ++r) ni += nir[r];
142 return std::make_pair(ni, nir);
148 if (nd.
nodetype == NodeType::Source)
return std::make_pair(zero, nir);
150 std::vector<std::size_t> K(R, 1), Ks(R, 0);
151 std::size_t srvw = 0;
152 for (std::size_t r = 0; r < R; ++r) {
153 K[r] =
sn.phasessz_of(ist, r + 1);
157 if (state_i.size() < nvar + srvw)
158 throw InputError(
"to_marginal_aggr: state row is narrower than its server block");
159 const std::size_t srv0 = state_i.size() - nvar - srvw;
161 for (std::size_t r = 0; r < R; ++r)
162 for (std::size_t k = 0; k < K[r]; ++k) nir[r] += state_i[srv0 + Ks[r] + k];
165 if (sched == SchedStrategy::EXT) {
173 std::numeric_limits<double>::infinity());
174 for (std::size_t r = 0; r < R; ++r) nir[r] = ext;
175 }
else if (state_detail::buffer_is_class_tag(sched)) {
176 for (std::size_t r = 0; r < R; ++r) {
178 for (std::size_t b = 0; b < srv0; ++b)
181 }
else if (state_detail::buffer_is_tag_phase_pairs(sched)) {
187 for (std::size_t r = 0; r < R; ++r) {
189 for (std::size_t b = 0; b < srv0; b += 2)
192 }
else if (state_detail::buffer_is_per_class_count(sched)) {
193 for (std::size_t r = 0; r < R && r < srv0; ++r) nir[r] += state_i[r];
194 }
else if (sched == SchedStrategy::PAS || sched == SchedStrategy::OI) {
208 for (std::size_t r = 0; r < R; ++r) nir[r] = zero;
209 const std::size_t w = state_i.size() > nvar ? state_i.size() - nvar : 0;
210 for (std::size_t b = 0; b < w; ++b) {
212 const long tag =
static_cast<long>(v + 0.5);
213 if (tag >= 1 &&
static_cast<std::size_t
>(tag) <= R)
221 for (std::size_t r = 0; r < R; ++r)
222 if (
sn.disabled[ist - 1][r]) nir[r] = zero;
225 for (std::size_t r = 0; r < R; ++r) ni += nir[r];
226 return std::make_pair(ni, nir);
246 if (
sn.droprule.size() < ist ||
sn.droprule[ist - 1].size() < cls)
return false;
248 return dr != DropStrategy::WAITQ &&
static_cast<int>(dr) != 0;
269 if (
sn.droprule.size() >= ist &&
sn.droprule[ist - 1].size() >= cls) {
271 if (dr == DropStrategy::BAS || dr == DropStrategy::BBS || dr == DropStrategy::RSRD)
281 if (
sn.isbasdestination.size() >= ist &&
sn.isbasdestination[ist - 1].size() >= cls &&
282 sn.isbasdestination[ist - 1][cls - 1])
286 const double nj =
sn.njobs()[cls - 1];
287 return !std::isfinite(nj);
293 std::vector<std::size_t>
K;
294 std::vector<std::size_t>
Ks;
302 const std::size_t R =
sn.nclasses;
303 const std::size_t ist =
sn.nodes[ind - 1].station;
307 for (std::size_t r = 0; r < R; ++r) {
308 L.
K[r] =
sn.phasessz_of(ist, r + 1);
312 L.
nvar =
sn.nvars_of(ind);
314 throw InputError(
"after_event_station: the state row is narrower than its server block");
331 const std::size_t nph =
sn.phases_of(ist, cls);
334 if (d.
D0.rows() == nph && d.
D1.rows() == nph && nph > 0 && !d.
disabled) {
340 }
catch (
const Error&) {
344 bool ok = pie.size() == nph;
347 for (std::size_t k = 0; k < nph; ++k) s += pie[k];
354 static_cast<long>(nph)));
355 for (std::size_t k = 0; k < nph; ++k) pie[k] = u;
371 std::size_t& pos, std::size_t& swk,
long& ctr);
374 std::size_t swk,
long ctr);
377 std::size_t R,
bool arrived, std::size_t& q,
int& mode,
long& budget);
380 std::size_t q,
int mode,
long budget,
const std::vector<T>& buf,
381 const std::vector<T>& srv,
const std::vector<T>& var,
const RowLayout<T>& L,
382 std::vector<std::vector<T>>& rows, std::vector<T>& probs);
395 const std::vector<T>& inspace,
EventType event,
415 const std::vector<T>& inspace, std::size_t cls) {
416 const std::size_t R =
sn.nclasses;
417 const std::size_t ist =
sn.nodes[ind - 1].station;
421 if (ist == 0)
throw InputError(
"after_event_station_arv: node is not a station");
425 if (sched == SchedStrategy::PAS || sched == SchedStrategy::OI)
434 if (
sn.nodes[ind - 1].nodetype == NodeType::Place) {
435 std::vector<T> row = inspace;
436 const double cap =
sn.classcap[ist - 1][cls - 1];
439 out.
space.push_back(row);
440 out.
rate.push_back(minus_one);
441 out.
prob.push_back(one);
444 out.
space.push_back(row);
445 out.
rate.push_back(minus_one);
446 out.
prob.push_back(zero);
454 const double cap_i =
sn.cap[ist - 1];
455 const double ccap =
sn.classcap[ist - 1][cls - 1];
456 const double S =
sn.stations[ist - 1].nservers;
459 for (std::size_t kentry = 0; kentry < L.
K[cls - 1]; ++kentry) {
460 std::vector<T> buf(inspace.begin(), inspace.begin() + L.
bufw);
461 std::vector<T> srv(inspace.begin() + L.
bufw, inspace.begin() + L.
bufw + L.
srvw);
462 std::vector<T> var(inspace.begin() + L.
bufw + L.
srvw, inspace.end());
463 std::vector<std::vector<T>> cand;
464 std::vector<T> cand_prob;
468 std::vector<std::size_t> cand_start, cand_preempt;
473 if (sched == SchedStrategy::EXT) {
476 if (!std::isfinite(
sn.njobs()[cls - 1])) {
477 out.
space.push_back(inspace);
478 out.
rate.push_back(zero);
479 out.
prob.push_back(one);
485 if (sched == SchedStrategy::PS || sched == SchedStrategy::INF ||
486 sched == SchedStrategy::DPS || sched == SchedStrategy::GPS ||
487 sched == SchedStrategy::PSPRIO || sched == SchedStrategy::DPSPRIO ||
488 sched == SchedStrategy::GPSPRIO || sched == SchedStrategy::LPS) {
490 const std::size_t col = L.
Ks[cls - 1] + kentry;
491 std::size_t started = 0;
495 cand_prob.push_back(pentry[kentry]);
497 cand_prob.push_back(zero);
499 std::vector<T> row = buf;
500 row.insert(row.end(), srv.begin(), srv.end());
501 row.insert(row.end(), var.begin(), var.end());
503 cand_start.push_back(started);
504 cand_preempt.push_back(0);
505 }
else if (sched == SchedStrategy::POLLING) {
513 std::size_t srvclass = 0;
514 for (std::size_t r = 1; r <= R; ++r) {
516 for (std::size_t p = 0; p < L.
K[r - 1]; ++p)
518 if (tot > 0) { srvclass = r;
break; }
520 std::size_t pos = 0, swk = 0;
523 if (srvclass == 0 && swk == 0) {
524 std::vector<long> nbuf(R, 0);
525 for (std::size_t r = 0; r < R && r < L.
bufw; ++r)
531 polling_next(pinfo, pos, nbuf, R,
true, q, mode, budget);
532 srv[L.
Ks[cls - 1] + kentry] += one;
534 cand_start.push_back(cls);
537 cand_start.push_back(0);
539 cand_preempt.push_back(0);
540 cand_prob.push_back(pentry[kentry]);
541 std::vector<T> row = buf;
542 row.insert(row.end(), srv.begin(), srv.end());
543 row.insert(row.end(), var.begin(), var.end());
545 }
else if (sched == SchedStrategy::SIRO || sched == SchedStrategy::SEPT ||
546 sched == SchedStrategy::LEPT) {
552 srv[L.
Ks[cls - 1] + kentry] += one;
553 cand_start.push_back(cls);
556 cand_start.push_back(0);
558 cand_preempt.push_back(0);
559 cand_prob.push_back(pentry[kentry]);
560 std::vector<T> row = buf;
561 row.insert(row.end(), srv.begin(), srv.end());
562 row.insert(row.end(), var.begin(), var.end());
564 }
else if (state_detail::buffer_is_class_tag(sched)) {
574 srv[L.
Ks[cls - 1] + kentry] += one;
575 std::vector<T> row = buf;
576 row.insert(row.end(), srv.begin(), srv.end());
577 row.insert(row.end(), var.begin(), var.end());
579 cand_prob.push_back(pentry[kentry]);
580 cand_start.push_back(cls);
581 cand_preempt.push_back(0);
583 std::size_t slot = 0;
584 for (std::size_t b = 0; b < L.
bufw; ++b)
591 ? (ni < cap_i && nir_c < ccap)
593 if (slot > 0 && has_room) {
595 std::vector<T> row = buf;
596 row.insert(row.end(), srv.begin(), srv.end());
597 row.insert(row.end(), var.begin(), var.end());
599 cand_prob.push_back(pentry[kentry]);
600 cand_start.push_back(0);
601 cand_preempt.push_back(0);
621 cand.push_back(inspace);
622 cand_prob.push_back(pentry[kentry]);
623 cand_start.push_back(0);
624 cand_preempt.push_back(0);
630 }
else if (state_detail::buffer_is_tag_phase_pairs(sched)) {
637 srv[L.
Ks[cls - 1] + kentry] += one;
638 std::vector<T> row = buf;
639 row.insert(row.end(), srv.begin(), srv.end());
640 row.insert(row.end(), var.begin(), var.end());
642 cand_prob.push_back(pentry[kentry]);
643 cand_start.push_back(cls);
644 cand_preempt.push_back(0);
650 const bool prio_aware = sched == SchedStrategy::FCFSPRPRIO ||
651 sched == SchedStrategy::FCFSPIPRIO ||
652 sched == SchedStrategy::LCFSPRPRIO ||
653 sched == SchedStrategy::LCFSPIPRIO;
654 const bool lcfs_family = sched == SchedStrategy::LCFSPRPRIO ||
655 sched == SchedStrategy::LCFSPIPRIO;
668 const bool fcfs_never_preempts = sched == SchedStrategy::FCFSPR ||
669 sched == SchedStrategy::FCFSPI;
673 const bool resume = sched == SchedStrategy::LCFSPR ||
674 sched == SchedStrategy::LCFSPRPRIO ||
675 sched == SchedStrategy::FCFSPR ||
676 sched == SchedStrategy::FCFSPRPRIO;
677 bool can_preempt_any =
false;
678 for (std::size_t cp = 1; cp <= R && !fcfs_never_preempts; ++cp) {
685 const int pa =
sn.classes[cls - 1].prio;
686 const int pv =
sn.classes[cp - 1].prio;
687 if (lcfs_family ? (pa > pv) : (pa >= pv))
continue;
689 for (std::size_t pp = 0; pp < L.
K[cp - 1]; ++pp) {
690 const std::size_t vcol = L.
Ks[cp - 1] + pp;
692 if (busy <= 0)
continue;
693 can_preempt_any =
true;
694 std::vector<T> b2 = buf, s2 = srv;
696 s2[L.
Ks[cls - 1] + kentry] += one;
700 std::size_t slot = 0;
701 for (std::size_t b = 0; b < L.
bufw; ++b)
703 if (slot == 0)
continue;
707 std::vector<T> row = b2;
708 row.insert(row.end(), s2.begin(), s2.end());
709 row.insert(row.end(), var.begin(), var.end());
713 cand_start.push_back(cls);
714 cand_preempt.push_back(cp);
728 if ((prio_aware || fcfs_never_preempts) && !can_preempt_any) {
729 std::size_t slot = 0;
730 for (std::size_t b = 0; b < L.
bufw; ++b)
733 std::vector<T> b2 = buf;
736 std::vector<T> row = b2;
737 row.insert(row.end(), srv.begin(), srv.end());
738 row.insert(row.end(), var.begin(), var.end());
740 cand_prob.push_back(pentry[kentry]);
741 cand_start.push_back(0);
742 cand_preempt.push_back(0);
749 " discipline is not ported yet");
754 for (std::size_t c = 0; c < cand.size(); ++c) {
758 out.
space.push_back(cand[c]);
759 out.
rate.push_back(minus_one);
760 out.
prob.push_back(cand_prob[c]);
762 tag_last(out, c < cand_start.size() ? cand_start[c] : 0,
763 c < cand_preempt.size() ? cand_preempt[c] : 0);
783 std::size_t ist, std::size_t cls) {
785 const std::size_t n =
sn.phases_of(ist, cls);
787 if (d.
D0.rows() != n || d.
D1.rows() != n)
return std::make_pair(mu, phi);
788 for (std::size_t k = 0; k < n; ++k) {
789 const T dk = T(-d.
D0(k, k));
796 for (std::size_t j = 0; j < n; ++j) s += d.
D1(k, j);
799 return std::make_pair(mu, phi);
805 const std::vector<T>& s =
sn.stations[ist - 1].lldscaling;
809 if (!std::isfinite(n) || n >=
static_cast<double>(s.size()))
return s.back();
811 return s[
static_cast<std::size_t
>(n) - 1];
837 for (std::size_t h = 0; h < 2; ++h) {
840 const std::vector<T> v = fun(nir);
843 "cd_factor: the class-dependence map returned an empty scaling vector");
844 f = T(f * v[std::min(cls, v.size()) - 1]);
869 std::size_t cls,
double ni,
double S) {
870 const std::size_t R =
sn.nclasses;
875 const bool prio_aware = sched == SchedStrategy::PSPRIO ||
876 sched == SchedStrategy::DPSPRIO ||
877 sched == SchedStrategy::GPSPRIO;
878 if (!prio_aware || ni <= S)
return p;
879 double best = std::numeric_limits<double>::infinity();
880 for (std::size_t r = 0; r < R; ++r)
882 best = std::min(best,
static_cast<double>(
sn.classes[r].prio));
883 if (
static_cast<double>(
sn.classes[cls - 1].prio) != best) {
889 for (std::size_t r = 0; r < R; ++r) {
890 if (
static_cast<double>(
sn.classes[r].prio) != best)
899T
service_share(
const NetworkStruct<T>&
sn, std::size_t ist,
const Marginal<T>& m,
900 std::size_t cls,
double ni,
double S);
919 const std::vector<T>& inspace, std::size_t cls,
920 bool no_promote =
false) {
921 const std::size_t R =
sn.nclasses;
922 const std::size_t ist =
sn.nodes[ind - 1].station;
925 if (ist == 0)
throw InputError(
"after_event_station_dep: node is not a station");
927 if (sched == SchedStrategy::PAS || sched == SchedStrategy::OI)
930 const double S =
sn.stations[ist - 1].nservers;
932 std::vector<std::size_t> ph(R, 1), shift(R, 0);
933 for (std::size_t r = 0; r < R; ++r) {
943 const std::size_t markof = sched == SchedStrategy::EXT ?
sn.markidx_of(ist, cls) : 0;
944 std::size_t phcls = cls;
946 const std::size_t carrier =
sn.mark_carrier_of(ist);
947 if (carrier >= 1 && carrier <= R) phcls = carrier;
953 const std::pair<std::vector<T>, std::vector<T>> mp =
phase_rates(
sn, ist, cls);
954 const std::vector<T>& mu = mp.first;
955 const std::vector<T>& phi = mp.second;
959 for (std::size_t r = 0; r < R; ++r) ni += num_traits<T>::to_double(m.
nir[r]);
970 const bool cd_takes_prio =
971 pp.
masked && (sched == SchedStrategy::DPSPRIO || sched == SchedStrategy::GPSPRIO);
979 bool suppress_promote = no_promote;
981 const typename std::map<std::size_t, RetrialParam<T>>::const_iterator rit =
982 sn.retrialparam.find(ist);
983 if (rit !=
sn.retrialparam.end())
984 for (std::size_t r = 0; r < rit->second.retrial_proc.size(); ++r)
985 if (!rit->second.retrial_proc[r].disabled) { suppress_promote =
true;
break; }
988 for (std::size_t k = 0; k < L.
K[phcls - 1]; ++k) {
989 std::vector<T> buf(inspace.begin(), inspace.begin() + L.
bufw);
990 std::vector<T> srv(inspace.begin() + L.
bufw, inspace.begin() + L.
bufw + L.
srvw);
991 std::vector<T> var(inspace.begin() + L.
bufw + L.
srvw, inspace.end());
992 const std::size_t col = L.
Ks[phcls - 1] + k;
994 const T kir = m.
kir[phcls - 1][k];
996 if (sched == SchedStrategy::EXT) {
1003 if (!std::isfinite(
sn.njobs()[cls - 1])) {
1011 markof > 0 && markof <= d.
Dmark.size() ? d.
Dmark[markof - 1] : d.
D1;
1012 for (std::size_t ke = 0; ke < L.
K[phcls - 1]; ++ke) {
1013 const T arv = D1k(k, ke);
1015 std::vector<T> row = inspace;
1016 row[L.
bufw + L.
Ks[phcls - 1] + k] -= one;
1017 row[L.
bufw + L.
Ks[phcls - 1] + ke] += one;
1018 out.
space.push_back(row);
1019 out.
rate.push_back(T(lld * arv));
1020 out.
prob.push_back(one);
1023 }
else if (sched == SchedStrategy::INF || sched == SchedStrategy::PS ||
1024 sched == SchedStrategy::LPS || sched == SchedStrategy::DPS ||
1025 sched == SchedStrategy::GPS || sched == SchedStrategy::PSPRIO ||
1026 sched == SchedStrategy::DPSPRIO || sched == SchedStrategy::GPSPRIO) {
1031 const T rate = T(mu[k] * phi[k] * kir *
service_share(
sn, ist, m, cls, ni, S));
1032 std::vector<T> row = buf;
1033 row.insert(row.end(), srv.begin(), srv.end());
1034 row.insert(row.end(), var.begin(), var.end());
1035 out.
space.push_back(row);
1036 out.
rate.push_back(T(lld * rate));
1037 out.
prob.push_back(one);
1038 }
else if (state_detail::buffer_is_class_tag(sched) && sched != SchedStrategy::FCFS) {
1043 const bool has_waiting = ni > S && !suppress_promote;
1044 const T rate = T(mu[k] * phi[k] * kir);
1047 std::vector<T> row = buf;
1048 row.insert(row.end(), srv.begin(), srv.end());
1049 row.insert(row.end(), var.begin(), var.end());
1050 out.
space.push_back(row);
1051 out.
rate.push_back(T(lld * rate));
1052 out.
prob.push_back(one);
1056 std::size_t pos = L.
bufw;
1057 if (sched == SchedStrategy::LCFS) {
1063 for (std::size_t b = 0; b < L.
bufw; ++b)
1071 double best = std::numeric_limits<double>::infinity();
1072 for (std::size_t b = 0; b < L.
bufw; ++b) {
1074 if (v <= 0)
continue;
1075 const double p =
sn.classes[
static_cast<std::size_t
>(v) - 1].prio;
1076 if (p < best) best = p;
1078 if (std::isfinite(best))
1079 for (std::size_t b = 0; b < L.
bufw; ++b) {
1081 if (v <= 0)
continue;
1082 if (
sn.classes[
static_cast<std::size_t
>(v) - 1].prio != best)
continue;
1084 if (sched == SchedStrategy::LCFSPRIO)
break;
1087 if (pos == L.
bufw)
continue;
1089 std::vector<T> b2 = buf;
1090 if (sched == SchedStrategy::LCFS) {
1096 for (std::size_t b = pos; b > 0; --b) b2[b] = b2[b - 1];
1100 for (std::size_t ke = 0; ke < L.
K[hc - 1]; ++ke) {
1101 std::vector<T> s3 = srv;
1102 s3[L.
Ks[hc - 1] + ke] += one;
1103 std::vector<T> row = b2;
1104 row.insert(row.end(), s3.begin(), s3.end());
1105 row.insert(row.end(), var.begin(), var.end());
1106 out.
space.push_back(row);
1107 out.
rate.push_back(T(lld * rate * pentry[ke]));
1108 out.
prob.push_back(one);
1111 }
else if (state_detail::buffer_is_class_tag(sched)) {
1121 std::vector<T> var2 = var;
1122 bool holds_reply =
false;
1123 if (
sn.replyblock.size() >= ind &&
sn.replyblock[ind - 1].size() >= cls &&
1124 sn.replyblock[ind - 1][cls - 1]) {
1126 const std::size_t sl = ri.
slot[cls - 1];
1127 if (sl !=
static_cast<std::size_t
>(-1) && sl < var2.size()) {
1133 const bool has_waiting = ni > (S - nb) && !suppress_promote && !holds_reply;
1134 for (std::size_t kd = 0; kd < L.
K[cls - 1]; ++kd) {
1135 const T rate = T(d.
D1(k, kd) * kir);
1136 std::vector<T> s2 = srv;
1139 std::vector<T> row = buf;
1140 row.insert(row.end(), s2.begin(), s2.end());
1141 row.insert(row.end(), var2.begin(), var2.end());
1142 out.
space.push_back(row);
1143 out.
rate.push_back(T(lld * rate));
1144 out.
prob.push_back(one);
1151 if (headv <= 0)
continue;
1152 const std::size_t hc =
static_cast<std::size_t
>(headv);
1153 std::vector<T> b2(L.
bufw, zero);
1154 for (std::size_t b = 1; b < L.
bufw; ++b) b2[b] = buf[b - 1];
1156 for (std::size_t ke = 0; ke < L.
K[hc - 1]; ++ke) {
1157 std::vector<T> s3 = s2;
1158 s3[L.
Ks[hc - 1] + ke] += one;
1159 std::vector<T> row = b2;
1160 row.insert(row.end(), s3.begin(), s3.end());
1161 row.insert(row.end(), var2.begin(), var2.end());
1162 const T r3 = T(lld * rate * pentry[ke]);
1163 out.
space.push_back(row);
1164 out.
rate.push_back(r3);
1172 }
else if (sched == SchedStrategy::POLLING) {
1177 const T rate = T(mu[k] * phi[k] * kir);
1179 std::size_t pos = 0, swk = 0;
1183 if (swk != 0)
continue;
1184 std::vector<long> nbuf(R, 0);
1185 for (std::size_t r = 0; r < R && r < L.
bufw; ++r)
1190 switch (pinfo.
ptype) {
1193 goon = nbuf[cls - 1] > 0;
1201 goon = ctrnext > 0 && nbuf[cls - 1] > 0;
1205 goon = nbuf[cls - 1] > ctr;
1208 std::size_t q = cls;
1210 long budget = ctrnext;
1211 if (!goon)
polling_next(pinfo, cls, nbuf, R,
false, q, mode, budget);
1212 std::vector<std::vector<T>> rows;
1213 std::vector<T> probs;
1214 polling_land(
sn, ist, pinfo, q, mode, budget, buf, srv, var, L, rows, probs);
1215 for (std::size_t j = 0; j < rows.size(); ++j) {
1216 out.
space.push_back(rows[j]);
1217 out.
rate.push_back(T(lld * rate * probs[j]));
1218 out.
prob.push_back(one);
1221 tag_last(out, mode == 1 ? q : 0, 0);
1223 }
else if (state_detail::buffer_is_tag_phase_pairs(sched)) {
1229 const T rate = T(mu[k] * phi[k] * kir);
1231 const bool prio_aware = sched == SchedStrategy::FCFSPRPRIO ||
1232 sched == SchedStrategy::FCFSPIPRIO ||
1233 sched == SchedStrategy::LCFSPRPRIO ||
1234 sched == SchedStrategy::LCFSPIPRIO;
1235 const bool lcfs = sched == SchedStrategy::LCFSPR ||
1236 sched == SchedStrategy::LCFSPI ||
1237 sched == SchedStrategy::LCFSPRPRIO ||
1238 sched == SchedStrategy::LCFSPIPRIO;
1242 const bool resume = sched == SchedStrategy::LCFSPR ||
1243 sched == SchedStrategy::LCFSPRPRIO ||
1244 sched == SchedStrategy::FCFSPR ||
1245 sched == SchedStrategy::FCFSPRPRIO;
1247 std::size_t pos = L.
bufw;
1248 if (ni > S && !suppress_promote && L.
bufw >= 2) {
1249 double best = std::numeric_limits<double>::infinity();
1256 for (std::size_t b = 0; b + 1 < L.
bufw; b += 2) {
1258 if (v <= 0)
continue;
1259 const double p =
sn.classes[
static_cast<std::size_t
>(v) - 1].prio;
1260 if (p < best) best = p;
1262 for (std::size_t b = 0; b + 1 < L.
bufw; b += 2) {
1264 if (v <= 0)
continue;
1265 if (prio_aware &&
sn.classes[
static_cast<std::size_t
>(v) - 1].prio != best)
1274 if (pos == L.
bufw) {
1275 std::vector<T> row = buf;
1276 row.insert(row.end(), srv.begin(), srv.end());
1277 row.insert(row.end(), var.begin(), var.end());
1278 out.
space.push_back(row);
1279 out.
rate.push_back(T(lld * rate));
1280 out.
prob.push_back(one);
1284 const std::size_t kst =
1286 if (hc == 0 || hc > R || kst == 0 || kst > L.
K[hc - 1])
1287 throw InputError(
"after_event_station_dep: station '" +
1288 sn.stations[ist - 1].name +
1289 "' holds a waiting job whose [class, phase] pair is malformed");
1296 std::vector<T> b2(L.
bufw, zero);
1297 for (std::size_t b = 2; b <= pos + 1; ++b) b2[b] = buf[b - 2];
1298 for (std::size_t b = pos + 2; b < L.
bufw; ++b) b2[b] = buf[b];
1300 std::vector<T> s3 = srv;
1301 s3[L.
Ks[hc - 1] + kst - 1] += one;
1302 std::vector<T> row = b2;
1303 row.insert(row.end(), s3.begin(), s3.end());
1304 row.insert(row.end(), var.begin(), var.end());
1305 out.
space.push_back(row);
1306 out.
rate.push_back(T(lld * rate));
1307 out.
prob.push_back(one);
1311 for (std::size_t ke = 0; ke < L.
K[hc - 1]; ++ke) {
1312 std::vector<T> s3 = srv;
1313 s3[L.
Ks[hc - 1] + ke] += one;
1314 std::vector<T> row = b2;
1315 row.insert(row.end(), s3.begin(), s3.end());
1316 row.insert(row.end(), var.begin(), var.end());
1317 out.
space.push_back(row);
1318 out.
rate.push_back(T(lld * rate * pentry[ke]));
1319 out.
prob.push_back(one);
1323 }
else if (state_detail::buffer_is_per_class_count(sched)) {
1328 const T rate = T(mu[k] * phi[k] * kir);
1330 for (std::size_t r = 0; r < R; ++r) waiting += num_traits<T>::to_double(buf[r]);
1331 if (waiting <= 0 || suppress_promote) {
1332 std::vector<T> row = buf;
1333 row.insert(row.end(), srv.begin(), srv.end());
1334 row.insert(row.end(), var.begin(), var.end());
1335 out.
space.push_back(row);
1336 out.
rate.push_back(T(lld * rate));
1337 out.
prob.push_back(one);
1340 for (std::size_t r = 1; r <= R; ++r) {
1342 if (nb <= 0)
continue;
1344 for (std::size_t ke = 0; ke < L.
K[r - 1]; ++ke) {
1345 std::vector<T> b2 = buf, s2 = srv;
1347 s2[L.
Ks[r - 1] + ke] += one;
1348 std::vector<T> row = b2;
1349 row.insert(row.end(), s2.begin(), s2.end());
1350 row.insert(row.end(), var.begin(), var.end());
1351 out.
space.push_back(row);
1352 out.
rate.push_back(T(lld * rate));
1360 " discipline is not ported yet");
1378 std::size_t cls,
double ni,
double S) {
1379 const std::size_t R =
sn.nclasses;
1389 if (!p.
served)
return zero;
1390 const std::vector<T>& nir = p.
nir;
1391 const double nieff = p.
ni;
1393 if (sched == SchedStrategy::PS || sched == SchedStrategy::LPS ||
1394 sched == SchedStrategy::PSPRIO)
1396 if (sched == SchedStrategy::DPS || sched == SchedStrategy::GPS ||
1397 sched == SchedStrategy::DPSPRIO || sched == SchedStrategy::GPSPRIO) {
1400 "state_events: multi-server DPS/GPS stations are not supported");
1401 const bool dps = sched == SchedStrategy::DPS || sched == SchedStrategy::DPSPRIO;
1402 const std::vector<T>& w =
sn.stations[ist - 1].schedparam;
1404 for (std::size_t r = 0; r < R; ++r) wsum += w[r];
1406 for (std::size_t r = 0; r < R; ++r) {
1410 denom += T(w[r] / wsum * nr);
1412 const T
nc = nir[cls - 1];
1415 const T sh = T((w[cls - 1] / wsum) / denom);
1416 return dps ? sh : T(sh /
nc);
1433 const std::vector<T>& inspace, std::size_t cls) {
1434 const std::size_t R =
sn.nclasses;
1435 const std::size_t ist =
sn.nodes[ind - 1].station;
1438 if (ist == 0)
throw InputError(
"after_event_station_phase: node is not a station");
1440 const double S =
sn.stations[ist - 1].nservers;
1442 std::vector<std::size_t> ph(R, 1), shift(R, 0);
1443 for (std::size_t r = 0; r < R; ++r) {
1451 for (std::size_t r = 0; r < R; ++r) ni += num_traits<T>::to_double(m.
nir[r]);
1459 if (d.
D0.rows() != L.
K[cls - 1])
return out;
1461 for (std::size_t k = 0; k < L.
K[cls - 1]; ++k) {
1463 for (std::size_t kd = 0; kd < L.
K[cls - 1]; ++kd) {
1464 if (kd == k)
continue;
1465 std::vector<T> row = inspace;
1466 row[L.
bufw + L.
Ks[cls - 1] + k] -= one;
1467 row[L.
bufw + L.
Ks[cls - 1] + kd] += one;
1468 out.
space.push_back(row);
1469 out.
rate.push_back(T(lld * d.
D0(k, kd) * m.
kir[cls - 1][k] * share));
1470 out.
prob.push_back(one);
1488 const std::vector<T>& inspace, std::size_t cls,
1489 const T& impatience_mu) {
1490 const std::size_t R =
sn.nclasses;
1491 const std::size_t ist =
sn.nodes[ind - 1].station;
1493 if (ist == 0)
throw InputError(
"after_event_station_renege: node is not a station");
1496 std::vector<std::size_t> ph(R, 1), shift(R, 0);
1497 for (std::size_t r = 0; r < R; ++r) {
1504 if (waiting <= 0)
return out;
1507 std::size_t slot = L.
bufw;
1508 for (std::size_t b = 0; b < L.
bufw; ++b)
1509 if (inspace[b] == tag) { slot = b;
break; }
1510 if (slot == L.
bufw)
return out;
1512 std::vector<T> row = inspace;
1513 for (std::size_t b = slot; b > 0; --b) row[b] = row[b - 1];
1515 out.
space.push_back(row);
1540 const std::vector<T>& inspace, std::size_t cls,
1541 const T& retrial_mu,
bool constant_policy =
false) {
1542 const std::size_t R =
sn.nclasses;
1543 const std::size_t ist =
sn.nodes[ind - 1].station;
1546 if (ist == 0)
throw InputError(
"after_event_station_retry: node is not a station");
1548 const double S =
sn.stations[ist - 1].nservers;
1550 std::vector<std::size_t> ph(R, 1), shift(R, 0);
1551 for (std::size_t r = 0; r < R; ++r) {
1560 if (orbit <= 0 || occ >= S)
return out;
1563 std::size_t slot = L.
bufw;
1564 for (std::size_t b = 0; b < L.
bufw; ++b)
1565 if (inspace[b] == tag) { slot = b;
break; }
1566 if (slot == L.
bufw)
return out;
1569 const T agg = constant_policy ? retrial_mu
1571 for (std::size_t ke = 0; ke < L.
K[cls - 1]; ++ke) {
1573 std::vector<T> row = inspace;
1574 for (std::size_t b = slot; b > 0; --b) row[b] = row[b - 1];
1576 row[L.
bufw + L.
Ks[cls - 1] + ke] += one;
1577 out.
space.push_back(row);
1578 out.
rate.push_back(T(agg * pentry[ke]));
1579 out.
prob.push_back(one);
1605 const std::vector<T>& inspace,
bool up,
1608 if (inspace.empty() || !
sn.has_breakdown_node(ind))
return out;
1612 if ((up && status != 0) || (!up && status != 1))
return out;
1613 std::vector<T> row = inspace;
1622 out.
space.push_back(row);
1623 out.
rate.push_back(rate);
1643 const std::vector<T>& inspace,
EventType event,
1645 const std::size_t R =
sn.nclasses;
1647 if (event != EventType::ARV)
return out;
1648 if (inspace.size() < R)
1649 throw InputError(
"after_event_fork: the Fork state row at node '" +
sn.nodes[ind - 1].name +
1650 "' is narrower than the class set");
1651 std::vector<T> row = inspace;
1655 out.
space.push_back(row);
1679 const std::vector<T>& inspace,
EventType event,
1681 const std::size_t R =
sn.nclasses;
1684 if (inspace.size() < R)
1685 throw InputError(
"after_event_join: the Join state row at node '" +
sn.nodes[ind - 1].name +
1686 "' is narrower than the class set");
1687 const std::size_t off = inspace.size() - R;
1689 if (event == EventType::ARV) {
1690 std::vector<T> row = inspace;
1691 row[off + cls - 1] += one;
1692 out.
space.push_back(row);
1694 out.
prob.push_back(one);
1697 if (event != EventType::DEP)
return out;
1699 const typename std::map<std::size_t, FjJoinParam>::const_iterator jit =
1700 sn.fjjoinparam.find(ind);
1701 const FjJoinParam* fjp = jit ==
sn.fjjoinparam.end() ? 0 : &jit->second;
1704 for (std::size_t x = 0; x < fjp->
origclasses.size(); ++x) {
1705 const std::map<std::size_t, std::vector<std::vector<std::size_t>>>::const_iterator ait =
1707 if (ait == fjp->
auxmatrix.end())
continue;
1708 for (std::size_t b = 0; b < ait->second.size(); ++b)
1709 for (std::size_t t = 0; t < ait->second[b].size(); ++t)
1710 if (ait->second[b][t] == cls)
return out;
1718 std::vector<T> row = inspace;
1719 row[off + cls - 1] -= one;
1720 out.
space.push_back(row);
1721 out.
rate.push_back(imm);
1722 out.
prob.push_back(one);
1725 if (!fjp)
return out;
1726 const std::map<std::size_t, std::vector<std::vector<std::size_t>>>::const_iterator ait =
1728 const std::map<std::size_t, std::vector<std::size_t>>::const_iterator rit =
1731 const std::vector<std::vector<std::size_t>>& aux = ait->second;
1732 const std::vector<std::size_t>& req = rit->second;
1733 if (aux.empty())
return out;
1734 const std::size_t B = aux.size(), Tt = aux[0].size();
1735 for (std::size_t t = 0; t < Tt; ++t) {
1736 bool complete =
true;
1737 for (std::size_t b = 0; b < B && complete; ++b) {
1738 const std::size_t a = aux[b][t];
1739 const double need = b < req.size() ?
static_cast<double>(req[b]) : 1.0;
1742 if (!complete)
continue;
1743 std::vector<T> row = inspace;
1744 for (std::size_t b = 0; b < B; ++b) {
1745 const std::size_t a = aux[b][t];
1746 const long need = b < req.size() ?
static_cast<long>(req[b]) : 1;
1749 out.
space.push_back(row);
1750 out.
rate.push_back(imm);
1751 out.
prob.push_back(one);
1767void rr_advance_row(
const NetworkStruct<T>&
sn, std::size_t ind, std::size_t cls,
1768 std::vector<std::vector<T>>& rows);
1783 const std::vector<T>& inspace,
EventType event,
1786 const std::size_t R =
sn.nclasses;
1787 if (inspace.size() < R)
return out;
1789 if (event == EventType::ARV) {
1790 std::vector<T> row = inspace;
1791 row[cls - 1] = T(row[cls - 1] + one);
1792 out.
space.push_back(row);
1795 out.
prob.push_back(one);
1798 if (event == EventType::DEP) {
1800 std::vector<T> row = inspace;
1801 row[cls - 1] = T(row[cls - 1] - one);
1802 out.
space.push_back(row);
1804 out.
prob.push_back(one);
1820 std::vector<std::vector<T>>& rows) {
1821 if (
sn.rr_var_slot(ind, cls) == 0)
return;
1822 const std::size_t w =
sn.nvars_of(ind);
1824 for (std::size_t i = 0; i < rows.size(); ++i) {
1825 if (rows[i].size() < w)
continue;
1826 std::vector<T> var(rows[i].end() - w, rows[i].end());
1827 sn.rr_advance(ind, cls, var);
1828 std::copy(var.begin(), var.end(), rows[i].end() - w);
1834 const std::vector<T>& inspace,
EventType event,
1835 std::size_t cls,
bool no_promote =
false,
1842 if ((event == EventType::DEP || event == EventType::PHASE) && !inspace.empty() &&
1844 const std::size_t ist =
sn.nodes[ind - 1].station;
1845 const T down =
sn.breakdownparam.at(ist).down_rate_of(cls);
1847 const T upr =
sn.rates(ist - 1, cls - 1);
1849 if (!std::isfinite(upd) || !(upd > 0.0))
1850 throw InputError(
"Station '" +
sn.nodes[ind - 1].name +
1851 "' declares a down-server service rate for class '" +
1852 sn.classes[cls - 1].name +
1853 "' but has no finite up-server service rate to rescale.");
1857 std::vector<T> upspace = inspace;
1861 const T scale = T(down / upr);
1862 for (std::size_t i = 0; i < o.
space.size(); ++i) {
1869 case EventType::ARV:
1874 if (
sn.issignal.size() >= cls &&
sn.issignal[cls - 1]) {
1875 if (!(
sn.signaltype.size() >= cls &&
1885 case EventType::DEP: {
1905 if (ind <=
sn.isbasblocking.size() &&
sn.isbasblocking[ind - 1] &&
1907 !out.
space.empty()) {
1914 for (std::size_t i = 0; i < out.
space.size(); ++i) {
1921 case EventType::PHASE:
1923 case EventType::RENEGE:
1925 case EventType::RETRY:
1927 case EventType::SWITCH:
1929 case EventType::FAILURE:
1931 case EventType::REPAIR:
1933 case EventType::LOCAL:
1938 " event is not ported yet");
1960 const std::vector<T>& inspace,
EventType event,
1963 if (event != EventType::PHASE)
return out;
1964 const typename std::map<std::size_t, TransitionParam<T>>::const_iterator it =
1965 sn.transparam.find(ind);
1966 if (it ==
sn.transparam.end())
1967 throw InputError(
"after_event_transition: node has no TransitionParam");
1969 if (mode == 0 || mode > tp.
nmodes)
1970 throw InputError(
"after_event_transition: mode index is out of range");
1973 std::vector<std::size_t> fK(tp.
nmodes, 1), fKs(tp.
nmodes, 0);
1974 std::size_t tot = 0;
1975 for (std::size_t m = 0; m < tp.
nmodes; ++m) {
1980 if (fK[mode - 1] <= 1)
return out;
1982 tp.
firingproc[mode - 1].D0.rows() != fK[mode - 1])
1986 for (std::size_t k = 0; k < fK[mode - 1]; ++k) {
1987 const std::size_t idx = tp.
nmodes + fKs[mode - 1] + k;
1988 const T cnt = inspace[idx];
1990 for (std::size_t kd = 0; kd < fK[mode - 1]; ++kd) {
1991 if (kd == k)
continue;
1993 std::vector<T> row = inspace;
1995 row[tp.
nmodes + fKs[mode - 1] + kd] += one;
1996 out.
space.push_back(row);
1997 out.
rate.push_back(T(D0(k, kd) * cnt));
1998 out.
prob.push_back(one);
2020 const std::vector<T>& inspace,
EventType event, std::size_t cls,
2021 bool no_promote =
false,
2023 if (ind == 0 || ind >
sn.nodes.size())
2024 throw InputError(
"after_event: node index is out of range");
2035 const bool cls_is_mode = (nd.
nodetype == NodeType::Transition &&
event == EventType::PHASE);
2036 if (!cls_is_mode && (cls == 0 || cls >
sn.nclasses))
2037 throw InputError(
"after_event: class index is out of range");
2042 if (
sn.isfjaugmented && nd.
nodetype == NodeType::Join)
2055 if (nd.
nodetype == NodeType::Transition)
2060 "' are not ported yet");
2063namespace signal_detail {
2067void merge_states(std::vector<std::vector<T>>& sp, std::vector<T>& pr) {
2068 std::vector<std::vector<T>> us;
2070 for (std::size_t i = 0; i < sp.size(); ++i) {
2071 std::size_t at = us.size();
2072 for (std::size_t j = 0; j < us.size(); ++j)
2073 if (us[j] == sp[i]) { at = j;
break; }
2074 if (at == us.size()) {
2075 us.push_back(sp[i]);
2076 up.push_back(pr[i]);
2098 std::vector<std::size_t> kv;
2100 if (
sn.signalremdist.size() < cls ||
sn.signalremdist[cls - 1].empty()) {
2103 return std::make_pair(kv, kp);
2105 const std::vector<T>& d =
sn.signalremdist[cls - 1];
2107 for (std::size_t b = 0; b < ntot; ++b) {
2123 return std::make_pair(kv, kp);
2126 for (std::size_t i = 0; i < kp.size(); ++i) tot += kp[i];
2128 for (std::size_t i = 0; i < kp.size(); ++i) kp[i] = T(kp[i] / tot);
2129 return std::make_pair(kv, kp);
2147 const std::vector<T>& inspace, std::size_t cls) {
2148 const std::size_t R =
sn.nclasses;
2149 const std::size_t ist =
sn.nodes[ind - 1].station;
2153 if (ist == 0)
throw InputError(
"after_event_station_signal: node is not a station");
2156 const double S =
sn.stations[ist - 1].nservers;
2158 std::vector<std::size_t> ph(R, 1), shift(R, 0);
2159 for (std::size_t r = 0; r < R; ++r) {
2168 std::vector<T> row(L.
bufw + L.
srvw, zero);
2169 row.insert(row.end(), inspace.end() - L.
nvar, inspace.end());
2170 out.
space.push_back(row);
2171 out.
rate.push_back(minus_one);
2172 out.
prob.push_back(one);
2178 std::vector<std::size_t> tgt;
2179 const std::size_t declared =
sn.signaltarget.size() >= cls ?
sn.signaltarget[cls - 1] : 0;
2180 if (declared >= 1) {
2181 tgt.push_back(declared);
2183 for (std::size_t r = 1; r <= R; ++r)
2184 if (
sn.issignal.size() < r || !
sn.issignal[r - 1]) tgt.push_back(r);
2186 std::vector<std::size_t> elig;
2187 std::size_t ntot = 0;
2188 for (std::size_t i = 0; i < tgt.size(); ++i) {
2191 elig.push_back(tgt[i]);
2192 ntot +=
static_cast<std::size_t
>(nr);
2197 out.
space.push_back(inspace);
2198 out.
rate.push_back(minus_one);
2199 out.
prob.push_back(one);
2204 ?
sn.signalrempolicy[cls - 1]
2206 const bool ordered = state_detail::buffer_is_class_tag(sched) ||
2207 state_detail::buffer_is_tag_phase_pairs(sched);
2208 const bool paired = state_detail::buffer_is_tag_phase_pairs(sched);
2209 const bool counted = state_detail::buffer_is_per_class_count(sched);
2210 const std::pair<std::vector<std::size_t>, std::vector<T>> pmf =
2213 std::vector<std::vector<T>> acc;
2214 std::vector<T> accp;
2215 for (std::size_t ik = 0; ik < pmf.first.size(); ++ik) {
2217 std::vector<std::vector<T>> cur(1, inspace);
2218 std::vector<T> curp(1, one);
2221 for (std::size_t step = 0; step < pmf.first[ik]; ++step) {
2222 std::vector<std::vector<T>> nxt;
2223 std::vector<T> nxtp;
2224 for (std::size_t row = 0; row < cur.size(); ++row) {
2225 std::vector<T> buf(cur[row].begin(), cur[row].begin() + L.
bufw);
2226 std::vector<T> srv(cur[row].begin() + L.
bufw,
2227 cur[row].begin() + L.
bufw + L.
srvw);
2228 const std::vector<T> var(cur[row].begin() + L.
bufw + L.
srvw, cur[row].end());
2231 std::vector<std::size_t> wpos, wcls, wwt;
2233 for (std::size_t b = 0; b < L.
bufw; b += paired ? 2 : 1) {
2235 if (v <= 0)
continue;
2237 for (std::size_t e = 0; e < elig.size(); ++e)
2238 if (elig[e] ==
static_cast<std::size_t
>(v)) ok =
true;
2241 wcls.push_back(
static_cast<std::size_t
>(v));
2244 }
else if (counted) {
2245 for (std::size_t e = 0; e < elig.size(); ++e) {
2246 const std::size_t r = elig[e];
2247 if (r > L.
bufw)
continue;
2249 if (v <= 0)
continue;
2250 wpos.push_back(r - 1);
2252 wwt.push_back(
static_cast<std::size_t
>(v));
2256 std::vector<std::size_t> scls, sph, scnt;
2257 for (std::size_t e = 0; e < elig.size(); ++e) {
2258 const std::size_t r = elig[e];
2259 for (std::size_t p = 0; p < L.
K[r - 1]; ++p) {
2261 if (v <= 0)
continue;
2264 scnt.push_back(
static_cast<std::size_t
>(v));
2267 std::size_t nwait = 0, nsrv = 0;
2268 for (std::size_t i = 0; i < wwt.size(); ++i) nwait += wwt[i];
2269 for (std::size_t i = 0; i < scnt.size(); ++i) nsrv += scnt[i];
2270 if (nwait == 0 && nsrv == 0) {
2272 nxt.push_back(cur[row]);
2273 nxtp.push_back(curp[row]);
2277 std::vector<std::vector<T>> sp;
2279 const bool age_ordered =
2282 if (age_ordered && nwait > 0) {
2285 std::size_t pick = 0;
2286 for (std::size_t i = 0; i < wpos.size(); ++i)
2288 : wpos[i] < wpos[pick])
2290 std::vector<T> b2 = buf;
2291 b2.erase(b2.begin() + wpos[pick], b2.begin() + wpos[pick] + (paired ? 2 : 1));
2292 b2.insert(b2.begin(), paired ? 2 : 1, zero);
2293 std::vector<T> nr = b2;
2294 nr.insert(nr.end(), srv.begin(), srv.end());
2295 nr.insert(nr.end(), var.begin(), var.end());
2304 : (nwait > 0 ? nwait : nsrv);
2305 for (std::size_t i = 0; i < wpos.size(); ++i) {
2306 std::vector<T> b2 = buf;
2308 b2[wcls[i] - 1] -= one;
2310 b2.erase(b2.begin() + wpos[i],
2311 b2.begin() + wpos[i] + (paired ? 2 : 1));
2312 b2.insert(b2.begin(), paired ? 2 : 1, zero);
2314 std::vector<T> nr = b2;
2315 nr.insert(nr.end(), srv.begin(), srv.end());
2316 nr.insert(nr.end(), var.begin(), var.end());
2319 static_cast<double>(total)));
2322 for (std::size_t i = 0; i < scls.size(); ++i) {
2323 std::vector<T> b2 = buf, s2 = srv;
2324 s2[L.
Ks[scls[i] - 1] + sph[i]] -= one;
2328 for (std::size_t j = 0; j < s2.size(); ++j)
2330 if (L.
bufw > 0 && occ < S) {
2332 std::size_t hp = L.
bufw;
2333 for (std::size_t b = 0; b < L.
bufw; b += paired ? 2 : 1)
2336 const std::size_t pc =
static_cast<std::size_t
>(
2342 pp = v >= 1 ?
static_cast<std::size_t
>(v) - 1 : 0;
2344 b2.erase(b2.begin() + hp,
2345 b2.begin() + hp + (paired ? 2 : 1));
2346 b2.insert(b2.begin(), paired ? 2 : 1, zero);
2347 s2[L.
Ks[pc - 1] + pp] += one;
2349 }
else if (counted) {
2354 for (std::size_t r = 1; r <= R && r <= L.
bufw; ++r)
2357 s2[L.
Ks[r - 1]] += one;
2362 std::vector<T> nr = b2;
2363 nr.insert(nr.end(), s2.begin(), s2.end());
2364 nr.insert(nr.end(), var.begin(), var.end());
2367 static_cast<double>(scnt[i]) /
static_cast<double>(total)));
2371 signal_detail::merge_states(sp, pr);
2372 for (std::size_t i = 0; i < sp.size(); ++i) {
2373 nxt.push_back(sp[i]);
2374 nxtp.push_back(T(curp[row] * pr[i]));
2377 signal_detail::merge_states(nxt, nxtp);
2381 for (std::size_t i = 0; i < cur.size(); ++i) {
2382 acc.push_back(cur[i]);
2383 accp.push_back(T(pmf.second[ik] * curp[i]));
2386 signal_detail::merge_states(acc, accp);
2387 out.
space.swap(acc);
2388 out.
prob.swap(accp);
2389 out.
rate.assign(out.
space.size(), minus_one);
2410 const std::vector<std::size_t>& c, std::size_t p,
2411 const std::vector<std::vector<bool>>& G) {
2412 const std::size_t n = c.size();
2413 if (p >= n)
throw InputError(
"pass_and_swap: position is out of range for the state");
2414 std::vector<std::size_t> chain(1, p);
2415 std::size_t moving = c[p], cur = p;
2418 for (std::size_t j = cur + 1; j < n; ++j)
2419 if (moving - 1 < G.size() && c[j] - 1 < G[moving - 1].size() &&
2420 G[moving - 1][c[j] - 1]) {
2429 const std::size_t dep = c[chain.back()];
2432 std::vector<std::size_t> cnew = c;
2433 for (std::size_t i = 0; i + 1 < chain.size(); ++i) cnew[chain[i + 1]] = c[chain[i]];
2434 cnew.erase(cnew.begin() + chain[0]);
2435 return std::make_pair(cnew, dep);
2450template <
class T,
class F>
2451inline std::vector<double>
pas_increments(
const F& mu_fun,
const std::vector<std::size_t>& c) {
2452 std::vector<double> inc(c.size(), 0.0);
2453 double mu_prev = 0.0;
2454 for (std::size_t p = 0; p < c.size(); ++p) {
2455 const std::vector<std::size_t> prefix(c.begin(), c.begin() + p + 1);
2457 inc[p] = mu_cur - mu_prev;
2469template <
class T,
class F>
2471 const std::vector<std::size_t>& cold,
2472 const std::vector<std::size_t>& cnew) {
2473 if (!mu_fun || out.
space.empty())
return;
2476 for (std::size_t p = 0; p < inc_new.size(); ++p) {
2477 if (inc_new[p] <= 0)
continue;
2478 if (p < inc_old.size() && inc_old[p] > 0)
continue;
2485 const std::vector<T>& inspace,
EventType event,
2487 const std::size_t ist =
sn.nodes[ind - 1].station;
2490 if (ist == 0)
throw InputError(
"after_event_station_pas: node is not a station");
2491 const typename std::map<std::size_t, typename NetworkStruct<T>::PasParam>::const_iterator it =
2492 sn.pasparam.find(ist);
2493 if (it ==
sn.pasparam.end() || !it->second.svc_rate_fun)
2495 "after_event_station_pas: the station has no service rate function mu(c); set one "
2498 const std::size_t V =
sn.nvars_of(ind);
2499 const std::size_t W = inspace.size() - V;
2500 std::vector<std::size_t> c;
2501 for (std::size_t i = 0; i < W; ++i) {
2503 if (v > 0) c.push_back(
static_cast<std::size_t
>(v));
2505 const std::vector<T> var(inspace.begin() + W, inspace.end());
2506 const double cap =
sn.cap[ist - 1];
2508 if (event == EventType::ARV) {
2511 if (
static_cast<double>(c.size()) >= cap)
return out;
2512 std::vector<std::size_t>
nc = c;
2523 if (
nc.size() > W)
return out;
2525 for (std::size_t i = 0; i <
nc.size(); ++i)
2527 row.resize(W, zero);
2528 row.insert(row.end(), var.begin(), var.end());
2529 out.
space.push_back(row);
2531 out.
prob.push_back(one);
2542 if (event != EventType::DEP)
return out;
2548 for (std::size_t p = 0; p < c.size(); ++p) {
2549 const std::vector<std::size_t> prefix(c.begin(), c.begin() + p + 1);
2550 const T mu_cur = it->second.svc_rate_fun(prefix);
2551 const T ratep = T(mu_cur - mu_prev);
2554 const std::pair<std::vector<std::size_t>, std::size_t> ps =
2558 if (ps.second != cls)
continue;
2560 for (std::size_t i = 0; i < ps.first.size(); ++i)
2562 row.resize(W, zero);
2563 row.insert(row.end(), var.begin(), var.end());
2564 out.
space.push_back(row);
2565 out.
rate.push_back(ratep);
2566 out.
prob.push_back(one);
2583 const std::size_t R =
sn.nclasses;
2585 ri.
slot.assign(R,
static_cast<std::size_t
>(-1));
2586 if (
sn.nvars.size() < ind ||
sn.nvars[ind - 1].size() < 3 * R + 1)
return ri;
2587 std::size_t pos = 0;
2588 for (std::size_t j = 0; j < 2 * R + 1; ++j) pos +=
sn.nvars[ind - 1][j];
2589 for (std::size_t r = 1; r <= R; ++r)
2590 if (
sn.nvars[ind - 1][2 * R + r] > 0) {
2591 ri.
slot[r - 1] = pos;
2604 for (std::size_t i = 0; i < ri.
classes.size(); ++i) {
2608 if (s !=
static_cast<std::size_t
>(-1) && s < var.size())
2632 const std::vector<T>& inspace, std::size_t cls) {
2633 const std::size_t R =
sn.nclasses;
2634 const std::size_t ist =
sn.nodes[ind - 1].station;
2637 if (ist == 0)
throw InputError(
"after_event_station_reply: node is not a station");
2640 const double S =
sn.stations[ist - 1].nservers;
2644 std::size_t callclass = 0;
2645 for (std::size_t i = 0; i < ri.
classes.size(); ++i) {
2646 const std::size_t r = ri.
classes[i];
2647 if (
sn.syncreply.size() >= r &&
sn.syncreply[r - 1] == cls) {
2653 std::vector<T> buf(inspace.begin(), inspace.begin() + L.
bufw);
2654 std::vector<T> srv(inspace.begin() + L.
bufw, inspace.begin() + L.
bufw + L.
srvw);
2655 std::vector<T> var(inspace.begin() + L.
bufw + L.
srvw, inspace.end());
2657 if (callclass > 0) {
2658 const std::size_t s = ri.
slot[callclass - 1];
2659 if (s !=
static_cast<std::size_t
>(-1) && s < var.size() &&
2672 for (std::size_t ke = 0; ke < L.
K[cls - 1]; ++ke) {
2674 std::vector<T> s2 = srv;
2675 s2[L.
Ks[cls - 1] + ke] += one;
2676 std::vector<T> row = buf;
2677 row.insert(row.end(), s2.begin(), s2.end());
2678 row.insert(row.end(), var.begin(), var.end());
2679 out.
space.push_back(row);
2681 out.
prob.push_back(pentry[ke]);
2687 std::vector<T> b2 = buf;
2688 std::size_t slot = b2.size();
2689 for (std::size_t b = 0; b < b2.size(); ++b)
2691 if (slot == b2.size()) {
2692 b2.insert(b2.begin(), zero);
2696 std::vector<T> row = b2;
2697 row.insert(row.end(), srv.begin(), srv.end());
2698 row.insert(row.end(), var.begin(), var.end());
2699 out.
space.push_back(row);
2701 out.
prob.push_back(one);
2709 std::size_t& pos, std::size_t& swk,
long& ctr) {
2710 pos = pi.
ipos !=
static_cast<std::size_t
>(-1)
2712 : (srvclass > 0 ? srvclass : 1);
2713 swk = pi.
iswk !=
static_cast<std::size_t
>(-1)
2716 ctr = pi.
ictr !=
static_cast<std::size_t
>(-1)
2724 std::size_t swk,
long ctr) {
2725 if (pi.
ipos !=
static_cast<std::size_t
>(-1))
2727 if (pi.
iswk !=
static_cast<std::size_t
>(-1))
2729 if (pi.
ictr !=
static_cast<std::size_t
>(-1))
2742 default:
throw InputError(
"polling_budget: unsupported polling type");
2756 std::size_t R,
bool arrived, std::size_t& q,
int& mode,
long& budget) {
2757 if (arrived && pi.
polled[pos - 1] && nbuf[pos - 1] > 0) {
2764 std::size_t p = pos;
2765 for (std::size_t step = 0; step < R; ++step) {
2767 if (!pi.
polled[p - 1])
continue;
2774 if (nbuf[p - 1] > 0) {
2789 std::size_t q,
int mode,
long budget,
const std::vector<T>& buf,
2790 const std::vector<T>& srv,
const std::vector<T>& var,
const RowLayout<T>& L,
2791 std::vector<std::vector<T>>& rows, std::vector<T>& probs) {
2795 std::vector<T> b2 = buf;
2798 for (std::size_t ke = 0; ke < L.
K[q - 1]; ++ke) {
2800 std::vector<T> s2 = srv;
2801 s2[L.
Ks[q - 1] + ke] += one;
2802 std::vector<T> row = b2;
2803 row.insert(row.end(), s2.begin(), s2.end());
2804 const std::vector<T> v2 =
polling_set(pi, var, q, 0, budget);
2805 row.insert(row.end(), v2.begin(), v2.end());
2806 rows.push_back(row);
2807 probs.push_back(pentry[ke]);
2809 }
else if (mode == 2) {
2811 for (std::size_t ke = 0; ke < pi.
ksw[q - 1]; ++ke) {
2813 std::vector<T> row = buf;
2814 row.insert(row.end(), srv.begin(), srv.end());
2815 const std::vector<T> v2 =
polling_set(pi, var, q, ke + 1, 0);
2816 row.insert(row.end(), v2.begin(), v2.end());
2817 rows.push_back(row);
2818 probs.push_back(pi.
sw_pie[q - 1][ke]);
2822 std::vector<T> row = buf;
2823 row.insert(row.end(), srv.begin(), srv.end());
2824 const std::vector<T> v2 =
polling_set(pi, var, q, 0, 0);
2825 row.insert(row.end(), v2.begin(), v2.end());
2826 rows.push_back(row);
2827 probs.push_back(one);
2843 const std::vector<T>& inspace, std::size_t cls) {
2844 const std::size_t R =
sn.nclasses;
2845 const std::size_t ist =
sn.nodes[ind - 1].station;
2848 if (ist == 0)
throw InputError(
"after_event_station_switch: node is not a station");
2850 if (!pinfo.
valid || !pinfo.
has_sw[cls - 1])
return out;
2853 const std::vector<T> buf(inspace.begin(), inspace.begin() + L.
bufw);
2854 const std::vector<T> srv(inspace.begin() + L.
bufw, inspace.begin() + L.
bufw + L.
srvw);
2855 const std::vector<T> var(inspace.begin() + L.
bufw + L.
srvw, inspace.end());
2857 std::size_t pos = 0, swk = 0;
2861 if (pos != cls || swk == 0)
return out;
2864 for (std::size_t kd = 0; kd < pinfo.
ksw[cls - 1]; ++kd) {
2865 if (kd + 1 == swk)
continue;
2866 const T r0 = pinfo.
sw_d0[cls - 1](swk - 1, kd);
2868 std::vector<T> row = buf;
2869 row.insert(row.end(), srv.begin(), srv.end());
2870 const std::vector<T> v2 =
polling_set(pinfo, var, cls, kd + 1, 0);
2871 row.insert(row.end(), v2.begin(), v2.end());
2872 out.
space.push_back(row);
2873 out.
rate.push_back(r0);
2874 out.
prob.push_back(one);
2878 for (std::size_t j = 0; j < pinfo.
ksw[cls - 1]; ++j) rate += pinfo.
sw_d1[cls - 1](swk - 1, j);
2880 std::vector<long> nbuf(R, 0);
2881 for (std::size_t r = 0; r < R && r < L.
bufw; ++r)
2886 polling_next(pinfo, cls, nbuf, R,
true, q, mode, budget);
2887 std::vector<std::vector<T>> rows;
2888 std::vector<T> probs;
2889 polling_land(
sn, ist, pinfo, q, mode, budget, buf, srv, var, L, rows, probs);
2890 for (std::size_t j = 0; j < rows.size(); ++j) {
2895 if (rows[j] == inspace)
continue;
2896 out.
space.push_back(rows[j]);
2897 out.
rate.push_back(T(rate * probs[j]));
2898 out.
prob.push_back(one);
2905 tag_last(out, mode == 1 ? q : 0, 0);
2927 const std::vector<T>& inspace,
EventType event,
2929 const std::size_t R =
sn.nclasses;
2933 const typename std::map<std::size_t, CacheParam<T>>::const_iterator ci =
sn.nodeparam.find(ind);
2934 if (ci ==
sn.nodeparam.end())
throw InputError(
"after_event_cache: node has no CacheParam");
2936 const std::size_t h = cp.
itemcap.size();
2937 const std::size_t n = cp.
nitems;
2938 std::size_t tcc = 0;
2939 for (std::size_t i = 0; i < h; ++i)
2940 if (cp.
itemcap[i] > 0) tcc +=
static_cast<std::size_t
>(cp.
itemcap[i]);
2942 const std::vector<int>& m = cp.
itemcap;
2944 const std::vector<int>& m;
2945 std::size_t operator()(std::size_t i, std::size_t j)
const {
2946 std::size_t base = 0;
2947 for (std::size_t t = 0; t + 1 < i; ++t) base +=
static_cast<std::size_t
>(m[t]);
2948 return base + j - 1;
2952 std::vector<T> srv(inspace.begin(), inspace.begin() + R);
2953 std::vector<T> var(inspace.begin() + R, inspace.end());
2955 if (event == EventType::ARV) {
2956 srv[cls - 1] += one;
2957 std::vector<T> row = srv;
2958 row.insert(row.end(), var.begin(), var.end());
2959 out.
space.push_back(row);
2961 out.
prob.push_back(one);
2965 if (event == EventType::DEP) {
2984 std::size_t item_dep = 0;
2991 if (item_dep != 0) {
2992 const std::size_t bitcol = tcc + item_dep - 1;
2993 if (bitcol < var.size()) {
2996 for (std::size_t r = 0; r < R; ++r)
2998 if (srvtot == 1)
return out;
3016 const std::size_t hc =
3017 cls - 1 < cp.
hitclass.size() ?
static_cast<std::size_t
>(cp.
hitclass[cls - 1]) : 0;
3018 const std::size_t
mc =
3020 if (hc != cls &&
mc != cls)
return out;
3024 srv[cls - 1] -= one;
3025 std::vector<T> row = srv;
3026 row.insert(row.end(), var.begin(), var.end());
3027 out.
space.push_back(row);
3028 out.
rate.push_back(imm);
3029 out.
prob.push_back(one);
3033 if (event != EventType::READ)
return out;
3037 for (std::size_t r = 0; r < R; ++r) tot += num_traits<T>::to_double(srv[r]);
3039 if (cls - 1 >= cp.
pread.size() || cp.
pread[cls - 1].empty())
return out;
3040 const std::vector<T>& p = cp.
pread[cls - 1];
3048 std::vector<std::size_t> rc_list, rc_items, rc_orig;
3050 const std::size_t block_b = tcc + n;
3051 std::size_t width_b = var.size() > block_b ? var.size() - block_b : 0;
3052 if (width_b != rc_list.size()) width_b = 0;
3057 ? std::numeric_limits<double>::infinity()
3059 bool from_retrieval =
false;
3060 for (std::size_t j = 0; j < rc_list.size(); ++j)
3061 if (rc_list[j] == cls) from_retrieval =
true;
3063 for (std::size_t k = 1; k <= n; ++k) {
3065 std::vector<T> srv_e = srv;
3066 srv_e[cls - 1] -= one;
3069 std::size_t posk = 0;
3070 for (std::size_t c = 0; c < tcc && c < var.size(); ++c)
3079 if (from_retrieval) posk = 0;
3081 k - 1 >= cp.
accost[cls - 1].size()
3083 : cp.
accost[cls - 1][k - 1];
3084 const bool have_ac = ac.
rows() >= h + 1 && ac.
cols() >= h + 1;
3089 const bool in_flight =
3091 std::size_t r_class = 0;
3098 if (from_retrieval && !in_flight)
continue;
3100 if (!from_retrieval && r_class != 0) {
3105 std::vector<T> srv_b = srv_e;
3106 std::vector<T> var_b = var;
3113 srv_b[r_class - 1] += one;
3115 if (width_b == 0)
continue;
3116 std::size_t bslot = width_b;
3117 for (std::size_t j = 0; j < rc_list.size(); ++j)
3118 if (rc_list[j] == r_class) { bslot = j;
break; }
3119 if (bslot >= width_b)
continue;
3121 for (std::size_t j = 0; j < width_b; ++j)
3123 if (pend >= maxpend)
continue;
3124 var_b[block_b + bslot] += one;
3126 std::vector<T> row = srv_b;
3127 row.insert(row.end(), var_b.begin(), var_b.end());
3128 out.
space.push_back(row);
3129 out.
rate.push_back(T(p[k - 1] * imm));
3130 out.
prob.push_back(one);
3139 std::vector<T> srv_m = srv_e;
3140 srv_m[cp.
missclass[cls - 1] - 1] += one;
3141 std::vector<T> var_m = var;
3142 if (tcc + k <= var_m.size()) var_m[tcc + k - 1] = zero;
3143 for (std::size_t j = 0; j < width_b; ++j) {
3144 if (rc_items[j] != k)
continue;
3146 if (held <= 0)
continue;
3147 const std::size_t oc = rc_orig[j];
3149 srv_m[cp.
hitclass[oc - 1] - 1] += var_m[block_b + j];
3150 var_m[block_b + j] = zero;
3155 const T rej = have_ac ? ac(0, 0) : zero;
3157 std::vector<T> row = srv_m;
3158 row.insert(row.end(), var_m.begin(), var_m.end());
3159 out.
space.push_back(row);
3160 out.
rate.push_back(T(rej * p[k - 1] * imm));
3161 out.
prob.push_back(one);
3163 for (std::size_t l = 1; l <= h; ++l) {
3164 const T w = have_ac ? ac(0, l) : (l == 1 ? one : zero);
3166 if (m[l - 1] <= 0)
continue;
3167 const std::size_t ml =
static_cast<std::size_t
>(m[l - 1]);
3170 for (std::size_t rr = 1; rr <= ml; ++rr) {
3171 std::vector<T> vp = var_m;
3173 std::vector<T> row = srv_m;
3174 row.insert(row.end(), vp.begin(), vp.end());
3175 out.
space.push_back(row);
3176 out.
rate.push_back(T(w * p[k - 1] /
3178 out.
prob.push_back(one);
3183 std::vector<T> vp = var_m;
3184 for (std::size_t j = ml; j >= 2; --j) vp[cpos(l, j)] = var_m[cpos(l, j - 1)];
3186 T rate = T(w * p[k - 1] * imm);
3190 const T q = cp.
qlru;
3192 std::vector<T> row0 = srv_m;
3193 row0.insert(row0.end(), var_m.begin(), var_m.end());
3194 out.
space.push_back(row0);
3195 out.
rate.push_back(T(rate * T(one - q)));
3196 out.
prob.push_back(one);
3201 std::vector<T> row = srv_m;
3202 row.insert(row.end(), vp.begin(), vp.end());
3203 out.
space.push_back(row);
3204 out.
rate.push_back(rate);
3205 out.
prob.push_back(one);
3212 std::vector<T> srv_h = srv_e;
3213 srv_h[cp.
hitclass[cls - 1] - 1] += one;
3214 std::size_t li = 1, acc = 0;
3215 for (std::size_t t = 0; t < h; ++t) {
3216 const std::size_t mt = m[t] > 0 ?
static_cast<std::size_t
>(m[t]) : 0;
3217 if (posk <= acc + mt) { li = t + 1;
break; }
3220 const std::size_t j = posk - acc;
3232 for (std::size_t inew = li; inew <= h; ++inew) {
3233 if (m[inew - 1] <= 0)
continue;
3234 const std::size_t mn =
static_cast<std::size_t
>(m[inew - 1]);
3235 const T w = have_ac ? ac(li, inew) : (inew == li + 1 ? one : zero);
3239 for (std::size_t r = 1; r <= mn; ++r) {
3240 std::vector<T> vp = var;
3241 vp[cpos(li, j)] = var[cpos(inew, r)];
3243 std::vector<T> row = srv_h;
3244 row.insert(row.end(), vp.begin(), vp.end());
3245 out.
space.push_back(row);
3249 out.
prob.push_back(one);
3256 std::vector<T> vp = var;
3261 for (std::size_t t = j; t >= 2; --t) vp[cpos(li, t)] = var[cpos(li, t - 1)];
3264 vp[cpos(li, ordered ? 1 : j)] = var[cpos(inew, mn)];
3265 for (std::size_t t = mn; t >= 2; --t) vp[cpos(inew, t)] = var[cpos(inew, t - 1)];
3267 std::vector<T> row = srv_h;
3268 row.insert(row.end(), vp.begin(), vp.end());
3269 out.
space.push_back(row);
3270 out.
rate.push_back(T(w * p[k - 1] * imm));
3271 out.
prob.push_back(one);
3278 std::vector<T> row = srv_h;
3279 row.insert(row.end(), var.begin(), var.end());
3280 out.
space.push_back(row);
3281 out.
rate.push_back(T(p[k - 1] * imm));
3282 out.
prob.push_back(one);
3286 std::vector<T> vp = var;
3287 for (std::size_t t = j; t >= 2; --t) vp[cpos(li, t)] = var[cpos(li, t - 1)];
3288 vp[cpos(li, 1)] = var[cpos(li, j)];
3289 std::vector<T> row = srv_h;
3290 row.insert(row.end(), vp.begin(), vp.end());
3291 out.
space.push_back(row);
3292 out.
rate.push_back(T(p[k - 1] * imm));
3293 out.
prob.push_back(one);
3335 std::vector<GlobalSync<T>> gsync;
3337 for (std::size_t ind = 1; ind <=
sn.nodes.size(); ++ind) {
3338 if (
sn.nodes[ind - 1].nodetype != NodeType::Transition)
continue;
3339 const typename std::map<std::size_t, TransitionParam<T>>::const_iterator it =
3340 sn.transparam.find(ind);
3341 if (it ==
sn.transparam.end())
continue;
3343 for (
int pass = 0; pass < 2; ++pass) {
3344 for (std::size_t m = 1; m <= tp.
nmodes; ++m) {
3349 std::vector<std::pair<std::size_t, std::size_t>> enab, fire, inhib;
3353 for (std::size_t q = 0; q < en.
rows(); ++q)
3354 for (std::size_t r = 0; r < en.
cols(); ++r)
3356 enab.push_back(std::make_pair(q + 1, r + 1));
3357 for (std::size_t q = 0; q < fi.
rows(); ++q)
3358 for (std::size_t r = 0; r < fi.
cols(); ++r)
3360 fire.push_back(std::make_pair(q + 1, r + 1));
3361 for (std::size_t q = 0; q < ih.
rows(); ++q)
3362 for (std::size_t r = 0; r < ih.
cols(); ++r) {
3369 for (std::size_t i = 0; i < enab.size(); ++i)
3370 dup = dup || enab[i].first == q + 1;
3371 for (std::size_t i = 0; i < fire.size(); ++i)
3372 dup = dup || fire[i].first == q + 1;
3373 for (std::size_t i = 0; i < inhib.size(); ++i)
3374 dup = dup || inhib[i].first == q + 1;
3375 if (!dup) inhib.push_back(std::make_pair(q + 1, r + 1));
3378 g.
active.event = pass == 0 ? EventType::ENABLE : EventType::FIRE;
3385 std::vector<std::size_t> seen;
3386 auto once = [&](std::size_t q, std::size_t r) {
3387 for (std::size_t i = 0; i < seen.size(); ++i)
3388 if (seen[i] == q)
return;
3392 for (std::size_t i = 0; i < enab.size(); ++i) once(enab[i].first, enab[i].second);
3393 for (std::size_t i = 0; i < inhib.size(); ++i)
3394 once(inhib[i].first, inhib[i].second);
3396 for (std::size_t i = 0; i < enab.size(); ++i)
3399 en(enab[i].first - 1, enab[i].second - 1)});
3400 for (std::size_t i = 0; i < fire.size(); ++i)
3403 fi(fire[i].first - 1, fire[i].second - 1)});
3404 for (std::size_t i = 0; i < inhib.size(); ++i)
3406 inhib[i].second, one});
3441 const std::size_t R =
sn.nclasses;
3442 const std::size_t ind = gl.
active.node;
3443 const std::size_t mode = gl.
active.mode;
3447 const std::size_t isf =
sn.stateful_index(ind);
3448 if (isf == 0)
throw InputError(
"after_global_event: the transition is not stateful");
3449 const typename std::map<std::size_t, TransitionParam<T>>::const_iterator it =
3450 sn.transparam.find(ind);
3451 if (it ==
sn.transparam.end())
throw InputError(
"after_global_event: node has no TransitionParam");
3454 std::vector<std::size_t> fK(tp.
nmodes, 1), fKs(tp.
nmodes, 0);
3455 std::size_t tot = 0;
3456 for (std::size_t m = 0; m < tp.
nmodes; ++m) {
3461 const std::vector<T>& row = glspace.
local[isf - 1];
3462 std::vector<T> buf(row.begin(), row.begin() + tp.
nmodes);
3463 std::vector<T> srv(row.begin() + tp.
nmodes, row.begin() + tp.
nmodes + tot);
3464 std::vector<T> fired(row.begin() + tp.
nmodes + tot,
3465 row.begin() + 2 * tp.
nmodes + tot);
3466 const std::vector<T> var(row.begin() + 2 * tp.
nmodes + tot, row.end());
3469 std::vector<std::vector<T>> ep(
sn.nodes.size() + 1, std::vector<T>(R, zero));
3470 for (std::size_t j = 0; j < gl.
passive.size(); ++j) {
3471 const std::size_t pn = gl.
passive[j].node;
3472 const std::size_t pisf =
sn.stateful_index(pn);
3473 if (pisf == 0)
continue;
3489 bool inhibited =
false;
3490 for (std::size_t q = 0; q < ih_m.
rows(); ++q)
3491 for (std::size_t r = 0; r < ih_m.
cols() && r < R; ++r) {
3493 if (std::isinf(thr))
continue;
3497 for (std::size_t q = 0; q < en_m.
rows(); ++q)
3498 for (std::size_t r = 0; r < en_m.
cols() && r < R; ++r) {
3500 if (need <= 0)
continue;
3503 long mark_degree = 0;
3504 if (!inhibited && !under) {
3508 for (std::size_t q = 0; q < en_m.
rows() && ok; ++q)
3509 for (std::size_t r = 0; r < en_m.
cols() && r < R && ok; ++r) {
3511 if (need <= 0)
continue;
3517 mark_degree = d - 1;
3520 const long nsrv = std::isfinite(svm) ?
static_cast<long>(svm)
3523 if (gl.
active.event == EventType::ENABLE) {
3525 for (std::size_t k = 0; k < fK[mode - 1]; ++k)
3527 if (inhibited || under) {
3529 std::vector<T> b2 = buf, s2 = srv;
3531 for (std::size_t k = 0; k < fK[mode - 1]; ++k) s2[fKs[mode - 1] + k] = zero;
3532 std::vector<T> nr = b2;
3533 nr.insert(nr.end(), s2.begin(), s2.end());
3534 nr.insert(nr.end(), fired.begin(), fired.end());
3535 nr.insert(nr.end(), var.begin(), var.end());
3536 if (nr == row)
return out;
3538 ns.
local[isf - 1] = nr;
3539 out.
space.push_back(ns);
3540 out.
rate.push_back(imm);
3541 out.
prob.push_back(one);
3545 const long want = std::min(mark_degree, nsrv);
3546 if (running == want)
return out;
3547 if (running < want) {
3551 const long nadd = want - running;
3552 std::vector<T> pe(fK[mode - 1], zero);
3554 static_cast<std::size_t
>(fK[mode - 1])) {
3559 for (std::size_t k = 0; k < fK[mode - 1]; ++k) pe[k] = pv[k];
3564 std::vector<std::vector<long>> combs;
3565 std::vector<long> cur(fK[mode - 1], 0);
3566 std::function<void(std::size_t,
long)> rec = [&](std::size_t k,
long left) {
3567 if (k + 1 == fK[mode - 1]) {
3569 combs.push_back(cur);
3572 for (
long v = left; v >= 0; --v) {
3574 rec(k + 1, left - v);
3578 for (std::size_t i = 0; i < combs.size(); ++i) {
3579 std::vector<T> b2 = buf, s2 = srv;
3581 double logp = std::lgamma(
static_cast<double>(nadd) + 1.0);
3582 bool zeroprob =
false;
3583 for (std::size_t k = 0; k < fK[mode - 1]; ++k) {
3587 logp += combs[i][k] * std::log(pk) -
3588 std::lgamma(
static_cast<double>(combs[i][k]) + 1.0);
3589 else if (combs[i][k] > 0)
3592 std::vector<T> nr = b2;
3593 nr.insert(nr.end(), s2.begin(), s2.end());
3594 nr.insert(nr.end(), fired.begin(), fired.end());
3595 nr.insert(nr.end(), var.begin(), var.end());
3597 ns.
local[isf - 1] = nr;
3598 out.
space.push_back(ns);
3599 out.
rate.push_back(imm);
3607 const long ndiff = running - want;
3608 std::vector<long> sv(fK[mode - 1], 0);
3609 for (std::size_t k = 0; k < fK[mode - 1]; ++k)
3611 std::vector<std::vector<long>> combs;
3612 std::vector<long> cur(fK[mode - 1], 0);
3613 std::function<void(std::size_t,
long)> rec = [&](std::size_t k,
long left) {
3614 if (k + 1 == fK[mode - 1]) {
3615 if (left > sv[k])
return;
3617 combs.push_back(cur);
3620 for (
long v = std::min(left, sv[k]); v >= 0; --v) {
3622 rec(k + 1, left - v);
3626 std::vector<double> w(combs.size(), 0.0);
3627 double wmax = -1e300;
3628 for (std::size_t i = 0; i < combs.size(); ++i) {
3630 for (std::size_t k = 0; k < fK[mode - 1]; ++k)
3631 lw += std::lgamma(
static_cast<double>(sv[k]) + 1.0) -
3632 std::lgamma(
static_cast<double>(combs[i][k]) + 1.0) -
3633 std::lgamma(
static_cast<double>(sv[k] - combs[i][k]) + 1.0);
3635 wmax = std::max(wmax, lw);
3638 for (std::size_t i = 0; i < w.size(); ++i) {
3639 w[i] = std::exp(w[i] - wmax);
3642 for (std::size_t i = 0; i < combs.size(); ++i) {
3643 std::vector<T> b2 = buf, s2 = srv;
3644 for (std::size_t k = 0; k < fK[mode - 1]; ++k)
3647 std::vector<T> nr = b2;
3648 nr.insert(nr.end(), s2.begin(), s2.end());
3649 nr.insert(nr.end(), fired.begin(), fired.end());
3650 nr.insert(nr.end(), var.begin(), var.end());
3652 ns.
local[isf - 1] = nr;
3653 out.
space.push_back(ns);
3654 out.
rate.push_back(imm);
3661 if (gl.
active.event != EventType::FIRE)
return out;
3663 const bool immediate_mode = mode - 1 < tp.
timing.size() &&
3665 const T fw = immediate_mode && mode - 1 < tp.
fireweight.size() ? tp.
fireweight[mode - 1] : one;
3666 const long en_degree = inhibited ? 0 : std::min(mark_degree, nsrv);
3667 const long imm_servers = immediate_mode ? std::min(mark_degree, nsrv) : 0;
3669 for (std::size_t k = 0; k < fK[mode - 1]; ++k) {
3671 const bool fires = immediate_mode ? (k == 0 && imm_servers >= 1)
3672 : (in_k > 0 && en_degree >= 1);
3673 if (!fires)
continue;
3675 if (immediate_mode) {
3680 for (std::size_t j = 0; j < tp.
firingproc[mode - 1].D1.cols(); ++j)
3687 for (std::size_t q = 1; q <=
sn.nodes.size(); ++q) {
3689 for (std::size_t r = 0; r < R; ++r) s2 += ep[q][r];
3692 rate = T(rate * tp.
firingdep[mode - 1](mk));
3697 std::vector<T> b2 = buf, s2 = srv;
3699 s2[fKs[mode - 1] + k] -= one;
3700 b2[mode - 1] += one;
3703 std::vector<T> nr = b2;
3704 nr.insert(nr.end(), s2.begin(), s2.end());
3705 nr.insert(nr.end(), fired.begin(), fired.end());
3706 nr.insert(nr.end(), var.begin(), var.end());
3707 ns.
local[isf - 1] = nr;
3713 for (std::size_t j = 0; j < gl.
passive.size(); ++j) {
3715 if (pe2.
event != EventType::PRE && pe2.
event != EventType::POST)
continue;
3716 const std::size_t pisf =
sn.stateful_index(pe2.
node);
3717 if (pisf == 0)
continue;
3718 std::vector<T>& prow = ns.
local[pisf - 1];
3720 const std::size_t pist =
sn.nodes[pe2.
node - 1].station;
3722 pist != 0 ?
sn.stations[pist - 1].sched : SchedStrategy::INF;
3723 const std::size_t c = pe2.
cls;
3724 if (pe2.
event == EventType::PRE) {
3725 if (state_detail::buffer_is_class_tag(psched)) {
3728 long left =
static_cast<long>(wgt);
3730 if (psched == SchedStrategy::LCFS) {
3731 for (std::size_t b = 0; b < prow.size() && left > 0; ++b)
3732 if (prow[b] == tag) { prow[b] = zero; --left; }
3734 for (std::size_t b = prow.size(); b-- > 0 && left > 0;)
3735 if (prow[b] == tag) { prow[b] = zero; --left; }
3737 }
else if (prow.size() > R) {
3743 prow[R + c - 1] = zero;
3744 }
else if (c - 1 < prow.size()) {
3748 if (state_detail::buffer_is_class_tag(psched)) {
3749 for (
long q = 0; q < static_cast<long>(wgt); ++q)
3751 }
else if (c - 1 < prow.size()) {
3756 out.
space.push_back(ns);
3757 out.
rate.push_back(rate);
3758 out.
prob.push_back(one);
3820 if (sy.
active.node == 0 || sy.
active.node >
sn.nodes.size())
return false;
3821 const std::size_t ist =
sn.nodes[sy.
active.node - 1].station;
3822 if (ist == 0)
return false;
3823 const std::size_t cls_p = sy.
passive.cls;
3824 if (ist >
sn.immfeed.size() || cls_p == 0 || cls_p >
sn.immfeed[ist - 1].size())
return false;
3825 return sn.immfeed[ist - 1][cls_p - 1];
3843 const std::vector<std::vector<bool>>& impatience_classes = std::vector<std::vector<bool>>(),
3844 const std::vector<std::size_t>& breakdown_nodes = std::vector<std::size_t>()) {
3845 const std::size_t R =
sn.nclasses;
3846 const std::size_t local =
sn.nodes.size() + 1;
3848 std::vector<Sync<T>> sync;
3850 for (std::size_t ind = 1; ind <=
sn.nodes.size(); ++ind) {
3852 const std::size_t ist = nd.
station;
3853 for (std::size_t r = 1; r <= R; ++r) {
3856 if (ist != 0 &&
sn.phases_of(ist, r) > 1) {
3862 if (ist != 0 && impatience_classes.size() >= ist &&
3863 impatience_classes[ist - 1].size() >= r && impatience_classes[ist - 1][r - 1]) {
3870 const typename std::map<std::size_t, RetrialParam<T>>::const_iterator rit =
3871 sn.retrialparam.find(ist);
3872 if (rit !=
sn.retrialparam.end() && rit->second.retrial_proc.size() >= r &&
3873 !rit->second.retrial_proc[r - 1].disabled) {
3883 if (ist != 0 && r == 1) {
3884 bool has_bd =
sn.has_breakdown_node(ind);
3885 for (std::size_t b = 0; b < breakdown_nodes.size() && !has_bd; ++b)
3886 if (breakdown_nodes[b] == ind) { has_bd =
true;
break; }
3899 if (ist != 0 &&
sn.stations[ist - 1].sched == SchedStrategy::POLLING) {
3911 if (nd.
nodetype == NodeType::Fork)
continue;
3925 bool cache_read_class =
false;
3926 if (nd.
nodetype == NodeType::Cache) {
3927 const typename std::map<std::size_t, CacheParam<T>>::const_iterator ci =
3928 sn.nodeparam.find(ind);
3929 if (ci !=
sn.nodeparam.end()) {
3930 if (r - 1 < ci->second.pread.size() && !ci->second.pread[r - 1].empty()) {
3937 r - 1 < ci->second.hitclass.size() && ci->second.hitclass[r - 1] != 0;
3944 if (nd.
nodetype == NodeType::Transition && r == 1) {
3945 const typename std::map<std::size_t, TransitionParam<T>>::const_iterator ti =
3946 sn.transparam.find(ind);
3947 if (ti !=
sn.transparam.end()) {
3948 for (std::size_t m = 1; m <= ti->second.nmodes; ++m) {
3956 if (cache_read_class)
continue;
3958 const std::size_t isf =
sn.stateful_index(ind);
3959 for (std::size_t jnd = 1; jnd <=
sn.nodes.size(); ++jnd) {
3960 if (!
sn.nodes[jnd - 1].stateful)
continue;
3961 const std::size_t jsf =
sn.stateful_index(jnd);
3962 for (std::size_t s = 1; s <= R; ++s) {
3963 const T p =
sn.rt((isf - 1) * R + (r - 1), (jsf - 1) * R + (s - 1));
3974 if (nd.
routing.size() >= s && nd.
routing[s - 1] == RoutingStrategy::SDR) {
3976 ns.
passive.rt_row = (isf - 1) * R + (r - 1);
3977 ns.
passive.rt_col = (jsf - 1) * R + (s - 1);
4017 const std::size_t R =
sn.nclasses;
4019 const std::size_t isf_f =
sn.stateful_index(e.
fork);
4020 if (isf_f == 0)
return out;
4021 const std::vector<T>& fs = gl.
local[isf_f - 1];
4022 if (fs.size() < R)
return out;
4026 const std::size_t B = e.
auxall.size();
4027 if (B == 0 || e.
tag == 0 || e.
tag > e.
auxall[0].size())
return out;
4028 const std::size_t Tt = e.
auxall[0].size();
4029 std::vector<double> nglobal(R, 0.0);
4030 for (std::size_t isf = 1; isf <=
sn.stateful_nodes.size(); ++isf) {
4031 const std::pair<T, std::vector<T>> mg =
4033 for (std::size_t r = 0; r < R; ++r) {
4039 if (std::isfinite(v)) nglobal[r] += v;
4042 std::vector<double> occ(Tt, 0.0);
4043 for (std::size_t t = 0; t < Tt; ++t)
4044 for (std::size_t b = 0; b < B; ++b) occ[t] += nglobal[e.
auxall[b][t] - 1];
4045 if (occ[e.
tag - 1] > 0)
return out;
4046 for (std::size_t t = 0; t + 1 < e.
tag; ++t)
4047 if (occ[t] == 0)
return out;
4050 seed.
local[isf_f - 1][seed.
local[isf_f - 1].size() - R + e.
cls - 1] -=
4053 std::vector<NetState<T>> partials(1, seed);
4059 std::vector<std::size_t> emissions;
4062 for (std::size_t rep = 0; rep < w; ++rep)
4063 for (std::size_t b = 0; b < B; ++b) emissions.push_back(b);
4065 std::size_t wmax = 0;
4066 for (std::size_t b = 0; b < e.
weightlink.size(); ++b)
4068 for (std::size_t rep = 1; rep <= wmax; ++rep)
4069 for (std::size_t b = 0; b < B; ++b)
4072 for (std::size_t ei = 0; ei < emissions.size(); ++ei) {
4073 const std::size_t b = emissions[ei];
4075 const std::size_t isf_b =
sn.stateful_index(bh);
4078 std::vector<NetState<T>> nextp;
4079 std::vector<T> nextq;
4080 for (std::size_t pp = 0; pp < partials.size(); ++pp) {
4082 after_event(
sn, bh, partials[pp].local[isf_b - 1], EventType::ARV, a);
4084 for (std::size_t
io = 0;
io < arv.
space.size(); ++
io) {
4087 nextp.push_back(ns);
4088 nextq.push_back(
io < arv.
prob.size() ? T(partprob[pp] * arv.
prob[
io])
4092 partials.swap(nextp);
4093 partprob.swap(nextq);
4096 out.
space = partials;
4097 for (std::size_t i = 0; i < partials.size(); ++i) {
4099 out.
prob.push_back(T(partprob[i] * e.
prob));
Base error for the multiprecision C++ port.
UnsupportedError(const std::string &what)
A network plus its refreshed NetworkStruct.
The exception types the port throws.
Enumerations and the minimal distribution descriptor shared by the model layer of the C++ port.
Markovian arrival process descriptors: stationary vectors, rate, moments, autocorrelation and the ind...
SchedStrategy
Scheduling disciplines, with the values of MATLAB SchedStrategy.
DropStrategy
Blocking and loss rules, with the values of MATLAB DropStrategy.
@ IMMEDIATE
fires with zero delay, resolved by weight and priority
@ REPLY
completes a synchronous call, releasing a held server
@ CATASTROPHE
removes EVERY job at the station
RemovalPolicy
Which job a negative signal removes, with the values of MATLAB RemovalPolicy.
@ FCFS
the oldest waiting job; servers only once nobody waits
@ LCFS
the newest waiting job; servers only once nobody waits
@ RANDOM
uniform over waiting AND in-service jobs
EventType
The events a state can undergo, with the values of MATLAB EventType.
@ 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
const char * sched_to_text(SchedStrategy s)
std::function< std::vector< T >(const std::vector< T > &)> CdScaling
A class-dependent scaling map, sn.cdscaling.
const char * event_to_text(EventType e)
@ QLRU
q-LRU: LRU with probabilistic admission on a miss
@ FIFO
first in, first out
std::vector< T > map_pie(const Map< T > &m)
Phase distribution seen by an arriving job, pie = pi D1 / (pi D1 e).
std::vector< T > entry_phase_dist(const NetworkStruct< T > &sn, std::size_t ist, std::size_t cls)
The entry-phase distribution pie{ist}{class}: which phase a service STARTS in.
long polling_budget(const PollingInfo< T > &pi, long nbufq)
Port of State.pollingBudget: how many services this visit may perform.
EventOutcome< T > after_event_join(const NetworkStruct< T > &sn, std::size_t ind, const std::vector< T > &inspace, EventType event, std::size_t cls)
Port of State.afterEventJoin: an event at a Join node of an FJ-augmented struct.
EventOutcome< T > after_event_station_pas(const NetworkStruct< T > &sn, std::size_t ind, const std::vector< T > &inspace, EventType event, std::size_t cls)
Defined below; the ARV and DEP branches divert to it before any slicing.
void tag_last(EventOutcome< T > &out, std::size_t start_cls, std::size_t preempt_cls)
Tag the successor row just appended to OUT: START_CLS begins service on it and PREEMPT_CLS is displac...
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,...
std::pair< std::vector< std::size_t >, std::vector< T > > signal_batch_pmf(const NetworkStruct< T > &sn, std::size_t cls, std::size_t ntot)
Port of State.signalBatchPMF: the batch size a negative signal removes.
ReplyBlockInfo reply_block_info(const NetworkStruct< T > &sn, std::size_t ind)
Defined below; the departure branch records a server held for a reply.
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.
void polling_get(const PollingInfo< T > &pi, const std::vector< T > &var, std::size_t srvclass, std::size_t &pos, std::size_t &swk, long &ctr)
Defined below; the polling branches of ARV, DEP and SWITCH use these.
EventOutcome< T > after_event_station_switch(const NetworkStruct< T > &sn, std::size_t ind, const std::vector< T > &inspace, std::size_t cls)
Port of the SWITCH branch: a polling server advances its switchover timer.
void rr_advance_row(const NetworkStruct< T > &sn, std::size_t ind, std::size_t cls, std::vector< std::vector< T > > &rows)
Port of State.afterEventStation's dispatch: the successors of one event at one station.
void polling_next(const PollingInfo< T > &pi, std::size_t pos, const std::vector< long > &nbuf, std::size_t R, bool arrived, std::size_t &q, int &mode, long &budget)
Port of State.pollingNext: where the server goes from buffer pos.
bool immfeed_self_loop(const NetworkStruct< T > &sn, const Sync< T > &sy)
True when a synchronization is an IMMEDIATE-FEEDBACK SELF-LOOP: a departure whose passive half is an ...
std::vector< T > polling_set(const PollingInfo< T > &pi, std::vector< T > var, std::size_t pos, std::size_t swk, long ctr)
Write (pos, swk, ctr) back into the local-variable block.
GlobalOutcome< T > after_global_event(const NetworkStruct< T > &sn, const NetState< T > &glspace, const GlobalSync< T > &gl)
Port of State.afterGlobalEvent: an SPN mode ENABLEs or FIREs.
EventOutcome< T > after_event_station_reply(const NetworkStruct< T > &sn, std::size_t ind, const std::vector< T > &inspace, std::size_t cls)
Port of State.afterEventStationReply: a REPLY signal completes a synchronous call at the station hold...
EventOutcome< T > after_event_station_arv(const NetworkStruct< T > &sn, std::size_t ind, const std::vector< T > &inspace, std::size_t cls)
Port of the ARV branch of State.afterEventStation: an arriving class-cls job joins node ind,...
EventOutcome< T > after_event_station_renege(const NetworkStruct< T > &sn, std::size_t ind, const std::vector< T > &inspace, std::size_t cls, const T &impatience_mu)
Port of the RENEGE branch: a WAITING class-cls job abandons the queue.
EventOutcome< T > after_event_cache(const NetworkStruct< T > &sn, std::size_t ind, const std::vector< T > &inspace, EventType event, std::size_t cls)
Port of State.afterEventCache: events at a Cache node.
EventOutcome< T > after_event_station_signal(const NetworkStruct< T > &sn, std::size_t ind, const std::vector< T > &inspace, std::size_t cls)
Port of State.afterEventStationSignal: a G-network signal arrives.
bool is_physical_capacity(const NetworkStruct< T > &sn, std::size_t ist, std::size_t cls)
Port of State.isPhysicalCapacity: true when the bound at (ist, class) is a PHYSICAL capacity rather t...
PrioPop< T > prio_pop(const NetworkStruct< T > &sn, std::size_t ist, const Marginal< T > &m, std::size_t cls, double ni, double S)
Compute the *PRIO effective population; a no-op for every other discipline.
T cd_factor(const NetworkStruct< T > &sn, std::size_t ist, const std::vector< T > &nir, std::size_t cls)
Port of State.cdclassfactor: the class-dependence multiplier of a class-cls rate at the per-class pop...
EventOutcome< T > after_event_station_phase(const NetworkStruct< T > &sn, std::size_t ind, const std::vector< T > &inspace, std::size_t cls)
Port of the PHASE branch of State.afterEventStation: service advances a phase WITHOUT completing.
std::pair< std::vector< T >, std::vector< T > > phase_rates(const NetworkStruct< T > &sn, std::size_t ist, std::size_t cls)
sn.mu and sn.phi for one (station, class), derived as MATLAB's Markovian.getMu / getPhi derive them f...
EventOutcome< T > after_event_transition(const NetworkStruct< T > &sn, std::size_t ind, const std::vector< T > &inspace, EventType event, std::size_t mode)
Port of State.afterEventTransition, the PHASE arm: one running server of the given mode advances its ...
EventOutcome< T > after_event_router(const NetworkStruct< T > &sn, std::size_t ind, const std::vector< T > &inspace, EventType event, std::size_t cls)
Port of State.afterEventRouter: a Router holds a job for the instant it takes to decide where it goes...
T lld_factor(const NetworkStruct< T > &sn, std::size_t ist, double n)
The limited-load-dependent multiplier at population n, 1 when unset.
void pad_tags(EventOutcome< T > &out)
Bring the tag vectors up to one entry per successor, so a caller can index them exactly like space.
void pas_tag_started(EventOutcome< T > &out, const F &mu_fun, const std::vector< std::size_t > &cold, const std::vector< std::size_t > &cnew)
Tag the successor just appended to OUT with the PAS positions that started service on it: those of CN...
std::vector< Sync< T > > refresh_sync(const NetworkStruct< T > &sn, const std::vector< std::vector< bool > > &impatience_classes=std::vector< std::vector< bool > >(), const std::vector< std::size_t > &breakdown_nodes=std::vector< std::size_t >())
Port of MNetwork.refreshSync: the synchronization list.
EventOutcome< T > after_event(const NetworkStruct< T > &sn, std::size_t ind, const std::vector< T > &inspace, EventType event, std::size_t cls, bool no_promote=false, const T &aux_rate=num_traits< T >::from_int(0))
Port of State.afterEvent: the successors of one event at one NODE.
std::pair< std::vector< std::size_t >, std::size_t > pass_and_swap(const std::vector< std::size_t > &c, std::size_t p, const std::vector< std::vector< bool > > &G)
Port of State.passAndSwap: the transition a service completion triggers at a pass-and-swap station (D...
std::pair< T, std::vector< T > > to_marginal_aggr(const NetworkStruct< T > &sn, std::size_t ind, const std::vector< T > &state_i)
Port of State.toMarginalAggr: the job counts of one node's state row, without the per-phase detail to...
EventOutcome< T > after_event_fork(const NetworkStruct< T > &sn, std::size_t ind, const std::vector< T > &inspace, EventType event, std::size_t cls)
Port of State.afterEventFork: an event at a STATEFUL Fork node.
EventOutcome< T > after_event_station(const NetworkStruct< T > &sn, std::size_t ind, const std::vector< T > &inspace, EventType event, std::size_t cls, bool no_promote=false, const T &aux_rate=num_traits< T >::from_int(0))
std::vector< GlobalSync< T > > refresh_global_sync(const NetworkStruct< T > &sn)
Port of MNetwork.refreshGlobalSync: the ENABLE and FIRE synchronizations.
std::vector< double > pas_increments(const F &mu_fun, const std::vector< std::size_t > &c)
Port of State.afterEventStationPAS: events at a pass-and-swap station.
T service_share(const NetworkStruct< T > &sn, std::size_t ist, const Marginal< T > &m, std::size_t cls, double ni, double S)
Defined below; DEP and PHASE must share one definition of the share.
GlobalOutcome< T > after_fj_event(const NetworkStruct< T > &sn, const FjSync< T > &e, const NetState< T > &gl)
Port of State.afterFJEvent: fire ONE entry of the fork firing list.
RowLayout< T > row_layout(const NetworkStruct< T > &sn, std::size_t ind, std::size_t width)
EventOutcome< T > after_event_station_dep(const NetworkStruct< T > &sn, std::size_t ind, const std::vector< T > &inspace, std::size_t cls, bool no_promote=false)
Port of the DEP branch of State.afterEventStation: a class-cls job completes service at station ind.
PollingInfo< T > polling_info(const NetworkStruct< T > &sn, std::size_t ind)
EventOutcome< T > after_event_station_breakdown(const NetworkStruct< T > &sn, std::size_t ind, const std::vector< T > &inspace, bool up, const T &mu)
Port of the FAILURE and REPAIR branches: the server goes down, or comes back.
bool arrival_is_lost(const NetworkStruct< T > &sn, std::size_t ist, std::size_t cls)
Port of State.arrivalIsLost: true when an arrival that finds no room is LOST, false when it must BLOC...
EventOutcome< T > after_event_station_retry(const NetworkStruct< T > &sn, std::size_t ind, const std::vector< T > &inspace, std::size_t cls, const T &retrial_mu, bool constant_policy=false)
Port of the RETRY branch: an ORBITING class-cls job retries entry.
void polling_land(const NetworkStruct< T > &sn, std::size_t ist, const PollingInfo< T > &pi, std::size_t q, int mode, long budget, const std::vector< T > &buf, const std::vector< T > &srv, const std::vector< T > &var, const RowLayout< T > &L, std::vector< std::vector< T > > &rows, std::vector< T > &probs)
Port of State.pollingLand: the states the walk lands in, with weights.
double reply_blocked(const NetworkStruct< T > &sn, std::size_t ind, const std::vector< T > &var)
Defined below; the reply block subtracts held servers in the ARV branch.
Conservation laws of a layered queueing network, enumerated from its structure.
A queueing network and its refreshed NetworkStruct.
State.pollingInfo and the controller description it returns.
Port of the MATLAB +State package: the encoding that turns a station's state row into marginal job co...
Matrix< T > D0
The (D0,D1) pair when the type carries one directly.
std::vector< Matrix< T > > Dmark
MMAP per-class D1 blocks / BMAP per-batch-size blocks; empty otherwise.
static constexpr double Immediate
Rate of an Immediate distribution; its mean is 1/Immediate = 1e-8.
A MAP as the pair of matrices (D0, D1).
Server breakdown and repair of a station whose server fails and is repaired.
T failure_rate
sn.breakdownMu: 1 / mean failure time
T repair_rate
sn.repairMu: 1 / mean repair time
T qlru
Delayed-hit retrieval system (Cache.setRetrievalSystem).
std::vector< std::vector< Matrix< T > > > accost
(u) x (n) of (h+1)x(h+1), or empty
long max_pending_retrieval
Truncation level of block B: how many secondary requests may be merged onto the in-flight fetches of ...
std::vector< std::vector< std::size_t > > retrieval_classes
(nitems x nclasses), 1-based
std::vector< int > itemcap
std::vector< std::size_t > missclass
std::vector< std::size_t > hitclass
lang::ReplacementStrategy replacestrat
std::vector< std::vector< T > > pread
(u) x (n), empty row = NaN
What one event produces at one node: the successor rows, their rates and their probabilities,...
std::vector< T > prob
per-row probability of the choice
std::vector< std::vector< T > > space
successor local state rows
std::vector< T > rate
per-row rate, -1 on a passive half
std::vector< std::vector< std::size_t > > start
START annotation: the 1-based classes that BEGIN or RESUME holding a server on each successor row.
std::vector< std::vector< std::size_t > > preempt
PREEMPT annotation: the 1-based classes pushed back into the buffer.
sn.nodeparam{j}.fj: what a Join node needs to fire on identity.
std::vector< std::size_t > origclasses
std::map< std::size_t, std::vector< std::vector< std::size_t > > > auxmatrix
std::map< std::size_t, std::vector< std::size_t > > required
One fork firing synchronization: sn.fjsync{k}.
std::size_t fork
1-based Fork node
std::vector< std::size_t > weightlink
Per-branch tasksPerLink, EMPTY when every branch carries weight.
std::size_t weight
tasksPerLink: siblings emitted per branch
std::vector< std::size_t > branchheads
1-based node per branch
std::size_t cls
1-based ORIGINAL class being forked
std::vector< std::vector< std::size_t > > auxall
(B x T) every auxiliary class of this (fork, class), for the tag scan.
std::vector< std::size_t > auxclasses
the tag's auxiliary class per branch
std::size_t tag
1-based tag this entry allocates
static constexpr double Immediate
Rate of an Immediate distribution; its mean is 1/Immediate = 1e-8.
static constexpr double MaxInt
Stand-in for an unbounded COUNT, MATLAB GlobalConstants.MaxInt.
What one global event produces: a whole network state per outcome.
std::vector< NetState< T > > space
std::vector< bool > completion
True where the outcome is a firing COMPLETION, i.e.
A GLOBAL synchronization: an SPN mode event and the place arcs it drives.
std::vector< ModeEvent< T > > passive
What State.toMarginal returns for one station and one state row.
std::vector< std::vector< T > > kir
jobs in service per class and phase
std::vector< T > nir
jobs per class
std::vector< T > sir
jobs in service per class
One half of a GLOBAL synchronization: a mode event at a node.
std::size_t mode
1-based mode index
std::size_t node
1-based node index (a Transition, or a place)
std::size_t cls
1-based class the arc moves
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
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< std::vector< T > > sw_pie
std::vector< Matrix< T > > sw_d0
std::vector< Matrix< T > > sw_d1
std::vector< bool > polled
The population the *PRIO disciplines actually share the server among.
std::vector< T > nir
nirprio when masked, the plain marginal otherwise
bool served
false when cls is not in the most urgent group
double ni
niprio when masked, the plain total otherwise
bool masked
whether the saturated-station mask was applied
Where node ind keeps its reply-block counters inside the local vars.
std::vector< std::size_t > slot
slot[r-1] = 0-based column, or npos
std::vector< std::size_t > classes
1-based calling classes holding a block
How a station's state row splits into [buffer | server | local vars].
std::size_t srvw
total server width
std::size_t bufw
buffer width, the only discipline-dependent part
std::vector< std::size_t > Ks
offset of class r's phase block
std::size_t nvar
local-variable width
std::vector< std::size_t > K
phases per class
One station of the network.
CdScaling< T > jdscaling
sn.jdscaling for this station: MATLAB's Station.ljdScaling, the JOINT dependence map eta_i(n),...
CdScaling< T > cdscaling
sn.cdscaling for this station: the class-dependence map, empty when unset.
One half of a synchronization: an event at a node, in a class.
std::size_t cls
1-based class index
T prob
routing probability, passive half
std::size_t rt_row
(isf-1)*nclasses + (r-1) of the active half
std::size_t rt_col
(jsf-1)*nclasses + (s-1) of this passive half
std::size_t node
1-based node index, or local for the dummy
bool statedep
The routing probability is a FUNCTION of the network state, so prob holds only the state-independent ...
One synchronization: an ACTIVE event and the PASSIVE event it drives.
The parameters of a Cache node, MATLAB's sn.nodeparam{ind} for a Cache.
std::vector< lang::TimingStrategy > timing
immediate or timed
std::vector< lang::Distrib< T > > firingproc
firing distribution per mode
std::vector< double > nmodeservers
servers per mode, may be infinite
std::vector< T > fireweight
weight among simultaneously enabled modes
std::vector< Matrix< T > > firing
firing[m](p,r): class-r tokens mode m moves to/from place p when it fires.
std::vector< Matrix< T > > enabling
enabling[m](p,r): class-r tokens of place p (0-based node) mode m needs.
std::vector< std::function< T(const std::vector< T > &)> > firingdep
Marking-dependent firing-rate multiplier g_m(marking); an empty entry is the unit multiplier.
std::vector< Matrix< T > > inhibiting
inhibiting[m](p,r): class-r tokens of p that BLOCK mode m (Inf = never).
std::vector< std::size_t > firingphases
phase count per mode, 0 when non-Markovian