5#ifndef LINE_LANG_QN_NETWORK_STRUCT_H
6#define LINE_LANG_QN_NETWORK_STRUCT_H
82using lang::GlobalConstants;
101 std::vector<std::vector<std::size_t>>
auxall;
131 std::map<std::size_t, std::vector<std::vector<std::size_t>>>
auxmatrix;
132 std::map<std::size_t, std::vector<std::size_t>>
required;
292 if (m >= a.size())
return v;
294 for (std::size_t p = 0; p < a[m].rows(); ++p) {
297 for (std::size_t r = 0; r < a[m].cols(); ++r) {
299 if (!std::isfinite(x))
continue;
303 v[p] = any || a[m].cols() == 0
319 if (m >= a.size())
return v;
320 const double inf = std::numeric_limits<double>::infinity();
322 for (std::size_t p = 0; p < a[m].rows(); ++p) {
324 for (std::size_t r = 0; r < a[m].cols(); ++r) {
326 if (std::isfinite(x) && x < best) best = x;
336 for (
int w = 0; w < 3; ++w)
337 for (std::size_t m = 0; m < all[w]->size(); ++m) {
338 std::size_t touched = 0;
339 for (std::size_t r = 0; r < (*all[w])[m].cols(); ++r) {
341 for (std::size_t p = 0; p < (*all[w])[m].rows() && !any; ++p) {
344 any = w == 1 ? (std::isfinite(v) && v > 0.0) : v > 0.0;
348 if (touched > 1)
return true;
356 for (
int w = 0; w < 3; ++w)
357 for (std::size_t m = 0; m < all[w]->size(); ++m)
358 for (std::size_t r = 0; r < (*all[w])[m].cols(); ++r)
359 for (std::size_t p = 0; p < (*all[w])[m].rows(); ++p) {
361 if (w == 1 ? (std::isfinite(v) && v > 0.0) : v > 0.0)
return r + 1;
368 std::vector<lang::TimingStrategy>
timing;
377 std::vector<std::function<T(
const std::vector<T>&)>>
firingdep;
393 std::function<double(
double)>
fun;
403 std::function<double(
const std::vector<double>&)>
fun;
419 static const std::vector<FluidArc> none;
423 static const std::vector<FluidGuard> none;
427 static const std::vector<FluidArc> none;
430 const std::vector<FluidDep>&
fluid_deps(std::size_t m)
const {
431 static const std::vector<FluidDep> none;
435 static const std::vector<FluidFlowDep> none;
440 for (std::size_t m = 0; m <
nmodes; ++m)
483 std::vector<lang::Distrib<T>>
setup;
487 for (std::size_t r =
setup.size(); r > 0; --r)
488 if (!
setup[r - 1].disabled) {
592 std::vector<std::vector<Matrix<T>>>
accost;
632 std::vector<std::size_t>& rc_items,
633 std::vector<std::size_t>& rc_orig) {
641 rc_items.push_back(k + 1);
642 rc_orig.push_back(c + 1);
646 std::vector<std::size_t> ord(rc_list.size());
647 for (std::size_t i = 0; i < ord.size(); ++i) ord[i] = i;
648 std::stable_sort(ord.begin(), ord.end(),
649 [&](std::size_t a, std::size_t b) { return rc_list[a] < rc_list[b]; });
650 std::vector<std::size_t> l(rc_list.size()), it(rc_list.size()), oc(rc_list.size());
651 for (std::size_t i = 0; i < ord.size(); ++i) {
652 l[i] = rc_list[ord[i]];
653 it[i] = rc_items[ord[i]];
654 oc[i] = rc_orig[ord[i]];
681 double cap = std::numeric_limits<double>::infinity();
874 double fluidcap = std::numeric_limits<double>::infinity();
916 double deadline = std::numeric_limits<double>::infinity();
946 std::vector<std::vector<std::size_t>>
pools;
947 std::vector<std::vector<std::size_t>>
off,
len;
948 std::vector<std::vector<std::vector<T>>>
alpha;
949 std::vector<std::vector<std::vector<T>>>
exit;
950 std::vector<std::vector<Matrix<T>>>
D0;
954 std::vector<std::vector<std::size_t>>
perms;
956 std::size_t
perm_index(
const std::vector<std::size_t>& order)
const {
957 for (std::size_t p = 0; p <
perms.size(); ++p)
958 if (
perms[p] == order)
return p + 1;
979 std::vector<std::pair<std::size_t, std::size_t>>
pairs;
996 "Class \"" + classname +
"\" is closed, but reneging" + where +
997 " removes a waiting job from the network, which would change a closed population. Reneging "
998 "is defined for open classes only; model the abandonment as a routing (e.g. a probabilistic "
999 "exit back to the reference station) or use an open class.");
1069 if (i >=
stations.size() ||
stations[i].nodetype != NodeType::Place)
return false;
1070 for (std::size_t r = 0; r <
service[i].size(); ++r)
1077 if (ind == 0 || ind >
nodes.size())
return false;
1078 const std::size_t st =
nodes[ind - 1].station;
1079 return st > 0 && st <=
stations.size() &&
stations[st - 1].nodetype == NodeType::Place &&
1085 if (s.nodetype == NodeType::Place && s.fluid)
return true;
1087 if (tp.second.has_fluid_arcs())
return true;
1114 std::vector<std::pair<std::size_t, std::size_t>>
fj;
1202 const typename std::map<std::size_t, ForkParam<T> >::const_iterator it =
1221 std::function<T(
const std::vector<T>&)>
fn;
1258 std::vector<std::vector<double>>
cap;
1291 if (ind == 0 || ind >
nodes.size())
return false;
1292 const std::size_t ist =
nodes[ind - 1].station;
1405 std::vector<std::vector<std::size_t>>
nvars;
1502 if (ist == 0 || ist >
stations.size())
return pp;
1503 const typename std::map<std::size_t, PollingParam>::const_iterator it =
1537 if (ind == 0 || ind >
nvars.size())
return 0;
1539 for (std::size_t j = 0; j <
nvars[ind - 1].size(); ++j) w +=
nvars[ind - 1][j];
1550 std::vector<double> v;
1579 std::vector<double> v(
nodes.size(), std::nan(
""));
1589 std::vector<double> v(
nstations, std::nan(
""));
1592 if (nd >= 1 && nd <= nsf.size()) v[ist - 1] = nsf[nd - 1];
1602 if (nd >= 1 && nd <=
nodes.size() &&
nodes[nd - 1].station != 0)
1603 v[k] =
static_cast<double>(
nodes[nd - 1].station);
1618 const std::size_t I =
nodes.size();
1621 for (
const auto& kv :
P) {
1623 if (B.
rows() < I || B.
cols() < I)
continue;
1624 for (std::size_t a = 0; a < I; ++a)
1625 for (std::size_t b = 0; b < I; ++b)
1626 if (B(a, b) > zero &&
1627 !(
nodes[a].nodetype == NodeType::Sink &&
nodes[b].nodetype == NodeType::Source))
1639 const std::size_t I =
nodes.size();
1641 for (std::size_t ind = 0; ind < I; ++ind) {
1642 if (
nodes[ind].nodetype == NodeType::Cache) m(ind, 1) = 1.0;
1644 if (rs == RoutingStrategy::RROBIN || rs == RoutingStrategy::WRROBIN || rs == RoutingStrategy::JSQ ||
1645 rs == RoutingStrategy::SQ || rs == RoutingStrategy::SDR)
1653 std::vector<double> v(
nodes.size(), 0.0);
1654 for (std::size_t ind = 1; ind <=
nodes.size(); ++ind)
1661 std::vector<bool> v(
nclasses,
false);
1678 if (
stations[i].nodetype == NodeType::Join)
1679 m(i, r) =
static_cast<double>(
static_cast<int>(ProcessType::IMMEDIATE));
1683 m(i, r) =
static_cast<double>(
static_cast<int>(
service[i][r].type));
1690 bool proc_is_empty(std::size_t i, std::size_t r)
const {
1696 bool proc_is_nan(std::size_t i, std::size_t r)
const {
1697 return service[i][r].disabled && !proc_is_empty(i, r);
1700 std::vector<Matrix<T>> proc_blocks(std::size_t i, std::size_t r)
const {
1702 std::vector<Matrix<T>> b;
1706 for (
const Matrix<T>& Dk : d.
Dmark) b.push_back(Dk);
1730 if (proc_is_empty(i, r) || d.
type == ProcessType::NHPP)
1733 m(i, r) =
static_cast<double>(proc_blocks(i, r)[0].rows());
1746 for (std::size_t i = 0; i < m.
rows(); ++i)
1747 for (std::size_t r = 0; r < m.
cols(); ++r) {
1748 if (
stations[i].nodetype != NodeType::Join && m(i, r) < 1.0) m(i, r) = 1.0;
1749 if (
markidx_of(i + 1, r + 1) > 1) m(i, r) = 1.0;
1758 for (std::size_t i = 0; i < sz.
rows(); ++i)
1759 for (std::size_t r = 0; r < sz.
cols(); ++r) m(i, r + 1) = m(i, r) + sz(i, r);
1769 std::vector<std::vector<std::vector<double>>>
mu()
const {
return rate_cells(
true); }
1772 std::vector<std::vector<std::vector<double>>>
phi()
const {
return rate_cells(
false); }
1780 std::vector<std::vector<std::vector<double>>>
pie()
const {
1781 std::vector<std::vector<std::vector<double>>> out(
nstations, std::vector<std::vector<double>>(
nclasses));
1786 out[i][r] = {std::nan(
"")};
1789 const std::vector<Matrix<T>> b = proc_blocks(i, r);
1805 const auto pies =
pie();
1818 using LstHandle = std::function<std::complex<double>(
const std::complex<double>&)>;
1828 std::vector<std::vector<LstHandle>>
lst()
const {
1829 std::vector<std::vector<LstHandle>> out(
nstations, std::vector<LstHandle>(
nclasses));
1834 if (nt == NodeType::Fork || nt == NodeType::Join)
continue;
1836 if (nt != NodeType::Source)
1837 out[i][r] = [](
const std::complex<double>&) {
return std::complex<double>(std::nan(
""), 0.0); };
1840 out[i][r] = [d](
const std::complex<double>& s) -> std::complex<double> {
1844 if (s.imag() != 0.0)
1846 "sn.lst: a complex argument needs transcendental arithmetic; solve in double");
1847 return std::complex<double>(
1856 std::vector<std::vector<std::vector<double>>> rate_cells(
bool want_mu)
const {
1857 std::vector<std::vector<std::vector<double>>> out(
nstations, std::vector<std::vector<double>>(
nclasses));
1861 if (proc_is_empty(i, r))
continue;
1863 out[i][r] = {std::nan(
"")};
1864 }
else if (d.
type == ProcessType::NHPP || d.
type == ProcessType::DMAP) {
1865 out[i][r] = {want_mu ? num_traits<T>::to_double(d.
rate()) : 1.0};
1868 out[i][r].push_back(num_traits<T>::to_double(x));
1878 return service[ist - 1][r - 1].type;
1898 std::size_t
phases_of(std::size_t ist, std::size_t r)
const {
1929 const std::size_t p =
phases_of(ist, r);
1930 return p > 0 ? p : 1;
1942 if (ist == 0 || ist >
stations.size())
return 0;
1943 const std::vector<std::size_t>&
mc =
stations[ist - 1].marked_classes;
1944 for (std::size_t k = 0; k <
mc.size(); ++k)
1945 if (
mc[k] == r)
return k + 1;
1954 if (ist == 0 || ist >
stations.size())
return 0;
1955 const std::vector<std::size_t>&
mc =
stations[ist - 1].marked_classes;
1956 return mc.empty() ? 0 :
mc[0];
1960 if (n.nodetype == NodeType::Fork)
return true;
1975 if (rs == RoutingStrategy::SDR)
return true;
1986 if (rs == RoutingStrategy::SDR || rs == RoutingStrategy::JSQ || rs == RoutingStrategy::SQ)
2006 std::vector<std::size_t>
rr_outlinks(std::size_t ind, std::size_t r)
const {
2007 std::vector<std::size_t> out;
2009 const std::size_t K =
classes.size(), I =
nodes.size();
2010 for (std::size_t j = 1; j <= I; ++j) {
2011 bool linked =
false;
2012 for (std::size_t s = 1; s <= K && !linked; ++s)
2013 if (
get_route(r, s, ind, j) > zero) linked =
true;
2014 if (linked) out.push_back(j);
2021 const std::vector<std::size_t> ol =
rr_outlinks(ind, r);
2022 const std::map<std::size_t, double>* w =
2023 (ind <=
nodes.size() &&
nodes[ind - 1].routing_weights.size() >= r)
2024 ? &
nodes[ind - 1].routing_weights[r - 1]
2026 std::vector<std::size_t> cycle;
2027 for (std::size_t d = 0; d < ol.size(); ++d) {
2030 const std::map<std::size_t, double>::const_iterator it = w->find(ol[d]);
2031 if (it != w->end() && it->second > 0.0)
2032 reps = std::lround(it->second) < 1 ? 1 : std::lround(it->second);
2034 for (
long q = 0; q < reps; ++q) cycle.push_back(ol[d]);
2041 if (
ctmcmapc.empty())
return nullptr;
2042 const auto it =
ctmcmapc.find(std::make_pair(ist, r));
2043 return it ==
ctmcmapc.end() ? nullptr : &it->second;
2048 std::size_t slot = 0;
2049 for (std::size_t j = 0; j + 1 < r && j <
nvars[ind - 1].size(); ++j) slot +=
nvars[ind - 1][j];
2063 const std::size_t R =
classes.size();
2064 if (ind == 0 || ind >
nodes.size() || r == 0 || r > R)
return 0;
2065 const std::vector<RoutingStrategy>& rt_i =
nodes[ind - 1].routing;
2066 if (rt_i.size() < r)
return 0;
2067 if (rt_i[r - 1] != RoutingStrategy::RROBIN && rt_i[r - 1] != RoutingStrategy::WRROBIN)
2069 if (
nvars.size() < ind)
return 0;
2070 std::size_t slot = 0;
2071 for (std::size_t j = 0; j < R + r && j <
nvars[ind - 1].size(); ++j)
2072 slot +=
nvars[ind - 1][j];
2082 std::size_t
rr_dest(std::size_t ind, std::size_t r,
const std::vector<T>& varrow)
const {
2084 if (slot == 0 || slot > varrow.size())
return 0;
2086 if (
nodes[ind - 1].routing[r - 1] == RoutingStrategy::RROBIN)
2087 return v > 0 ?
static_cast<std::size_t
>(v) : 0;
2089 if (v < 1 ||
static_cast<std::size_t
>(v) > cycle.size())
return 0;
2090 return cycle[
static_cast<std::size_t
>(v) - 1];
2099 void rr_advance(std::size_t ind, std::size_t r, std::vector<T>& varrow)
const {
2101 if (slot == 0 || slot > varrow.size())
return;
2102 if (
nodes[ind - 1].routing[r - 1] == RoutingStrategy::RROBIN) {
2103 const std::vector<std::size_t> ol =
rr_outlinks(ind, r);
2104 if (ol.empty())
return;
2106 std::size_t idx = ol.size();
2107 for (std::size_t d = 0; d < ol.size(); ++d)
2108 if (
static_cast<long>(ol[d]) == cur) { idx = d;
break; }
2109 const std::size_t nxt = (idx + 1 < ol.size()) ? idx + 1 : 0;
2114 if (cycle.empty())
return;
2116 const long nxt = (pos < 1 || static_cast<std::size_t>(pos) >= cycle.size()) ? 1 : pos + 1;
2124 if (rs == RoutingStrategy::RROBIN || rs == RoutingStrategy::WRROBIN)
return true;
2148 bool declared =
false;
2149 for (
const std::vector<bool>& row :
immfeed) {
2155 if (declared)
break;
2157 if (!declared)
return false;
2162 for (std::size_t ist = 1; ist <=
immfeed.size(); ++ist) {
2164 if (ind == 0 || ind >
nodes.size())
continue;
2166 if (isf == 0)
continue;
2167 for (std::size_t r = 1; r <=
immfeed[ist - 1].size() && r <= R; ++r) {
2168 if (!
immfeed[ist - 1][r - 1])
continue;
2169 const std::size_t col = (isf - 1) * R + (r - 1);
2170 if (col >=
rt.
cols())
continue;
2171 for (std::size_t sc = 0; sc < R; ++sc) {
2172 const std::size_t row = (isf - 1) * R + sc;
2199 throw InputError(
"network: a station is not a stateful node");
2211 nodes.push_back(nd);
2225 nodes.push_back(nd);
2228 return nodes.size();
2239 service[station - 1][cls - 1] = d;
2243 void set_route(std::size_t r, std::size_t s, std::size_t i, std::size_t j,
const T& p) {
2244 auto key = std::make_pair(r, s);
2245 auto it =
P.find(key);
2250 it->second(i - 1, j - 1) = p;
2266 auto key = std::make_pair(r, s);
2267 auto it =
Peff.find(key);
2268 if (it ==
Peff.end())
2271 if (it->second.rows() !=
nodes.size()) {
2273 for (std::size_t a = 0; a < it->second.rows(); ++a)
2274 for (std::size_t b = 0; b < it->second.cols(); ++b) g(a, b) = it->second(a, b);
2277 it->second(i - 1, j - 1) = p;
2288 T
get_route(std::size_t r, std::size_t s, std::size_t i, std::size_t j)
const {
2289 auto it =
P.find(std::make_pair(r, s));
2291 return it->second(i - 1, j - 1);
2295 T
route_eff(std::size_t r, std::size_t s, std::size_t i, std::size_t j)
const {
2297 auto it =
Peff.find(std::make_pair(r, s));
2299 return it->second(i - 1, j - 1);
2346 for (std::size_t i = 0; i <
stations.size(); ++i)
2347 for (std::size_t r = 0; r <
stations[i].impatience.size() && r <
classes.size(); ++r)
2349 std::isfinite(
classes[r].population))
2359 if (ind == 0 || ind >
replyblock.size())
return false;
2360 for (std::size_t k = 0; k <
syncreply.size(); ++k)
2378 if (ind == 0 || ind >
nodes.size())
return true;
2380 if (nt != NodeType::Queue && nt != NodeType::Delay)
return true;
2381 const std::size_t sti =
nodes[ind - 1].station;
2382 if (sti == 0 || sti >
stations.size())
return true;
2383 if (!
stations[sti - 1].server_types.empty())
return true;
2384 if (
procid(sti, r + 1) != ProcessType::DISABLED)
return true;
2402 std::vector<std::vector<bool>> reached;
2403 if (N == 0 || K == 0)
return reached;
2405 reached.assign(N, std::vector<bool>(K,
false));
2406 std::vector<std::vector<bool>> seed(N, std::vector<bool>(K,
false));
2407 for (std::size_t i = 0; i <
stations.size(); ++i) {
2408 if (
stations[i].nodetype != NodeType::Source)
continue;
2410 if (ind == 0 || ind > N)
continue;
2411 for (std::size_t r = 0; r < K; ++r)
2412 if (
procid(i + 1, r + 1) != ProcessType::DISABLED) seed[ind - 1][r] =
true;
2414 for (std::size_t r = 0; r < K && r <
classes.size(); ++r) {
2415 const double pop =
classes[r].population;
2416 if (!std::isfinite(pop) || pop <= 0.0)
continue;
2418 if (ind == 0 || ind > N)
continue;
2419 seed[ind - 1][r] =
true;
2421 std::vector<std::pair<std::size_t, std::size_t>> stack;
2422 for (std::size_t i = 0; i < N; ++i)
2423 for (std::size_t r = 0; r < K; ++r)
2425 reached[i][r] =
true;
2426 stack.push_back(std::make_pair(i, r));
2428 while (!stack.empty()) {
2429 const std::size_t i = stack.back().first;
2430 const std::size_t r = stack.back().second;
2433 if (nt == NodeType::Sink)
continue;
2434 if (nt == NodeType::Source && !seed[i][r])
continue;
2436 const std::size_t row = i * K + r;
2437 for (std::size_t col = 0; col < N * K; ++col) {
2441 const std::size_t j = col / K, sIdx = col % K;
2442 if (!reached[j][sIdx]) {
2443 reached[j][sIdx] =
true;
2444 stack.push_back(std::make_pair(j, sIdx));
2492 for (std::size_t i = 0; i <
nstations; ++i) {
2494 if (nt != NodeType::Queue && nt != NodeType::Delay)
continue;
2495 for (std::size_t r = 0; r <
classes.size() && r <
issignal.size(); ++r)
2496 if (
issignal[r] &&
procid(i + 1, r + 1) == ProcessType::DISABLED)
2506 for (std::size_t ind = 0; ind <
nodes.size(); ++ind) {
2508 if (nt == NodeType::Cache || nt == NodeType::Place ||
2509 nt == NodeType::Transition || nt == NodeType::Fork ||
2510 nt == NodeType::Join)
2515 if (reached.empty())
return;
2516 for (std::size_t i = 0; i <
nstations; ++i) {
2518 if (nt != NodeType::Queue && nt != NodeType::Delay)
continue;
2522 if (!
stations[i].server_types.empty())
continue;
2524 if (ind == 0)
continue;
2525 for (std::size_t r = 0; r < K; ++r) {
2526 if (
procid(i + 1, r + 1) != ProcessType::DISABLED)
continue;
2532 if (ind - 1 >= reached.size() || r >= reached[ind - 1].size())
continue;
2533 if (!reached[ind - 1][r])
continue;
2534 const std::string kind = (nt == NodeType::Delay) ?
"Delay" :
"Queue";
2536 "' has no service configured for job class '" +
2538 "', but the class is routed to it. Jobs would arrive and "
2539 "never leave. Configure a service for that class, or route "
2556 immfeed.assign(M, std::vector<bool>(R,
false));
2557 for (std::size_t i = 0; i < M; ++i)
2558 for (std::size_t r = 0; r < R; ++r) {
2559 const bool station_has =
2577 if (ind == 0 || ind >
nodes.size() ||
nodes[ind - 1].stateful)
return;
2578 nodes[ind - 1].stateful =
true;
2597 for (std::size_t ind = 1; ind <=
nodes.size(); ++ind) {
2601 for (std::size_t r = 0; r < nd.
routing.size(); ++r)
2602 if (nd.
routing[r] == RoutingStrategy::RROBIN ||
2603 nd.
routing[r] == RoutingStrategy::WRROBIN ||
2604 nd.
routing[r] == RoutingStrategy::JSQ || nd.
routing[r] == RoutingStrategy::SQ)
2621 const std::size_t R =
classes.size();
2626 nvars.assign(
nodes.size(), std::vector<std::size_t>(3 * R + 1, 0));
2627 for (std::size_t ind = 1; ind <=
nodes.size(); ++ind) {
2628 const std::size_t ist =
nodes[ind - 1].station;
2632 for (std::size_t r = 1; r <= R; ++r) {
2634 if (pt == ProcessType::MAP || pt == ProcessType::MMPP2)
2635 nvars[ind - 1][r - 1] += 1;
2639 const std::vector<RoutingStrategy>& rt_i =
nodes[ind - 1].routing;
2640 for (std::size_t r = 1; r <= R && r <= rt_i.size(); ++r)
2641 if (rt_i[r - 1] == RoutingStrategy::RROBIN ||
2642 rt_i[r - 1] == RoutingStrategy::WRROBIN)
2643 nvars[ind - 1][R + r - 1] += 1;
2652 if (ist != 0 &&
stations[ist - 1].sched == SchedStrategy::POLLING) {
2655 for (std::size_t r = 0; r < pp.
switchover.size(); ++r) {
2657 if (!d.
disabled && d.
D0.rows() > 0 && d.
type != ProcessType::IMMEDIATE)
2660 std::size_t w = anysw ? 2 : 0;
2662 nvars[ind - 1][2 * R] = w;
2665 for (std::size_t r = 1; r <= R; ++r)
2668 nvars[ind - 1][2 * R + r] = 1;
2677 if (
stations[ist - 1].sched == SchedStrategy::POLLING)
2679 "Server breakdowns are not supported at a polling station (" +
2680 nodes[ind - 1].name +
2681 "): the polling controller and the breakdown status share one "
2682 "local-state column.");
2683 for (std::size_t r = 1; r <= R; ++r)
2687 "Server breakdowns are not supported at station '" +
2688 nodes[ind - 1].name +
2689 "', which also holds servers for a synchronous reply: the reply "
2690 "counters would trail the breakdown status the service handlers read");
2691 nvars[ind - 1][2 * R] = 1;
2693 const typename std::map<std::size_t, CacheParam<T>>::const_iterator ci =
2700 for (std::size_t u = 0; u < ci->second.itemcap.size(); ++u)
2701 if (ci->second.itemcap[u] > 0)
2702 w +=
static_cast<std::size_t
>(ci->second.itemcap[u]);
2703 if (ci->second.retrieval_capacity > 0) {
2704 w += ci->second.nitems;
2705 std::vector<std::size_t> rcl, rci, rco;
2709 nvars[ind - 1][2 * R] = w;
2731 const std::size_t R =
classes.size(), N =
nodes.size();
2733 for (std::size_t r = 0; r < R && r <
syncreply.size(); ++r)
2736 replyblock.assign(N, std::vector<bool>(R,
false));
2737 for (std::size_t r = 1; r <= R; ++r) {
2740 if (s < 1 || s > R)
continue;
2741 for (std::size_t ind = 1; ind <= N; ++ind) {
2742 const std::size_t ist =
nodes[ind - 1].station;
2744 if (
stations[ist - 1].sched == SchedStrategy::INF)
continue;
2745 bool arrives_here =
false;
2746 for (std::size_t i = 1; i <= N && !arrives_here; ++i)
2747 for (std::size_t q = 1; q <= R; ++q)
2750 rtnodes((i - 1) * R + q - 1, (ind - 1) * R + s - 1)) > 0) {
2751 arrives_here =
true;
2754 if (!arrives_here)
continue;
2755 if (
stations[ist - 1].sched != SchedStrategy::FCFS)
2757 "network '" +
name +
2758 "': synchronous calls (REPLY signals) are supported only at FCFS "
2761 "' uses another discipline. A held server is encoded as a per-class "
2762 "counter, which is exact only where servers are interchangeable (FCFS) "
2763 "or unlimited (INF); the other disciplines are not yet encoded rather than "
2764 "infeasible. Set this station to FCFS or INF, or simulate the layered model "
2765 "directly with SolverLDES.");
2786 const std::size_t R =
classes.size();
2787 const std::size_t N =
nodes.size();
2788 std::vector<std::size_t> out;
2790 std::vector<bool> seen(N + 1,
false);
2791 std::vector<std::size_t> frontier(1, ind);
2793 while (!frontier.empty()) {
2794 const std::size_t i = frontier.back();
2795 frontier.pop_back();
2796 for (std::size_t j = 1; j <= N; ++j) {
2797 if (seen[j])
continue;
2798 bool linked =
false;
2799 for (std::size_t r = 0; r < R && !linked; ++r)
2800 for (std::size_t s = 0; s < R && !linked; ++s)
2802 rtnodes((i - 1) * R + r, (j - 1) * R + s)) > 0)
2804 if (!linked)
continue;
2806 if (
nodes[j - 1].station != 0) {
2809 frontier.push_back(j);
2821 const std::size_t R =
classes.size();
2822 const std::size_t N =
nodes.size();
2826 for (std::size_t ind = 1; ind <= N; ++ind) {
2827 const std::size_t ist =
nodes[ind - 1].station;
2828 if (ist == 0)
continue;
2830 if (nt == NodeType::Source || nt == NodeType::Cache)
continue;
2832 bool declares =
false;
2833 for (std::size_t r = 1; r <= R; ++r) {
2834 const bool here_bas =
droprule.size() >= ist &&
droprule[ist - 1].size() >= r &&
2835 droprule[ist - 1][r - 1] == DropStrategy::BAS;
2836 for (std::size_t d = 0; d < dests.size(); ++d) {
2837 const std::size_t jst =
nodes[dests[d] - 1].station;
2838 if (jst == 0 ||
nodes[dests[d] - 1].nodetype == NodeType::Source)
continue;
2849 const double dcap =
stations[jst - 1].cap;
2850 if (!std::isfinite(dcap) || !(dcap > 0))
continue;
2851 const bool there_bas =
2853 droprule[jst - 1][r - 1] == DropStrategy::BAS;
2854 if (!here_bas && !there_bas)
continue;
2862 if (!declares)
continue;
2868 "station '" +
nodes[ind - 1].name +
2869 "' combines server breakdowns with true-BAS blocking: the breakdown status "
2870 "and the BAS blocked marker share one local-state column. Remove the BAS drop "
2871 "rule or the breakdown");
2872 if (
stations[ist - 1].sched == SchedStrategy::POLLING)
2874 "true BAS blocking is not supported at the polling station '" +
2875 nodes[ind - 1].name +
2876 "': the polling controller and the BAS blocked marker share one local-state "
2877 "column. Use a non-polling discipline at the blocking station, or remove the "
2879 for (std::size_t r = 1; r <= R; ++r)
2883 "true BAS blocking is not supported at station '" +
nodes[ind - 1].name +
2884 "', which also holds servers for a synchronous reply: fromMarginal appends "
2885 "the reply counters AFTER the blocked marker, so the marker would no "
2886 "longer be the trailing column the departure handler reads");
2887 nvars[ind - 1][2 * R] = 1;
2908 for (std::size_t i = 0; i <
stations.size(); ++i) {
2910 if (st.
sched == SchedStrategy::DPS || st.
sched == SchedStrategy::GPS) {
2915 if (st.
sched == SchedStrategy::SEPT || st.
sched == SchedStrategy::LEPT) {
2917 std::vector<double> means;
2918 for (std::size_t r = 0; r <
classes.size(); ++r)
2920 std::vector<double> sorted = means;
2921 std::sort(sorted.begin(), sorted.end());
2922 sorted.erase(std::unique(sorted.begin(), sorted.end()), sorted.end());
2923 if (st.
sched == SchedStrategy::LEPT)
2924 std::reverse(sorted.begin(), sorted.end());
2926 for (std::size_t r = 0; r <
classes.size(); ++r)
2927 for (std::size_t k = 0; k < sorted.size(); ++k)
2928 if (sorted[k] == means[r])
2966 const std::size_t K =
classes.size(), I =
nodes.size();
2968 bool trivial =
true;
2971 if (rs != RoutingStrategy::PROB && rs != RoutingStrategy::DISABLED) trivial =
false;
2978 bool has_cs =
false;
2980 if (nd.nodetype == NodeType::ClassSwitch) has_cs =
true;
2983 const bool has_cache = !
nodeparam.empty();
2984 if (trivial && !has_cs && !has_cache)
return;
2986 for (
const auto& kv :
P)
Peff[kv.first] = kv.second;
2990 std::vector<char> conn(I * I, 0);
2991 for (
const auto& kv :
P) {
2993 if (M.
rows() < I || M.
cols() < I)
continue;
2994 for (std::size_t a = 0; a < I; ++a)
2995 for (std::size_t b = 0; b < I; ++b)
2996 if (M(a, b) > zero) conn[a * I + b] = 1;
2998 auto eff_at = [&](std::size_t r, std::size_t s) ->
Matrix<T>& {
2999 auto key = std::make_pair(r, s);
3000 auto it =
Peff.find(key);
3001 if (it ==
Peff.end())
3003 if (it->second.rows() != I) {
3005 for (std::size_t a = 0; a < it->second.rows(); ++a)
3006 for (std::size_t b = 0; b < it->second.cols(); ++b) g(a, b) = it->second(a, b);
3012 for (std::size_t i = 1; i <= I; ++i) {
3014 for (std::size_t r = 1; r <= K; ++r) {
3016 nd.
routing.size() >= r ? nd.
routing[r - 1] : RoutingStrategy::PROB;
3017 if (rs == RoutingStrategy::PROB || rs == RoutingStrategy::DISABLED)
continue;
3018 if (rs != RoutingStrategy::RAND && rs != RoutingStrategy::RROBIN &&
3019 rs != RoutingStrategy::JSQ && rs != RoutingStrategy::SQ &&
3020 rs != RoutingStrategy::WRROBIN && rs != RoutingStrategy::SDR)
3023 "' has no routing-matrix expansion in this port");
3039 const bool open_class = !std::isfinite(
3041 const bool from_source = nd.
nodetype == NodeType::Source;
3042 const bool from_sink = nd.
nodetype == NodeType::Sink;
3043 if (!open_class && (from_source || from_sink))
continue;
3044 std::vector<std::pair<std::size_t, std::size_t>> dest;
3045 for (std::size_t j = 1; j <= I; ++j) {
3046 if (!open_class &&
nodes[j - 1].nodetype == NodeType::Sink)
continue;
3047 if (conn[(i - 1) * I + (j - 1)]) dest.emplace_back(j, r);
3049 if (dest.empty())
continue;
3054 std::vector<T> share(dest.size(),
3057 if (rs == RoutingStrategy::WRROBIN) {
3058 const std::map<std::size_t, double>* w =
3061 std::vector<double> raw(dest.size(), 0.0);
3063 for (std::size_t d = 0; d < dest.size(); ++d) {
3064 const std::map<std::size_t, double>::const_iterator it =
3065 w->find(dest[d].first);
3066 raw[d] = (it == w->end()) ? 0.0 : it->second;
3070 for (std::size_t d = 0; d < dest.size(); ++d)
3075 for (std::size_t s = 1; s <= K; ++s) {
3076 if (
Peff.find(std::make_pair(r, s)) ==
Peff.end())
continue;
3078 for (std::size_t j = 1; j <= I; ++j) B(i - 1, j - 1) = zero;
3080 for (std::size_t d = 0; d < dest.size(); ++d)
3081 eff_at(r, dest[d].second)(i - 1, dest[d].first - 1) = share[d];
3087 const std::size_t cs = kv.first;
3089 if (C.
rows() != K || C.
cols() != K)
3090 throw InputError(
"network: the class-switch matrix of node '" +
3091 nodes[cs - 1].
name +
"' is not (nclasses x nclasses)");
3106 std::vector<std::vector<T>> diag(K, std::vector<T>(I, zero));
3107 for (std::size_t s = 1; s <= K; ++s) {
3108 if (!
Peff.empty() &&
Peff.find(std::make_pair(s, s)) ==
Peff.end())
continue;
3109 for (std::size_t j = 1; j <= I; ++j)
3110 diag[s - 1][j - 1] =
3111 Peff.empty() ?
get_route(s, s, cs, j) : eff_at(s, s)(cs - 1, j - 1);
3114 for (std::size_t r = 1; r <= K; ++r)
3115 for (std::size_t s = 1; s <= K; ++s) {
3116 if (
Peff.find(std::make_pair(r, s)) ==
Peff.end())
continue;
3118 for (std::size_t j = 1; j <= I; ++j) B(cs - 1, j - 1) = zero;
3120 for (std::size_t r = 1; r <= K; ++r)
3121 for (std::size_t s = 1; s <= K; ++s) {
3122 if (!(C(r - 1, s - 1) > zero))
continue;
3124 for (std::size_t j = 1; j <= I; ++j)
3125 if (diag[s - 1][j - 1] > zero)
3126 B(cs - 1, j - 1) = T(diag[s - 1][j - 1] * C(r - 1, s - 1));
3140 const std::size_t ci = kv.first;
3142 for (std::size_t r = 0; r < cp.
hitclass.size() && r < K; ++r) {
3145 for (std::size_t s = 1; s <= K; ++s) {
3147 for (std::size_t j = 1; j <= I; ++j) B(ci - 1, j - 1) = zero;
3149 eff_at(r + 1, cp.
hitclass[r])(ci - 1, ci - 1) = half;
3151 eff_at(r + 1, cp.
missclass[r])(ci - 1, ci - 1) = half;
3168 const std::size_t I =
nodes.size();
3169 if (joinNode == 0 || joinNode > I)
return 0;
3170 std::size_t forkNode = 0;
3171 for (std::size_t a = 0; a <
fj.size(); ++a)
3172 if (
fj[a].second == joinNode) {
3173 forkNode =
fj[a].first;
3177 std::vector<bool> seen(I + 1,
false);
3178 std::size_t deg = 0;
3179 for (
typename std::map<std::pair<std::size_t, std::size_t>,
Matrix<T> >::const_iterator
3181 it !=
P.end(); ++it) {
3182 if (it->second.rows() < I || it->second.cols() < I)
continue;
3183 for (std::size_t b = 1; b <= I; ++b) {
3184 if (seen[b])
continue;
3185 const T v = (forkNode != 0) ? it->second(forkNode - 1, b - 1)
3186 : it->second(b - 1, joinNode - 1);
3193 if (forkNode == 0 || forkNode > I)
return deg;
3207 const std::size_t lo = (r != 0 && r <= fol.
cols()) ? r - 1 : 0;
3208 const std::size_t hi = (r != 0 && r <= fol.
cols()) ? r - 1 : fol.
cols() - 1;
3210 for (std::size_t c = lo; c <= hi && c < fol.
cols(); ++c) {
3212 for (std::size_t d = 0; d < fol.
rows(); ++d) {
3214 if (!(link > 0.0))
continue;
3218 if (acc > best) best = acc;
3220 if (best > 0.0)
return static_cast<std::size_t
>(best + 0.5);
3223 double w =
nodes[forkNode - 1].tasks_per_link;
3224 if (!(w >= 1.0)) w = 1.0;
3225 return deg *
static_cast<std::size_t
>(w + 0.5);
3236 std::vector<std::size_t> out;
3237 for (
typename std::map<std::size_t, JoinDecl>::const_iterator it =
joindecl.begin();
3240 if (it->second.quorum <= 0.0)
continue;
3242 const std::size_t k =
static_cast<std::size_t
>(it->second.quorum + 0.5);
3243 if (n == 0 || k < n) out.push_back(it->first);
3278 const double inf = std::numeric_limits<double>::infinity();
3280 classcap.assign(M, std::vector<double>(K, inf));
3281 droprule.assign(M, std::vector<DropStrategy>(K, DropStrategy::WAITQ));
3282 std::vector<std::vector<double>> chaincap(M, std::vector<double>(std::max(
nchains, K), inf));
3290 std::vector<char> quorum_class(K + 1, 0);
3294 for (std::size_t x = 0; x < qj.size(); ++x)
3295 for (
typename std::map<std::pair<std::size_t, std::size_t>,
3297 it !=
P.end(); ++it) {
3298 if (it->second.rows() <
nodes.size() || qj[x] >
nodes.size())
continue;
3299 for (std::size_t a = 1; a <=
nodes.size(); ++a)
3300 if (it->second(a - 1, qj[x] - 1) > zero) {
3301 if (it->first.first <= K) quorum_class[it->first.first] = 1;
3302 if (it->first.second <= K) quorum_class[it->first.second] = 1;
3314 double fork_task_factor = 1.0;
3315 for (std::size_t i = 0; i <
nodes.size(); ++i) {
3316 if (
nodes[i].nodetype != NodeType::Fork)
continue;
3317 const double w =
nodes[i].tasks_per_link;
3318 if (w >= 1.0 && std::isfinite(w)) fork_task_factor *= std::floor(w + 0.5);
3321 for (std::size_t c = 0; c <
nchains; ++c) {
3322 double chain_cap = 0.0;
3324 bool quorum =
false;
3325 for (std::size_t r :
inchain[c]) {
3326 if (std::isinf(
classes[r - 1].population)) open =
true;
3327 else chain_cap +=
classes[r - 1].population;
3328 if (r <= K && quorum_class[r]) quorum =
true;
3332 bool spawn_fed =
false;
3333 for (std::size_t q = 0; q < K && !spawn_fed; ++q)
3334 for (std::size_t r :
inchain[c])
3335 if (
classes[q].spawn == r) spawn_fed =
true;
3336 chain_cap *= fork_task_factor;
3337 if (open || quorum || spawn_fed) chain_cap = inf;
3338 for (std::size_t r :
inchain[c])
3339 for (std::size_t i = 0; i < M; ++i) {
3342 if (st.
nodetype != NodeType::Source) {
3343 const bool cap_finite = st.
cap >= 0.0 && !std::isinf(st.
cap);
3344 const bool classcap_finite = st.
classcap.size() >= r &&
3348 st.
droprule[r - 1] ==
static_cast<int>(DropStrategy::WAITQ) &&
3349 std::isinf(
classes[r - 1].population) &&
3350 (cap_finite || classcap_finite))
3352 "station '" + st.
name +
"' declares setDropRule(WAITQ) for the "
3353 "open class '" +
classes[r - 1].name +
"' at a finite capacity: "
3354 "LINE does not implement waiting-room blocking for an open "
3355 "arrival at a plain finite buffer. Use DropStrategy.DROP for a "
3356 "loss station, or BAS / BBS / RSRD for blocking between "
3360 }
else if (std::isinf(st.
cap)) {
3361 droprule[i][r - 1] = DropStrategy::WAITQ;
3362 }
else if (!std::isinf(
classes[r - 1].population)) {
3363 droprule[i][r - 1] = DropStrategy::WAITQ;
3365 droprule[i][r - 1] = DropStrategy::DROP;
3371 chaincap[i][c] = 0.0;
3374 chaincap[i][c] = chain_cap;
3381 for (std::size_t i = 0; i < M; ++i) {
3386 double sc = 0.0, scl = 0.0;
3387 for (std::size_t c = 0; c < chaincap[i].size(); ++c) sc += chaincap[i][c];
3388 for (std::size_t r = 0; r < K; ++r) scl +=
classcap[i][r];
3389 cap[i] = std::min(sc, scl);
3403 const std::size_t K =
classes.size(), I =
nodes.size();
3404 std::vector<std::size_t> all(K);
3405 for (std::size_t r = 0; r < K; ++r) all[r] = r + 1;
3409 for (std::size_t a = 0; a < I; ++a)
3410 for (std::size_t b = 0; b < I; ++b)
rtnodes(a * K + r - 1, b * K + s - 1) = M(a, b);
3427 const std::size_t K =
classes.size();
3428 std::size_t cidx = 0;
3430 const std::size_t ci = kv.first;
3432 for (std::size_t r = 0; r < cp.
hitclass.size() && r < K; ++r) {
3444 for (std::size_t c = 0; c <
nchains; ++c) {
3462 for (std::size_t i = 0; i <
nstations; ++i)
3463 for (std::size_t r = 0; r <
nclasses; ++r) {
3465 if (
stations[i].nodetype == NodeType::Join) {
3468 std::numeric_limits<double>::infinity());
3480 const std::size_t mk =
markidx_of(i + 1, r + 1);
3481 if (mk > 0 && mk <= d.
Dmark.size()) {
3486 scv(i, r) = ms.second;
3512 for (std::size_t a = 0; a < m.
D0.rows(); ++a)
3513 for (std::size_t b = 0; b < m.
D0.cols(); ++b)
3514 m.
D0(a, b) += T(d.
D1(a, b) - m.
D1(a, b));
3534 std::vector<std::vector<bool>> cs(K, std::vector<bool>(K,
false));
3535 for (std::size_t r = 0; r < K; ++r) cs[r][r] =
true;
3536 for (
const auto& kv : (
Peff.empty() ?
P :
Peff)) {
3538 for (std::size_t a = 0; a < kv.second.rows() && !any; ++a)
3539 for (std::size_t b = 0; b < kv.second.cols() && !any; ++b)
3540 if (kv.second(a, b) > zero) any =
true;
3541 if (any) cs[kv.first.first - 1][kv.first.second - 1] =
true;
3551 for (std::size_t r = 0; r < K && r < C.
rows(); ++r)
3552 for (std::size_t s = 0; s < K && s < C.
cols(); ++s)
3553 if (C(r, s) > zero) cs[r][s] =
true;
3561 for (std::size_t r = 0; r < cp.
hitclass.size() && r < K; ++r) {
3575 for (std::size_t r = 0; r < row.size() && r < K; ++r)
3576 if (row[r] != 0) cs[r][row[r] - 1] =
true;
3579 std::vector<std::size_t> comp(K, K);
3580 std::size_t ncomp = 0;
3581 for (std::size_t r = 0; r < K; ++r) {
3582 if (comp[r] != K)
continue;
3583 std::vector<std::size_t> stack{r};
3585 while (!stack.empty()) {
3586 const std::size_t v = stack.back();
3588 for (std::size_t w = 0; w < K; ++w)
3589 if (comp[w] == K && (cs[v][w] || cs[w][v])) {
3601 for (std::size_t r = 0; r < K; ++r) {
3602 chains[comp[r]][r] =
true;
3603 inchain[comp[r]].push_back(r + 1);
3608 for (std::size_t c = 0; c <
nchains; ++c)
3609 for (std::size_t k :
inchain[c])
3612 for (std::size_t c = 0; c <
nchains; ++c) {
3614 for (std::size_t k :
inchain[c])
3615 if (
classes[k - 1].refstat != rs)
3616 throw InputError(
"network '" +
name +
"': classes within a chain have different "
3617 "reference stations");
3626 for (std::size_t c = 0; c <
nchains; ++c) {
3661 for (
auto& kv :
P) {
3662 if (kv.second.rows() <
nodes.size())
continue;
3663 kv.second(
sinkNode - 1, src - 1) = zero;
3665 for (
auto& kv :
Peff) {
3666 if (kv.second.rows() <
nodes.size())
continue;
3667 kv.second(
sinkNode - 1, src - 1) = zero;
3669 for (std::size_t c = 0; c <
nchains; ++c) {
3671 for (std::size_t k :
inchain[c])
3672 if (std::isinf(
classes[k - 1].population)) open =
true;
3673 if (!open)
continue;
3675 for (std::size_t k :
inchain[c])
3679 for (std::size_t s :
inchain[c]) {
3686 if (!(p > zero))
continue;
3694 std::vector<std::size_t> v(
nodes.size());
3695 for (std::size_t i = 0; i <
nodes.size(); ++i) v[i] = i + 1;
3717 std::vector<std::size_t>
chain_seeds(std::size_t c,
const std::vector<std::size_t>& sel)
const {
3718 const std::vector<std::size_t>& ic =
inchain[c];
3719 const std::size_t refst =
classes[ic[0] - 1].refstat;
3721 std::vector<std::size_t> seeds;
3722 std::size_t refpos = sel.size();
3723 for (std::size_t a = 0; a < sel.size(); ++a)
3724 if (sel[a] == refnode) refpos = a;
3725 if (refpos == sel.size())
return seeds;
3726 for (std::size_t x = 0; x < ic.size(); ++x) {
3732 const bool dis = refst - 1 <
disabled.size() && ic[x] - 1 <
disabled[refst - 1].size() &&
3736 held = !dis && std::isfinite(rate) && rate > 0;
3738 if (held) seeds.push_back(refpos * ic.size() + x);
3749 const std::vector<std::size_t>& sel)
const {
3750 std::vector<std::pair<std::size_t, std::size_t>> edges;
3751 const std::size_t nIC = ic.size();
3753 const std::vector<std::vector<std::size_t>>& rc = kv.second.retrieval_classes;
3754 if (rc.empty())
continue;
3755 std::size_t pos = sel.size();
3756 for (std::size_t a = 0; a < sel.size(); ++a)
3757 if (sel[a] == kv.first) pos = a;
3758 if (pos == sel.size())
continue;
3759 for (std::size_t x = 0; x < nIC; ++x)
3760 for (
const std::vector<std::size_t>& row : rc) {
3761 if (ic[x] - 1 >= row.size() || row[ic[x] - 1] == 0)
continue;
3762 for (std::size_t y = 0; y < nIC; ++y)
3763 if (ic[y] == row[ic[x] - 1]) edges.emplace_back(pos * nIC + x, pos * nIC + y);
3773 const std::vector<std::pair<std::size_t, std::size_t>>& edges) {
3774 const std::size_t n =
P.rows();
3775 if (seeds.empty())
return std::vector<bool>(n,
true);
3776 std::vector<std::vector<std::size_t>> extra(n);
3777 for (
const std::pair<std::size_t, std::size_t>& e : edges)
3778 if (e.first < n && e.second < n) extra[e.first].push_back(e.second);
3779 std::vector<bool> reach(n,
false);
3780 std::vector<std::size_t> frontier;
3781 for (std::size_t sd : seeds)
3782 if (sd < n && !reach[sd]) {
3784 frontier.push_back(sd);
3786 while (!frontier.empty()) {
3787 std::vector<std::size_t> nxt;
3788 for (std::size_t row : frontier) {
3789 for (std::size_t col = 0; col < n; ++col) {
3791 if (!reach[col] && v != 0.0) {
3796 for (std::size_t col : extra[row])
3810 const std::vector<std::size_t>& ic =
inchain[c];
3811 const std::size_t nIC = ic.size();
3812 const std::size_t dim = sel.size() * nIC;
3819 std::vector<std::size_t> cpos(
nclasses + 1, nIC);
3820 for (std::size_t x = 0; x < nIC; ++x) cpos[ic[x]] = x;
3823 const std::size_t x = cpos[r], y = cpos[s];
3824 if (x == nIC || y == nIC)
return;
3825 for (std::size_t a = 0; a < sel.size(); ++a)
3826 for (std::size_t b = 0; b < sel.size(); ++b)
3827 Pc(a * nIC + x, b * nIC + y) = M(sel[a] - 1, sel[b] - 1);
3853 std::vector<bool> served(dim,
true);
3855 for (std::size_t a = 0; a < sel.size(); ++a) {
3856 const std::size_t sti =
nodes[sel[a] - 1].station;
3857 if (sti == 0 || sti >
stations.size())
continue;
3859 if (nt == NodeType::Place || nt == NodeType::Transition)
continue;
3860 if (!
stations[sti - 1].server_types.empty())
continue;
3861 if (sti >
disabled.size())
continue;
3868 for (std::size_t x = 0; x < nIC; ++x)
3870 served[a * nIC + x] =
false;
3872 for (std::size_t row = 0; row < dim; ++row)
3874 for (std::size_t col = 0; col < dim; ++col) Pc(row, col) = zero;
3875 for (std::size_t col = 0; col < dim; ++col)
3877 for (std::size_t row = 0; row < dim; ++row) Pc(row, col) = zero;
3883 std::vector<std::size_t> visited;
3884 std::vector<T> rowsum(dim, zero);
3885 for (std::size_t row = 0; row < dim; ++row) {
3887 for (std::size_t col = 0; col < dim; ++col) s += Pc(row, col);
3889 if (s > zero && reach[row]) visited.push_back(row);
3891 bool oversum =
false;
3893 for (std::size_t row = 0; row < dim; ++row) {
3897 for (std::size_t col = 0; col < dim; ++col)
3898 Pc(row, col) = T(Pc(row, col) / rowsum[row]);
3928 bool reducible =
false;
3929 if (!fork && !visited.empty()) {
3930 Matrix<T> Pv0(visited.size(), visited.size(), zero);
3931 for (std::size_t a = 0; a < visited.size(); ++a)
3932 for (std::size_t b = 0; b < visited.size(); ++b) Pv0(a, b) = Pc(visited[a], visited[b]);
3934 std::size_t nrec = 0;
3937 reducible = (nrec > 1) && mc::detail::weak_components(Pv0).size() == 1;
3946 std::vector<std::size_t> nconn(sel.size(), 0);
3947 std::vector<std::vector<bool>> conn(sel.size(), std::vector<bool>(sel.size(),
false));
3948 for (std::size_t a = 0; a < sel.size(); ++a)
3949 for (std::size_t b = 0; b < sel.size(); ++b) {
3951 for (std::size_t x = 0; x < nIC && !cbit; ++x)
3952 for (std::size_t y = 0; y < nIC && !cbit; ++y)
3953 if (Pc(a * nIC + x, b * nIC + y) > zero) cbit =
true;
3955 if (cbit) ++nconn[a];
3957 for (std::size_t a = 0; a < sel.size(); ++a) {
3958 if (nconn[a] == 0)
continue;
3959 for (std::size_t x = 0; x < nIC; ++x) {
3961 for (std::size_t col = 0; col < dim; ++col) outsum += Pc(a * nIC + x, col);
3962 if (outsum > zero)
continue;
3965 for (std::size_t b = 0; b < sel.size(); ++b)
3966 if (conn[a][b]) Pc(a * nIC + x, b * nIC + x) = p;
3978 for (std::size_t row = 0; row < dim; ++row)
3980 for (std::size_t col = 0; col < dim; ++col) Pc(row, col) = zero;
3981 for (std::size_t col = 0; col < dim; ++col)
3983 for (std::size_t row = 0; row < dim; ++row) Pc(row, col) = zero;
3985 for (std::size_t row = 0; row < dim; ++row) {
3987 for (std::size_t col = 0; col < dim; ++col) s += Pc(row, col);
3988 if (s > zero && reach[row]) visited.push_back(row);
3992 std::vector<T> alpha(dim, zero);
3993 if (!visited.empty()) {
3994 Matrix<T> Pv(visited.size(), visited.size(), zero);
3995 for (std::size_t a = 0; a < visited.size(); ++a)
3996 for (std::size_t b = 0; b < visited.size(); ++b)
3997 Pv(a, b) = Pc(visited[a], visited[b]);
4004 bool allzero =
true, hasnan =
false;
4005 for (
const T& x : av) {
4006 if (x != zero) allzero =
false;
4009 if (allzero || hasnan) ok =
false;
4010 }
catch (
const Error&) {
4018 for (std::size_t a = 0; a < visited.size(); ++a) alpha[visited[a]] = av[a];
4038 for (std::size_t a = 0; a < visited.size(); ++a)
4039 if (!scc.
recurrent[scc.
scc[a] - 1]) alpha[visited[a]] = zero;
4043 if (fork && oversum) {
4044 for (std::size_t idx = 0; idx < dim; ++idx) {
4046 const std::size_t nd = sel[idx / nIC];
4047 if (!complement &&
nodes[nd - 1].nodetype == NodeType::Join) {
4054 const std::size_t r = ic[idx % nIC];
4055 std::size_t nsrc = 0;
4056 for (std::size_t src = 1; src <=
nodes.size(); ++src)
4057 for (std::size_t q = 1; q <=
nclasses; ++q)
4069 for (std::size_t a = 0; a < sel.size(); ++a)
4070 for (std::size_t x = 0; x < nIC; ++x) out(a, ic[x] - 1) = alpha[a * nIC + x];
4073 const std::size_t rstat =
classes[ic[0] - 1].refstat;
4075 std::size_t refrow = sel.size();
4076 for (std::size_t a = 0; a < sel.size(); ++a)
4077 if (sel[a] == refnode) refrow = a;
4078 if (refrow < sel.size()) {
4080 for (std::size_t x = 0; x < nIC; ++x) norm += out(refrow, ic[x] - 1);
4082 for (std::size_t a = 0; a < sel.size(); ++a)
4083 for (std::size_t x = 0; x < nIC; ++x)
4084 out(a, ic[x] - 1) = T(out(a, ic[x] - 1) / norm);
4086 for (std::size_t a = 0; a < sel.size(); ++a)
4087 for (std::size_t x = 0; x < nIC; ++x)
4088 if (out(a, ic[x] - 1) < zero) out(a, ic[x] - 1) = T(-out(a, ic[x] - 1));
4102 const std::vector<std::size_t>& ic, std::size_t refnode)
const {
4104 const std::size_t nIC = ic.size();
4105 const std::size_t dim = Pc_in.
rows();
4108 for (std::size_t row = 0; row < dim; ++row) {
4110 std::size_t nnan = 0;
4111 for (std::size_t col = 0; col < dim; ++col) {
4114 else nonnan = T(nonnan + Pc(row, col));
4116 if (nnan == 0)
continue;
4119 for (std::size_t col = 0; col < dim; ++col) {
4121 if (v != v) Pc(row, col) = fill;
4125 for (std::size_t c = 0; c <
nchains; ++c)
4126 if (
inchain[c] == ic) chain = c;
4127 const std::vector<bool> reach =
4130 std::vector<std::size_t> visited;
4131 for (std::size_t row = 0; row < dim; ++row) {
4133 for (std::size_t col = 0; col < dim; ++col) s += Pc(row, col);
4134 if (s > zero && reach[row]) visited.push_back(row);
4136 std::vector<T> alpha(dim, zero);
4137 if (!visited.empty()) {
4138 Matrix<T> Pv(visited.size(), visited.size(), zero);
4139 for (std::size_t a = 0; a < visited.size(); ++a)
4140 for (std::size_t b = 0; b < visited.size(); ++b) Pv(a, b) = Pc(visited[a], visited[b]);
4146 bool allzero =
true, hasnan =
false;
4147 for (
const T& x : av) {
4148 if (x != zero) allzero =
false;
4151 if (allzero || hasnan) ok =
false;
4152 }
catch (
const Error&) {
4156 for (std::size_t a = 0; a < visited.size(); ++a) alpha[visited[a]] = av[a];
4159 for (std::size_t a = 0; a < sel.size(); ++a)
4160 for (std::size_t x = 0; x < nIC; ++x) out(a, ic[x] - 1) = alpha[a * nIC + x];
4161 std::size_t refrow = sel.size();
4162 for (std::size_t a = 0; a < sel.size(); ++a)
4163 if (sel[a] == refnode) refrow = a;
4164 if (refrow < sel.size()) {
4166 for (std::size_t x = 0; x < nIC; ++x) norm += out(refrow, ic[x] - 1);
4168 for (std::size_t a = 0; a < sel.size(); ++a)
4169 for (std::size_t x = 0; x < nIC; ++x)
4170 out(a, ic[x] - 1) = T(out(a, ic[x] - 1) / norm);
4172 for (std::size_t a = 0; a < sel.size(); ++a)
4173 for (std::size_t x = 0; x < nIC; ++x)
4174 if (out(a, ic[x] - 1) < zero) out(a, ic[x] - 1) = T(-out(a, ic[x] - 1));
4190 if (nd.nodetype == NodeType::Fork)
4192 "route_eff visit path");
4193 std::vector<std::size_t> keep;
4194 keep.reserve(M * K);
4195 for (std::size_t p = 0; p < M; ++p) {
4197 for (std::size_t r = 0; r < K; ++r) keep.push_back(base + r);
4201 std::vector<std::size_t> allnodes(I);
4202 for (std::size_t a = 0; a < I; ++a) allnodes[a] = a + 1;
4205 for (std::size_t c = 0; c <
nchains; ++c) {
4206 const std::vector<std::size_t>& ic =
inchain[c];
4207 const std::size_t nIC = ic.size();
4210 for (std::size_t a = 0; a < M; ++a)
4211 for (std::size_t x = 0; x < nIC; ++x)
4212 for (std::size_t b = 0; b < M; ++b)
4213 for (std::size_t y = 0; y < nIC; ++y)
4214 Ps(a * nIC + x, b * nIC + y) =
rt(a * K + (ic[x] - 1), b * K + (ic[y] - 1));
4215 const std::size_t rstat =
classes[ic[0] - 1].refstat;
4222 for (std::size_t a = 0; a < I; ++a)
4223 for (std::size_t x = 0; x < nIC; ++x)
4224 for (std::size_t b = 0; b < I; ++b)
4225 for (std::size_t y = 0; y < nIC; ++y)
4226 Pn(a * nIC + x, b * nIC + y) =
4227 rtnodes(a * K + (ic[x] - 1), b * K + (ic[y] - 1));
4241 const std::size_t nIC = ic.size();
4242 const std::size_t I =
nodes.size();
4244 std::vector<std::size_t> pos(
classes.size() + 1, 0);
4245 for (std::size_t x = 0; x < nIC; ++x) pos[ic[x]] = x + 1;
4247 if (r >= pos.size() || s >= pos.size() || pos[r] == 0 || pos[s] == 0)
return;
4248 const std::size_t x = pos[r] - 1, y = pos[s] - 1;
4249 for (std::size_t a = 0; a < I; ++a)
4250 for (std::size_t b = 0; b < I; ++b) full(a * nIC + x, b * nIC + y) = M(a, b);
4261 const std::map<std::pair<std::size_t, std::size_t>,
Matrix<T>>& src =
Peff.empty() ?
P :
Peff;
4262 for (
const auto& kv : src)
4263 if (kv.second.rows() >=
nodes.size() && kv.second.cols() >=
nodes.size())
4264 f(kv.first.first, kv.first.second, kv.second);
4283 const std::size_t I =
nodes.size();
4284 std::vector<std::size_t> keep, drop;
4285 for (std::size_t a = 0; a < I; ++a) {
4286 const bool st =
nodes[a].stateful;
4287 for (std::size_t x = 0; x < nIC; ++x) (st ? keep : drop).push_back(a * nIC + x);
4289 if (drop.empty())
return full;
4294 std::vector<char> isdrop(full.
rows(), 0), seen(full.
rows(), 0);
4295 for (std::size_t d : drop) isdrop[d] = 1;
4296 std::vector<std::size_t> stack;
4297 for (std::size_t k : keep)
4298 for (std::size_t d : drop)
4299 if (!seen[d] && full(k, d) != zero) { seen[d] = 1; stack.push_back(d); }
4300 while (!stack.empty()) {
4301 const std::size_t u = stack.back();
4303 for (std::size_t d : drop)
4304 if (!seen[d] && full(u, d) != zero) { seen[d] = 1; stack.push_back(d); }
4306 std::vector<std::size_t> reach;
4307 for (std::size_t d : drop)
4308 if (seen[d]) reach.push_back(d);
4312 Matrix<T> S(keep.size(), keep.size(), zero);
4313 for (std::size_t a = 0; a < keep.size(); ++a)
4314 for (std::size_t b = 0; b < keep.size(); ++b) S(a, b) = full(keep[a], keep[b]);
4318 const std::size_t nk = keep.size(), nd = drop.size();
4319 Matrix<T> P11(nk, nk, zero), P12(nk, nd, zero), P21(nd, nk, zero), A(nd, nd, zero);
4320 for (std::size_t a = 0; a < nk; ++a) {
4321 for (std::size_t b = 0; b < nk; ++b) P11(a, b) = full(keep[a], keep[b]);
4322 for (std::size_t b = 0; b < nd; ++b) P12(a, b) = full(keep[a], drop[b]);
4324 for (std::size_t a = 0; a < nd; ++a) {
4325 for (std::size_t b = 0; b < nk; ++b) P21(a, b) = full(drop[a], keep[b]);
4326 for (std::size_t b = 0; b < nd; ++b)
4327 A(a, b) = T((a == b ? one : zero) - full(drop[a], drop[b]));
4331 std::vector<std::size_t> piv(nd);
4332 for (std::size_t i = 0; i < nd; ++i) piv[i] = i;
4333 for (std::size_t col = 0; col < nd; ++col) {
4334 std::size_t best = col;
4336 for (std::size_t r2 = col + 1; r2 < nd; ++r2) {
4338 if (v > bv) { bv = v; best = r2; }
4341 for (std::size_t b = 0; b < nd; ++b) std::swap(A(col, b), A(best, b));
4342 for (std::size_t b = 0; b < nk; ++b) std::swap(X(col, b), X(best, b));
4344 if (A(col, col) == zero)
4347 std::vector<std::size_t> nzA, nzX;
4348 for (std::size_t b = 0; b < nd; ++b)
4349 if (A(col, b) != zero) nzA.push_back(b);
4350 for (std::size_t b = 0; b < nk; ++b)
4351 if (X(col, b) != zero) nzX.push_back(b);
4352 for (std::size_t r2 = 0; r2 < nd; ++r2) {
4353 if (r2 == col)
continue;
4354 const T f = T(A(r2, col) / A(col, col));
4355 if (f == zero)
continue;
4356 for (std::size_t b : nzA) A(r2, b) = T(A(r2, b) - f * A(col, b));
4357 for (std::size_t b : nzX) X(r2, b) = T(X(r2, b) - f * X(col, b));
4360 for (std::size_t r2 = 0; r2 < nd; ++r2)
4361 for (std::size_t b = 0; b < nk; ++b) X(r2, b) = T(X(r2, b) / A(r2, r2));
4365 std::vector<T> acc(nk, zero);
4366 for (std::size_t a = 0; a < nk; ++a) {
4367 std::fill(acc.begin(), acc.end(), zero);
4368 for (std::size_t m = 0; m < nd; ++m) {
4369 const T w = P12(a, m);
4370 if (w == zero)
continue;
4371 for (std::size_t b = 0; b < nk; ++b) acc[b] += w * X(m, b);
4373 for (std::size_t b = 0; b < nk; ++b) S(a, b) = T(S(a, b) + acc[b]);
4382 if (std::isinf(c.population))
return true;
4394 if (!std::isinf(c.population))
return false;
4400 if (std::isfinite(s.nservers) && s.nservers > 1.0)
return true;
4406 if (std::isfinite(c.population) && c.population != std::floor(c.population + 0.5))
4415 if (c.prio > 0)
return true;
4428 if (
classes.empty())
return false;
4430 if (c.prio !=
classes.front().prio)
return true;
4446 case SchedStrategy::HOL:
4447 case SchedStrategy::PSPRIO:
4448 case SchedStrategy::DPSPRIO:
4449 case SchedStrategy::GPSPRIO:
4450 case SchedStrategy::LCFSPRIO:
4451 case SchedStrategy::LCFSPRPRIO:
4452 case SchedStrategy::LCFSPIPRIO:
4453 case SchedStrategy::FCFSPRPRIO:
4454 case SchedStrategy::FCFSPIPRIO:
4455 case SchedStrategy::SRPTPRIO:
4478 std::size_t count = 0;
4480 if (
stations[i].sched == strategy) ++count;
4486 for (std::size_t i = 0; i <
nstations; ++i) {
4487 if (
stations[i].sched != SchedStrategy::FCFS)
continue;
4490 for (std::size_t r = 0; r <
nclasses; ++r) {
4493 lo = hi =
rates(i, r);
4510 if (!(s.sched == SchedStrategy::INF || s.sched == SchedStrategy::PS ||
4511 s.sched == SchedStrategy::FCFS || s.sched == SchedStrategy::LCFSPR ||
4512 s.sched == SchedStrategy::LCFS || s.sched == SchedStrategy::EXT))
4524 for (std::size_t i = 0; i <
nstations; ++i) {
4525 if (
stations[i].sched != SchedStrategy::FCFS)
continue;
4526 for (std::size_t r = 0; r <
nclasses; ++r) {
4528 if (std::isinf(v) || !(v > 0.0))
continue;
4542 double k = std::numeric_limits<double>::infinity();
4543 if (
cap[ist - 1] >= 0.0) k = std::min(k,
cap[ist - 1]);
4545 bool anyServed =
false;
4546 for (std::size_t r = 0; r <
nclasses; ++r)
4551 if (anyServed) k = std::min(k, ccap);
4555 double reachable = 0.0;
4556 for (std::size_t r = 0; r <
nclasses; ++r)
4558 return (k >= reachable) ? std::numeric_limits<double>::infinity() : k;
4564 for (std::size_t k = 0; k <
classes.size(); ++k)
4565 if (std::isfinite(
classes[k].population))
return false;
4566 std::size_t nq = 0, nsrc = 0, nsink = 0, qnode = 0, snode = 0;
4567 for (std::size_t a = 0; a <
nodes.size(); ++a) {
4568 switch (
nodes[a].nodetype) {
4569 case NodeType::Queue: ++nq; qnode = a + 1;
break;
4570 case NodeType::Source: ++nsrc; snode = a + 1;
break;
4571 case NodeType::Sink: ++nsink;
break;
4572 default:
return false;
4575 if (nq != 1 || nsrc != 1 || nsink != 1)
return false;
4576 const std::size_t qist =
nodes[qnode - 1].station;
4577 const std::size_t sist =
nodes[snode - 1].station;
4578 if (qist == 0 || sist == 0)
return false;
4579 if (
stations[qist - 1].nservers != 1.0)
return false;
4581 droprule[qist - 1][0] != DropStrategy::DROP)
4583 if (!(qist <=
cap.size()) || !std::isfinite(
cap[qist - 1]) || !(
cap[qist - 1] > 0.0))
4605 if (!
regions.empty())
return true;
4606 for (std::size_t a = 0; a <
nodes.size(); ++a)
4607 if (
nodes[a].nodetype == NodeType::Cache)
return false;
4609 for (std::size_t ist = 1; ist <=
stations.size(); ++ist)
4618 if (rs == RoutingStrategy::RROBIN || rs == RoutingStrategy::WRROBIN ||
4619 rs == RoutingStrategy::JSQ || rs == RoutingStrategy::SQ || rs == RoutingStrategy::SDR)
4655 if (!(s.sched == SchedStrategy::INF || s.sched == SchedStrategy::PS ||
4656 s.sched == SchedStrategy::FCFS || s.sched == SchedStrategy::LCFSPR ||
4657 s.sched == SchedStrategy::EXT))
4660 for (std::size_t i = 0; i <
nstations; ++i) {
4661 if (
stations[i].sched != SchedStrategy::FCFS)
continue;
4662 for (std::size_t r = 0; r <
nclasses; ++r) {
4665 if (!std::isinf(v) && v > 0.0 &&
4669 if (!check_means ||
visits.empty())
continue;
4671 double stmin = 0.0, stmax = 0.0;
4672 bool anyserved =
false;
4673 for (std::size_t c = 0; c <
nchains && c <
visits.size(); ++c) {
4674 double num = 0.0, den = 0.0;
4675 for (std::size_t r = 0; r <
nclasses; ++r) {
4686 const double st = num / den;
4691 stmin = std::min(stmin, st);
4692 stmax = std::max(stmax, st);
4708 for (std::size_t a = 0; a < B.
rows(); ++a)
4709 for (std::size_t b = 0; b < B.
cols(); ++b) g(a, b) = B(a, b);
4717 if (std::isfinite(c.population)) s += c.population;
4740 const std::size_t R =
sn.nclasses;
4744 if (st.
sched != SchedStrategy::PAS)
return Matrix<T>(R, R, zero);
4746 for (std::size_t r = 0; r < R; ++r) g(r, r) = zero;
4755 for (std::size_t a = 0; a < g.
rows(); ++a)
4756 for (std::size_t b = 0; b < g.
cols(); ++b)
4757 if (g(a, b) != zero)
return false;
Base error for the multiprecision C++ port.
NumericError(const std::string &what)
UnsupportedError(const std::string &what)
A network plus its refreshed NetworkStruct.
void set_route(std::size_t r, std::size_t s, std::size_t i, std::size_t j, const T &p)
P{r,s}(i,j) = p, with 1-based NODE and class indices.
std::size_t sourceIdx
1-based station index of the Source, 0 = none
Matrix< double > phases() const
sn.phases (M x K), as refreshProcessRepresentations.m leaves it: 0 for a disabled pair,...
bool has_multi_class_heter_fcfs() const
bool has_distinct_priorities() const
Whether the classes carry more than one priority level.
std::size_t nvars_of(std::size_t ind) const
Total local-variable width of node ind (1-based).
pfqn::SdrStruct sdr_nodes
Node-indexed twin of sdr.
std::size_t add_class(const JobClass &cl)
Add a class and grow the service table.
T get_route(std::size_t r, std::size_t s, std::size_t i, std::size_t j) const
P{r,s}(i,j), AS THE USER SET IT.
std::vector< Matrix< T > > nodevisits
(nchains) each (nnodes x nclasses)
void refresh_rates()
Port of MNetwork.refreshRates: lower each service process onto a rate and an SCV.
std::vector< double > node_to_stateful() const
sn.nodeToStateful (1 x N): the stateful index of each node, NaN when it is not stateful.
bool has_fluid_places() const
sn_has_fluid_places: does the net hold a fluid place, or a transition declaring a fluid arc?
std::function< std::complex< double >(const std::complex< double > &)> LstHandle
One LST handle: E[exp(-sX)] at a complex argument.
std::vector< std::size_t > chain_seeds(std::size_t c, const std::vector< std::size_t > &sel) const
Port of the per-chain body of sn_refresh_visits, over an arbitrary node subset – the stateful nodes f...
Matrix< T > chain_visits(std::size_t c, const std::vector< std::size_t > &sel, bool complement, bool fork) const
std::size_t stateful_index(std::size_t ind) const
1-based stateful index of node ind, 0 when the node is not stateful.
void refresh_cacheqn_actual_visits(const Matrix< T > &hitprob, const Matrix< T > &missprob)
Re-resolve the cache read self-switch from the offered 1/2-1/2 to the ACTUAL hit/miss probabilities t...
std::vector< std::vector< std::vector< double > > > pie() const
sn.pie (M x K cells): the phase an arriving job enters, map_pie of sn.proc{i}{r} (the Erlang conversi...
bool has_immediate_feedback() const
Whether immediate feedback is EFFECTIVE anywhere in the model.
bool has_class_switching() const
std::vector< lang::RemovalPolicy > signalrempolicy
bool has_rtfun_routing() const
True when some routing must be re-read at every state from rt_state: SDR, and the JSQ and SQ(d) dispa...
std::vector< std::vector< bool > > immfeed
sn.immfeed: (nstations x nclasses) IMMEDIATE FEEDBACK, the reference's refreshStruct field.
const ForkParam< T > * fork_param_of(std::size_t node) const
The fork's override block, or null when it declares none.
std::size_t stateful_of_station(std::size_t st) const
std::vector< std::size_t > downstream_stations(std::size_t ind) const
The nodes directly downstream of ind, walking THROUGH stateless nodes and stopping at the first stati...
std::size_t nof_nodes() const
std::size_t nof_stateful() const
bool has_rr_routing() const
Whether ANY (node, class) pair dispatches round-robin.
Matrix< double > phaseshift() const
sn.phaseshift (M x K+1) = [0, cumsum(phasessz, 2)].
std::map< std::pair< std::size_t, std::size_t >, Matrix< T > > P
P[(r,s)] is an (nnodes x nnodes) block; absent means all zero.
std::size_t phases_of(std::size_t ist, std::size_t r) const
sn.phases(i,r): the order of the process representation.
std::map< std::size_t, TransitionParam< T > > transparam
Transition (SPN) parameters, keyed by 1-based node index.
void check_closed_reneging() const
Refuses RENEGING declared for a class of finite population at any station (closed_reneging_refusal).
std::size_t mark_carrier_of(std::size_t ist) const
The CARRIER of station i's marked arrival: the class of mark 1, whose phase block holds the one modul...
std::vector< std::vector< bool > > replyblock
sn.replyblock (nnodes x nclasses) and sn.syncreply (nclasses).
std::vector< std::size_t > all_nodes() const
Every node index, 1-based, for the node-level visit computation.
std::vector< std::vector< bool > > isbasdestination
sn.isbasdestination, (nstations x nclasses): true where a refusal at this station must BLOCK an upstr...
bool is_mm1k_loss() const
Implementation of api::sn_is_mm1k_loss; that free function delegates here.
void for_each_route_block(F f) const
Visit every (r, s) block of the routing in force, the one route_eff reads: Peff when the expansion ra...
bool has_sdr_routing() const
MATLAB's any(sn.isstatedep(:,3)) NARROWED TO THE ONE STRATEGY THIS PORT EVALUATES PER STATE: Krzesins...
std::vector< Reward > reward
std::vector< std::size_t > stateful_nodes
1-based node indices, ascending
Matrix< double > phasessz() const
sn.phasessz (M x K) = max(phases, 1), with MATLAB's two exceptions: a Join keeps its 0 and a non-carr...
bool sched_has_priority_aware() const
Whether some station runs a discipline that READS the class priorities.
std::vector< bool > iscatastrophe() const
sn.iscatastrophe (K x 1): true where class r is a catastrophe signal.
bool holds_reply_for(std::size_t ind, std::size_t r) const
True when node ind (1-based) holds a server across a synchronous call whose reply class is r (1-based...
void refresh_replyblock()
sn.replyblock, DERIVED from sn.syncreply and the routing.
std::vector< std::vector< Distrib< T > > > service
service[i][r], 0-based station and class; a disabled entry marks a pair never visited.
void refresh_chains()
Port of MNetwork.refreshChains followed by sn_refresh_visits.
std::vector< std::vector< bool > > csmask
(nclasses x nclasses) class r can switch into s, diagonal set
void refresh_capacity()
Port of MNetwork.refreshCapacity.
std::vector< std::vector< bool > > chains
(nchains x nclasses)
void apply_sink_closure()
Route every open chain from the Sink back into the Source, as the tail of MATLAB's getRoutingMatrix d...
std::vector< std::size_t > refclass
(nchains) 1-based class, 0 = none
int gdscalingcutoff
sn.gdscalingcutoff: the per-slot OPEN-class truncation used when gdscaling is materialized onto the J...
std::map< std::size_t, SetupDelayOffParam< T > > setupparam
Setup / delay-off, keyed by 1-based STATION index.
std::map< std::size_t, BreakdownParam< T > > breakdownparam
Server breakdown / repair, keyed by 1-based STATION index.
bool has_exponential_fcfs() const
BCMP type 1 asks the FCFS service to be exponential.
void check_service_reachable() const
bool has_breakdown() const
Any station at all, the guard every solver gate needs first.
GdScaling< T > gdscaling
sn.gdscaling: the network-level globally state-dependent (Whittle) rate scaling phi(n).
std::vector< bool > fjauxclass
sn.fjauxclass: (nclasses+1, 1-based) true where the class is an MMT AUXILIARY OPEN class,...
std::vector< std::vector< std::size_t > > nvars
sn.nvars, (nnodes x 3R+1): the LOCAL VARIABLE columns each node appends to its state,...
bool has_service_law(std::size_t i, std::size_t r) const
Does (station i, class r) have a service law an analyzer may convert?
std::vector< std::vector< bool > > disabled
Matrix< T > visits_from_block(const Matrix< T > &Pc_in, const std::vector< std::size_t > &sel, const std::vector< std::size_t > &ic, std::size_t refnode) const
The visit ratios of one chain from an already-formed chain routing block Pc (dim = sel....
pfqn::SdrStruct sdr
Krzesinski (1987) product-form state-dependent routing, in 0-based STATION indices; empty unless a no...
std::vector< std::vector< bool > > reached_node_classes() const
The (node, class) pairs a job can actually ARRIVE at, 0-based on both axes.
void refresh_sched_param()
Port of MNetwork.refreshScheduling's schedparam half.
std::map< std::size_t, FjJoinParam > fjjoinparam
sn.nodeparam{j}.fj for each Join node: the tag matrix and the required sibling multiplicity after_eve...
std::vector< std::vector< LstHandle > > lst() const
sn.lst (M x K handles), refreshLST.m: the Laplace-Stieltjes transform of each law,...
bool serves_class(std::size_t ind, std::size_t r) const
Whether a job of class r (0-based) can LEAVE node ind (1-based) again.
double total_jobs() const
Total population, as MATLAB's getNumberOfJobs summed.
Matrix< T > rt
sn.rt and sn.rtnodes: the class-expanded routing.
void fill_signal_services()
Refuses a class that is ROUTED TO a station which cannot serve it.
const CtmcMapc< T > * mapc_of(std::size_t ist, std::size_t r) const
The pair form of class r (1-based) at station ist (1-based), or null when there is none.
std::map< std::size_t, RetrialParam< T > > retrialparam
Retrial parameters, keyed by 1-based STATION index.
void promote_stateful(std::size_t ind)
Make node ind stateful, keeping stateful_nodes ascending.
std::vector< bool > issignal
The G-network signal declaration, per CLASS.
void grow_routing()
Grow every routing block to the current node count.
std::map< std::size_t, CacheParam< T > > nodeparam
Cache parameters by 1-based NODE index; only Cache nodes have an entry.
Matrix< double > procid() const
sn.procid (M x K): the ProcessType id of each (station, class) pair, as refreshProcessTypes....
void grow_block(Matrix< T > &B) const
std::size_t map_var_slot(std::size_t ind, std::size_t r) const
0-based column of class r's MAP memory inside node ind's local-variable block.
bool has_priorities() const
std::size_t add_node(const std::string &nm, NodeType ty, bool stateful)
Add a non-station node (a Fork, a Router).
std::map< std::size_t, PasParam > pasparam
std::vector< double > cap
sn.cap and sn.classcap: the total and per-class buffers.
std::map< std::pair< std::size_t, std::size_t >, CtmcMapc< T > > ctmcmapc
MAP services in CTMC pair form, keyed by (1-based station, 1-based class).
std::vector< JobClass > classes
void rr_advance(std::size_t ind, std::size_t r, std::vector< T > &varrow) const
Advance the pointer of (ind, r) in VARROW by one position, cyclically.
std::vector< bool > isbasblocking
sn.isbasblocking, per NODE: true where the node is the BLOCKING (upstream) side of a true-BAS relatio...
bool has_product_form_not_het_fcfs(bool check_means=true) const
Port of sn_has_product_form_not_het_fcfs: LCFS is excluded, and at FCFS the service must be exponenti...
std::size_t sinkNode
1-based NODE index of the Sink, 0 = none (it is not a station)
std::size_t nregions() const
sn.nregions: the number of finite capacity regions.
Matrix< double > isph() const
sn.isph (M x K): true where sn.proc{i}{r} with sn.pie{i}{r} admits a phase-type reading (sn_is_phaset...
std::vector< std::vector< std::vector< double > > > mu() const
sn.mu (M x K cells): the total outgoing rate of each phase, MATLAB's getServiceRates/getSourceRates.
Matrix< double > connmatrix() const
sn.connmatrix (N x N): 1 where some class routes node i to node j with positive probability.
std::map< std::size_t, JoinDecl > joindecl
std::vector< std::size_t > signaltarget
std::vector< std::vector< std::vector< double > > > phi() const
sn.phi (M x K cells): the completion probability of each phase; 1 where mu is a single rate.
void refresh_local_vars()
Port of MNetwork.refreshLocalVars: the per-node local-variable widths.
ProcessType procid(std::size_t ist, std::size_t r) const
sn.procid(i,r): the process type of a (station, class) pair.
std::size_t rr_dest(std::size_t ind, std::size_t r, const std::vector< T > &varrow) const
The destination node the pointer in VARROW names, or 0 when (ind, r) does not dispatch round-robin or...
PollingParam effective_polling(std::size_t ist) const
The polling controller of station ist, from whichever API declared it.
std::vector< T > gdscalingpeak
sn.gdscalingpeak: the declared (nstations x nclasses) peak of gdscaling, row-major,...
std::size_t rr_var_slot(std::size_t ind, std::size_t r) const
1-BASED index of the pointer of (ind, r) INSIDE the node's local-variable block, or 0 when that pair ...
void refresh_bas_blocking()
Port of refreshLocalVars' true-BAS block and its declaresBlockedMarker helper: which nodes carry the ...
std::vector< Station< T > > stations
stations[k-1] is the k-th station
std::vector< std::size_t > rr_outlinks(std::size_t ind, std::size_t r) const
ROUND-ROBIN DISPATCH, the state that makes it deterministic.
Matrix< T > rates
(nstations x nclasses) service rates and SCVs, with a PARALLEL disabled flag instead of MATLAB's NaN ...
void refresh_struct()
The whole chain, in MATLAB's refreshStruct order.
T route_eff(std::size_t r, std::size_t s, std::size_t i, std::size_t j) const
The routing actually in force: the expansion when there is one, else P.
bool is_queueing_place(std::size_t i) const
Is station i (0-based) a QUEUEING PLACE, i.e.
void set_service(std::size_t station, std::size_t cls, const Distrib< T > &d)
std::vector< std::size_t > syncreply
std::map< std::pair< std::size_t, std::size_t >, Matrix< T > > Peff
The routing after refresh_routing() has expanded the non-PROB strategies and folded the class switche...
std::vector< std::vector< std::size_t > > inchain
1-based class indices per chain
Matrix< double > isstatedep() const
sn.isstatedep (N x 3): column 1 the input section (never set by the reference), column 2 state-depend...
std::size_t node_of_station(std::size_t st) const
1-based node index of station st, 0 when the map has no entry.
bool has_multi_server() const
void da_recompute_visits_from_rtnodes()
Recompute rt, visits and nodevisits after the caller has rewritten rtnodes in place – the cacheqn dri...
std::vector< NodeDef > nodes
every node, in creation order
std::vector< std::vector< double > > classcap
bool has_sd_routing() const
sn_has_sd_routing: RROBIN, WRROBIN, JSQ, SQ or SDR at some node.
std::vector< std::size_t > rr_weighted_outlinks(std::size_t ind, std::size_t r) const
The WRROBIN cycle: each outlink repeated by its weight, weight 0 once.
std::map< std::size_t, Matrix< T > > csmatrix
The class-switch matrix of a ClassSwitch node, by 1-based NODE index.
std::vector< double > njobs() const
sn.njobs: the population of each class, infinite for an open one.
std::vector< std::pair< std::size_t, std::size_t > > chain_retrieval_edges(const std::vector< std::size_t > &ic, const std::vector< std::size_t > &sel) const
sn_refresh_visits.m retrievalEdges: extra [from, to] chain-block positions for a retrieval cache,...
bool has_breakdown_node(std::size_t ind) const
sn.hasbreakdown(ind): does the NODE's server break down?
std::vector< double > hasbreakdown() const
sn.hasbreakdown (N x 1): 1 where the node's server is subject to breakdowns.
void refresh_router_stateful()
A Router that DISPATCHES (round-robin, JSQ or SQ(d)) holds state, so it must survive the stochastic c...
bool is_open_model() const
sn_is_open_model: EVERY class is open, which is not has_open_classes.
bool has_open_classes() const
bool sched_is_product_form() const
std::vector< std::vector< DropStrategy > > droprule
std::string log_path
Network.setLogPath / getLogPath: the directory every Logger writes into, and the logPath attribute of...
bool has_blocking() const
Some station can REFUSE a job: its own buffer BINDS, or a finite capacity region caps a set of statio...
void refresh_rt()
sn.rt and sn.rtnodes: the class-expanded routing matrices.
bool priorities_ignored() const
Priorities were declared and no station will read them.
std::vector< Matrix< T > > visits
(nchains) each (nstateful x nclasses)
double buffer_size(std::size_t ist) const
Kendall's K of station IST (1-based), +inf when unbounded.
std::map< std::size_t, std::vector< T > > initmarking
The DECLARED initial state of a stateful node, by 1-based node index.
std::pair< T, T > mark_marginal_moments(const Distrib< T > &d, std::size_t mk) const
Mean and SCV of ONE MARK'S MARGINAL MAP, MarkedMAP.toMAPs(k).
std::vector< double > station_to_stateful() const
sn.stationToStateful (1 x M): the stateful index of each station.
std::map< std::size_t, std::vector< T > > stateprior
bool has_homogeneous_scheduling(SchedStrategy strategy) const
Port of sn_has_homogeneous_scheduling: true when EVERY station uses strategy, the reference's length(...
std::map< std::size_t, CtmcPool< T > > ctmcpool
Heterogeneous server pools rewritten for the CTMC, by 1-based NODE index.
double nclosedjobs() const
sn.nclosedjobs: the total population of the closed classes.
std::vector< std::pair< std::size_t, std::size_t > > fj
fj(f,j): the Join node j that closes the Fork node f, 1-based.
std::size_t nof_stations() const
void set_route_effective(std::size_t r, std::size_t s, std::size_t i, std::size_t j, const T &p)
Write into the routing the consumers actually read.
std::size_t join_siblings(std::size_t joinNode, std::size_t r=0) const
The number of siblings the fork-join pair ending at Join node joinNode (1-based) emits per parent job...
std::vector< double > stateful_to_station() const
sn.statefulToStation (1 x S): the station index of each stateful node, NaN when it is not a station.
std::size_t phasessz_of(std::size_t ist, std::size_t r) const
sn.phasessz(i,r) = max(sn.phases(i,r),1): THE WIDTH of class r's phase block in a state row,...
bool has_product_form() const
sn_has_product_form, conjunct for conjunct.
std::vector< lang::SignalType > signaltype
std::vector< std::size_t > fjclassmap
sn.fjclassmap: the ORIGINAL class of each auxiliary sibling class, 0 for an original class.
std::map< std::size_t, PollingParam > pollingparam
bool is_fluid_node(std::size_t ind) const
Is 1-based node ind a FLUID place (Place.setFluid, MATLAB sn.fluid(ind))?
std::vector< std::size_t > quorum_joins() const
The 1-based Join nodes that fire on a STRICT quorum, i.e.
bool has_fractional_populations() const
std::map< std::size_t, Matrix< T > > statespace
std::size_t markidx_of(std::size_t ist, std::size_t r) const
sn.markidx(i,r): the 1-based MARK that class r carries in station i's marked arrival process,...
Matrix< T > stoch_comp_stateful(const Matrix< T > &full, std::size_t nIC) const
The stochastic complement of a NODE-level routing block over the stateful nodes, S = P11 + P12 (I - P...
std::size_t add_station(const Station< T > &st)
Add a station, which is also a node, and grow the service table.
std::vector< std::vector< T > > signalremdist
Matrix< T > station_routing(const std::vector< std::size_t > &ic) const
The chain-restricted routing over the STATEFUL nodes: the node-level routing with the non-stateful no...
bool isfjaugmented
sn.isfjaugmented: this struct came out of fj_tag, so its Fork nodes are STATEFUL and its Join nodes c...
std::vector< std::size_t > station_to_node
(nstations) 1-based node index
static std::vector< bool > chain_reachable(const Matrix< T > &P, const std::vector< std::size_t > &seeds, const std::vector< std::pair< std::size_t, std::size_t > > &edges)
sn_refresh_visits.m chainReachable: states reachable from the seeds along nonzero entries and the ext...
void refresh_routing()
Port of the part of MNetwork.refreshRoutingMatrix this port reaches: the expansion of a routing STRAT...
std::vector< Region > regions
std::size_t nof_classes() const
void refresh_immfeed()
Port of the sn.immfeed block of @@MNetwork/refreshStruct.m.
std::map< std::size_t, ForkParam< T > > forkparam
Variable forking levels, by 1-based Fork node; absent on a plain fork.
static std::string plural(long n, const std::string &singular, const std::string &plural_form)
Count with an agreeing noun, e.g.
static void compiling(const std::string &name)
Announce the compilation of a model structure.
static void compile_detail(const char *fmt,...)
One stage line of a structure compile: silenced inside a Quiet scope, and inside an open run,...
What refreshProcessRepresentations and refreshLST compute FROM a distribution: the (D0,...
Equilibrium distribution of a discrete-time Markov chain, and stochastic complementation.
Limiting distribution of a discrete-time Markov chain whose transition matrix may be reducible.
Stochastic complement of a DTMC partition, a port of matlab/lib/kpctoolbox/mc/dtmc_stochcomp....
The exception types the port throws.
Enumerations and the minimal distribution descriptor shared by the model layer of the C++ port.
int dispatch(const Options &in, bool allow_server, bool no_args)
Everything main did, with the arguments already in hand.
Running progress log of a LINE solver run (the "solver console").
Markovian arrival process descriptors: stationary vectors, rate, moments, autocorrelation and the ind...
Dense matrix and non-owning view.
bool sn_is_phasetype(const std::vector< Matrix< T > > &maps, const std::vector< T > &pie)
Whether a (D0, D1, ...) list is a valid phase-type / MAP representation.
mam::Map< T > dist_to_map(const Distrib< T > &d)
The (D0,D1) pair that reaches sn.proc.
SchedStrategy
Scheduling disciplines, with the values of MATLAB SchedStrategy.
DropStrategy
Blocking and loss rules, with the values of MATLAB DropStrategy.
BalkingStrategy
Balking rules, with the values of MATLAB BalkingStrategy.
@ CATASTROPHE
removes EVERY job at the station
JoinStrategy
Join rules, with the values of MATLAB JoinStrategy.
RoutingStrategy
Routing strategies, with the values of MATLAB RoutingStrategy.
T dist_lst(const Distrib< T > &d, const T &s)
sn.lst: the Laplace-Stieltjes transform E[exp(-sX)].
HeteroSchedPolicy
How a heterogeneous station picks among its server types, MATLAB HeteroSchedPolicy.
PollingType
Polling service disciplines, with the values of MATLAB PollingType.
@ KLIMITED
serve at most K per visit (K in pollingPar)
@ EXHAUSTIVE
serve until the queue empties
JobClassType
Job class kinds, with the values of MATLAB JobClassType.
ProcessType
Distribution kinds, with the values of MATLAB ProcessType.
std::function< std::vector< T >(const std::vector< T > &)> GdScaling
A globally state-dependent scaling, sn.gdscaling.
std::function< std::vector< T >(const std::vector< T > &)> CdScaling
A class-dependent scaling map, sn.cdscaling.
const char * routing_to_text(RoutingStrategy r)
NodeType
Node kinds, with the values of MATLAB NodeType.
ReplacementStrategy
Cache replacement policies, with the values of MATLAB ReplacementStrategy.
T map_mean(const Map< T > &m)
Mean inter-arrival time, 1/lambda.
std::vector< T > map_pie(const Map< T > &m)
Phase distribution seen by an arriving job, pie = pi D1 / (pi D1 e).
T map_scv(const Map< T > &m)
Squared coefficient of variation.
ReducibleResult< T > dtmc_solve_reducible(const Matrix< T > &P, const std::vector< T > &pin, double zeroColTol=1e-12)
Limiting distribution of a discrete-time Markov chain whose transition matrix may be reducible.
Matrix< T > dtmc_stochcomp(const Matrix< T > &P, const std::vector< std::size_t > &keep)
Stochastic complement of a DTMC partition, a port of matlab/lib/kpctoolbox/mc/dtmc_stochcomp....
SccResult stronglyconncomp(const Matrix< T > &A)
Strongly connected components of a directed graph, and which of them are recurrent (closed under the ...
std::vector< T > dtmc_solve(const Matrix< T > &P)
Stationary distribution of a stochastic matrix P.
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,...
Matrix< T > station_swap_graph(const NetworkStruct< T > &sn, std::size_t ist)
The swap graph of a PAS / OI station, with the defaults refreshLocalVars.m installs applied.
bool station_swap_graph_is_zero(const NetworkStruct< T > &sn, std::size_t ist)
True when the station's materialized swap graph is entirely zero.
const char * routing_to_text(RoutingStrategy r)
void closed_reneging_refusal(const std::string &classname, const std::string &where)
Refuses RENEGING on a class of finite population (LINE:input:Model; MATLAB closedRenegingRefusal....
Conservation laws of a layered queueing network, enumerated from its structure.
Number-type abstraction for the templated API port.
Product-form state-dependent routing.
Whether a (D0, D1, ...) list is a valid phase-type / MAP representation.
Strongly connected components of a directed graph, and which of them are recurrent (closed under the ...
The <kind> part of a LINE:<category>:<kind> identifier (see _kb/17-error-vocabulary....
The DECLARED join rule of a Join node, by 1-based node index.
The pass-and-swap / order-independent parameters of a PAS station, keyed by station index (Dorsman an...
The polling controller of a POLLING station, keyed by station index.
FINITE CAPACITY REGIONS, MATLAB's refreshRegions output.
sn.reward: the user-declared reward functions, MATLAB's model.setReward(name, fn).
std::vector< T > mu_vec() const
Phase rates, MATLAB's getMu: the total outgoing rate of each phase.
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.
T rate() const
The rate MATLAB's refreshRates would store: 1/mean, with the Immediate singleton short-circuited to i...
std::vector< T > phi_vec() const
Completion probabilities, MATLAB's getPhi: (D1 e) .
std::size_t phases() const
The order of the representation, MATLAB's sn.phases.
A MAP as the pair of matrices (D0, D1).
std::vector< bool > recurrent
recurrent[c-1] is true when component c has no edge leaving it.
std::vector< std::size_t > scc
Component index of each state, 1-based as in MATLAB (0 is never used).
Topology and coefficients of a state-dependent routing subnetwork.
Server breakdown and repair of a station whose server fails and is repaired.
T failure_rate
sn.breakdownMu: 1 / mean failure time
T down_rate_of(std::size_t cls_1based) const
lang::Distrib< T > repair
time to repair of a down server
lang::Distrib< T > failure
time to failure of an up server
T repair_rate
sn.repairMu: 1 / mean repair time
std::vector< T > down_service_rates
sn.downServiceRates(ist, :): per class, 0 = no service while down.
The popularity LAW each class declared, beside the pmf it expands to.
std::size_t n
support size of a Zipf or a DiscreteSampler
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< Popularity > preadkind
per class, parallel to pread
std::vector< T > initstate
The DECLARED initial contents of the cache, as the reference dumps the node's state row: the per-clas...
std::vector< int > itemsize
Per-item storage cost (size) and per-list cap on the total cost of the resident items (ton21cache Sec...
std::vector< int > costcap
std::map< std::size_t, std::vector< std::size_t > > retrieval_queues
read class(0-based)->nodes
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::size_t > classitem
Item read by each per-item class of a cache network (MATLAB Cache.setItemReadClasses,...
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
std::vector< T > done
completion rate D1(i,j)/V(i,j)
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
bool has_map() const
True when the type carries a (D0,D1) pair of its own.
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 Distrib disabled_dist()
static Distrib immediate()
The point mass at zero.
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 join
1-based Join node that closes it
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
Variable forking levels, the twin of MATLAB sn.nodeparam{f}.fanOutLink / .fanOutProb / ....
std::vector< std::vector< lang::Distrib< T > > > fan_out_dist
static constexpr double Immediate
Rate of an Immediate distribution; its mean is 1/Immediate = 1e-8.
static constexpr double FineTol
static constexpr double Zero
static constexpr double CoarseTol
One job class of the network.
std::size_t refstat
1-based reference station
bool completes
Whether passage through the reference station is a COMPLETION.
double deadline
sn.classdeadline(r): the soft deadline EDD and EDF order by, and the tardiness JMT reports.
int attr_kind
LayeredNetworkElement of the element it stands for.
std::size_t attr_idx
index of that element
double population
infinite for an open class
bool immfeed
Class-level immediate feedback, ORed with the station's own setting into sn.immfeed.
std::size_t spawn
sn.classspawn(r): the 1-based class injected at the SAME station on every completion of this class,...
bool self_looping
A SelfLoopingClass: a closed class that perpetually cycles at its reference station.
bool is_ref_class
marks the chain's reference class
lang::JoinStrategy strategy
double quorum
0 = every sibling
std::function< T(const std::vector< std::size_t > &)> svc_rate_fun
std::vector< std::vector< bool > > swap_graph
The polling controller of a POLLING station, keyed by station index.
std::size_t pk
the K of K-LIMITED
std::vector< lang::Distrib< T > > switchover
std::vector< T > lincon_b
Matrix< T > lincon_A
optional linear constraint A n <= b
std::vector< std::vector< double > > cap
(nstations x nclasses+1), -1 = unbounded
std::string name
The region's declared name, as the wire carries it; a generated one otherwise.
std::vector< double > maxmem
per member station, -1 = unbounded
std::vector< DropStrategy > rule
per class
std::vector< T > size
per class; size is the memory footprint
std::vector< bool > members
membership, independent of the caps
std::function< T(const std::vector< T > &)> fn
std::string kind
The DECLARATIVE form the reward was built from, when it was: the template name (QLen,...
A Logger node's trace configuration, MATLAB's Logger properties and sn.nodeparam{ind}...
std::string file_name
base name, no directory
std::string file_path
directory, MATLAB's model.getLogPath
std::vector< int > routing_param
The scalar parameter of a parameterized dispatcher, per class: the d of a power-of-d (SQ) choice.
std::vector< std::map< std::size_t, double > > routing_weights
The per-destination weights of a WRROBIN dispatcher, per class: a map from 1-based destination NODE i...
bool queue_object
Declared as a Queue although its INF discipline makes nodetype Delay (Network::add_queue).
std::vector< RoutingStrategy > routing
sn.routing, per class.
double tasks_per_link
Fork.output.tasksPerLink == MATLAB sn.nodeparam{f}.fanOut: how many tasks a fork emits per outgoing l...
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.
std::vector< int > max_orbit
MATLAB sn.orbitMaxJobs: -1 = unbounded.
std::vector< int > policy
MATLAB sn.retrialPolicy: 1 = LINEAR (per-job clocks), 2 = CONSTANT (one clock per orbit).
Setup and delay-off of a station that powers down when it falls idle.
bool last(lang::Distrib< T > &su, lang::Distrib< T > &doff) const
The pair the solvers use: the last class that declares one.
std::vector< lang::Distrib< T > > setup
per class, disabled = not declared
std::vector< lang::Distrib< T > > delayoff
per class
Per class; strategy == NONE is a class that declares no balking.
lang::BalkingStrategy strategy
std::vector< BalkingThreshold > thresholds
One balking threshold: with min_jobs <= n <= max_jobs at the station, an arriving job of the class re...
A heterogeneous server pool: count servers that serve only compatible classes, each with its own serv...
std::vector< bool > compatible
per class; empty = every class
std::vector< Distrib< T > > service
per class
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...
double cap
Station capacity in Kendall's K, as setCapacity sets it.
std::vector< T > jdscalingpeak
sn.jdscalingpeak for this station: the declared peak joint-dependent scaling per class.
std::vector< BalkingParam > balking
std::function< T(const std::vector< std::size_t > &)> svc_rate_fun
sn.nodeparam{ind}.svcRateFun for a PAS / OI station: the TOTAL service rate as a function of the orde...
std::vector< T > batch_reject
Queue.setBatchRejectProbability: per-class rejection of a whole batch.
std::vector< Distrib< T > > patience
Queue.setPatience(class, dist): the abandonment timer of a WAITING job, with impatience[r] naming whi...
std::vector< std::size_t > server_parallelism
Queue.setServerParallelism(class, n): the servers a job seizes for the whole of its service,...
std::vector< int > droprule
Per-class blocking rule as an INT, with 0 meaning "not set".
std::vector< std::vector< Distrib< T > > > switchover_pair
Queue.setSwitchover(fromClass, toClass, distrib): the walk the server takes when it turns from servin...
double nservers
may be infinite (a Delay, or an inf-scheduled task)
std::vector< lang::PollingType > polling_type
Polling parameters for a POLLING station, MATLAB's pollingType, switchoverTime and pollingPar on the ...
Matrix< T > swap_graph
sn.nodeparam{ind}.swapGraph: which class a departing job promotes the jobs behind it into.
CdScaling< T > jdscaling
sn.jdscaling for this station: MATLAB's Station.ljdScaling, the JOINT dependence map eta_i(n),...
std::vector< T > cdscalingpeak
sn.cdscalingpeak for this station: the DECLARED peak rate scaling per class, empty when the station i...
std::vector< std::size_t > marked_classes
Source.markedClasses: the 1-based class of each mark of an MMAP arrival.
std::vector< T > lldscaling
sn.lldscaling for this station: the multiplier at population 1, 2, ... Empty when the station is not ...
std::vector< lang::ImpatienceType > impatience
std::vector< T > schedparam
sn.schedparam, per class: the DPS / GPS weight, or the SEPT / LEPT rank.
lang::HeteroSchedPolicy hetero_policy
CdScaling< T > cdscaling
sn.cdscaling for this station: the class-dependence map, empty when unset.
std::vector< double > classcap
Per-class buffer from setChainCapacity; infinite where unset.
std::vector< lang::DepartureDiscipline > departure_discipline
Place.departureDiscipline, per class.
std::vector< Distrib< T > > arrival_batch
Source.setArrivalBatch(class, dist): the batch-size law released at each arrival epoch.
std::vector< Distrib< T > > switchover
bool fluid
Place.setFluid (MATLAB sn.fluid): the place holds a continuous LEVEL rather than tokens,...
std::vector< bool > immfeed
Node-level immediate feedback, per class; empty when the station sets none.
std::vector< ServerType > server_types
std::size_t attr_idx
LQN element this station stands for.
One fluid arc of a mode: node is the 1-based fluid place, value a rate or an impulse.
A fluid rate dependence: the firing rate is multiplied by fun(level(node)).
std::function< double(double)> fun
A marking-dependent fluid flow (setFluidFlowDependence): the flow of the mode on fluid place node is ...
std::vector< std::size_t > read
std::function< double(const std::vector< double > &)> fun
A fluid guard: the mode is enabled only while level(node) >= thr (sgn = +1) or <= thr (sgn = -1).
The parameters of a Transition node: MATLAB sn.nodeparam{ind} for an SPN transition,...
const std::vector< FluidArc > & fluid_rates(std::size_t m) const
static std::vector< T > inhibit_total(const std::vector< Matrix< T > > &a, std::size_t m)
The inhibiting THRESHOLD of one mode per place, class blind.
std::vector< std::vector< FluidDep > > fluiddep
static std::vector< T > arc_total(const std::vector< Matrix< T > > &a, std::size_t m)
The arcs of one mode summed over classes, for a consumer that is class blind BECAUSE THE NET IS SINGL...
bool is_multiclass() const
True when any mode's arcs touch more than one class.
std::vector< double > firingprio
firing priority per mode
std::vector< std::vector< FluidGuard > > fluidguard
std::vector< std::vector< FluidFlowDep > > fluidflowdep
std::vector< lang::TimingStrategy > timing
immediate or timed
std::vector< std::string > modenames
std::vector< std::vector< FluidArc > > fluidimpulse
std::vector< lang::Distrib< T > > firingproc
firing distribution per mode
bool has_fluid_arcs() const
Transition.hasFluidArcs: any mode declares a fluid rate, guard, impulse, rate or flow dependence.
std::vector< double > nmodeservers
servers per mode, may be infinite
const std::vector< FluidArc > & fluid_impulses(std::size_t m) const
std::vector< T > fireweight
weight among simultaneously enabled modes
std::size_t single_class() const
The one class every arc of every mode touches, 1-based; 0 when none does.
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.
const std::vector< FluidDep > & fluid_deps(std::size_t m) const
const std::vector< FluidFlowDep > & fluid_flow_deps(std::size_t m) const
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).
const std::vector< FluidGuard > & fluid_guards(std::size_t m) const
std::vector< std::vector< FluidArc > > fluidrate
FSPN arcs per mode, MATLAB sn.transparam{ind}.fluidrate/fluidguard/fluidimpulse/fluiddep.
std::vector< std::size_t > firingphases
phase count per mode, 0 when non-Markovian