5#ifndef LINE_LANG_QN_STATE_EVENTS_H
6#define LINE_LANG_QN_STATE_EVENTS_H
55 std::vector<std::vector<T>>
space;
63 std::vector<std::vector<std::size_t>>
start;
65 std::vector<std::vector<std::size_t>>
preempt;
77 if (out.
space.empty())
return;
80 if (start_cls) out.
start.back().push_back(start_cls);
81 if (preempt_cls) out.
preempt.back().push_back(preempt_cls);
112 const std::vector<T>& state_i) {
113 const std::size_t R =
sn.nclasses;
115 std::vector<T> nir(R, zero);
116 if (ind == 0 || ind >
sn.nodes.size())
117 throw InputError(
"to_marginal_aggr: node index is out of range");
119 const std::size_t ist = nd.
station;
120 const std::size_t nvar =
sn.nvars_of(ind);
126 if (
sn.isfjaugmented && nd.
nodetype == NodeType::Join && state_i.size() >= R) {
128 for (std::size_t r = 0; r < R; ++r) {
129 nir[r] = state_i[state_i.size() - R + r];
132 return std::make_pair(ni, nir);
139 const std::size_t bufw = state_i.size() > nvar ? state_i.size() - nvar : 0;
140 for (std::size_t r = 0; r < R && r < bufw; ++r) nir[r] = state_i[r];
142 for (std::size_t r = 0; r < R; ++r) ni += nir[r];
143 return std::make_pair(ni, nir);
149 if (nd.
nodetype == NodeType::Source)
return std::make_pair(zero, nir);
151 std::vector<std::size_t> K(R, 1), Ks(R, 0);
152 std::size_t srvw = 0;
153 for (std::size_t r = 0; r < R; ++r) {
154 K[r] =
sn.phasessz_of(ist, r + 1);
158 if (state_i.size() < nvar + srvw)
159 throw InputError(
"to_marginal_aggr: state row is narrower than its server block");
160 const std::size_t srv0 = state_i.size() - nvar - srvw;
162 for (std::size_t r = 0; r < R; ++r)
163 for (std::size_t k = 0; k < K[r]; ++k) nir[r] += state_i[srv0 + Ks[r] + k];
166 if (sched == SchedStrategy::EXT) {
174 std::numeric_limits<double>::infinity());
175 for (std::size_t r = 0; r < R; ++r) nir[r] = ext;
176 }
else if (state_detail::buffer_is_class_tag(sched)) {
177 for (std::size_t r = 0; r < R; ++r) {
179 for (std::size_t b = 0; b < srv0; ++b)
182 }
else if (state_detail::buffer_is_tag_phase_pairs(sched)) {
188 for (std::size_t r = 0; r < R; ++r) {
190 for (std::size_t b = 0; b < srv0; b += 2)
193 }
else if (state_detail::buffer_is_per_class_count(sched)) {
194 for (std::size_t r = 0; r < R && r < srv0; ++r) nir[r] += state_i[r];
195 }
else if (sched == SchedStrategy::PAS || sched == SchedStrategy::OI) {
209 for (std::size_t r = 0; r < R; ++r) nir[r] = zero;
210 const std::size_t w = state_i.size() > nvar ? state_i.size() - nvar : 0;
211 for (std::size_t b = 0; b < w; ++b) {
213 const long tag =
static_cast<long>(v + 0.5);
214 if (tag >= 1 &&
static_cast<std::size_t
>(tag) <= R)
222 for (std::size_t r = 0; r < R; ++r)
223 if (
sn.disabled[ist - 1][r]) nir[r] = zero;
226 for (std::size_t r = 0; r < R; ++r) ni += nir[r];
227 return std::make_pair(ni, nir);
247 if (
sn.droprule.size() < ist ||
sn.droprule[ist - 1].size() < cls)
return false;
249 return dr != DropStrategy::WAITQ &&
static_cast<int>(dr) != 0;
270 if (
sn.droprule.size() >= ist &&
sn.droprule[ist - 1].size() >= cls) {
272 if (dr == DropStrategy::BAS || dr == DropStrategy::BBS || dr == DropStrategy::RSRD)
282 if (
sn.isbasdestination.size() >= ist &&
sn.isbasdestination[ist - 1].size() >= cls &&
283 sn.isbasdestination[ist - 1][cls - 1])
287 const double nj =
sn.njobs()[cls - 1];
288 return !std::isfinite(nj);
294 std::vector<std::size_t>
K;
295 std::vector<std::size_t>
Ks;
303 const std::size_t R =
sn.nclasses;
304 const std::size_t ist =
sn.nodes[ind - 1].station;
308 for (std::size_t r = 0; r < R; ++r) {
309 L.
K[r] =
sn.phasessz_of(ist, r + 1);
313 L.
nvar =
sn.nvars_of(ind);
315 throw InputError(
"after_event_station: the state row is narrower than its server block");
332 const std::size_t nph =
sn.phases_of(ist, cls);
335 if (d.
D0.rows() == nph && d.
D1.rows() == nph && nph > 0 && !d.
disabled) {
341 }
catch (
const Error&) {
345 bool ok = pie.size() == nph;
348 for (std::size_t k = 0; k < nph; ++k) s += pie[k];
355 static_cast<long>(nph)));
356 for (std::size_t k = 0; k < nph; ++k) pie[k] = u;
372 std::size_t& pos, std::size_t& swk,
long& ctr);
375 std::size_t swk,
long ctr);
378 std::size_t R,
bool arrived, std::size_t& q,
int& mode,
long& budget);
381 std::size_t q,
int mode,
long budget,
const std::vector<T>& buf,
382 const std::vector<T>& srv,
const std::vector<T>& var,
const RowLayout<T>& L,
383 std::vector<std::vector<T>>& rows, std::vector<T>& probs);
396 const std::vector<T>& inspace,
EventType event,
416 const std::vector<T>& inspace, std::size_t cls) {
417 const std::size_t R =
sn.nclasses;
418 const std::size_t ist =
sn.nodes[ind - 1].station;
422 if (ist == 0)
throw InputError(
"after_event_station_arv: node is not a station");
426 if (sched == SchedStrategy::PAS || sched == SchedStrategy::OI)
435 if (
sn.nodes[ind - 1].nodetype == NodeType::Place) {
436 std::vector<T> row = inspace;
437 const double cap =
sn.classcap[ist - 1][cls - 1];
440 out.
space.push_back(row);
441 out.
rate.push_back(minus_one);
442 out.
prob.push_back(one);
445 out.
space.push_back(row);
446 out.
rate.push_back(minus_one);
447 out.
prob.push_back(zero);
455 const double cap_i =
sn.cap[ist - 1];
456 const double ccap =
sn.classcap[ist - 1][cls - 1];
457 const double S =
sn.stations[ist - 1].nservers;
462 const std::size_t mslotA = mcA ?
sn.map_var_slot(ind, cls) : 0;
465 for (std::size_t t = 0; t < mcA->
pairs.size(); ++t)
466 pentry[t] =
static_cast<long>(mcA->
pairs[t].first) + 1 == hA
467 ? mcA->
V(mcA->
pairs[t].first, mcA->
pairs[t].second) : zero;
468 for (std::size_t t = 0; mcA->
single && t < mcA->
p; ++t)
469 pentry[t] =
static_cast<long>(t) + 1 == hA ? one : zero;
472 for (std::size_t kentry = 0; kentry < L.
K[cls - 1]; ++kentry) {
474 std::vector<T> buf(inspace.begin(), inspace.begin() + L.
bufw);
475 std::vector<T> srv(inspace.begin() + L.
bufw, inspace.begin() + L.
bufw + L.
srvw);
476 std::vector<T> var(inspace.begin() + L.
bufw + L.
srvw, inspace.end());
477 std::vector<std::vector<T>> cand;
478 std::vector<T> cand_prob;
482 std::vector<std::size_t> cand_start, cand_preempt;
487 if (sched == SchedStrategy::EXT) {
490 if (!std::isfinite(
sn.njobs()[cls - 1])) {
491 out.
space.push_back(inspace);
492 out.
rate.push_back(zero);
493 out.
prob.push_back(one);
499 if (sched == SchedStrategy::PS || sched == SchedStrategy::INF ||
500 sched == SchedStrategy::DPS || sched == SchedStrategy::GPS ||
501 sched == SchedStrategy::PSPRIO || sched == SchedStrategy::DPSPRIO ||
502 sched == SchedStrategy::GPSPRIO || sched == SchedStrategy::LPS) {
504 const std::size_t col = L.
Ks[cls - 1] + kentry;
505 std::size_t started = 0;
509 cand_prob.push_back(pentry[kentry]);
511 cand_prob.push_back(zero);
513 std::vector<T> row = buf;
514 row.insert(row.end(), srv.begin(), srv.end());
515 row.insert(row.end(), var.begin(), var.end());
517 cand_start.push_back(started);
518 cand_preempt.push_back(0);
519 }
else if (sched == SchedStrategy::POLLING) {
527 std::size_t srvclass = 0;
528 for (std::size_t r = 1; r <= R; ++r) {
530 for (std::size_t p = 0; p < L.
K[r - 1]; ++p)
532 if (tot > 0) { srvclass = r;
break; }
534 std::size_t pos = 0, swk = 0;
537 if (srvclass == 0 && swk == 0) {
538 std::vector<long> nbuf(R, 0);
539 for (std::size_t r = 0; r < R && r < L.
bufw; ++r)
545 polling_next(pinfo, pos, nbuf, R,
true, q, mode, budget);
546 srv[L.
Ks[cls - 1] + kentry] += one;
548 cand_start.push_back(cls);
551 cand_start.push_back(0);
553 cand_preempt.push_back(0);
554 cand_prob.push_back(pentry[kentry]);
555 std::vector<T> row = buf;
556 row.insert(row.end(), srv.begin(), srv.end());
557 row.insert(row.end(), var.begin(), var.end());
559 }
else if (sched == SchedStrategy::SIRO || sched == SchedStrategy::SEPT ||
560 sched == SchedStrategy::LEPT) {
566 srv[L.
Ks[cls - 1] + kentry] += one;
567 cand_start.push_back(cls);
570 cand_start.push_back(0);
572 cand_preempt.push_back(0);
573 cand_prob.push_back(pentry[kentry]);
574 std::vector<T> row = buf;
575 row.insert(row.end(), srv.begin(), srv.end());
576 row.insert(row.end(), var.begin(), var.end());
578 }
else if (state_detail::buffer_is_class_tag(sched)) {
588 srv[L.
Ks[cls - 1] + kentry] += one;
591 std::vector<T> row = buf;
592 row.insert(row.end(), srv.begin(), srv.end());
593 row.insert(row.end(), var.begin(), var.end());
595 cand_prob.push_back(pentry[kentry]);
596 cand_start.push_back(cls);
597 cand_preempt.push_back(0);
599 std::size_t slot = 0;
600 for (std::size_t b = 0; b < L.
bufw; ++b)
607 ? (ni < cap_i && nir_c < ccap)
609 if (slot > 0 && has_room) {
611 if (sched == SchedStrategy::LCFSPRIO) {
615 const int pc =
sn.classes[cls - 1].prio;
616 for (std::size_t c = slot - 1; c + 1 < L.
bufw; ++c) {
618 if (!(nb > 0) ||
sn.classes[
static_cast<std::size_t
>(nb) - 1].prio <= pc)
break;
623 std::vector<T> row = buf;
624 row.insert(row.end(), srv.begin(), srv.end());
625 row.insert(row.end(), var.begin(), var.end());
627 cand_prob.push_back(pentry[kentry]);
628 cand_start.push_back(0);
629 cand_preempt.push_back(0);
649 cand.push_back(inspace);
650 cand_prob.push_back(pentry[kentry]);
651 cand_start.push_back(0);
652 cand_preempt.push_back(0);
658 }
else if (state_detail::buffer_is_tag_phase_pairs(sched)) {
665 srv[L.
Ks[cls - 1] + kentry] += one;
666 std::vector<T> row = buf;
667 row.insert(row.end(), srv.begin(), srv.end());
668 row.insert(row.end(), var.begin(), var.end());
670 cand_prob.push_back(pentry[kentry]);
671 cand_start.push_back(cls);
672 cand_preempt.push_back(0);
678 const bool prio_aware = sched == SchedStrategy::FCFSPRPRIO ||
679 sched == SchedStrategy::FCFSPIPRIO ||
680 sched == SchedStrategy::LCFSPRPRIO ||
681 sched == SchedStrategy::LCFSPIPRIO;
682 const bool lcfs_family = sched == SchedStrategy::LCFSPRPRIO ||
683 sched == SchedStrategy::LCFSPIPRIO;
696 const bool fcfs_never_preempts = sched == SchedStrategy::FCFSPR ||
697 sched == SchedStrategy::FCFSPI;
701 const bool resume = sched == SchedStrategy::LCFSPR ||
702 sched == SchedStrategy::LCFSPRPRIO ||
703 sched == SchedStrategy::FCFSPR ||
704 sched == SchedStrategy::FCFSPRPRIO;
705 bool can_preempt_any =
false;
706 for (std::size_t cp = 1; cp <= R && !fcfs_never_preempts; ++cp) {
713 const int pa =
sn.classes[cls - 1].prio;
714 const int pv =
sn.classes[cp - 1].prio;
715 if (lcfs_family ? (pa > pv) : (pa >= pv))
continue;
717 for (std::size_t pp = 0; pp < L.
K[cp - 1]; ++pp) {
718 const std::size_t vcol = L.
Ks[cp - 1] + pp;
720 if (busy <= 0)
continue;
721 can_preempt_any =
true;
722 std::vector<T> b2 = buf, s2 = srv;
724 s2[L.
Ks[cls - 1] + kentry] += one;
728 std::size_t slot = 0;
729 for (std::size_t b = 0; b < L.
bufw; ++b)
731 if (slot == 0)
continue;
735 std::vector<T> row = b2;
736 row.insert(row.end(), s2.begin(), s2.end());
737 row.insert(row.end(), var.begin(), var.end());
741 cand_start.push_back(cls);
742 cand_preempt.push_back(cp);
756 if ((prio_aware || fcfs_never_preempts) && !can_preempt_any) {
757 std::size_t slot = 0;
758 for (std::size_t b = 0; b < L.
bufw; ++b)
761 std::vector<T> b2 = buf;
764 std::vector<T> row = b2;
765 row.insert(row.end(), srv.begin(), srv.end());
766 row.insert(row.end(), var.begin(), var.end());
768 cand_prob.push_back(pentry[kentry]);
769 cand_start.push_back(0);
770 cand_preempt.push_back(0);
777 " discipline is not ported yet");
782 for (std::size_t c = 0; c < cand.size(); ++c) {
786 out.
space.push_back(cand[c]);
787 out.
rate.push_back(minus_one);
788 out.
prob.push_back(cand_prob[c]);
790 tag_last(out, c < cand_start.size() ? cand_start[c] : 0,
791 c < cand_preempt.size() ? cand_preempt[c] : 0);
811 std::size_t ist, std::size_t cls) {
813 const std::size_t n =
sn.phases_of(ist, cls);
815 if (d.
D0.rows() != n || d.
D1.rows() != n)
return std::make_pair(mu, phi);
816 for (std::size_t k = 0; k < n; ++k) {
817 const T dk = T(-d.
D0(k, k));
824 for (std::size_t j = 0; j < n; ++j) s += d.
D1(k, j);
827 return std::make_pair(mu, phi);
833 const std::vector<T>& s =
sn.stations[ist - 1].lldscaling;
837 if (!std::isfinite(n) || n >=
static_cast<double>(s.size()))
return s.back();
839 return s[
static_cast<std::size_t
>(n) - 1];
865 for (std::size_t h = 0; h < 2; ++h) {
868 const std::vector<T> v = fun(nir);
871 "cd_factor: the class-dependence map returned an empty scaling vector");
872 f = T(f * v[std::min(cls, v.size()) - 1]);
897 std::size_t cls,
double ni,
double S) {
898 const std::size_t R =
sn.nclasses;
903 const bool prio_aware = sched == SchedStrategy::PSPRIO ||
904 sched == SchedStrategy::DPSPRIO ||
905 sched == SchedStrategy::GPSPRIO;
906 if (!prio_aware || ni <= S)
return p;
907 double best = std::numeric_limits<double>::infinity();
908 for (std::size_t r = 0; r < R; ++r)
910 best = std::min(best,
static_cast<double>(
sn.classes[r].prio));
911 if (
static_cast<double>(
sn.classes[cls - 1].prio) != best) {
917 for (std::size_t r = 0; r < R; ++r) {
918 if (
static_cast<double>(
sn.classes[r].prio) != best)
927T
service_share(
const NetworkStruct<T>&
sn, std::size_t ist,
const Marginal<T>& m,
928 std::size_t cls,
double ni,
double S);
947 const std::vector<T>& inspace, std::size_t cls,
948 bool no_promote =
false) {
949 const std::size_t R =
sn.nclasses;
950 const std::size_t ist =
sn.nodes[ind - 1].station;
953 if (ist == 0)
throw InputError(
"after_event_station_dep: node is not a station");
955 if (sched == SchedStrategy::PAS || sched == SchedStrategy::OI)
958 const double S =
sn.stations[ist - 1].nservers;
960 std::vector<std::size_t> ph(R, 1), shift(R, 0);
961 for (std::size_t r = 0; r < R; ++r) {
971 const std::size_t markof = sched == SchedStrategy::EXT ?
sn.markidx_of(ist, cls) : 0;
972 std::size_t phcls = cls;
974 const std::size_t carrier =
sn.mark_carrier_of(ist);
975 if (carrier >= 1 && carrier <= R) phcls = carrier;
981 const std::pair<std::vector<T>, std::vector<T>> mp =
phase_rates(
sn, ist, cls);
982 const std::vector<T>& mu = mp.first;
983 const std::vector<T>& phi = mp.second;
987 for (std::size_t r = 0; r < R; ++r) ni += num_traits<T>::to_double(m.
nir[r]);
998 const bool cd_takes_prio =
999 pp.
masked && (sched == SchedStrategy::DPSPRIO || sched == SchedStrategy::GPSPRIO);
1007 bool suppress_promote = no_promote;
1009 const typename std::map<std::size_t, RetrialParam<T>>::const_iterator rit =
1010 sn.retrialparam.find(ist);
1011 if (rit !=
sn.retrialparam.end())
1012 for (std::size_t r = 0; r < rit->second.retrial_proc.size(); ++r)
1013 if (!rit->second.retrial_proc[r].disabled) { suppress_promote =
true;
break; }
1016 for (std::size_t k = 0; k < L.
K[phcls - 1]; ++k) {
1017 std::vector<T> buf(inspace.begin(), inspace.begin() + L.
bufw);
1018 std::vector<T> srv(inspace.begin() + L.
bufw, inspace.begin() + L.
bufw + L.
srvw);
1019 std::vector<T> var(inspace.begin() + L.
bufw + L.
srvw, inspace.end());
1020 const std::size_t col = L.
Ks[phcls - 1] + k;
1022 const T kir = m.
kir[phcls - 1][k];
1024 if (sched == SchedStrategy::EXT) {
1031 if (!std::isfinite(
sn.njobs()[cls - 1])) {
1039 markof > 0 && markof <= d.
Dmark.size() ? d.
Dmark[markof - 1] : d.
D1;
1040 for (std::size_t ke = 0; ke < L.
K[phcls - 1]; ++ke) {
1041 const T arv = D1k(k, ke);
1043 std::vector<T> row = inspace;
1044 row[L.
bufw + L.
Ks[phcls - 1] + k] -= one;
1045 row[L.
bufw + L.
Ks[phcls - 1] + ke] += one;
1046 out.
space.push_back(row);
1047 out.
rate.push_back(T(lld * arv));
1048 out.
prob.push_back(one);
1051 }
else if (sched == SchedStrategy::INF || sched == SchedStrategy::PS ||
1052 sched == SchedStrategy::LPS || sched == SchedStrategy::DPS ||
1053 sched == SchedStrategy::GPS || sched == SchedStrategy::PSPRIO ||
1054 sched == SchedStrategy::DPSPRIO || sched == SchedStrategy::GPSPRIO) {
1059 const T rate = T(mu[k] * phi[k] * kir *
service_share(
sn, ist, m, cls, ni, S));
1060 std::vector<T> row = buf;
1061 row.insert(row.end(), srv.begin(), srv.end());
1062 row.insert(row.end(), var.begin(), var.end());
1063 out.
space.push_back(row);
1064 out.
rate.push_back(T(lld * rate));
1065 out.
prob.push_back(one);
1066 }
else if (state_detail::buffer_is_class_tag(sched) && sched != SchedStrategy::FCFS) {
1071 const bool has_waiting = ni > S && !suppress_promote;
1072 const T rate = T(mu[k] * phi[k] * kir);
1075 std::vector<T> row = buf;
1076 row.insert(row.end(), srv.begin(), srv.end());
1077 row.insert(row.end(), var.begin(), var.end());
1078 out.
space.push_back(row);
1079 out.
rate.push_back(T(lld * rate));
1080 out.
prob.push_back(one);
1084 std::size_t pos = L.
bufw;
1085 if (sched == SchedStrategy::LCFS) {
1091 for (std::size_t b = 0; b < L.
bufw; ++b)
1099 double best = std::numeric_limits<double>::infinity();
1100 for (std::size_t b = 0; b < L.
bufw; ++b) {
1102 if (v <= 0)
continue;
1103 const double p =
sn.classes[
static_cast<std::size_t
>(v) - 1].prio;
1104 if (p < best) best = p;
1106 if (std::isfinite(best))
1107 for (std::size_t b = 0; b < L.
bufw; ++b) {
1109 if (v <= 0)
continue;
1110 if (
sn.classes[
static_cast<std::size_t
>(v) - 1].prio != best)
continue;
1112 if (sched == SchedStrategy::LCFSPRIO)
break;
1115 if (pos == L.
bufw)
continue;
1117 std::vector<T> b2 = buf;
1118 if (sched == SchedStrategy::LCFS) {
1124 for (std::size_t b = pos; b > 0; --b) b2[b] = b2[b - 1];
1128 for (std::size_t ke = 0; ke < L.
K[hc - 1]; ++ke) {
1129 std::vector<T> s3 = srv;
1130 s3[L.
Ks[hc - 1] + ke] += one;
1131 std::vector<T> row = b2;
1132 row.insert(row.end(), s3.begin(), s3.end());
1133 row.insert(row.end(), var.begin(), var.end());
1134 out.
space.push_back(row);
1135 out.
rate.push_back(T(lld * rate * pentry[ke]));
1136 out.
prob.push_back(one);
1139 }
else if (state_detail::buffer_is_class_tag(sched)) {
1149 std::vector<T> var2 = var;
1150 bool holds_reply =
false;
1151 if (
sn.replyblock.size() >= ind &&
sn.replyblock[ind - 1].size() >= cls &&
1152 sn.replyblock[ind - 1][cls - 1]) {
1154 const std::size_t sl = ri.
slot[cls - 1];
1155 if (sl !=
static_cast<std::size_t
>(-1) && sl < var2.size()) {
1161 const bool has_waiting = ni > (S - nb) && !suppress_promote && !holds_reply;
1165 const bool pairD = mcD && !mcD->single;
1166 const std::size_t mslotD = mcD ?
sn.map_var_slot(ind, cls) : 0;
1167 const std::vector<T> var2_in = var2;
1168 for (std::size_t kd = 0; kd < L.
K[cls - 1]; ++kd) {
1169 if (pairD && kd > 0)
break;
1170 const T rate = pairD ? T(mcD->done[k] * kir) : T(d.
D1(k, kd) * kir);
1173 std::vector<T> s2 = srv;
1176 std::vector<T> row = buf;
1177 row.insert(row.end(), s2.begin(), s2.end());
1178 row.insert(row.end(), var2.begin(), var2.end());
1179 out.
space.push_back(row);
1180 out.
rate.push_back(T(lld * rate));
1181 out.
prob.push_back(one);
1188 if (headv <= 0)
continue;
1189 const std::size_t hc =
static_cast<std::size_t
>(headv);
1190 std::vector<T> b2(L.
bufw, zero);
1191 for (std::size_t b = 1; b < L.
bufw; ++b) b2[b] = buf[b - 1];
1195 const std::size_t mslotP = mcP ?
sn.map_var_slot(ind, hc) : 0;
1198 for (std::size_t t = 0; t < mcP->
pairs.size(); ++t)
1199 pentry[t] =
static_cast<long>(mcP->
pairs[t].first) + 1 == hP
1200 ? mcP->
V(mcP->
pairs[t].first, mcP->
pairs[t].second) : zero;
1201 for (std::size_t t = 0; mcP->
single && t < mcP->
p; ++t)
1202 pentry[t] =
static_cast<long>(t) + 1 == hP ? one : zero;
1204 for (std::size_t ke = 0; ke < L.
K[hc - 1]; ++ke) {
1206 std::vector<T> s3 = s2;
1207 s3[L.
Ks[hc - 1] + ke] += one;
1208 std::vector<T> var3 = var2;
1211 std::vector<T> row = b2;
1212 row.insert(row.end(), s3.begin(), s3.end());
1213 row.insert(row.end(), var3.begin(), var3.end());
1214 const T r3 = T(lld * rate * pentry[ke]);
1215 out.
space.push_back(row);
1216 out.
rate.push_back(r3);
1224 }
else if (sched == SchedStrategy::POLLING) {
1229 const T rate = T(mu[k] * phi[k] * kir);
1231 std::size_t pos = 0, swk = 0;
1235 if (swk != 0)
continue;
1236 std::vector<long> nbuf(R, 0);
1237 for (std::size_t r = 0; r < R && r < L.
bufw; ++r)
1242 switch (pinfo.
ptype) {
1245 goon = nbuf[cls - 1] > 0;
1253 goon = ctrnext > 0 && nbuf[cls - 1] > 0;
1257 goon = nbuf[cls - 1] > ctr;
1260 std::size_t q = cls;
1262 long budget = ctrnext;
1263 if (!goon)
polling_next(pinfo, cls, nbuf, R,
false, q, mode, budget);
1264 std::vector<std::vector<T>> rows;
1265 std::vector<T> probs;
1266 polling_land(
sn, ist, pinfo, q, mode, budget, buf, srv, var, L, rows, probs);
1267 for (std::size_t j = 0; j < rows.size(); ++j) {
1268 out.
space.push_back(rows[j]);
1269 out.
rate.push_back(T(lld * rate * probs[j]));
1270 out.
prob.push_back(one);
1273 tag_last(out, mode == 1 ? q : 0, 0);
1275 }
else if (state_detail::buffer_is_tag_phase_pairs(sched)) {
1281 const T rate = T(mu[k] * phi[k] * kir);
1283 const bool prio_aware = sched == SchedStrategy::FCFSPRPRIO ||
1284 sched == SchedStrategy::FCFSPIPRIO ||
1285 sched == SchedStrategy::LCFSPRPRIO ||
1286 sched == SchedStrategy::LCFSPIPRIO;
1287 const bool lcfs = sched == SchedStrategy::LCFSPR ||
1288 sched == SchedStrategy::LCFSPI ||
1289 sched == SchedStrategy::LCFSPRPRIO ||
1290 sched == SchedStrategy::LCFSPIPRIO;
1294 const bool resume = sched == SchedStrategy::LCFSPR ||
1295 sched == SchedStrategy::LCFSPRPRIO ||
1296 sched == SchedStrategy::FCFSPR ||
1297 sched == SchedStrategy::FCFSPRPRIO;
1299 std::size_t pos = L.
bufw;
1300 if (ni > S && !suppress_promote && L.
bufw >= 2) {
1301 double best = std::numeric_limits<double>::infinity();
1308 for (std::size_t b = 0; b + 1 < L.
bufw; b += 2) {
1310 if (v <= 0)
continue;
1311 const double p =
sn.classes[
static_cast<std::size_t
>(v) - 1].prio;
1312 if (p < best) best = p;
1314 for (std::size_t b = 0; b + 1 < L.
bufw; b += 2) {
1316 if (v <= 0)
continue;
1317 if (prio_aware &&
sn.classes[
static_cast<std::size_t
>(v) - 1].prio != best)
1326 if (pos == L.
bufw) {
1327 std::vector<T> row = buf;
1328 row.insert(row.end(), srv.begin(), srv.end());
1329 row.insert(row.end(), var.begin(), var.end());
1330 out.
space.push_back(row);
1331 out.
rate.push_back(T(lld * rate));
1332 out.
prob.push_back(one);
1336 const std::size_t kst =
1338 if (hc == 0 || hc > R || kst == 0 || kst > L.
K[hc - 1])
1339 throw InputError(
"after_event_station_dep: station '" +
1340 sn.stations[ist - 1].name +
1341 "' holds a waiting job whose [class, phase] pair is malformed");
1348 std::vector<T> b2(L.
bufw, zero);
1349 for (std::size_t b = 2; b <= pos + 1; ++b) b2[b] = buf[b - 2];
1350 for (std::size_t b = pos + 2; b < L.
bufw; ++b) b2[b] = buf[b];
1352 std::vector<T> s3 = srv;
1353 s3[L.
Ks[hc - 1] + kst - 1] += one;
1354 std::vector<T> row = b2;
1355 row.insert(row.end(), s3.begin(), s3.end());
1356 row.insert(row.end(), var.begin(), var.end());
1357 out.
space.push_back(row);
1358 out.
rate.push_back(T(lld * rate));
1359 out.
prob.push_back(one);
1363 for (std::size_t ke = 0; ke < L.
K[hc - 1]; ++ke) {
1364 std::vector<T> s3 = srv;
1365 s3[L.
Ks[hc - 1] + ke] += one;
1366 std::vector<T> row = b2;
1367 row.insert(row.end(), s3.begin(), s3.end());
1368 row.insert(row.end(), var.begin(), var.end());
1369 out.
space.push_back(row);
1370 out.
rate.push_back(T(lld * rate * pentry[ke]));
1371 out.
prob.push_back(one);
1375 }
else if (state_detail::buffer_is_per_class_count(sched)) {
1380 const T rate = T(mu[k] * phi[k] * kir);
1382 for (std::size_t r = 0; r < R; ++r) waiting += num_traits<T>::to_double(buf[r]);
1383 if (waiting <= 0 || suppress_promote) {
1384 std::vector<T> row = buf;
1385 row.insert(row.end(), srv.begin(), srv.end());
1386 row.insert(row.end(), var.begin(), var.end());
1387 out.
space.push_back(row);
1388 out.
rate.push_back(T(lld * rate));
1389 out.
prob.push_back(one);
1392 for (std::size_t r = 1; r <= R; ++r) {
1394 if (nb <= 0)
continue;
1396 for (std::size_t ke = 0; ke < L.
K[r - 1]; ++ke) {
1397 std::vector<T> b2 = buf, s2 = srv;
1399 s2[L.
Ks[r - 1] + ke] += one;
1400 std::vector<T> row = b2;
1401 row.insert(row.end(), s2.begin(), s2.end());
1402 row.insert(row.end(), var.begin(), var.end());
1403 out.
space.push_back(row);
1404 out.
rate.push_back(T(lld * rate));
1412 " discipline is not ported yet");
1430 std::size_t cls,
double ni,
double S) {
1431 const std::size_t R =
sn.nclasses;
1441 if (!p.
served)
return zero;
1442 const std::vector<T>& nir = p.
nir;
1443 const double nieff = p.
ni;
1445 if (sched == SchedStrategy::PS || sched == SchedStrategy::LPS ||
1446 sched == SchedStrategy::PSPRIO)
1448 if (sched == SchedStrategy::DPS || sched == SchedStrategy::GPS ||
1449 sched == SchedStrategy::DPSPRIO || sched == SchedStrategy::GPSPRIO) {
1452 "state_events: multi-server DPS/GPS stations are not supported");
1453 const bool dps = sched == SchedStrategy::DPS || sched == SchedStrategy::DPSPRIO;
1454 const std::vector<T>& w =
sn.stations[ist - 1].schedparam;
1456 for (std::size_t r = 0; r < R; ++r) wsum += w[r];
1458 for (std::size_t r = 0; r < R; ++r) {
1462 denom += T(w[r] / wsum * nr);
1464 const T
nc = nir[cls - 1];
1467 const T sh = T((w[cls - 1] / wsum) / denom);
1468 return dps ? sh : T(sh /
nc);
1485 const std::vector<T>& inspace, std::size_t cls) {
1486 const std::size_t R =
sn.nclasses;
1487 const std::size_t ist =
sn.nodes[ind - 1].station;
1490 if (ist == 0)
throw InputError(
"after_event_station_phase: node is not a station");
1492 const double S =
sn.stations[ist - 1].nservers;
1494 std::vector<std::size_t> ph(R, 1), shift(R, 0);
1495 for (std::size_t r = 0; r < R; ++r) {
1503 for (std::size_t r = 0; r < R; ++r) ni += num_traits<T>::to_double(m.
nir[r]);
1511 if (d.
D0.rows() != L.
K[cls - 1])
return out;
1514 for (std::size_t k = 0; k < L.
K[cls - 1]; ++k) {
1516 for (std::size_t kd = 0; kd < L.
K[cls - 1]; ++kd) {
1517 if (kd == k)
continue;
1518 std::vector<T> row = inspace;
1519 row[L.
bufw + L.
Ks[cls - 1] + k] -= one;
1520 row[L.
bufw + L.
Ks[cls - 1] + kd] += one;
1524 out.
space.push_back(row);
1525 out.
rate.push_back(T(lld * d.
D0(k, kd) * m.
kir[cls - 1][k] * share));
1526 out.
prob.push_back(one);
1558 if (!patWhy.empty())
return patWhy +
" Use SolverLDES or SolverJMT for any other patience.";
1559 for (std::size_t i = 0; i <
sn.stations.size(); ++i) {
1561 for (std::size_t r = 0; r < st.
balking.size(); ++r)
1564 return solver +
" supports only QUEUE_LENGTH balking. Use SolverLDES or SolverJMT "
1565 "for wait-time-based balking.";
1567 for (
const auto& kv :
sn.retrialparam) {
1571 for (std::size_t r = 0; r < rp.
retrial_proc.size(); ++r) {
1575 return solver +
" supports only exponential (memoryless) retrial delay. Use "
1576 "SolverLDES for a non-exponential retrial delay (SolverMAM requires an exponential one too).";
1578 return solver +
" supports only unlimited retrials. Use SolverLDES for finite "
1581 return solver +
" does not model abandonment from the retrial orbit "
1582 "(set_orbit_impatience). Use SolverMAM or SolverLDES.";
1585 std::size_t served = 0;
1586 for (std::size_t r = 0; r <
sn.nclasses; ++r)
1587 if (!
sn.disabled[kv.first - 1][r] &&
sn.service[kv.first - 1][r].D0.rows() > 0) ++served;
1589 return solver +
" supports retrial only for single-class stations. Use SolverLDES for "
1590 "multi-class retrial.";
1598 for (std::size_t r = 1; r <=
sn.nclasses; ++r)
1610 const typename std::map<std::size_t, RetrialParam<T>>::const_iterator rit =
1611 sn.retrialparam.find(ist);
1612 if (rit ==
sn.retrialparam.end())
return zero;
1625 const typename std::map<std::size_t, RetrialParam<T>>::const_iterator rit =
1626 sn.retrialparam.find(ist);
1627 return rit !=
sn.retrialparam.end() && cls <= rit->second.policy.size() &&
1628 rit->second.policy[cls - 1] == 2;
1640 const std::vector<T>& inspace, std::size_t cls,
EventOutcome<T>& out) {
1641 const std::size_t ist =
sn.nodes[ind - 1].station;
1642 if (ist == 0 || out.
space.empty())
return;
1646 const std::size_t R =
sn.nclasses;
1648 std::vector<std::size_t> ph(R, 1), shift(R, 0);
1649 for (std::size_t r = 0; r < R; ++r) {
1656 if (qlen >= th.min_jobs && (th.max_jobs < 0 || qlen <= th.max_jobs)) {
1657 pbalk = th.probability;
1661 for (std::size_t i = 0; i < out.
prob.size(); ++i)
1663 out.
space.push_back(inspace);
1665 out.
prob.push_back(pbalk);
1681 const std::vector<T>& inspace, std::size_t cls,
1682 const T& impatience_mu) {
1683 const std::size_t R =
sn.nclasses;
1684 const std::size_t ist =
sn.nodes[ind - 1].station;
1686 if (ist == 0)
throw InputError(
"after_event_station_renege: node is not a station");
1689 std::vector<std::size_t> ph(R, 1), shift(R, 0);
1690 for (std::size_t r = 0; r < R; ++r) {
1697 if (waiting <= 0)
return out;
1704 std::size_t slot = L.
bufw;
1705 for (std::size_t b = 0; b < L.
bufw; ++b)
1706 if (inspace[b] == tag) { slot = b;
break; }
1707 if (slot == L.
bufw)
return out;
1709 std::vector<T> row = inspace;
1710 for (std::size_t b = slot; b > 0; --b) row[b] = row[b - 1];
1712 out.
space.push_back(row);
1737 const std::vector<T>& inspace, std::size_t cls,
1738 const T& retrial_mu,
bool constant_policy =
false) {
1739 const std::size_t R =
sn.nclasses;
1740 const std::size_t ist =
sn.nodes[ind - 1].station;
1743 if (ist == 0)
throw InputError(
"after_event_station_retry: node is not a station");
1745 const double S =
sn.stations[ist - 1].nservers;
1747 std::vector<std::size_t> ph(R, 1), shift(R, 0);
1748 for (std::size_t r = 0; r < R; ++r) {
1757 if (orbit <= 0 || occ >= S)
return out;
1760 std::size_t slot = L.
bufw;
1761 for (std::size_t b = 0; b < L.
bufw; ++b)
1762 if (inspace[b] == tag) { slot = b;
break; }
1763 if (slot == L.
bufw)
return out;
1772 for (std::size_t ke = 0; ke < L.
K[cls - 1]; ++ke) {
1774 std::vector<T> row = inspace;
1775 for (std::size_t b = slot; b > 0; --b) row[b] = row[b - 1];
1777 row[L.
bufw + L.
Ks[cls - 1] + ke] += one;
1778 out.
space.push_back(row);
1779 out.
rate.push_back(T(agg * pentry[ke]));
1780 out.
prob.push_back(one);
1806 const std::vector<T>& inspace,
bool up,
1809 if (inspace.empty() || !
sn.has_breakdown_node(ind))
return out;
1813 if ((up && status != 0) || (!up && status != 1))
return out;
1814 std::vector<T> row = inspace;
1823 out.
space.push_back(row);
1824 out.
rate.push_back(rate);
1844 const std::vector<T>& inspace,
EventType event,
1846 const std::size_t R =
sn.nclasses;
1848 if (event != EventType::ARV)
return out;
1849 if (inspace.size() < R)
1850 throw InputError(
"after_event_fork: the Fork state row at node '" +
sn.nodes[ind - 1].name +
1851 "' is narrower than the class set");
1852 std::vector<T> row = inspace;
1856 out.
space.push_back(row);
1880 const std::vector<T>& inspace,
EventType event,
1882 const std::size_t R =
sn.nclasses;
1885 if (inspace.size() < R)
1886 throw InputError(
"after_event_join: the Join state row at node '" +
sn.nodes[ind - 1].name +
1887 "' is narrower than the class set");
1888 const std::size_t off = inspace.size() - R;
1890 if (event == EventType::ARV) {
1891 std::vector<T> row = inspace;
1892 row[off + cls - 1] += one;
1893 out.
space.push_back(row);
1895 out.
prob.push_back(one);
1898 if (event != EventType::DEP)
return out;
1900 const typename std::map<std::size_t, FjJoinParam>::const_iterator jit =
1901 sn.fjjoinparam.find(ind);
1902 const FjJoinParam* fjp = jit ==
sn.fjjoinparam.end() ? 0 : &jit->second;
1905 for (std::size_t x = 0; x < fjp->
origclasses.size(); ++x) {
1906 const std::map<std::size_t, std::vector<std::vector<std::size_t>>>::const_iterator ait =
1908 if (ait == fjp->
auxmatrix.end())
continue;
1909 for (std::size_t b = 0; b < ait->second.size(); ++b)
1910 for (std::size_t t = 0; t < ait->second[b].size(); ++t)
1911 if (ait->second[b][t] == cls)
return out;
1919 std::vector<T> row = inspace;
1920 row[off + cls - 1] -= one;
1921 out.
space.push_back(row);
1922 out.
rate.push_back(imm);
1923 out.
prob.push_back(one);
1926 if (!fjp)
return out;
1927 const std::map<std::size_t, std::vector<std::vector<std::size_t>>>::const_iterator ait =
1929 const std::map<std::size_t, std::vector<std::size_t>>::const_iterator rit =
1932 const std::vector<std::vector<std::size_t>>& aux = ait->second;
1933 const std::vector<std::size_t>& req = rit->second;
1934 if (aux.empty())
return out;
1935 const std::size_t B = aux.size(), Tt = aux[0].size();
1936 for (std::size_t t = 0; t < Tt; ++t) {
1937 bool complete =
true;
1938 for (std::size_t b = 0; b < B && complete; ++b) {
1939 const std::size_t a = aux[b][t];
1940 const double need = b < req.size() ?
static_cast<double>(req[b]) : 1.0;
1943 if (!complete)
continue;
1944 std::vector<T> row = inspace;
1945 for (std::size_t b = 0; b < B; ++b) {
1946 const std::size_t a = aux[b][t];
1947 const long need = b < req.size() ?
static_cast<long>(req[b]) : 1;
1950 out.
space.push_back(row);
1951 out.
rate.push_back(imm);
1952 out.
prob.push_back(one);
1968void rr_advance_row(
const NetworkStruct<T>&
sn, std::size_t ind, std::size_t cls,
1969 std::vector<std::vector<T>>& rows);
1984 const std::vector<T>& inspace,
EventType event,
1987 const std::size_t R =
sn.nclasses;
1988 if (inspace.size() < R)
return out;
1990 if (event == EventType::ARV) {
1991 std::vector<T> row = inspace;
1992 row[cls - 1] = T(row[cls - 1] + one);
1993 out.
space.push_back(row);
1996 out.
prob.push_back(one);
1999 if (event == EventType::DEP) {
2001 std::vector<T> row = inspace;
2002 row[cls - 1] = T(row[cls - 1] - one);
2003 out.
space.push_back(row);
2005 out.
prob.push_back(one);
2021 std::vector<std::vector<T>>& rows) {
2022 if (
sn.rr_var_slot(ind, cls) == 0)
return;
2023 const std::size_t w =
sn.nvars_of(ind);
2025 for (std::size_t i = 0; i < rows.size(); ++i) {
2026 if (rows[i].size() < w)
continue;
2027 std::vector<T> var(rows[i].end() - w, rows[i].end());
2028 sn.rr_advance(ind, cls, var);
2029 std::copy(var.begin(), var.end(), rows[i].end() - w);
2046 const std::vector<T>& buf,
const std::vector<T>& srv, std::size_t s,
2047 std::size_t t,
const T& w, std::vector<
PoolStart<T>>& out) {
2048 const std::vector<std::size_t>& ps = pool.
pools[s - 1];
2050 while (k < ps.size() && ps[k] != t) ++k;
2051 const std::vector<T>& a = pool.
alpha[s - 1][k];
2052 for (std::size_t j = 0; j < a.size(); ++j) {
2064 const std::vector<T>& buf,
const std::vector<T>& srv,
2066 const std::size_t R =
sn.nclasses;
2068 std::vector<PoolStart<T>> out;
2069 if (sched == SchedStrategy::SIRO) {
2071 for (std::size_t s = 0; s < R; ++s)
2077 for (std::size_t s = 0; s < R; ++s) {
2079 if (!pool.
compat[t - 1][s] || bs <= 0)
continue;
2080 std::vector<T> b = buf;
2086 std::vector<std::size_t> pos;
2087 for (std::size_t p = 0; p < buf.size(); ++p) {
2089 if (c >= 1 &&
static_cast<std::size_t
>(c) <= R && pool.
compat[t - 1][c - 1]) pos.push_back(p);
2095 const auto cls_at = [&](std::size_t p) {
2098 if (sched == SchedStrategy::HOL || sched == SchedStrategy::LCFSPRIO) {
2099 int best =
sn.classes[cls_at(pos[0]) - 1].prio;
2100 for (std::size_t i = 1; i < pos.size(); ++i)
2101 best = std::min(best,
sn.classes[cls_at(pos[i]) - 1].prio);
2102 std::vector<std::size_t> keep;
2103 for (std::size_t i = 0; i < pos.size(); ++i)
2104 if (
sn.classes[cls_at(pos[i]) - 1].prio == best) keep.push_back(pos[i]);
2108 const bool lcfs = sched == SchedStrategy::LCFS || sched == SchedStrategy::LCFSPRIO;
2109 const std::size_t p = lcfs ? pos.front() : pos.back();
2110 const std::size_t s = cls_at(p);
2111 std::vector<T> b(1, zero);
2112 for (std::size_t q = 0; q < buf.size(); ++q)
2113 if (q != p) b.push_back(buf[q]);
2114 pool_start(pool, Ks, b, srv, s, t, one, out);
2134 const std::vector<T>& inspace,
EventType event,
2137 const std::size_t R =
sn.nclasses;
2138 const std::size_t ist =
sn.nodes[ind - 1].station;
2143 const std::vector<T> buf(inspace.begin(), inspace.begin() + L.
bufw);
2144 const std::vector<T> srv(inspace.begin() + L.
bufw, inspace.begin() + L.
bufw + L.
srvw);
2145 const std::vector<T> var(inspace.begin() + L.
bufw + L.
srvw, inspace.end());
2146 const std::vector<std::size_t>& myp = pool.
pools[cls - 1];
2148 const auto emit = [&](
const std::vector<T>& b,
const std::vector<T>& s,
const std::vector<T>& v,
2149 const T& rate,
const T& prob, std::size_t started) {
2150 std::vector<T> row = b;
2151 row.insert(row.end(), s.begin(), s.end());
2152 row.insert(row.end(), v.begin(), v.end());
2153 out.
space.push_back(row);
2154 out.
rate.push_back(rate);
2155 out.
prob.push_back(prob);
2158 if (myp.empty())
return out;
2159 if (event == EventType::ARV) {
2164 (ni >=
sn.cap[ist - 1] || nir >=
sn.classcap[ist - 1][cls - 1])) {
2170 std::vector<double> busy(pool.
ntypes, 0.0);
2171 for (std::size_t r = 0; r < R; ++r)
2172 for (std::size_t k = 0; k < pool.
pools[r].size(); ++k)
2173 for (std::size_t j = 0; j < pool.
len[r][k]; ++j)
2174 busy[pool.
pools[r][k] - 1] +=
2176 std::vector<std::size_t> cand;
2177 for (std::size_t k = 0; k < myp.size(); ++k)
2178 if (busy[myp[k] - 1] < pool.
count[myp[k] - 1]) cand.push_back(myp[k]);
2181 std::vector<T> b = buf;
2182 if (sched == SchedStrategy::SIRO) {
2185 std::size_t slot = 0;
2186 for (std::size_t q = 0; q < b.size(); ++q)
2194 emit(b, srv, var, minus_one, one, 0);
2198 std::vector<std::size_t> choice(1, cand[0]);
2199 std::vector<T> pchoice(1, one);
2200 std::vector<T> varc = var;
2201 if (cand.size() > 1) {
2204 for (std::size_t q = 0; q < pool.
alfsorder.size(); ++q)
2205 if (std::find(cand.begin(), cand.end(), pool.
alfsorder[q]) != cand.end()) {
2212 for (std::size_t q = 1; q < cand.size(); ++q)
2213 if (pool.
fsfrate[cand[q] - 1][cls - 1] > pool.
fsfrate[cand[at] - 1][cls - 1]) at = q;
2214 choice[0] = cand[at];
2224 const std::size_t vp = varc.size() - 1;
2225 const std::size_t pid =
2227 std::vector<std::size_t> ord = pool.
perms.at(pid - 1);
2228 for (std::size_t q = 0; q < ord.size(); ++q)
2229 if (std::find(cand.begin(), cand.end(), ord[q]) != cand.end()) {
2231 ord.erase(ord.begin() +
static_cast<std::ptrdiff_t
>(q));
2232 ord.push_back(choice[0]);
2242 std::vector<PoolStart<T>> starts;
2243 for (std::size_t c = 0; c < choice.size(); ++c)
2245 for (std::size_t i = 0; i < starts.size(); ++i)
2246 emit(starts[i].buf, starts[i].srv, varc, minus_one, starts[i].p, cls);
2250 for (std::size_t k = 0; k < myp.size(); ++k) {
2251 const std::size_t t = myp[k];
2252 for (std::size_t j = 0; j < pool.
len[cls - 1][k]; ++j) {
2253 const std::size_t col = L.
Ks[cls - 1] + pool.
off[cls - 1][k] + j;
2254 const T nj = srv[col];
2256 if (event == EventType::DEP) {
2257 const T ex = pool.
exit[cls - 1][k][j];
2259 std::vector<T> sd = srv;
2261 const std::vector<PoolStart<T>> nx =
2263 for (std::size_t b = 0; b < nx.size(); ++b)
2264 emit(nx[b].buf, nx[b].srv, var, T(ex * nj * nx[b].p), one, nx[b].cls);
2265 }
else if (event == EventType::PHASE) {
2267 for (std::size_t jd = 0; jd < pool.
len[cls - 1][k]; ++jd) {
2269 std::vector<T> sp = srv;
2271 sp[L.
Ks[cls - 1] + pool.
off[cls - 1][k] + jd] += one;
2272 emit(buf, sp, var, T(D0(j, jd) * nj), one, 0);
2283 const std::vector<T>& inspace,
EventType event,
2284 std::size_t cls,
bool no_promote =
false,
2291 if ((event == EventType::DEP || event == EventType::PHASE) && !inspace.empty() &&
2293 const std::size_t ist =
sn.nodes[ind - 1].station;
2294 const T down =
sn.breakdownparam.at(ist).down_rate_of(cls);
2296 const T upr =
sn.rates(ist - 1, cls - 1);
2298 if (!std::isfinite(upd) || !(upd > 0.0))
2299 throw InputError(
"Station '" +
sn.nodes[ind - 1].name +
2300 "' declares a down-server service rate for class '" +
2301 sn.classes[cls - 1].name +
2302 "' but has no finite up-server service rate to rescale.");
2306 std::vector<T> upspace = inspace;
2310 const T scale = T(down / upr);
2311 for (std::size_t i = 0; i < o.
space.size(); ++i) {
2318 if ((event == EventType::ARV || event == EventType::DEP || event == EventType::PHASE) &&
2319 !
sn.ctmcpool.empty() &&
sn.ctmcpool.count(ind))
2322 case EventType::ARV:
2327 if (
sn.issignal.size() >= cls &&
sn.issignal[cls - 1]) {
2328 if (!(
sn.signaltype.size() >= cls &&
2342 case EventType::DEP: {
2362 if (ind <=
sn.isbasblocking.size() &&
sn.isbasblocking[ind - 1] &&
2364 !out.
space.empty()) {
2371 for (std::size_t i = 0; i < out.
space.size(); ++i) {
2378 case EventType::PHASE:
2380 case EventType::RENEGE:
2382 case EventType::RETRY:
2384 case EventType::SWITCH:
2386 case EventType::FAILURE:
2388 case EventType::REPAIR:
2390 case EventType::LOCAL:
2395 " event is not ported yet");
2417 const std::vector<T>& inspace,
EventType event,
2420 if (event != EventType::PHASE)
return out;
2421 const typename std::map<std::size_t, TransitionParam<T>>::const_iterator it =
2422 sn.transparam.find(ind);
2423 if (it ==
sn.transparam.end())
2424 throw InputError(
"after_event_transition: node has no TransitionParam");
2426 if (mode == 0 || mode > tp.
nmodes)
2427 throw InputError(
"after_event_transition: mode index is out of range");
2430 std::vector<std::size_t> fK(tp.
nmodes, 1), fKs(tp.
nmodes, 0);
2431 std::size_t tot = 0;
2432 for (std::size_t m = 0; m < tp.
nmodes; ++m) {
2437 if (fK[mode - 1] <= 1)
return out;
2439 tp.
firingproc[mode - 1].D0.rows() != fK[mode - 1])
2443 for (std::size_t k = 0; k < fK[mode - 1]; ++k) {
2444 const std::size_t idx = tp.
nmodes + fKs[mode - 1] + k;
2445 const T cnt = inspace[idx];
2447 for (std::size_t kd = 0; kd < fK[mode - 1]; ++kd) {
2448 if (kd == k)
continue;
2450 std::vector<T> row = inspace;
2452 row[tp.
nmodes + fKs[mode - 1] + kd] += one;
2453 out.
space.push_back(row);
2454 out.
rate.push_back(T(D0(k, kd) * cnt));
2455 out.
prob.push_back(one);
2477 const std::vector<T>& inspace,
EventType event, std::size_t cls,
2478 bool no_promote =
false,
2480 if (ind == 0 || ind >
sn.nodes.size())
2481 throw InputError(
"after_event: node index is out of range");
2492 const bool cls_is_mode = (nd.
nodetype == NodeType::Transition &&
event == EventType::PHASE);
2493 if (!cls_is_mode && (cls == 0 || cls >
sn.nclasses))
2494 throw InputError(
"after_event: class index is out of range");
2499 if (
sn.isfjaugmented && nd.
nodetype == NodeType::Join)
2512 if (nd.
nodetype == NodeType::Transition)
2517 "' are not ported yet");
2520namespace signal_detail {
2524void merge_states(std::vector<std::vector<T>>& sp, std::vector<T>& pr) {
2525 std::vector<std::vector<T>> us;
2527 for (std::size_t i = 0; i < sp.size(); ++i) {
2528 std::size_t at = us.size();
2529 for (std::size_t j = 0; j < us.size(); ++j)
2530 if (us[j] == sp[i]) { at = j;
break; }
2531 if (at == us.size()) {
2532 us.push_back(sp[i]);
2533 up.push_back(pr[i]);
2555 std::vector<std::size_t> kv;
2557 if (
sn.signalremdist.size() < cls ||
sn.signalremdist[cls - 1].empty()) {
2560 return std::make_pair(kv, kp);
2562 const std::vector<T>& d =
sn.signalremdist[cls - 1];
2564 for (std::size_t b = 0; b < ntot; ++b) {
2580 return std::make_pair(kv, kp);
2583 for (std::size_t i = 0; i < kp.size(); ++i) tot += kp[i];
2585 for (std::size_t i = 0; i < kp.size(); ++i) kp[i] = T(kp[i] / tot);
2586 return std::make_pair(kv, kp);
2604 const std::vector<T>& inspace, std::size_t cls) {
2605 const std::size_t R =
sn.nclasses;
2606 const std::size_t ist =
sn.nodes[ind - 1].station;
2610 if (ist == 0)
throw InputError(
"after_event_station_signal: node is not a station");
2613 const double S =
sn.stations[ist - 1].nservers;
2615 std::vector<std::size_t> ph(R, 1), shift(R, 0);
2616 for (std::size_t r = 0; r < R; ++r) {
2625 std::vector<T> row(L.
bufw + L.
srvw, zero);
2626 row.insert(row.end(), inspace.end() - L.
nvar, inspace.end());
2627 out.
space.push_back(row);
2628 out.
rate.push_back(minus_one);
2629 out.
prob.push_back(one);
2635 std::vector<std::size_t> tgt;
2636 const std::size_t declared =
sn.signaltarget.size() >= cls ?
sn.signaltarget[cls - 1] : 0;
2637 if (declared >= 1) {
2638 tgt.push_back(declared);
2640 for (std::size_t r = 1; r <= R; ++r)
2641 if (
sn.issignal.size() < r || !
sn.issignal[r - 1]) tgt.push_back(r);
2643 std::vector<std::size_t> elig;
2644 std::size_t ntot = 0;
2645 for (std::size_t i = 0; i < tgt.size(); ++i) {
2648 elig.push_back(tgt[i]);
2649 ntot +=
static_cast<std::size_t
>(nr);
2654 out.
space.push_back(inspace);
2655 out.
rate.push_back(minus_one);
2656 out.
prob.push_back(one);
2661 ?
sn.signalrempolicy[cls - 1]
2663 const bool ordered = state_detail::buffer_is_class_tag(sched) ||
2664 state_detail::buffer_is_tag_phase_pairs(sched);
2665 const bool paired = state_detail::buffer_is_tag_phase_pairs(sched);
2666 const bool counted = state_detail::buffer_is_per_class_count(sched);
2667 const std::pair<std::vector<std::size_t>, std::vector<T>> pmf =
2670 std::vector<std::vector<T>> acc;
2671 std::vector<T> accp;
2672 for (std::size_t ik = 0; ik < pmf.first.size(); ++ik) {
2674 std::vector<std::vector<T>> cur(1, inspace);
2675 std::vector<T> curp(1, one);
2678 for (std::size_t step = 0; step < pmf.first[ik]; ++step) {
2679 std::vector<std::vector<T>> nxt;
2680 std::vector<T> nxtp;
2681 for (std::size_t row = 0; row < cur.size(); ++row) {
2682 std::vector<T> buf(cur[row].begin(), cur[row].begin() + L.
bufw);
2683 std::vector<T> srv(cur[row].begin() + L.
bufw,
2684 cur[row].begin() + L.
bufw + L.
srvw);
2685 const std::vector<T> var(cur[row].begin() + L.
bufw + L.
srvw, cur[row].end());
2688 std::vector<std::size_t> wpos, wcls, wwt;
2690 for (std::size_t b = 0; b < L.
bufw; b += paired ? 2 : 1) {
2692 if (v <= 0)
continue;
2694 for (std::size_t e = 0; e < elig.size(); ++e)
2695 if (elig[e] ==
static_cast<std::size_t
>(v)) ok =
true;
2698 wcls.push_back(
static_cast<std::size_t
>(v));
2701 }
else if (counted) {
2702 for (std::size_t e = 0; e < elig.size(); ++e) {
2703 const std::size_t r = elig[e];
2704 if (r > L.
bufw)
continue;
2706 if (v <= 0)
continue;
2707 wpos.push_back(r - 1);
2709 wwt.push_back(
static_cast<std::size_t
>(v));
2713 std::vector<std::size_t> scls, sph, scnt;
2714 for (std::size_t e = 0; e < elig.size(); ++e) {
2715 const std::size_t r = elig[e];
2716 for (std::size_t p = 0; p < L.
K[r - 1]; ++p) {
2718 if (v <= 0)
continue;
2721 scnt.push_back(
static_cast<std::size_t
>(v));
2724 std::size_t nwait = 0, nsrv = 0;
2725 for (std::size_t i = 0; i < wwt.size(); ++i) nwait += wwt[i];
2726 for (std::size_t i = 0; i < scnt.size(); ++i) nsrv += scnt[i];
2727 if (nwait == 0 && nsrv == 0) {
2729 nxt.push_back(cur[row]);
2730 nxtp.push_back(curp[row]);
2734 std::vector<std::vector<T>> sp;
2736 const bool age_ordered =
2739 if (age_ordered && nwait > 0) {
2742 std::size_t pick = 0;
2743 for (std::size_t i = 0; i < wpos.size(); ++i)
2745 : wpos[i] < wpos[pick])
2747 std::vector<T> b2 = buf;
2748 b2.erase(b2.begin() + wpos[pick], b2.begin() + wpos[pick] + (paired ? 2 : 1));
2749 b2.insert(b2.begin(), paired ? 2 : 1, zero);
2750 std::vector<T> nr = b2;
2751 nr.insert(nr.end(), srv.begin(), srv.end());
2752 nr.insert(nr.end(), var.begin(), var.end());
2761 : (nwait > 0 ? nwait : nsrv);
2762 for (std::size_t i = 0; i < wpos.size(); ++i) {
2763 std::vector<T> b2 = buf;
2765 b2[wcls[i] - 1] -= one;
2767 b2.erase(b2.begin() + wpos[i],
2768 b2.begin() + wpos[i] + (paired ? 2 : 1));
2769 b2.insert(b2.begin(), paired ? 2 : 1, zero);
2771 std::vector<T> nr = b2;
2772 nr.insert(nr.end(), srv.begin(), srv.end());
2773 nr.insert(nr.end(), var.begin(), var.end());
2776 static_cast<double>(total)));
2779 for (std::size_t i = 0; i < scls.size(); ++i) {
2780 std::vector<T> b2 = buf, s2 = srv;
2781 s2[L.
Ks[scls[i] - 1] + sph[i]] -= one;
2785 for (std::size_t j = 0; j < s2.size(); ++j)
2787 if (L.
bufw > 0 && occ < S) {
2789 std::size_t hp = L.
bufw;
2790 for (std::size_t b = 0; b < L.
bufw; b += paired ? 2 : 1)
2793 const std::size_t pc =
static_cast<std::size_t
>(
2799 pp = v >= 1 ?
static_cast<std::size_t
>(v) - 1 : 0;
2801 b2.erase(b2.begin() + hp,
2802 b2.begin() + hp + (paired ? 2 : 1));
2803 b2.insert(b2.begin(), paired ? 2 : 1, zero);
2804 s2[L.
Ks[pc - 1] + pp] += one;
2806 }
else if (counted) {
2811 for (std::size_t r = 1; r <= R && r <= L.
bufw; ++r)
2814 s2[L.
Ks[r - 1]] += one;
2819 std::vector<T> nr = b2;
2820 nr.insert(nr.end(), s2.begin(), s2.end());
2821 nr.insert(nr.end(), var.begin(), var.end());
2824 static_cast<double>(scnt[i]) /
static_cast<double>(total)));
2828 signal_detail::merge_states(sp, pr);
2829 for (std::size_t i = 0; i < sp.size(); ++i) {
2830 nxt.push_back(sp[i]);
2831 nxtp.push_back(T(curp[row] * pr[i]));
2834 signal_detail::merge_states(nxt, nxtp);
2838 for (std::size_t i = 0; i < cur.size(); ++i) {
2839 acc.push_back(cur[i]);
2840 accp.push_back(T(pmf.second[ik] * curp[i]));
2843 signal_detail::merge_states(acc, accp);
2844 out.
space.swap(acc);
2845 out.
prob.swap(accp);
2846 out.
rate.assign(out.
space.size(), minus_one);
2867 const std::vector<std::size_t>& c, std::size_t p,
2868 const std::vector<std::vector<bool>>& G) {
2869 const std::size_t n = c.size();
2870 if (p >= n)
throw InputError(
"pass_and_swap: position is out of range for the state");
2871 std::vector<std::size_t> chain(1, p);
2872 std::size_t moving = c[p], cur = p;
2875 for (std::size_t j = cur + 1; j < n; ++j)
2876 if (moving - 1 < G.size() && c[j] - 1 < G[moving - 1].size() &&
2877 G[moving - 1][c[j] - 1]) {
2886 const std::size_t dep = c[chain.back()];
2889 std::vector<std::size_t> cnew = c;
2890 for (std::size_t i = 0; i + 1 < chain.size(); ++i) cnew[chain[i + 1]] = c[chain[i]];
2891 cnew.erase(cnew.begin() + chain[0]);
2892 return std::make_pair(cnew, dep);
2898template <
class T,
class F>
2899inline std::vector<double>
pas_increments(
const F& mu_fun,
const std::vector<std::size_t>& c) {
2900 std::vector<double> inc(c.size(), 0.0);
2901 double mu_prev = 0.0;
2902 for (std::size_t p = 0; p < c.size(); ++p) {
2903 const std::vector<std::size_t> prefix(c.begin(), c.begin() + p + 1);
2905 inc[p] = mu_cur - mu_prev;
2917template <
class T,
class F>
2919 const std::vector<std::size_t>& cold,
2920 const std::vector<std::size_t>& cnew) {
2921 if (!mu_fun || out.
space.empty())
return;
2924 for (std::size_t p = 0; p < inc_new.size(); ++p) {
2925 if (inc_new[p] <= 0)
continue;
2926 if (p < inc_old.size() && inc_old[p] > 0)
continue;
2942 const std::vector<T>& inspace,
EventType event,
2944 const std::size_t ist =
sn.nodes[ind - 1].station;
2947 if (ist == 0)
throw InputError(
"after_event_station_pas: node is not a station");
2948 const typename std::map<std::size_t, typename NetworkStruct<T>::PasParam>::const_iterator it =
2949 sn.pasparam.find(ist);
2950 if (it ==
sn.pasparam.end() || !it->second.svc_rate_fun)
2952 "after_event_station_pas: the station has no service rate function mu(c); set one "
2955 const std::size_t V =
sn.nvars_of(ind);
2956 const std::size_t W = inspace.size() - V;
2957 std::vector<std::size_t> c;
2958 for (std::size_t i = 0; i < W; ++i) {
2960 if (v > 0) c.push_back(
static_cast<std::size_t
>(v));
2962 const std::vector<T> var(inspace.begin() + W, inspace.end());
2963 const double cap =
sn.cap[ist - 1];
2965 if (event == EventType::ARV) {
2968 if (
static_cast<double>(c.size()) >= cap)
return out;
2969 std::vector<std::size_t>
nc = c;
2980 if (
nc.size() > W)
return out;
2982 for (std::size_t i = 0; i <
nc.size(); ++i)
2984 row.resize(W, zero);
2985 row.insert(row.end(), var.begin(), var.end());
2986 out.
space.push_back(row);
2988 out.
prob.push_back(one);
2999 if (event != EventType::DEP)
return out;
3005 for (std::size_t p = 0; p < c.size(); ++p) {
3006 const std::vector<std::size_t> prefix(c.begin(), c.begin() + p + 1);
3007 const T mu_cur = it->second.svc_rate_fun(prefix);
3008 const T ratep = T(mu_cur - mu_prev);
3011 const std::pair<std::vector<std::size_t>, std::size_t> ps =
3015 if (ps.second != cls)
continue;
3017 for (std::size_t i = 0; i < ps.first.size(); ++i)
3019 row.resize(W, zero);
3020 row.insert(row.end(), var.begin(), var.end());
3021 out.
space.push_back(row);
3022 out.
rate.push_back(ratep);
3023 out.
prob.push_back(one);
3040 const std::size_t R =
sn.nclasses;
3042 ri.
slot.assign(R,
static_cast<std::size_t
>(-1));
3043 if (
sn.nvars.size() < ind ||
sn.nvars[ind - 1].size() < 3 * R + 1)
return ri;
3044 std::size_t pos = 0;
3045 for (std::size_t j = 0; j < 2 * R + 1; ++j) pos +=
sn.nvars[ind - 1][j];
3046 for (std::size_t r = 1; r <= R; ++r)
3047 if (
sn.nvars[ind - 1][2 * R + r] > 0) {
3048 ri.
slot[r - 1] = pos;
3061 for (std::size_t i = 0; i < ri.
classes.size(); ++i) {
3065 if (s !=
static_cast<std::size_t
>(-1) && s < var.size())
3089 const std::vector<T>& inspace, std::size_t cls) {
3090 const std::size_t R =
sn.nclasses;
3091 const std::size_t ist =
sn.nodes[ind - 1].station;
3094 if (ist == 0)
throw InputError(
"after_event_station_reply: node is not a station");
3097 const double S =
sn.stations[ist - 1].nservers;
3101 std::size_t callclass = 0;
3102 for (std::size_t i = 0; i < ri.
classes.size(); ++i) {
3103 const std::size_t r = ri.
classes[i];
3104 if (
sn.syncreply.size() >= r &&
sn.syncreply[r - 1] == cls) {
3110 std::vector<T> buf(inspace.begin(), inspace.begin() + L.
bufw);
3111 std::vector<T> srv(inspace.begin() + L.
bufw, inspace.begin() + L.
bufw + L.
srvw);
3112 std::vector<T> var(inspace.begin() + L.
bufw + L.
srvw, inspace.end());
3114 if (callclass > 0) {
3115 const std::size_t s = ri.
slot[callclass - 1];
3116 if (s !=
static_cast<std::size_t
>(-1) && s < var.size() &&
3129 for (std::size_t ke = 0; ke < L.
K[cls - 1]; ++ke) {
3131 std::vector<T> s2 = srv;
3132 s2[L.
Ks[cls - 1] + ke] += one;
3133 std::vector<T> row = buf;
3134 row.insert(row.end(), s2.begin(), s2.end());
3135 row.insert(row.end(), var.begin(), var.end());
3136 out.
space.push_back(row);
3138 out.
prob.push_back(pentry[ke]);
3144 std::vector<T> b2 = buf;
3145 std::size_t slot = b2.size();
3146 for (std::size_t b = 0; b < b2.size(); ++b)
3148 if (slot == b2.size()) {
3149 b2.insert(b2.begin(), zero);
3153 std::vector<T> row = b2;
3154 row.insert(row.end(), srv.begin(), srv.end());
3155 row.insert(row.end(), var.begin(), var.end());
3156 out.
space.push_back(row);
3158 out.
prob.push_back(one);
3166 std::size_t& pos, std::size_t& swk,
long& ctr) {
3167 pos = pi.
ipos !=
static_cast<std::size_t
>(-1)
3169 : (srvclass > 0 ? srvclass : 1);
3170 swk = pi.
iswk !=
static_cast<std::size_t
>(-1)
3173 ctr = pi.
ictr !=
static_cast<std::size_t
>(-1)
3181 std::size_t swk,
long ctr) {
3182 if (pi.
ipos !=
static_cast<std::size_t
>(-1))
3184 if (pi.
iswk !=
static_cast<std::size_t
>(-1))
3186 if (pi.
ictr !=
static_cast<std::size_t
>(-1))
3213 std::size_t R,
bool arrived, std::size_t& q,
int& mode,
long& budget) {
3214 if (arrived && pi.
polled[pos - 1] && nbuf[pos - 1] > 0) {
3221 std::size_t p = pos;
3222 for (std::size_t step = 0; step < R; ++step) {
3224 if (!pi.
polled[p - 1])
continue;
3231 if (nbuf[p - 1] > 0) {
3246 std::size_t q,
int mode,
long budget,
const std::vector<T>& buf,
3247 const std::vector<T>& srv,
const std::vector<T>& var,
const RowLayout<T>& L,
3248 std::vector<std::vector<T>>& rows, std::vector<T>& probs) {
3252 std::vector<T> b2 = buf;
3255 for (std::size_t ke = 0; ke < L.
K[q - 1]; ++ke) {
3257 std::vector<T> s2 = srv;
3258 s2[L.
Ks[q - 1] + ke] += one;
3259 std::vector<T> row = b2;
3260 row.insert(row.end(), s2.begin(), s2.end());
3261 const std::vector<T> v2 =
polling_set(pi, var, q, 0, budget);
3262 row.insert(row.end(), v2.begin(), v2.end());
3263 rows.push_back(row);
3264 probs.push_back(pentry[ke]);
3266 }
else if (mode == 2) {
3268 for (std::size_t ke = 0; ke < pi.
ksw[q - 1]; ++ke) {
3270 std::vector<T> row = buf;
3271 row.insert(row.end(), srv.begin(), srv.end());
3272 const std::vector<T> v2 =
polling_set(pi, var, q, ke + 1, 0);
3273 row.insert(row.end(), v2.begin(), v2.end());
3274 rows.push_back(row);
3275 probs.push_back(pi.
sw_pie[q - 1][ke]);
3279 std::vector<T> row = buf;
3280 row.insert(row.end(), srv.begin(), srv.end());
3281 const std::vector<T> v2 =
polling_set(pi, var, q, 0, 0);
3282 row.insert(row.end(), v2.begin(), v2.end());
3283 rows.push_back(row);
3284 probs.push_back(one);
3300 const std::vector<T>& inspace, std::size_t cls) {
3301 const std::size_t R =
sn.nclasses;
3302 const std::size_t ist =
sn.nodes[ind - 1].station;
3305 if (ist == 0)
throw InputError(
"after_event_station_switch: node is not a station");
3307 if (!pinfo.
valid || !pinfo.
has_sw[cls - 1])
return out;
3310 const std::vector<T> buf(inspace.begin(), inspace.begin() + L.
bufw);
3311 const std::vector<T> srv(inspace.begin() + L.
bufw, inspace.begin() + L.
bufw + L.
srvw);
3312 const std::vector<T> var(inspace.begin() + L.
bufw + L.
srvw, inspace.end());
3314 std::size_t pos = 0, swk = 0;
3318 if (pos != cls || swk == 0)
return out;
3321 for (std::size_t kd = 0; kd < pinfo.
ksw[cls - 1]; ++kd) {
3322 if (kd + 1 == swk)
continue;
3323 const T r0 = pinfo.
sw_d0[cls - 1](swk - 1, kd);
3325 std::vector<T> row = buf;
3326 row.insert(row.end(), srv.begin(), srv.end());
3327 const std::vector<T> v2 =
polling_set(pinfo, var, cls, kd + 1, 0);
3328 row.insert(row.end(), v2.begin(), v2.end());
3329 out.
space.push_back(row);
3330 out.
rate.push_back(r0);
3331 out.
prob.push_back(one);
3335 for (std::size_t j = 0; j < pinfo.
ksw[cls - 1]; ++j) rate += pinfo.
sw_d1[cls - 1](swk - 1, j);
3337 std::vector<long> nbuf(R, 0);
3338 for (std::size_t r = 0; r < R && r < L.
bufw; ++r)
3343 polling_next(pinfo, cls, nbuf, R,
true, q, mode, budget);
3344 std::vector<std::vector<T>> rows;
3345 std::vector<T> probs;
3346 polling_land(
sn, ist, pinfo, q, mode, budget, buf, srv, var, L, rows, probs);
3347 for (std::size_t j = 0; j < rows.size(); ++j) {
3352 if (rows[j] == inspace)
continue;
3353 out.
space.push_back(rows[j]);
3354 out.
rate.push_back(T(rate * probs[j]));
3355 out.
prob.push_back(one);
3362 tag_last(out, mode == 1 ? q : 0, 0);
3384 const std::vector<T>& inspace,
EventType event,
3386 const std::size_t R =
sn.nclasses;
3390 const typename std::map<std::size_t, CacheParam<T>>::const_iterator ci =
sn.nodeparam.find(ind);
3391 if (ci ==
sn.nodeparam.end())
throw InputError(
"after_event_cache: node has no CacheParam");
3393 const std::size_t h = cp.
itemcap.size();
3394 const std::size_t n = cp.
nitems;
3395 std::size_t tcc = 0;
3396 for (std::size_t i = 0; i < h; ++i)
3397 if (cp.
itemcap[i] > 0) tcc +=
static_cast<std::size_t
>(cp.
itemcap[i]);
3399 const std::vector<int>& m = cp.
itemcap;
3401 const std::vector<int>& m;
3402 std::size_t operator()(std::size_t i, std::size_t j)
const {
3403 std::size_t base = 0;
3404 for (std::size_t t = 0; t + 1 < i; ++t) base +=
static_cast<std::size_t
>(m[t]);
3405 return base + j - 1;
3409 std::vector<T> srv(inspace.begin(), inspace.begin() + R);
3410 std::vector<T> var(inspace.begin() + R, inspace.end());
3412 if (event == EventType::ARV) {
3413 srv[cls - 1] += one;
3414 std::vector<T> row = srv;
3415 row.insert(row.end(), var.begin(), var.end());
3416 out.
space.push_back(row);
3418 out.
prob.push_back(one);
3422 if (event == EventType::DEP) {
3441 std::size_t item_dep = 0;
3448 if (item_dep != 0) {
3449 const std::size_t bitcol = tcc + item_dep - 1;
3450 if (bitcol < var.size()) {
3453 for (std::size_t r = 0; r < R; ++r)
3455 if (srvtot == 1)
return out;
3473 const std::size_t hc =
3474 cls - 1 < cp.
hitclass.size() ?
static_cast<std::size_t
>(cp.
hitclass[cls - 1]) : 0;
3475 const std::size_t
mc =
3477 if (hc != cls &&
mc != cls)
return out;
3481 srv[cls - 1] -= one;
3482 std::vector<T> row = srv;
3483 row.insert(row.end(), var.begin(), var.end());
3484 out.
space.push_back(row);
3485 out.
rate.push_back(imm);
3486 out.
prob.push_back(one);
3490 if (event != EventType::READ)
return out;
3494 for (std::size_t r = 0; r < R; ++r) tot += num_traits<T>::to_double(srv[r]);
3496 if (cls - 1 >= cp.
pread.size() || cp.
pread[cls - 1].empty())
return out;
3497 const std::vector<T>& p = cp.
pread[cls - 1];
3505 std::vector<std::size_t> rc_list, rc_items, rc_orig;
3507 const std::size_t block_b = tcc + n;
3508 std::size_t width_b = var.size() > block_b ? var.size() - block_b : 0;
3509 if (width_b != rc_list.size()) width_b = 0;
3514 ? std::numeric_limits<double>::infinity()
3516 bool from_retrieval =
false;
3517 for (std::size_t j = 0; j < rc_list.size(); ++j)
3518 if (rc_list[j] == cls) from_retrieval =
true;
3520 for (std::size_t k = 1; k <= n; ++k) {
3522 std::vector<T> srv_e = srv;
3523 srv_e[cls - 1] -= one;
3526 std::size_t posk = 0;
3527 for (std::size_t c = 0; c < tcc && c < var.size(); ++c)
3536 if (from_retrieval) posk = 0;
3538 k - 1 >= cp.
accost[cls - 1].size()
3540 : cp.
accost[cls - 1][k - 1];
3541 const bool have_ac = ac.
rows() >= h + 1 && ac.
cols() >= h + 1;
3546 const bool in_flight =
3548 std::size_t r_class = 0;
3555 if (from_retrieval && !in_flight)
continue;
3557 if (!from_retrieval && r_class != 0) {
3562 std::vector<T> srv_b = srv_e;
3563 std::vector<T> var_b = var;
3570 srv_b[r_class - 1] += one;
3572 if (width_b == 0)
continue;
3573 std::size_t bslot = width_b;
3574 for (std::size_t j = 0; j < rc_list.size(); ++j)
3575 if (rc_list[j] == r_class) { bslot = j;
break; }
3576 if (bslot >= width_b)
continue;
3578 for (std::size_t j = 0; j < width_b; ++j)
3580 if (pend >= maxpend)
continue;
3581 var_b[block_b + bslot] += one;
3583 std::vector<T> row = srv_b;
3584 row.insert(row.end(), var_b.begin(), var_b.end());
3585 out.
space.push_back(row);
3586 out.
rate.push_back(T(p[k - 1] * imm));
3587 out.
prob.push_back(one);
3596 std::vector<T> srv_m = srv_e;
3597 srv_m[cp.
missclass[cls - 1] - 1] += one;
3598 std::vector<T> var_m = var;
3599 if (tcc + k <= var_m.size()) var_m[tcc + k - 1] = zero;
3600 for (std::size_t j = 0; j < width_b; ++j) {
3601 if (rc_items[j] != k)
continue;
3603 if (held <= 0)
continue;
3604 const std::size_t oc = rc_orig[j];
3606 srv_m[cp.
hitclass[oc - 1] - 1] += var_m[block_b + j];
3607 var_m[block_b + j] = zero;
3612 const T rej = have_ac ? ac(0, 0) : zero;
3614 std::vector<T> row = srv_m;
3615 row.insert(row.end(), var_m.begin(), var_m.end());
3616 out.
space.push_back(row);
3617 out.
rate.push_back(T(rej * p[k - 1] * imm));
3618 out.
prob.push_back(one);
3620 for (std::size_t l = 1; l <= h; ++l) {
3621 const T w = have_ac ? ac(0, l) : (l == 1 ? one : zero);
3623 if (m[l - 1] <= 0)
continue;
3624 const std::size_t ml =
static_cast<std::size_t
>(m[l - 1]);
3627 for (std::size_t rr = 1; rr <= ml; ++rr) {
3628 std::vector<T> vp = var_m;
3630 std::vector<T> row = srv_m;
3631 row.insert(row.end(), vp.begin(), vp.end());
3632 out.
space.push_back(row);
3633 out.
rate.push_back(T(w * p[k - 1] /
3635 out.
prob.push_back(one);
3640 std::vector<T> vp = var_m;
3641 for (std::size_t j = ml; j >= 2; --j) vp[cpos(l, j)] = var_m[cpos(l, j - 1)];
3643 T rate = T(w * p[k - 1] * imm);
3647 const T q = cp.
qlru;
3649 std::vector<T> row0 = srv_m;
3650 row0.insert(row0.end(), var_m.begin(), var_m.end());
3651 out.
space.push_back(row0);
3652 out.
rate.push_back(T(rate * T(one - q)));
3653 out.
prob.push_back(one);
3658 std::vector<T> row = srv_m;
3659 row.insert(row.end(), vp.begin(), vp.end());
3660 out.
space.push_back(row);
3661 out.
rate.push_back(rate);
3662 out.
prob.push_back(one);
3669 std::vector<T> srv_h = srv_e;
3670 srv_h[cp.
hitclass[cls - 1] - 1] += one;
3671 std::size_t li = 1, acc = 0;
3672 for (std::size_t t = 0; t < h; ++t) {
3673 const std::size_t mt = m[t] > 0 ?
static_cast<std::size_t
>(m[t]) : 0;
3674 if (posk <= acc + mt) { li = t + 1;
break; }
3677 const std::size_t j = posk - acc;
3689 for (std::size_t inew = li; inew <= h; ++inew) {
3690 if (m[inew - 1] <= 0)
continue;
3691 const std::size_t mn =
static_cast<std::size_t
>(m[inew - 1]);
3692 const T w = have_ac ? ac(li, inew) : (inew == li + 1 ? one : zero);
3697 std::vector<T> vp = var;
3702 for (std::size_t t = j; t >= 2; --t) vp[cpos(li, t)] = var[cpos(li, t - 1)];
3703 vp[cpos(li, 1)] = var[cpos(li, j)];
3705 std::vector<T> row = srv_h;
3706 row.insert(row.end(), vp.begin(), vp.end());
3707 out.
space.push_back(row);
3708 out.
rate.push_back(T(w * p[k - 1] * imm));
3709 out.
prob.push_back(one);
3714 for (std::size_t r = 1; r <= mn; ++r) {
3715 std::vector<T> vp = var;
3716 vp[cpos(li, j)] = var[cpos(inew, r)];
3718 std::vector<T> row = srv_h;
3719 row.insert(row.end(), vp.begin(), vp.end());
3720 out.
space.push_back(row);
3724 out.
prob.push_back(one);
3730 std::vector<T> vp = var;
3735 for (std::size_t t = j; t >= 2; --t) vp[cpos(li, t)] = var[cpos(li, t - 1)];
3738 vp[cpos(li, ordered ? 1 : j)] = var[cpos(inew, mn)];
3739 for (std::size_t t = mn; t >= 2; --t) vp[cpos(inew, t)] = var[cpos(inew, t - 1)];
3741 std::vector<T> row = srv_h;
3742 row.insert(row.end(), vp.begin(), vp.end());
3743 out.
space.push_back(row);
3744 out.
rate.push_back(T(w * p[k - 1] * imm));
3745 out.
prob.push_back(one);
3752 std::vector<T> row = srv_h;
3753 row.insert(row.end(), var.begin(), var.end());
3754 out.
space.push_back(row);
3755 out.
rate.push_back(T(p[k - 1] * imm));
3756 out.
prob.push_back(one);
3760 std::vector<T> vp = var;
3761 for (std::size_t t = j; t >= 2; --t) vp[cpos(li, t)] = var[cpos(li, t - 1)];
3762 vp[cpos(li, 1)] = var[cpos(li, j)];
3763 std::vector<T> row = srv_h;
3764 row.insert(row.end(), vp.begin(), vp.end());
3765 out.
space.push_back(row);
3766 out.
rate.push_back(T(p[k - 1] * imm));
3767 out.
prob.push_back(one);
3809 std::vector<GlobalSync<T>> gsync;
3811 for (std::size_t ind = 1; ind <=
sn.nodes.size(); ++ind) {
3812 if (
sn.nodes[ind - 1].nodetype != NodeType::Transition)
continue;
3813 const typename std::map<std::size_t, TransitionParam<T>>::const_iterator it =
3814 sn.transparam.find(ind);
3815 if (it ==
sn.transparam.end())
continue;
3817 for (
int pass = 0; pass < 2; ++pass) {
3818 for (std::size_t m = 1; m <= tp.
nmodes; ++m) {
3823 std::vector<std::pair<std::size_t, std::size_t>> enab, fire, inhib;
3827 for (std::size_t q = 0; q < en.
rows(); ++q)
3828 for (std::size_t r = 0; r < en.
cols(); ++r)
3830 enab.push_back(std::make_pair(q + 1, r + 1));
3831 for (std::size_t q = 0; q < fi.
rows(); ++q)
3832 for (std::size_t r = 0; r < fi.
cols(); ++r)
3834 fire.push_back(std::make_pair(q + 1, r + 1));
3835 for (std::size_t q = 0; q < ih.
rows(); ++q)
3836 for (std::size_t r = 0; r < ih.
cols(); ++r) {
3843 for (std::size_t i = 0; i < enab.size(); ++i)
3844 dup = dup || enab[i].first == q + 1;
3845 for (std::size_t i = 0; i < fire.size(); ++i)
3846 dup = dup || fire[i].first == q + 1;
3847 for (std::size_t i = 0; i < inhib.size(); ++i)
3848 dup = dup || inhib[i].first == q + 1;
3849 if (!dup) inhib.push_back(std::make_pair(q + 1, r + 1));
3852 g.
active.event = pass == 0 ? EventType::ENABLE : EventType::FIRE;
3859 std::vector<std::size_t> seen;
3860 auto once = [&](std::size_t q, std::size_t r) {
3861 for (std::size_t i = 0; i < seen.size(); ++i)
3862 if (seen[i] == q)
return;
3866 for (std::size_t i = 0; i < enab.size(); ++i) once(enab[i].first, enab[i].second);
3867 for (std::size_t i = 0; i < inhib.size(); ++i)
3868 once(inhib[i].first, inhib[i].second);
3870 for (std::size_t i = 0; i < enab.size(); ++i)
3873 en(enab[i].first - 1, enab[i].second - 1)});
3874 for (std::size_t i = 0; i < fire.size(); ++i)
3877 fi(fire[i].first - 1, fire[i].second - 1)});
3878 for (std::size_t i = 0; i < inhib.size(); ++i)
3880 inhib[i].second, one});
3915 const std::size_t R =
sn.nclasses;
3916 const std::size_t ind = gl.
active.node;
3917 const std::size_t mode = gl.
active.mode;
3921 const std::size_t isf =
sn.stateful_index(ind);
3922 if (isf == 0)
throw InputError(
"after_global_event: the transition is not stateful");
3923 const typename std::map<std::size_t, TransitionParam<T>>::const_iterator it =
3924 sn.transparam.find(ind);
3925 if (it ==
sn.transparam.end())
throw InputError(
"after_global_event: node has no TransitionParam");
3928 std::vector<std::size_t> fK(tp.
nmodes, 1), fKs(tp.
nmodes, 0);
3929 std::size_t tot = 0;
3930 for (std::size_t m = 0; m < tp.
nmodes; ++m) {
3935 const std::vector<T>& row = glspace.
local[isf - 1];
3936 std::vector<T> buf(row.begin(), row.begin() + tp.
nmodes);
3937 std::vector<T> srv(row.begin() + tp.
nmodes, row.begin() + tp.
nmodes + tot);
3938 std::vector<T> fired(row.begin() + tp.
nmodes + tot,
3939 row.begin() + 2 * tp.
nmodes + tot);
3940 const std::vector<T> var(row.begin() + 2 * tp.
nmodes + tot, row.end());
3943 std::vector<std::vector<T>> ep(
sn.nodes.size() + 1, std::vector<T>(R, zero));
3944 for (std::size_t j = 0; j < gl.
passive.size(); ++j) {
3945 const std::size_t pn = gl.
passive[j].node;
3946 const std::size_t pisf =
sn.stateful_index(pn);
3947 if (pisf == 0)
continue;
3963 bool inhibited =
false;
3964 for (std::size_t q = 0; q < ih_m.
rows(); ++q)
3965 for (std::size_t r = 0; r < ih_m.
cols() && r < R; ++r) {
3967 if (std::isinf(thr))
continue;
3971 for (std::size_t q = 0; q < en_m.
rows(); ++q)
3972 for (std::size_t r = 0; r < en_m.
cols() && r < R; ++r) {
3974 if (need <= 0)
continue;
3977 long mark_degree = 0;
3978 if (!inhibited && !under) {
3982 for (std::size_t q = 0; q < en_m.
rows() && ok; ++q)
3983 for (std::size_t r = 0; r < en_m.
cols() && r < R && ok; ++r) {
3985 if (need <= 0)
continue;
3991 mark_degree = d - 1;
3994 const long nsrv = std::isfinite(svm) ?
static_cast<long>(svm)
3997 if (gl.
active.event == EventType::ENABLE) {
3999 for (std::size_t k = 0; k < fK[mode - 1]; ++k)
4001 if (inhibited || under) {
4003 std::vector<T> b2 = buf, s2 = srv;
4005 for (std::size_t k = 0; k < fK[mode - 1]; ++k) s2[fKs[mode - 1] + k] = zero;
4006 std::vector<T> nr = b2;
4007 nr.insert(nr.end(), s2.begin(), s2.end());
4008 nr.insert(nr.end(), fired.begin(), fired.end());
4009 nr.insert(nr.end(), var.begin(), var.end());
4010 if (nr == row)
return out;
4012 ns.
local[isf - 1] = nr;
4013 out.
space.push_back(ns);
4014 out.
rate.push_back(imm);
4015 out.
prob.push_back(one);
4019 const long want = std::min(mark_degree, nsrv);
4020 if (running == want)
return out;
4021 if (running < want) {
4025 const long nadd = want - running;
4026 std::vector<T> pe(fK[mode - 1], zero);
4028 static_cast<std::size_t
>(fK[mode - 1])) {
4033 for (std::size_t k = 0; k < fK[mode - 1]; ++k) pe[k] = pv[k];
4038 std::vector<std::vector<long>> combs;
4039 std::vector<long> cur(fK[mode - 1], 0);
4040 std::function<void(std::size_t,
long)> rec = [&](std::size_t k,
long left) {
4041 if (k + 1 == fK[mode - 1]) {
4043 combs.push_back(cur);
4046 for (
long v = left; v >= 0; --v) {
4048 rec(k + 1, left - v);
4052 for (std::size_t i = 0; i < combs.size(); ++i) {
4053 std::vector<T> b2 = buf, s2 = srv;
4055 double logp = std::lgamma(
static_cast<double>(nadd) + 1.0);
4056 bool zeroprob =
false;
4057 for (std::size_t k = 0; k < fK[mode - 1]; ++k) {
4061 logp += combs[i][k] * std::log(pk) -
4062 std::lgamma(
static_cast<double>(combs[i][k]) + 1.0);
4063 else if (combs[i][k] > 0)
4066 std::vector<T> nr = b2;
4067 nr.insert(nr.end(), s2.begin(), s2.end());
4068 nr.insert(nr.end(), fired.begin(), fired.end());
4069 nr.insert(nr.end(), var.begin(), var.end());
4071 ns.
local[isf - 1] = nr;
4072 out.
space.push_back(ns);
4073 out.
rate.push_back(imm);
4081 const long ndiff = running - want;
4082 std::vector<long> sv(fK[mode - 1], 0);
4083 for (std::size_t k = 0; k < fK[mode - 1]; ++k)
4085 std::vector<std::vector<long>> combs;
4086 std::vector<long> cur(fK[mode - 1], 0);
4087 std::function<void(std::size_t,
long)> rec = [&](std::size_t k,
long left) {
4088 if (k + 1 == fK[mode - 1]) {
4089 if (left > sv[k])
return;
4091 combs.push_back(cur);
4094 for (
long v = std::min(left, sv[k]); v >= 0; --v) {
4096 rec(k + 1, left - v);
4100 std::vector<double> w(combs.size(), 0.0);
4101 double wmax = -1e300;
4102 for (std::size_t i = 0; i < combs.size(); ++i) {
4104 for (std::size_t k = 0; k < fK[mode - 1]; ++k)
4105 lw += std::lgamma(
static_cast<double>(sv[k]) + 1.0) -
4106 std::lgamma(
static_cast<double>(combs[i][k]) + 1.0) -
4107 std::lgamma(
static_cast<double>(sv[k] - combs[i][k]) + 1.0);
4109 wmax = std::max(wmax, lw);
4112 for (std::size_t i = 0; i < w.size(); ++i) {
4113 w[i] = std::exp(w[i] - wmax);
4116 for (std::size_t i = 0; i < combs.size(); ++i) {
4117 std::vector<T> b2 = buf, s2 = srv;
4118 for (std::size_t k = 0; k < fK[mode - 1]; ++k)
4121 std::vector<T> nr = b2;
4122 nr.insert(nr.end(), s2.begin(), s2.end());
4123 nr.insert(nr.end(), fired.begin(), fired.end());
4124 nr.insert(nr.end(), var.begin(), var.end());
4126 ns.
local[isf - 1] = nr;
4127 out.
space.push_back(ns);
4128 out.
rate.push_back(imm);
4135 if (gl.
active.event != EventType::FIRE)
return out;
4137 const bool immediate_mode = mode - 1 < tp.
timing.size() &&
4139 const T fw = immediate_mode && mode - 1 < tp.
fireweight.size() ? tp.
fireweight[mode - 1] : one;
4140 const long en_degree = inhibited ? 0 : std::min(mark_degree, nsrv);
4141 const long imm_servers = immediate_mode ? std::min(mark_degree, nsrv) : 0;
4143 for (std::size_t k = 0; k < fK[mode - 1]; ++k) {
4145 const bool fires = immediate_mode ? (k == 0 && imm_servers >= 1)
4146 : (in_k > 0 && en_degree >= 1);
4147 if (!fires)
continue;
4149 if (immediate_mode) {
4154 for (std::size_t j = 0; j < tp.
firingproc[mode - 1].D1.cols(); ++j)
4162 for (std::size_t q = 1; q <=
sn.nodes.size(); ++q)
4163 for (std::size_t r = 0; r < R; ++r) mk.push_back(ep[q][r]);
4164 rate = T(rate * tp.
firingdep[mode - 1](mk));
4169 std::vector<T> b2 = buf, s2 = srv;
4171 s2[fKs[mode - 1] + k] -= one;
4172 b2[mode - 1] += one;
4175 std::vector<T> nr = b2;
4176 nr.insert(nr.end(), s2.begin(), s2.end());
4177 nr.insert(nr.end(), fired.begin(), fired.end());
4178 nr.insert(nr.end(), var.begin(), var.end());
4179 ns.
local[isf - 1] = nr;
4185 for (std::size_t j = 0; j < gl.
passive.size(); ++j) {
4187 if (pe2.
event != EventType::PRE && pe2.
event != EventType::POST)
continue;
4188 const std::size_t pisf =
sn.stateful_index(pe2.
node);
4189 if (pisf == 0)
continue;
4190 std::vector<T>& prow = ns.
local[pisf - 1];
4192 const std::size_t pist =
sn.nodes[pe2.
node - 1].station;
4194 pist != 0 ?
sn.stations[pist - 1].sched : SchedStrategy::INF;
4195 const std::size_t c = pe2.
cls;
4196 if (pe2.
event == EventType::PRE) {
4197 if (state_detail::buffer_is_class_tag(psched)) {
4200 long left =
static_cast<long>(wgt);
4202 if (psched == SchedStrategy::LCFS) {
4203 for (std::size_t b = 0; b < prow.size() && left > 0; ++b)
4204 if (prow[b] == tag) { prow[b] = zero; --left; }
4206 for (std::size_t b = prow.size(); b-- > 0 && left > 0;)
4207 if (prow[b] == tag) { prow[b] = zero; --left; }
4209 }
else if (prow.size() > R) {
4215 prow[R + c - 1] = zero;
4216 }
else if (c - 1 < prow.size()) {
4220 if (state_detail::buffer_is_class_tag(psched)) {
4221 for (
long q = 0; q < static_cast<long>(wgt); ++q)
4223 }
else if (c - 1 < prow.size()) {
4228 out.
space.push_back(ns);
4229 out.
rate.push_back(rate);
4230 out.
prob.push_back(one);
4292 if (sy.
active.node == 0 || sy.
active.node >
sn.nodes.size())
return false;
4293 const std::size_t ist =
sn.nodes[sy.
active.node - 1].station;
4294 if (ist == 0)
return false;
4295 const std::size_t cls_p = sy.
passive.cls;
4296 if (ist >
sn.immfeed.size() || cls_p == 0 || cls_p >
sn.immfeed[ist - 1].size())
return false;
4297 return sn.immfeed[ist - 1][cls_p - 1];
4315 const std::vector<std::vector<bool>>& impatience_classes = std::vector<std::vector<bool>>(),
4316 const std::vector<std::size_t>& breakdown_nodes = std::vector<std::size_t>()) {
4317 const std::size_t R =
sn.nclasses;
4318 const std::size_t local =
sn.nodes.size() + 1;
4320 std::vector<Sync<T>> sync;
4322 for (std::size_t ind = 1; ind <=
sn.nodes.size(); ++ind) {
4324 const std::size_t ist = nd.
station;
4325 for (std::size_t r = 1; r <= R; ++r) {
4328 if (ist != 0 &&
sn.phases_of(ist, r) > 1) {
4336 if (ist != 0 && ((impatience_classes.size() >= ist &&
4337 impatience_classes[ist - 1].size() >= r &&
4338 impatience_classes[ist - 1][r - 1]) ||
4346 const typename std::map<std::size_t, RetrialParam<T>>::const_iterator rit =
4347 sn.retrialparam.find(ist);
4348 if (rit !=
sn.retrialparam.end() && rit->second.retrial_proc.size() >= r &&
4349 !rit->second.retrial_proc[r - 1].disabled) {
4359 if (ist != 0 && r == 1) {
4360 bool has_bd =
sn.has_breakdown_node(ind);
4361 for (std::size_t b = 0; b < breakdown_nodes.size() && !has_bd; ++b)
4362 if (breakdown_nodes[b] == ind) { has_bd =
true;
break; }
4375 if (ist != 0 &&
sn.stations[ist - 1].sched == SchedStrategy::POLLING) {
4387 if (nd.
nodetype == NodeType::Fork)
continue;
4401 bool cache_read_class =
false;
4402 if (nd.
nodetype == NodeType::Cache) {
4403 const typename std::map<std::size_t, CacheParam<T>>::const_iterator ci =
4404 sn.nodeparam.find(ind);
4405 if (ci !=
sn.nodeparam.end()) {
4406 if (r - 1 < ci->second.pread.size() && !ci->second.pread[r - 1].empty()) {
4413 r - 1 < ci->second.hitclass.size() && ci->second.hitclass[r - 1] != 0;
4420 if (nd.
nodetype == NodeType::Transition && r == 1) {
4421 const typename std::map<std::size_t, TransitionParam<T>>::const_iterator ti =
4422 sn.transparam.find(ind);
4423 if (ti !=
sn.transparam.end()) {
4424 for (std::size_t m = 1; m <= ti->second.nmodes; ++m) {
4432 if (cache_read_class)
continue;
4434 const std::size_t isf =
sn.stateful_index(ind);
4435 for (std::size_t jnd = 1; jnd <=
sn.nodes.size(); ++jnd) {
4436 if (!
sn.nodes[jnd - 1].stateful)
continue;
4437 const std::size_t jsf =
sn.stateful_index(jnd);
4438 for (std::size_t s = 1; s <= R; ++s) {
4439 const T p =
sn.rt((isf - 1) * R + (r - 1), (jsf - 1) * R + (s - 1));
4453 nd.
routing.size() >= r ? nd.
routing[r - 1] : RoutingStrategy::PROB;
4454 if ((nd.
routing.size() >= s && nd.
routing[s - 1] == RoutingStrategy::SDR) ||
4455 rsr == RoutingStrategy::JSQ || rsr == RoutingStrategy::SQ) {
4457 ns.
passive.rt_row = (isf - 1) * R + (r - 1);
4458 ns.
passive.rt_col = (jsf - 1) * R + (s - 1);
4498 const std::size_t R =
sn.nclasses;
4500 const std::size_t isf_f =
sn.stateful_index(e.
fork);
4501 if (isf_f == 0)
return out;
4502 const std::vector<T>& fs = gl.
local[isf_f - 1];
4503 if (fs.size() < R)
return out;
4507 const std::size_t B = e.
auxall.size();
4508 if (B == 0 || e.
tag == 0 || e.
tag > e.
auxall[0].size())
return out;
4509 const std::size_t Tt = e.
auxall[0].size();
4510 std::vector<double> nglobal(R, 0.0);
4511 for (std::size_t isf = 1; isf <=
sn.stateful_nodes.size(); ++isf) {
4512 const std::pair<T, std::vector<T>> mg =
4514 for (std::size_t r = 0; r < R; ++r) {
4520 if (std::isfinite(v)) nglobal[r] += v;
4523 std::vector<double> occ(Tt, 0.0);
4524 for (std::size_t t = 0; t < Tt; ++t)
4525 for (std::size_t b = 0; b < B; ++b) occ[t] += nglobal[e.
auxall[b][t] - 1];
4526 if (occ[e.
tag - 1] > 0)
return out;
4527 for (std::size_t t = 0; t + 1 < e.
tag; ++t)
4528 if (occ[t] == 0)
return out;
4531 seed.
local[isf_f - 1][seed.
local[isf_f - 1].size() - R + e.
cls - 1] -=
4534 std::vector<NetState<T>> partials(1, seed);
4540 std::vector<std::size_t> emissions;
4543 for (std::size_t rep = 0; rep < w; ++rep)
4544 for (std::size_t b = 0; b < B; ++b) emissions.push_back(b);
4546 std::size_t wmax = 0;
4547 for (std::size_t b = 0; b < e.
weightlink.size(); ++b)
4549 for (std::size_t rep = 1; rep <= wmax; ++rep)
4550 for (std::size_t b = 0; b < B; ++b)
4553 for (std::size_t ei = 0; ei < emissions.size(); ++ei) {
4554 const std::size_t b = emissions[ei];
4556 const std::size_t isf_b =
sn.stateful_index(bh);
4559 std::vector<NetState<T>> nextp;
4560 std::vector<T> nextq;
4561 for (std::size_t pp = 0; pp < partials.size(); ++pp) {
4563 after_event(
sn, bh, partials[pp].local[isf_b - 1], EventType::ARV, a);
4565 for (std::size_t
io = 0;
io < arv.
space.size(); ++
io) {
4568 nextp.push_back(ns);
4569 nextq.push_back(
io < arv.
prob.size() ? T(partprob[pp] * arv.
prob[
io])
4573 partials.swap(nextp);
4574 partprob.swap(nextq);
4577 out.
space = partials;
4578 for (std::size_t i = 0; i < partials.size(); ++i) {
4580 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...
std::string sn_patience_exp_refusal(const qn::NetworkStruct< T > &sn, std::size_t ist, std::size_t r)
Port of sn_patience_exp_refusal.m: the by-name refusal of a reneging patience that is not EXPONENTIAL...
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
RoutingStrategy
Routing strategies, with the values of MATLAB RoutingStrategy.
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< PoolStart< T > > pool_serve_next(const NetworkStruct< T > &sn, const CtmcPool< T > &pool, SchedStrategy sched, const std::vector< std::size_t > &Ks, const std::vector< T > &buf, const std::vector< T > &srv, std::size_t t)
The freed server of pool t takes the next compatible waiting job, in the discipline's order.
void pool_start(const CtmcPool< T > &pool, const std::vector< std::size_t > &Ks, const std::vector< T > &buf, const std::vector< T > &srv, std::size_t s, std::size_t t, const T &w, std::vector< PoolStart< T > > &out)
Class s starts service on pool t in every entry phase of the pool's block.
std::string state_impatience_unsupported(const NetworkStruct< T > &sn, const std::string &solver)
Port of solver_ctmc_state_supports.m: the impatience laws the state machinery cannot serve,...
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 ...
T station_renege_mu(const NetworkStruct< T > &sn, std::size_t ist, std::size_t cls)
sn.impatienceMu(ist,cls): the rate of an exponential reneging patience, 0 when the class declares non...
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.
T station_retrial_mu(const NetworkStruct< T > &sn, std::size_t ist, std::size_t cls)
sn.retrialMu(ist,cls): the rate of the exponential retrial delay, falling back to the scalar retrial_...
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.
EventOutcome< T > after_event_station_pool(const NetworkStruct< T > &sn, std::size_t ind, const std::vector< T > &inspace, EventType event, std::size_t cls)
Port of State.afterEventStationPool: ARV, DEP and PHASE at a station whose heterogeneous server pools...
std::vector< double > pas_increments(const F &mu_fun, const std::vector< std::size_t > &c)
Per-position service rate increments Delta_mu(c1..cp) = mu(c1..cp) - mu(c1..c_{p-1}...
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.
void apply_station_balking(const NetworkStruct< T > &sn, std::size_t ind, const std::vector< T > &inspace, std::size_t cls, EventOutcome< T > &out)
Port of the QUEUE_LENGTH balking branch of the ARV event: with the probability of the threshold band ...
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.
bool station_has_reneging(const NetworkStruct< T > &sn, std::size_t ist)
True when station ist declares exponential reneging for some class.
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.
bool station_retrial_constant(const NetworkStruct< T > &sn, std::size_t ist, std::size_t cls)
sn.retrialPolicy(ist,cls) == CONSTANT: one retry clock for the whole orbit.
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 matlab/src/api/sn/sn_patience_handles.m.
Port of the MATLAB +State package: the encoding that turns a station's state row into marginal job co...
The <kind> part of a LINE:<category>:<kind> identifier (see _kb/17-error-vocabulary....
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
The parameters of a Cache node, MATLAB's sn.nodeparam{ind} for a Cache.
int retrieval_capacity
Delayed-hit retrieval system (Cache.setRetrievalSystem).
T qlru
q-LRU admission probability; 1 admits every miss (plain LRU).
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
CTMC pair form of a MAP service at an FCFS station, written by ctmc::ctmc_mapc on the solver's privat...
Matrix< T > V
landing law (-D0)^-1 D1
std::size_t p
phases of the original MAP
std::vector< std::pair< std::size_t, std::size_t > > pairs
0-based (i,j), i-major, V(i,j) > 0
bool single
c = 1: carried phase, no pairs
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::vector< T > > > alpha
entry vector of block k of class r
std::vector< std::vector< std::vector< T > > > exit
exit rates of block k of class r
std::vector< std::vector< bool > > compat
compat[t-1][r-1]
std::vector< double > count
servers per pool
std::vector< std::size_t > alfsorder
pools by ascending class count (ALFS)
std::vector< std::vector< Matrix< T > > > D0
D0 of block k of class r.
std::vector< std::vector< std::size_t > > pools
pools[r-1]: compatible pools of r, ascending
lang::HeteroSchedPolicy policy
bool rotate
ALIS/FAIRNESS order is part of the state.
std::vector< std::vector< std::size_t > > off
std::size_t perm_index(const std::vector< std::size_t > &order) const
1-based index of order in perms, 0 when absent.
std::vector< std::vector< double > > fsfrate
fsfrate[t-1][r-1] = 1/mean (FSF)
std::vector< std::vector< std::size_t > > perms
every pool order, identity first
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
The parameters of a retrial station: MATLAB sn.retrialProc and friends.
std::vector< int > max_attempts
0 = unbounded
std::vector< T > retrial_rate
mu_r, the per-class orbit retry rate
std::vector< lang::Distrib< T > > retrial_proc
retrial_proc[r] is the class-r retrial process; empty = not a retrial class.
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 balking threshold: with min_jobs <= n <= max_jobs at the station, an arriving job of the class re...
One station of the network.
std::vector< Distrib< T > > orbit_impatience
Queue.setOrbitImpatience(class, dist): abandonment from the RETRIAL ORBIT, which is a different popul...
std::vector< BalkingParam > balking
std::vector< Distrib< T > > patience
Queue.setPatience(class, dist): the abandonment timer of a WAITING job, with impatience[r] naming whi...
CdScaling< T > jdscaling
sn.jdscaling for this station: MATLAB's Station.ljdScaling, the JOINT dependence map eta_i(n),...
std::vector< lang::ImpatienceType > impatience
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 Transition node: MATLAB sn.nodeparam{ind} for an SPN transition,...
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
One successor of a pooled service start: the buffer, the servers, its weight and the class started.