5#ifndef LINE_LANG_QN_NETWORK_STRUCT_H
6#define LINE_LANG_QN_NETWORK_STRUCT_H
85using lang::GlobalConstants;
104 std::vector<std::vector<std::size_t>>
auxall;
134 std::map<std::size_t, std::vector<std::vector<std::size_t>>>
auxmatrix;
135 std::map<std::size_t, std::vector<std::size_t>>
required;
306 if (m >= a.size())
return v;
308 for (std::size_t p = 0; p < a[m].rows(); ++p) {
311 for (std::size_t r = 0; r < a[m].cols(); ++r) {
313 if (!std::isfinite(x))
continue;
317 v[p] = any || a[m].cols() == 0
333 if (m >= a.size())
return v;
334 const double inf = std::numeric_limits<double>::infinity();
336 for (std::size_t p = 0; p < a[m].rows(); ++p) {
338 for (std::size_t r = 0; r < a[m].cols(); ++r) {
340 if (std::isfinite(x) && x < best) best = x;
350 for (
int w = 0; w < 3; ++w)
351 for (std::size_t m = 0; m < all[w]->size(); ++m) {
352 std::size_t touched = 0;
353 for (std::size_t r = 0; r < (*all[w])[m].cols(); ++r) {
355 for (std::size_t p = 0; p < (*all[w])[m].rows() && !any; ++p) {
358 any = w == 1 ? (std::isfinite(v) && v > 0.0) : v > 0.0;
362 if (touched > 1)
return true;
370 for (
int w = 0; w < 3; ++w)
371 for (std::size_t m = 0; m < all[w]->size(); ++m)
372 for (std::size_t r = 0; r < (*all[w])[m].cols(); ++r)
373 for (std::size_t p = 0; p < (*all[w])[m].rows(); ++p) {
375 if (w == 1 ? (std::isfinite(v) && v > 0.0) : v > 0.0)
return r + 1;
382 std::vector<lang::TimingStrategy>
timing;
389 std::vector<std::function<T(
const std::vector<T>&)>>
firingdep;
423 std::vector<lang::Distrib<T>>
setup;
427 for (std::size_t r =
setup.size(); r > 0; --r)
428 if (!
setup[r - 1].disabled) {
515 std::vector<std::vector<Matrix<T>>>
accost;
555 std::vector<std::size_t>& rc_items,
556 std::vector<std::size_t>& rc_orig) {
564 rc_items.push_back(k + 1);
565 rc_orig.push_back(c + 1);
569 std::vector<std::size_t> ord(rc_list.size());
570 for (std::size_t i = 0; i < ord.size(); ++i) ord[i] = i;
571 std::stable_sort(ord.begin(), ord.end(),
572 [&](std::size_t a, std::size_t b) { return rc_list[a] < rc_list[b]; });
573 std::vector<std::size_t> l(rc_list.size()), it(rc_list.size()), oc(rc_list.size());
574 for (std::size_t i = 0; i < ord.size(); ++i) {
575 l[i] = rc_list[ord[i]];
576 it[i] = rc_items[ord[i]];
577 oc[i] = rc_orig[ord[i]];
604 double cap = std::numeric_limits<double>::infinity();
811 double deadline = std::numeric_limits<double>::infinity();
904 std::vector<std::pair<std::size_t, std::size_t>>
fj;
969 const typename std::map<std::size_t, ForkParam<T> >::const_iterator it =
988 std::function<T(
const std::vector<T>&)>
fn;
1025 std::vector<std::vector<double>>
cap;
1058 if (ind == 0 || ind >
nodes.size())
return false;
1059 const std::size_t ist =
nodes[ind - 1].station;
1171 std::vector<std::vector<std::size_t>>
nvars;
1277 if (ist == 0 || ist >
stations.size())
return pp;
1278 const typename std::map<std::size_t, PollingParam>::const_iterator it =
1303 if (ind == 0 || ind >
nvars.size())
return 0;
1305 for (std::size_t j = 0; j <
nvars[ind - 1].size(); ++j) w +=
nvars[ind - 1][j];
1316 std::vector<double> v;
1327 return service[ist - 1][r - 1].type;
1352 std::size_t
phases_of(std::size_t ist, std::size_t r)
const {
1380 const std::size_t p =
phases_of(ist, r);
1381 return p > 0 ? p : 1;
1385 if (n.nodetype == NodeType::Fork)
return true;
1401 if (rs == RoutingStrategy::SDR)
return true;
1420 std::vector<std::size_t>
rr_outlinks(std::size_t ind, std::size_t r)
const {
1421 std::vector<std::size_t> out;
1423 const std::size_t K =
classes.size(), I =
nodes.size();
1424 for (std::size_t j = 1; j <= I; ++j) {
1425 bool linked =
false;
1426 for (std::size_t s = 1; s <= K && !linked; ++s)
1427 if (
get_route(r, s, ind, j) > zero) linked =
true;
1428 if (linked) out.push_back(j);
1435 const std::vector<std::size_t> ol =
rr_outlinks(ind, r);
1436 const std::map<std::size_t, double>* w =
1437 (ind <=
nodes.size() &&
nodes[ind - 1].routing_weights.size() >= r)
1438 ? &
nodes[ind - 1].routing_weights[r - 1]
1440 std::vector<std::size_t> cycle;
1441 for (std::size_t d = 0; d < ol.size(); ++d) {
1444 const std::map<std::size_t, double>::const_iterator it = w->find(ol[d]);
1445 if (it != w->end() && it->second > 0.0)
1446 reps = std::lround(it->second) < 1 ? 1 : std::lround(it->second);
1448 for (
long q = 0; q < reps; ++q) cycle.push_back(ol[d]);
1463 const std::size_t R =
classes.size();
1464 if (ind == 0 || ind >
nodes.size() || r == 0 || r > R)
return 0;
1465 const std::vector<RoutingStrategy>& rt_i =
nodes[ind - 1].routing;
1466 if (rt_i.size() < r)
return 0;
1467 if (rt_i[r - 1] != RoutingStrategy::RROBIN && rt_i[r - 1] != RoutingStrategy::WRROBIN)
1469 if (
nvars.size() < ind)
return 0;
1470 std::size_t slot = 0;
1471 for (std::size_t j = 0; j < R + r && j <
nvars[ind - 1].size(); ++j)
1472 slot +=
nvars[ind - 1][j];
1482 std::size_t
rr_dest(std::size_t ind, std::size_t r,
const std::vector<T>& varrow)
const {
1484 if (slot == 0 || slot > varrow.size())
return 0;
1486 if (
nodes[ind - 1].routing[r - 1] == RoutingStrategy::RROBIN)
1487 return v > 0 ?
static_cast<std::size_t
>(v) : 0;
1489 if (v < 1 ||
static_cast<std::size_t
>(v) > cycle.size())
return 0;
1490 return cycle[
static_cast<std::size_t
>(v) - 1];
1499 void rr_advance(std::size_t ind, std::size_t r, std::vector<T>& varrow)
const {
1501 if (slot == 0 || slot > varrow.size())
return;
1502 if (
nodes[ind - 1].routing[r - 1] == RoutingStrategy::RROBIN) {
1503 const std::vector<std::size_t> ol =
rr_outlinks(ind, r);
1504 if (ol.empty())
return;
1506 std::size_t idx = ol.size();
1507 for (std::size_t d = 0; d < ol.size(); ++d)
1508 if (
static_cast<long>(ol[d]) == cur) { idx = d;
break; }
1509 const std::size_t nxt = (idx + 1 < ol.size()) ? idx + 1 : 0;
1514 if (cycle.empty())
return;
1516 const long nxt = (pos < 1 || static_cast<std::size_t>(pos) >= cycle.size()) ? 1 : pos + 1;
1524 if (rs == RoutingStrategy::RROBIN || rs == RoutingStrategy::WRROBIN)
return true;
1530 for (
const std::vector<bool>& row :
immfeed)
1554 throw InputError(
"network: a station is not a stateful node");
1566 nodes.push_back(nd);
1580 nodes.push_back(nd);
1583 return nodes.size();
1594 service[station - 1][cls - 1] = d;
1598 void set_route(std::size_t r, std::size_t s, std::size_t i, std::size_t j,
const T& p) {
1599 auto key = std::make_pair(r, s);
1600 auto it =
P.find(key);
1605 it->second(i - 1, j - 1) = p;
1621 auto key = std::make_pair(r, s);
1622 auto it =
Peff.find(key);
1623 if (it ==
Peff.end())
1626 if (it->second.rows() !=
nodes.size()) {
1628 for (std::size_t a = 0; a < it->second.rows(); ++a)
1629 for (std::size_t b = 0; b < it->second.cols(); ++b) g(a, b) = it->second(a, b);
1632 it->second(i - 1, j - 1) = p;
1643 T
get_route(std::size_t r, std::size_t s, std::size_t i, std::size_t j)
const {
1644 auto it =
P.find(std::make_pair(r, s));
1646 return it->second(i - 1, j - 1);
1650 T
route_eff(std::size_t r, std::size_t s, std::size_t i, std::size_t j)
const {
1652 auto it =
Peff.find(std::make_pair(r, s));
1654 return it->second(i - 1, j - 1);
1702 if (ind == 0 || ind >
replyblock.size())
return false;
1703 for (std::size_t k = 0; k <
syncreply.size(); ++k)
1721 if (ind == 0 || ind >
nodes.size())
return true;
1723 if (nt != NodeType::Queue && nt != NodeType::Delay)
return true;
1724 const std::size_t sti =
nodes[ind - 1].station;
1725 if (sti == 0 || sti >
stations.size())
return true;
1726 if (!
stations[sti - 1].server_types.empty())
return true;
1727 if (
procid(sti, r + 1) != ProcessType::DISABLED)
return true;
1745 std::vector<std::vector<bool>> reached;
1746 if (N == 0 || K == 0)
return reached;
1748 reached.assign(N, std::vector<bool>(K,
false));
1749 std::vector<std::vector<bool>> seed(N, std::vector<bool>(K,
false));
1750 for (std::size_t i = 0; i <
stations.size(); ++i) {
1751 if (
stations[i].nodetype != NodeType::Source)
continue;
1753 if (ind == 0 || ind > N)
continue;
1754 for (std::size_t r = 0; r < K; ++r)
1755 if (
procid(i + 1, r + 1) != ProcessType::DISABLED) seed[ind - 1][r] =
true;
1757 for (std::size_t r = 0; r < K && r <
classes.size(); ++r) {
1758 const double pop =
classes[r].population;
1759 if (!std::isfinite(pop) || pop <= 0.0)
continue;
1761 if (ind == 0 || ind > N)
continue;
1762 seed[ind - 1][r] =
true;
1764 std::vector<std::pair<std::size_t, std::size_t>> stack;
1765 for (std::size_t i = 0; i < N; ++i)
1766 for (std::size_t r = 0; r < K; ++r)
1768 reached[i][r] =
true;
1769 stack.push_back(std::make_pair(i, r));
1771 while (!stack.empty()) {
1772 const std::size_t i = stack.back().first;
1773 const std::size_t r = stack.back().second;
1776 if (nt == NodeType::Sink)
continue;
1777 if (nt == NodeType::Source && !seed[i][r])
continue;
1779 const std::size_t row = i * K + r;
1780 for (std::size_t col = 0; col < N * K; ++col) {
1784 const std::size_t j = col / K, sIdx = col % K;
1785 if (!reached[j][sIdx]) {
1786 reached[j][sIdx] =
true;
1787 stack.push_back(std::make_pair(j, sIdx));
1846 for (std::size_t ind = 0; ind <
nodes.size(); ++ind) {
1848 if (nt == NodeType::Cache || nt == NodeType::Place ||
1849 nt == NodeType::Transition || nt == NodeType::Fork ||
1850 nt == NodeType::Join)
1855 if (reached.empty())
return;
1856 for (std::size_t i = 0; i <
nstations; ++i) {
1858 if (nt != NodeType::Queue && nt != NodeType::Delay)
continue;
1862 if (!
stations[i].server_types.empty())
continue;
1864 if (ind == 0)
continue;
1865 for (std::size_t r = 0; r < K; ++r) {
1866 if (
procid(i + 1, r + 1) != ProcessType::DISABLED)
continue;
1872 if (ind - 1 >= reached.size() || r >= reached[ind - 1].size())
continue;
1873 if (!reached[ind - 1][r])
continue;
1874 const std::string kind = (nt == NodeType::Delay) ?
"Delay" :
"Queue";
1876 "' has no service configured for job class '" +
1878 "', but the class is routed to it. Jobs would arrive and "
1879 "never leave. Configure a service for that class, or route "
1896 immfeed.assign(M, std::vector<bool>(R,
false));
1897 for (std::size_t i = 0; i < M; ++i)
1898 for (std::size_t r = 0; r < R; ++r) {
1899 const bool station_has =
1924 for (std::size_t ind = 1; ind <=
nodes.size(); ++ind) {
1928 for (std::size_t r = 0; r < nd.
routing.size(); ++r)
1929 if (nd.
routing[r] == RoutingStrategy::RROBIN ||
1930 nd.
routing[r] == RoutingStrategy::WRROBIN)
1940 const std::size_t R =
classes.size();
1942 nvars.assign(
nodes.size(), std::vector<std::size_t>(3 * R + 1, 0));
1943 for (std::size_t ind = 1; ind <=
nodes.size(); ++ind) {
1944 const std::size_t ist =
nodes[ind - 1].station;
1948 for (std::size_t r = 1; r <= R; ++r) {
1950 if (pt == ProcessType::MAP || pt == ProcessType::MMPP2)
1951 nvars[ind - 1][r - 1] += 1;
1955 const std::vector<RoutingStrategy>& rt_i =
nodes[ind - 1].routing;
1956 for (std::size_t r = 1; r <= R && r <= rt_i.size(); ++r)
1957 if (rt_i[r - 1] == RoutingStrategy::RROBIN ||
1958 rt_i[r - 1] == RoutingStrategy::WRROBIN)
1959 nvars[ind - 1][R + r - 1] += 1;
1968 if (ist != 0 &&
stations[ist - 1].sched == SchedStrategy::POLLING) {
1971 for (std::size_t r = 0; r < pp.
switchover.size(); ++r) {
1973 if (!d.
disabled && d.
D0.rows() > 0 && d.
type != ProcessType::IMMEDIATE)
1976 std::size_t w = anysw ? 2 : 0;
1978 nvars[ind - 1][2 * R] = w;
1981 for (std::size_t r = 1; r <= R; ++r)
1984 nvars[ind - 1][2 * R + r] = 1;
1985 const typename std::map<std::size_t, CacheParam<T>>::const_iterator ci =
1992 for (std::size_t u = 0; u < ci->second.itemcap.size(); ++u)
1993 if (ci->second.itemcap[u] > 0)
1994 w +=
static_cast<std::size_t
>(ci->second.itemcap[u]);
1995 if (ci->second.retrieval_capacity > 0) {
1996 w += ci->second.nitems;
1997 std::vector<std::size_t> rcl, rci, rco;
2001 nvars[ind - 1][2 * R] = w;
2023 const std::size_t R =
classes.size(), N =
nodes.size();
2025 for (std::size_t r = 0; r < R && r <
syncreply.size(); ++r)
2028 replyblock.assign(N, std::vector<bool>(R,
false));
2029 for (std::size_t r = 1; r <= R; ++r) {
2032 if (s < 1 || s > R)
continue;
2033 for (std::size_t ind = 1; ind <= N; ++ind) {
2034 const std::size_t ist =
nodes[ind - 1].station;
2036 if (
stations[ist - 1].sched == SchedStrategy::INF)
continue;
2037 bool arrives_here =
false;
2038 for (std::size_t i = 1; i <= N && !arrives_here; ++i)
2039 for (std::size_t q = 1; q <= R; ++q)
2042 rtnodes((i - 1) * R + q - 1, (ind - 1) * R + s - 1)) > 0) {
2043 arrives_here =
true;
2046 if (!arrives_here)
continue;
2047 if (
stations[ist - 1].sched != SchedStrategy::FCFS)
2049 "network '" +
name +
2050 "': synchronous calls (REPLY signals) are supported only at FCFS "
2053 "' uses another discipline. A held server is encoded as a per-class "
2054 "counter, which is exact only where servers are interchangeable (FCFS) "
2055 "or unlimited (INF).");
2076 const std::size_t R =
classes.size();
2077 const std::size_t N =
nodes.size();
2078 std::vector<std::size_t> out;
2080 std::vector<bool> seen(N + 1,
false);
2081 std::vector<std::size_t> frontier(1, ind);
2083 while (!frontier.empty()) {
2084 const std::size_t i = frontier.back();
2085 frontier.pop_back();
2086 for (std::size_t j = 1; j <= N; ++j) {
2087 if (seen[j])
continue;
2088 bool linked =
false;
2089 for (std::size_t r = 0; r < R && !linked; ++r)
2090 for (std::size_t s = 0; s < R && !linked; ++s)
2092 rtnodes((i - 1) * R + r, (j - 1) * R + s)) > 0)
2094 if (!linked)
continue;
2096 if (
nodes[j - 1].station != 0) {
2099 frontier.push_back(j);
2111 const std::size_t R =
classes.size();
2112 const std::size_t N =
nodes.size();
2116 for (std::size_t ind = 1; ind <= N; ++ind) {
2117 const std::size_t ist =
nodes[ind - 1].station;
2118 if (ist == 0)
continue;
2120 if (nt == NodeType::Source || nt == NodeType::Cache)
continue;
2122 bool declares =
false;
2123 for (std::size_t r = 1; r <= R; ++r) {
2124 const bool here_bas =
droprule.size() >= ist &&
droprule[ist - 1].size() >= r &&
2125 droprule[ist - 1][r - 1] == DropStrategy::BAS;
2126 for (std::size_t d = 0; d < dests.size(); ++d) {
2127 const std::size_t jst =
nodes[dests[d] - 1].station;
2128 if (jst == 0 ||
nodes[dests[d] - 1].nodetype == NodeType::Source)
continue;
2139 const double dcap =
stations[jst - 1].cap;
2140 if (!std::isfinite(dcap) || !(dcap > 0))
continue;
2141 const bool there_bas =
2143 droprule[jst - 1][r - 1] == DropStrategy::BAS;
2144 if (!here_bas && !there_bas)
continue;
2152 if (!declares)
continue;
2159 "' combines server breakdowns with true-BAS blocking: the breakdown status "
2160 "and the BAS blocked marker share one local-state column. Remove the BAS drop "
2161 "rule or the breakdown");
2162 if (
stations[ist - 1].sched == SchedStrategy::POLLING)
2164 "true BAS blocking is not supported at the polling station '" +
2166 "': the polling controller and the BAS blocked marker share one local-state "
2167 "column. Use a non-polling discipline at the blocking station, or remove the "
2169 for (std::size_t r = 1; r <= R; ++r)
2173 "true BAS blocking is not supported at station '" +
nodes[ind - 1].
name +
2174 "', which also holds servers for a synchronous reply: fromMarginal appends "
2175 "the reply counters AFTER the blocked marker, so the marker would no "
2176 "longer be the trailing column the departure handler reads");
2177 nvars[ind - 1][2 * R] = 1;
2198 for (std::size_t i = 0; i <
stations.size(); ++i) {
2200 if (st.
sched == SchedStrategy::DPS || st.
sched == SchedStrategy::GPS) {
2205 if (st.
sched == SchedStrategy::SEPT || st.
sched == SchedStrategy::LEPT) {
2207 std::vector<double> means;
2208 for (std::size_t r = 0; r <
classes.size(); ++r)
2210 std::vector<double> sorted = means;
2211 std::sort(sorted.begin(), sorted.end());
2212 sorted.erase(std::unique(sorted.begin(), sorted.end()), sorted.end());
2213 if (st.
sched == SchedStrategy::LEPT)
2214 std::reverse(sorted.begin(), sorted.end());
2216 for (std::size_t r = 0; r <
classes.size(); ++r)
2217 for (std::size_t k = 0; k < sorted.size(); ++k)
2218 if (sorted[k] == means[r])
2255 const std::size_t K =
classes.size(), I =
nodes.size();
2257 bool trivial =
true;
2260 if (rs != RoutingStrategy::PROB && rs != RoutingStrategy::DISABLED) trivial =
false;
2267 bool has_cs =
false;
2269 if (nd.nodetype == NodeType::ClassSwitch) has_cs =
true;
2272 const bool has_cache = !
nodeparam.empty();
2273 if (trivial && !has_cs && !has_cache)
return;
2275 for (
const auto& kv :
P)
Peff[kv.first] = kv.second;
2276 auto eff_at = [&](std::size_t r, std::size_t s) ->
Matrix<T>& {
2277 auto key = std::make_pair(r, s);
2278 auto it =
Peff.find(key);
2279 if (it ==
Peff.end())
2281 if (it->second.rows() != I) {
2283 for (std::size_t a = 0; a < it->second.rows(); ++a)
2284 for (std::size_t b = 0; b < it->second.cols(); ++b) g(a, b) = it->second(a, b);
2290 for (std::size_t i = 1; i <= I; ++i) {
2292 for (std::size_t r = 1; r <= K; ++r) {
2294 nd.
routing.size() >= r ? nd.
routing[r - 1] : RoutingStrategy::PROB;
2295 if (rs == RoutingStrategy::PROB || rs == RoutingStrategy::DISABLED)
continue;
2296 if (rs != RoutingStrategy::RAND && rs != RoutingStrategy::RROBIN &&
2297 rs != RoutingStrategy::JSQ && rs != RoutingStrategy::SQ &&
2298 rs != RoutingStrategy::WRROBIN && rs != RoutingStrategy::SDR)
2301 "' has no routing-matrix expansion in this port");
2317 const bool open_class = !std::isfinite(
2319 const bool from_source = nd.
nodetype == NodeType::Source;
2320 const bool from_sink = nd.
nodetype == NodeType::Sink;
2321 if (!open_class && (from_source || from_sink))
continue;
2322 std::vector<std::pair<std::size_t, std::size_t>> dest;
2323 for (std::size_t j = 1; j <= I; ++j) {
2324 if (!open_class &&
nodes[j - 1].nodetype == NodeType::Sink)
continue;
2325 bool connected =
false;
2326 for (std::size_t a = 1; a <= K && !connected; ++a)
2327 for (std::size_t b = 1; b <= K && !connected; ++b)
2328 if (
get_route(a, b, i, j) > zero) connected =
true;
2329 if (connected) dest.emplace_back(j, r);
2331 if (dest.empty())
continue;
2336 std::vector<T> share(dest.size(),
2339 if (rs == RoutingStrategy::WRROBIN) {
2340 const std::map<std::size_t, double>* w =
2343 std::vector<double> raw(dest.size(), 0.0);
2345 for (std::size_t d = 0; d < dest.size(); ++d) {
2346 const std::map<std::size_t, double>::const_iterator it =
2347 w->find(dest[d].first);
2348 raw[d] = (it == w->end()) ? 0.0 : it->second;
2352 for (std::size_t d = 0; d < dest.size(); ++d)
2355 for (std::size_t s = 1; s <= K; ++s) {
2357 for (std::size_t j = 1; j <= I; ++j) B(i - 1, j - 1) = zero;
2359 for (std::size_t d = 0; d < dest.size(); ++d)
2360 eff_at(r, dest[d].second)(i - 1, dest[d].first - 1) = share[d];
2366 const std::size_t cs = kv.first;
2368 if (C.
rows() != K || C.
cols() != K)
2369 throw InputError(
"network: the class-switch matrix of node '" +
2370 nodes[cs - 1].
name +
"' is not (nclasses x nclasses)");
2385 std::vector<std::vector<T>> diag(K, std::vector<T>(I, zero));
2386 for (std::size_t s = 1; s <= K; ++s)
2387 for (std::size_t j = 1; j <= I; ++j)
2388 diag[s - 1][j - 1] =
2389 Peff.empty() ?
get_route(s, s, cs, j) : eff_at(s, s)(cs - 1, j - 1);
2390 for (std::size_t r = 1; r <= K; ++r)
2391 for (std::size_t s = 1; s <= K; ++s) {
2393 for (std::size_t j = 1; j <= I; ++j) B(cs - 1, j - 1) = zero;
2395 for (std::size_t r = 1; r <= K; ++r)
2396 for (std::size_t s = 1; s <= K; ++s) {
2397 if (!(C(r - 1, s - 1) > zero))
continue;
2399 for (std::size_t j = 1; j <= I; ++j)
2400 if (diag[s - 1][j - 1] > zero)
2401 B(cs - 1, j - 1) = T(diag[s - 1][j - 1] * C(r - 1, s - 1));
2415 const std::size_t ci = kv.first;
2417 for (std::size_t r = 0; r < cp.
hitclass.size() && r < K; ++r) {
2420 for (std::size_t s = 1; s <= K; ++s) {
2422 for (std::size_t j = 1; j <= I; ++j) B(ci - 1, j - 1) = zero;
2424 eff_at(r + 1, cp.
hitclass[r])(ci - 1, ci - 1) = half;
2426 eff_at(r + 1, cp.
missclass[r])(ci - 1, ci - 1) = half;
2471 const std::size_t I =
nodes.size();
2472 if (joinNode == 0 || joinNode > I)
return 0;
2473 std::size_t forkNode = 0;
2474 for (std::size_t a = 0; a <
fj.size(); ++a)
2475 if (
fj[a].second == joinNode) {
2476 forkNode =
fj[a].first;
2480 std::vector<bool> seen(I + 1,
false);
2481 std::size_t deg = 0;
2482 for (
typename std::map<std::pair<std::size_t, std::size_t>,
Matrix<T> >::const_iterator
2484 it !=
P.end(); ++it) {
2485 if (it->second.rows() < I || it->second.cols() < I)
continue;
2486 for (std::size_t b = 1; b <= I; ++b) {
2487 if (seen[b])
continue;
2488 const T v = (forkNode != 0) ? it->second(forkNode - 1, b - 1)
2489 : it->second(b - 1, joinNode - 1);
2496 if (forkNode == 0 || forkNode > I)
return deg;
2510 const std::size_t lo = (r != 0 && r <= fol.
cols()) ? r - 1 : 0;
2511 const std::size_t hi = (r != 0 && r <= fol.
cols()) ? r - 1 : fol.
cols() - 1;
2513 for (std::size_t c = lo; c <= hi && c < fol.
cols(); ++c) {
2515 for (std::size_t d = 0; d < fol.
rows(); ++d) {
2517 if (!(link > 0.0))
continue;
2521 if (acc > best) best = acc;
2523 if (best > 0.0)
return static_cast<std::size_t
>(best + 0.5);
2526 double w =
nodes[forkNode - 1].tasks_per_link;
2527 if (!(w >= 1.0)) w = 1.0;
2528 return deg *
static_cast<std::size_t
>(w + 0.5);
2539 std::vector<std::size_t> out;
2540 for (
typename std::map<std::size_t, JoinDecl>::const_iterator it =
joindecl.begin();
2543 if (it->second.quorum <= 0.0)
continue;
2545 const std::size_t k =
static_cast<std::size_t
>(it->second.quorum + 0.5);
2546 if (n == 0 || k < n) out.push_back(it->first);
2553 const double inf = std::numeric_limits<double>::infinity();
2555 classcap.assign(M, std::vector<double>(K, inf));
2556 droprule.assign(M, std::vector<DropStrategy>(K, DropStrategy::WAITQ));
2557 std::vector<std::vector<double>> chaincap(M, std::vector<double>(std::max(
nchains, K), inf));
2565 std::vector<char> quorum_class(K + 1, 0);
2569 for (std::size_t x = 0; x < qj.size(); ++x)
2570 for (
typename std::map<std::pair<std::size_t, std::size_t>,
2572 it !=
P.end(); ++it) {
2573 if (it->second.rows() <
nodes.size() || qj[x] >
nodes.size())
continue;
2574 for (std::size_t a = 1; a <=
nodes.size(); ++a)
2575 if (it->second(a - 1, qj[x] - 1) > zero) {
2576 if (it->first.first <= K) quorum_class[it->first.first] = 1;
2577 if (it->first.second <= K) quorum_class[it->first.second] = 1;
2589 double fork_task_factor = 1.0;
2590 for (std::size_t i = 0; i <
nodes.size(); ++i) {
2591 if (
nodes[i].nodetype != NodeType::Fork)
continue;
2592 const double w =
nodes[i].tasks_per_link;
2593 if (w >= 1.0 && std::isfinite(w)) fork_task_factor *= std::floor(w + 0.5);
2596 for (std::size_t c = 0; c <
nchains; ++c) {
2597 double chain_cap = 0.0;
2599 bool quorum =
false;
2600 for (std::size_t r :
inchain[c]) {
2601 if (std::isinf(
classes[r - 1].population)) open =
true;
2602 else chain_cap +=
classes[r - 1].population;
2603 if (r <= K && quorum_class[r]) quorum =
true;
2605 chain_cap *= fork_task_factor;
2606 if (open || quorum) chain_cap = inf;
2607 for (std::size_t r :
inchain[c])
2608 for (std::size_t i = 0; i < M; ++i) {
2611 if (st.
nodetype != NodeType::Source) {
2612 const bool cap_finite = st.
cap >= 0.0 && !std::isinf(st.
cap);
2613 const bool classcap_finite = st.
classcap.size() >= r &&
2617 st.
droprule[r - 1] ==
static_cast<int>(DropStrategy::WAITQ) &&
2618 std::isinf(
classes[r - 1].population) &&
2619 (cap_finite || classcap_finite))
2621 "station '" + st.
name +
"' declares setDropRule(WAITQ) for the "
2622 "open class '" +
classes[r - 1].name +
"' at a finite capacity: "
2623 "LINE does not implement waiting-room blocking for an open "
2624 "arrival at a plain finite buffer. Use DropStrategy.DROP for a "
2625 "loss station, or BAS / BBS / RSRD for blocking between "
2629 }
else if (std::isinf(st.
cap)) {
2630 droprule[i][r - 1] = DropStrategy::WAITQ;
2631 }
else if (!std::isinf(
classes[r - 1].population)) {
2632 droprule[i][r - 1] = DropStrategy::WAITQ;
2634 droprule[i][r - 1] = DropStrategy::DROP;
2640 chaincap[i][c] = 0.0;
2643 chaincap[i][c] = chain_cap;
2650 for (std::size_t i = 0; i < M; ++i) {
2655 double sc = 0.0, scl = 0.0;
2656 for (std::size_t c = 0; c < chaincap[i].size(); ++c) sc += chaincap[i][c];
2657 for (std::size_t r = 0; r < K; ++r) scl +=
classcap[i][r];
2658 cap[i] = std::min(sc, scl);
2672 const std::size_t K =
classes.size(), I =
nodes.size();
2673 std::vector<std::size_t> all(K);
2674 for (std::size_t r = 0; r < K; ++r) all[r] = r + 1;
2676 for (std::size_t a = 0; a < I; ++a)
2677 for (std::size_t r = 0; r < K; ++r)
2678 for (std::size_t b = 0; b < I; ++b)
2679 for (std::size_t s = 0; s < K; ++s)
2696 const std::size_t K =
classes.size();
2697 std::size_t cidx = 0;
2699 const std::size_t ci = kv.first;
2701 for (std::size_t r = 0; r < cp.
hitclass.size() && r < K; ++r) {
2713 for (std::size_t c = 0; c <
nchains; ++c) {
2731 for (std::size_t i = 0; i <
nstations; ++i)
2732 for (std::size_t r = 0; r <
nclasses; ++r) {
2734 if (
stations[i].nodetype == NodeType::Join) {
2737 std::numeric_limits<double>::infinity());
2765 std::vector<std::vector<bool>> cs(K, std::vector<bool>(K,
false));
2766 for (std::size_t r = 0; r < K; ++r) cs[r][r] =
true;
2767 for (
const auto& kv : (
Peff.empty() ?
P :
Peff)) {
2769 for (std::size_t a = 0; a < kv.second.rows() && !any; ++a)
2770 for (std::size_t b = 0; b < kv.second.cols() && !any; ++b)
2771 if (kv.second(a, b) > zero) any =
true;
2772 if (any) cs[kv.first.first - 1][kv.first.second - 1] =
true;
2782 for (std::size_t r = 0; r < K && r < C.
rows(); ++r)
2783 for (std::size_t s = 0; s < K && s < C.
cols(); ++s)
2784 if (C(r, s) > zero) cs[r][s] =
true;
2792 for (std::size_t r = 0; r < cp.
hitclass.size() && r < K; ++r) {
2806 for (std::size_t r = 0; r < row.size() && r < K; ++r)
2807 if (row[r] != 0) cs[r][row[r] - 1] =
true;
2809 std::vector<std::size_t> comp(K, K);
2810 std::size_t ncomp = 0;
2811 for (std::size_t r = 0; r < K; ++r) {
2812 if (comp[r] != K)
continue;
2813 std::vector<std::size_t> stack{r};
2815 while (!stack.empty()) {
2816 const std::size_t v = stack.back();
2818 for (std::size_t w = 0; w < K; ++w)
2819 if (comp[w] == K && (cs[v][w] || cs[w][v])) {
2831 for (std::size_t r = 0; r < K; ++r) {
2832 chains[comp[r]][r] =
true;
2833 inchain[comp[r]].push_back(r + 1);
2838 for (std::size_t c = 0; c <
nchains; ++c)
2839 for (std::size_t k :
inchain[c])
2842 for (std::size_t c = 0; c <
nchains; ++c) {
2844 for (std::size_t k :
inchain[c])
2845 if (
classes[k - 1].refstat != rs)
2846 throw InputError(
"network '" +
name +
"': classes within a chain have different "
2847 "reference stations");
2856 for (std::size_t c = 0; c <
nchains; ++c) {
2891 for (
auto& kv :
P) {
2892 if (kv.second.rows() <
nodes.size())
continue;
2893 kv.second(
sinkNode - 1, src - 1) = zero;
2895 for (
auto& kv :
Peff) {
2896 if (kv.second.rows() <
nodes.size())
continue;
2897 kv.second(
sinkNode - 1, src - 1) = zero;
2899 for (std::size_t c = 0; c <
nchains; ++c) {
2901 for (std::size_t k :
inchain[c])
2902 if (std::isinf(
classes[k - 1].population)) open =
true;
2903 if (!open)
continue;
2905 for (std::size_t k :
inchain[c])
2909 for (std::size_t s :
inchain[c]) {
2916 if (!(p > zero))
continue;
2924 std::vector<std::size_t> v(
nodes.size());
2925 for (std::size_t i = 0; i <
nodes.size(); ++i) v[i] = i + 1;
2945 const std::vector<std::size_t>& ic =
inchain[c];
2946 const std::size_t nIC = ic.size();
2947 const std::size_t dim = sel.size() * nIC;
2953 for (std::size_t a = 0; a < sel.size(); ++a)
2954 for (std::size_t x = 0; x < nIC; ++x)
2955 for (std::size_t b = 0; b < sel.size(); ++b)
2956 for (std::size_t y = 0; y < nIC; ++y)
2957 Pc(a * nIC + x, b * nIC + y) =
route_eff(ic[x], ic[y], sel[a], sel[b]);
2982 std::vector<bool> served(dim,
true);
2984 for (std::size_t a = 0; a < sel.size(); ++a) {
2985 const std::size_t sti =
nodes[sel[a] - 1].station;
2986 if (sti == 0 || sti >
stations.size())
continue;
2988 if (nt == NodeType::Place || nt == NodeType::Transition)
continue;
2989 if (!
stations[sti - 1].server_types.empty())
continue;
2990 if (sti >
disabled.size())
continue;
2997 for (std::size_t x = 0; x < nIC; ++x)
2999 served[a * nIC + x] =
false;
3001 for (std::size_t row = 0; row < dim; ++row)
3003 for (std::size_t col = 0; col < dim; ++col) Pc(row, col) = zero;
3004 for (std::size_t col = 0; col < dim; ++col)
3006 for (std::size_t row = 0; row < dim; ++row) Pc(row, col) = zero;
3009 std::vector<std::size_t> visited;
3010 std::vector<T> rowsum(dim, zero);
3011 for (std::size_t row = 0; row < dim; ++row) {
3013 for (std::size_t col = 0; col < dim; ++col) s += Pc(row, col);
3015 if (s > zero) visited.push_back(row);
3017 bool oversum =
false;
3019 for (std::size_t row = 0; row < dim; ++row) {
3023 for (std::size_t col = 0; col < dim; ++col)
3024 Pc(row, col) = T(Pc(row, col) / rowsum[row]);
3034 bool reducible =
false;
3035 if (!fork && !visited.empty()) {
3036 Matrix<T> Pv0(visited.size(), visited.size(), zero);
3037 for (std::size_t a = 0; a < visited.size(); ++a)
3038 for (std::size_t b = 0; b < visited.size(); ++b) Pv0(a, b) = Pc(visited[a], visited[b]);
3040 std::size_t nrec = 0;
3043 reducible = (nrec > 1);
3052 std::vector<std::size_t> nconn(sel.size(), 0);
3053 std::vector<std::vector<bool>> conn(sel.size(), std::vector<bool>(sel.size(),
false));
3054 for (std::size_t a = 0; a < sel.size(); ++a)
3055 for (std::size_t b = 0; b < sel.size(); ++b) {
3057 for (std::size_t x = 0; x < nIC && !cbit; ++x)
3058 for (std::size_t y = 0; y < nIC && !cbit; ++y)
3059 if (Pc(a * nIC + x, b * nIC + y) > zero) cbit =
true;
3061 if (cbit) ++nconn[a];
3063 for (std::size_t a = 0; a < sel.size(); ++a) {
3064 if (nconn[a] == 0)
continue;
3065 for (std::size_t x = 0; x < nIC; ++x) {
3067 for (std::size_t col = 0; col < dim; ++col) outsum += Pc(a * nIC + x, col);
3068 if (outsum > zero)
continue;
3071 for (std::size_t b = 0; b < sel.size(); ++b)
3072 if (conn[a][b]) Pc(a * nIC + x, b * nIC + x) = p;
3084 for (std::size_t row = 0; row < dim; ++row)
3086 for (std::size_t col = 0; col < dim; ++col) Pc(row, col) = zero;
3087 for (std::size_t col = 0; col < dim; ++col)
3089 for (std::size_t row = 0; row < dim; ++row) Pc(row, col) = zero;
3091 for (std::size_t row = 0; row < dim; ++row) {
3093 for (std::size_t col = 0; col < dim; ++col) s += Pc(row, col);
3094 if (s > zero) visited.push_back(row);
3098 std::vector<T> alpha(dim, zero);
3099 if (!visited.empty()) {
3100 Matrix<T> Pv(visited.size(), visited.size(), zero);
3101 for (std::size_t a = 0; a < visited.size(); ++a)
3102 for (std::size_t b = 0; b < visited.size(); ++b)
3103 Pv(a, b) = Pc(visited[a], visited[b]);
3110 bool allzero =
true, hasnan =
false;
3111 for (
const T& x : av) {
3112 if (x != zero) allzero =
false;
3115 if (allzero || hasnan) ok =
false;
3116 }
catch (
const Error&) {
3124 for (std::size_t a = 0; a < visited.size(); ++a) alpha[visited[a]] = av[a];
3127 if (fork && oversum) {
3128 for (std::size_t idx = 0; idx < dim; ++idx) {
3130 const std::size_t nd = sel[idx / nIC];
3131 if (!complement &&
nodes[nd - 1].nodetype == NodeType::Join) {
3138 const std::size_t r = ic[idx % nIC];
3139 std::size_t nsrc = 0;
3140 for (std::size_t src = 1; src <=
nodes.size(); ++src)
3141 for (std::size_t q = 1; q <=
nclasses; ++q)
3153 for (std::size_t a = 0; a < sel.size(); ++a)
3154 for (std::size_t x = 0; x < nIC; ++x) out(a, ic[x] - 1) = alpha[a * nIC + x];
3157 const std::size_t rstat =
classes[ic[0] - 1].refstat;
3159 std::size_t refrow = sel.size();
3160 for (std::size_t a = 0; a < sel.size(); ++a)
3161 if (sel[a] == refnode) refrow = a;
3162 if (refrow < sel.size()) {
3164 for (std::size_t x = 0; x < nIC; ++x) norm += out(refrow, ic[x] - 1);
3166 for (std::size_t a = 0; a < sel.size(); ++a)
3167 for (std::size_t x = 0; x < nIC; ++x)
3168 out(a, ic[x] - 1) = T(out(a, ic[x] - 1) / norm);
3170 for (std::size_t a = 0; a < sel.size(); ++a)
3171 for (std::size_t x = 0; x < nIC; ++x)
3172 if (out(a, ic[x] - 1) < zero) out(a, ic[x] - 1) = T(-out(a, ic[x] - 1));
3186 const std::vector<std::size_t>& ic, std::size_t refnode)
const {
3188 const std::size_t nIC = ic.size();
3189 const std::size_t dim = Pc_in.
rows();
3192 for (std::size_t row = 0; row < dim; ++row) {
3194 std::size_t nnan = 0;
3195 for (std::size_t col = 0; col < dim; ++col) {
3198 else nonnan = T(nonnan + Pc(row, col));
3200 if (nnan == 0)
continue;
3203 for (std::size_t col = 0; col < dim; ++col) {
3205 if (v != v) Pc(row, col) = fill;
3208 std::vector<std::size_t> visited;
3209 for (std::size_t row = 0; row < dim; ++row) {
3211 for (std::size_t col = 0; col < dim; ++col) s += Pc(row, col);
3212 if (s > zero) visited.push_back(row);
3214 std::vector<T> alpha(dim, zero);
3215 if (!visited.empty()) {
3216 Matrix<T> Pv(visited.size(), visited.size(), zero);
3217 for (std::size_t a = 0; a < visited.size(); ++a)
3218 for (std::size_t b = 0; b < visited.size(); ++b) Pv(a, b) = Pc(visited[a], visited[b]);
3224 bool allzero =
true, hasnan =
false;
3225 for (
const T& x : av) {
3226 if (x != zero) allzero =
false;
3229 if (allzero || hasnan) ok =
false;
3230 }
catch (
const Error&) {
3234 for (std::size_t a = 0; a < visited.size(); ++a) alpha[visited[a]] = av[a];
3237 for (std::size_t a = 0; a < sel.size(); ++a)
3238 for (std::size_t x = 0; x < nIC; ++x) out(a, ic[x] - 1) = alpha[a * nIC + x];
3239 std::size_t refrow = sel.size();
3240 for (std::size_t a = 0; a < sel.size(); ++a)
3241 if (sel[a] == refnode) refrow = a;
3242 if (refrow < sel.size()) {
3244 for (std::size_t x = 0; x < nIC; ++x) norm += out(refrow, ic[x] - 1);
3246 for (std::size_t a = 0; a < sel.size(); ++a)
3247 for (std::size_t x = 0; x < nIC; ++x)
3248 out(a, ic[x] - 1) = T(out(a, ic[x] - 1) / norm);
3250 for (std::size_t a = 0; a < sel.size(); ++a)
3251 for (std::size_t x = 0; x < nIC; ++x)
3252 if (out(a, ic[x] - 1) < zero) out(a, ic[x] - 1) = T(-out(a, ic[x] - 1));
3268 if (nd.nodetype == NodeType::Fork)
3269 throw UnsupportedError(
"da_recompute_visits_from_rtnodes: fork models keep the "
3270 "route_eff visit path");
3271 std::vector<std::size_t> keep;
3272 keep.reserve(M * K);
3273 for (std::size_t p = 0; p < M; ++p) {
3275 for (std::size_t r = 0; r < K; ++r) keep.push_back(base + r);
3279 std::vector<std::size_t> allnodes(I);
3280 for (std::size_t a = 0; a < I; ++a) allnodes[a] = a + 1;
3283 for (std::size_t c = 0; c <
nchains; ++c) {
3284 const std::vector<std::size_t>& ic =
inchain[c];
3285 const std::size_t nIC = ic.size();
3288 for (std::size_t a = 0; a < M; ++a)
3289 for (std::size_t x = 0; x < nIC; ++x)
3290 for (std::size_t b = 0; b < M; ++b)
3291 for (std::size_t y = 0; y < nIC; ++y)
3292 Ps(a * nIC + x, b * nIC + y) =
rt(a * K + (ic[x] - 1), b * K + (ic[y] - 1));
3293 const std::size_t rstat =
classes[ic[0] - 1].refstat;
3300 for (std::size_t a = 0; a < I; ++a)
3301 for (std::size_t x = 0; x < nIC; ++x)
3302 for (std::size_t b = 0; b < I; ++b)
3303 for (std::size_t y = 0; y < nIC; ++y)
3304 Pn(a * nIC + x, b * nIC + y) =
3305 rtnodes(a * K + (ic[x] - 1), b * K + (ic[y] - 1));
3319 const std::size_t nIC = ic.size();
3320 const std::size_t I =
nodes.size();
3322 for (std::size_t a = 0; a < I; ++a)
3323 for (std::size_t x = 0; x < nIC; ++x)
3324 for (std::size_t b = 0; b < I; ++b)
3325 for (std::size_t y = 0; y < nIC; ++y)
3326 full(a * nIC + x, b * nIC + y) =
route_eff(ic[x], ic[y], a + 1, b + 1);
3346 const std::size_t I =
nodes.size();
3347 std::vector<std::size_t> keep, drop;
3348 for (std::size_t a = 0; a < I; ++a) {
3349 const bool st =
nodes[a].stateful;
3350 for (std::size_t x = 0; x < nIC; ++x) (st ? keep : drop).push_back(a * nIC + x);
3352 if (drop.empty())
return full;
3354 const std::size_t nk = keep.size(), nd = drop.size();
3355 Matrix<T> P11(nk, nk, zero), P12(nk, nd, zero), P21(nd, nk, zero), A(nd, nd, zero);
3356 for (std::size_t a = 0; a < nk; ++a) {
3357 for (std::size_t b = 0; b < nk; ++b) P11(a, b) = full(keep[a], keep[b]);
3358 for (std::size_t b = 0; b < nd; ++b) P12(a, b) = full(keep[a], drop[b]);
3360 for (std::size_t a = 0; a < nd; ++a) {
3361 for (std::size_t b = 0; b < nk; ++b) P21(a, b) = full(drop[a], keep[b]);
3362 for (std::size_t b = 0; b < nd; ++b)
3363 A(a, b) = T((a == b ? one : zero) - full(drop[a], drop[b]));
3367 std::vector<std::size_t> piv(nd);
3368 for (std::size_t i = 0; i < nd; ++i) piv[i] = i;
3369 for (std::size_t col = 0; col < nd; ++col) {
3370 std::size_t best = col;
3372 for (std::size_t r2 = col + 1; r2 < nd; ++r2) {
3374 if (v > bv) { bv = v; best = r2; }
3377 for (std::size_t b = 0; b < nd; ++b) std::swap(A(col, b), A(best, b));
3378 for (std::size_t b = 0; b < nk; ++b) std::swap(X(col, b), X(best, b));
3380 if (A(col, col) == zero)
3381 throw NumericError(
"network: the stochastic complement is singular");
3382 for (std::size_t r2 = 0; r2 < nd; ++r2) {
3383 if (r2 == col)
continue;
3384 const T f = T(A(r2, col) / A(col, col));
3385 if (f == zero)
continue;
3386 for (std::size_t b = 0; b < nd; ++b) A(r2, b) = T(A(r2, b) - f * A(col, b));
3387 for (std::size_t b = 0; b < nk; ++b) X(r2, b) = T(X(r2, b) - f * X(col, b));
3390 for (std::size_t r2 = 0; r2 < nd; ++r2)
3391 for (std::size_t b = 0; b < nk; ++b) X(r2, b) = T(X(r2, b) / A(r2, r2));
3394 for (std::size_t a = 0; a < nk; ++a)
3395 for (std::size_t b = 0; b < nk; ++b) {
3397 for (std::size_t m = 0; m < nd; ++m) acc += P12(a, m) * X(m, b);
3398 S(a, b) = T(S(a, b) + acc);
3407 if (std::isinf(c.population))
return true;
3419 if (!std::isinf(c.population))
return false;
3425 if (std::isfinite(s.nservers) && s.nservers > 1.0)
return true;
3431 if (std::isfinite(c.population) && c.population != std::floor(c.population + 0.5))
3440 if (c.prio > 0)
return true;
3453 if (
classes.empty())
return false;
3455 if (c.prio !=
classes.front().prio)
return true;
3471 case SchedStrategy::HOL:
3472 case SchedStrategy::PSPRIO:
3473 case SchedStrategy::DPSPRIO:
3474 case SchedStrategy::GPSPRIO:
3475 case SchedStrategy::LCFSPRIO:
3476 case SchedStrategy::LCFSPRPRIO:
3477 case SchedStrategy::LCFSPIPRIO:
3478 case SchedStrategy::FCFSPRPRIO:
3479 case SchedStrategy::FCFSPIPRIO:
3480 case SchedStrategy::SRPTPRIO:
3510 for (std::size_t i = 0; i <
nstations; ++i) {
3511 if (
stations[i].sched != SchedStrategy::FCFS)
continue;
3514 for (std::size_t r = 0; r <
nclasses; ++r) {
3517 lo = hi =
rates(i, r);
3524 if (any && hi > lo) bad =
true;
3531 if (!(s.sched == SchedStrategy::INF || s.sched == SchedStrategy::PS ||
3532 s.sched == SchedStrategy::FCFS || s.sched == SchedStrategy::LCFSPR ||
3533 s.sched == SchedStrategy::LCFS || s.sched == SchedStrategy::EXT))
3545 for (std::size_t i = 0; i <
nstations; ++i) {
3546 if (
stations[i].sched != SchedStrategy::FCFS)
continue;
3547 for (std::size_t r = 0; r <
nclasses; ++r) {
3549 if (std::isinf(v) || !(v > 0.0))
continue;
3563 double k = std::numeric_limits<double>::infinity();
3564 if (
cap[ist - 1] >= 0.0) k = std::min(k,
cap[ist - 1]);
3566 bool anyServed =
false;
3567 for (std::size_t r = 0; r <
nclasses; ++r)
3572 if (anyServed) k = std::min(k, ccap);
3573 double reachable = 0.0;
3574 for (std::size_t r = 0; r <
nclasses; ++r)
3575 if (!anyServed ||
classcap[ist - 1][r] > 0.0) reachable +=
classes[r].population;
3576 return (k >= reachable) ? std::numeric_limits<double>::infinity() : k;
3582 for (std::size_t k = 0; k <
classes.size(); ++k)
3583 if (std::isfinite(
classes[k].population))
return false;
3584 std::size_t nq = 0, nsrc = 0, nsink = 0, qnode = 0, snode = 0;
3585 for (std::size_t a = 0; a <
nodes.size(); ++a) {
3586 switch (
nodes[a].nodetype) {
3587 case NodeType::Queue: ++nq; qnode = a + 1;
break;
3588 case NodeType::Source: ++nsrc; snode = a + 1;
break;
3589 case NodeType::Sink: ++nsink;
break;
3590 default:
return false;
3593 if (nq != 1 || nsrc != 1 || nsink != 1)
return false;
3594 const std::size_t qist =
nodes[qnode - 1].station;
3595 const std::size_t sist =
nodes[snode - 1].station;
3596 if (qist == 0 || sist == 0)
return false;
3597 if (
stations[qist - 1].nservers != 1.0)
return false;
3599 droprule[qist - 1][0] != DropStrategy::DROP)
3601 if (!(qist <=
cap.size()) || !std::isfinite(
cap[qist - 1]) || !(
cap[qist - 1] > 0.0))
3614 if (!
regions.empty())
return true;
3615 for (std::size_t a = 0; a <
nodes.size(); ++a)
3616 if (
nodes[a].nodetype == NodeType::Cache)
return false;
3618 for (std::size_t ist = 1; ist <=
stations.size(); ++ist)
3649 if (!(s.sched == SchedStrategy::INF || s.sched == SchedStrategy::PS ||
3650 s.sched == SchedStrategy::FCFS || s.sched == SchedStrategy::LCFSPR ||
3651 s.sched == SchedStrategy::EXT))
3654 for (std::size_t i = 0; i <
nstations; ++i) {
3655 if (
stations[i].sched != SchedStrategy::FCFS)
continue;
3656 for (std::size_t r = 0; r <
nclasses; ++r) {
3659 if (!std::isinf(v) && v > 0.0 &&
3663 if (!check_means ||
visits.empty())
continue;
3665 double stmin = 0.0, stmax = 0.0;
3666 bool anyserved =
false;
3667 for (std::size_t c = 0; c <
nchains && c <
visits.size(); ++c) {
3668 double num = 0.0, den = 0.0;
3669 for (std::size_t r = 0; r <
nclasses; ++r) {
3680 const double st = num / den;
3685 stmin = std::min(stmin, st);
3686 stmax = std::max(stmax, st);
3702 for (std::size_t a = 0; a < B.
rows(); ++a)
3703 for (std::size_t b = 0; b < B.
cols(); ++b) g(a, b) = B(a, b);
3711 if (std::isfinite(c.population)) s += c.population;
3734 const std::size_t R =
sn.nclasses;
3738 if (st.
sched != SchedStrategy::PAS)
return Matrix<T>(R, R, zero);
3740 for (std::size_t r = 0; r < R; ++r) g(r, r) = zero;
3749 for (std::size_t a = 0; a < g.
rows(); ++a)
3750 for (std::size_t b = 0; b < g.
cols(); ++b)
3751 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
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.
Matrix< T > chain_visits(std::size_t c, const std::vector< std::size_t > &sel, bool complement, bool fork) const
Port of the per-chain body of sn_refresh_visits, over an arbitrary node subset – the stateful nodes f...
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...
bool has_immediate_feedback() const
any(sn.immfeed(:)): whether any (station, class) pair feeds back.
bool has_class_switching() const
std::vector< lang::RemovalPolicy > signalrempolicy
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.
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.
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.
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
bool sched_has_priority_aware() const
Whether some station runs a discipline that READS the class priorities.
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 > > chains
(nchains x nclasses)
bool has_homogeneous_scheduling(SchedStrategy) const
Port of sn_has_homogeneous_scheduling.
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
Refuses a class that is ROUTED TO a station which cannot serve it.
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< 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...
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.
std::map< std::size_t, RetrialParam< T > > retrialparam
Retrial parameters, keyed by 1-based STATION index.
std::vector< bool > issignal
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.
void grow_block(Matrix< T > &B) const
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::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::map< std::size_t, JoinDecl > joindecl
std::vector< std::size_t > signaltarget
void refresh_local_vars()
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.
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
std::size_t node_of_station(std::size_t st) const
1-based node index of a station, and the reverse; 0 when absent.
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
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.
bool has_breakdown_node(std::size_t ind) const
sn.hasbreakdown(ind): does the NODE's server break down?
void refresh_router_stateful()
Port of MNetwork.refreshLocalVars: the per-node local-variable widths.
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::map< std::size_t, std::vector< T > > stateprior
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
Port of MNetwork.refreshCapacity.
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
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
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
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
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,...
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.
Running progress log of a LINE solver run (the "solver console").
Dense matrix and non-owning view.
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.
JoinStrategy
Join rules, with the values of MATLAB JoinStrategy.
RoutingStrategy
Routing strategies, with the values of MATLAB RoutingStrategy.
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.
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)
Number-type abstraction for the templated API port.
Product-form state-dependent routing.
Strongly connected components of a directed graph, and which of them are recurrent (closed under the ...
The DECLARED join rule of a Join node, by 1-based node index.
The G-network signal declaration, per CLASS.
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).
Matrix< T > D0
The (D0,D1) pair when the type carries one directly.
T rate() const
The rate MATLAB's refreshRates would store: 1/mean, with the Immediate singleton short-circuited to i...
std::size_t phases() const
The order of the representation, MATLAB's sn.phases.
std::vector< bool > recurrent
recurrent[c-1] is true when component c has no edge leaving it.
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
T qlru
Delayed-hit retrieval system (Cache.setRetrievalSystem).
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
static Distrib disabled_dist()
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 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...
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.
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".
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
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.
The parameters of a Cache node, MATLAB's sn.nodeparam{ind} for a Cache.
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.
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< lang::TimingStrategy > timing
immediate or timed
std::vector< std::string > modenames
std::vector< lang::Distrib< T > > firingproc
firing distribution per mode
std::vector< double > nmodeservers
servers per mode, may be infinite
std::vector< T > fireweight
weight among simultaneously enabled modes
std::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.
std::vector< std::function< T(const std::vector< T > &)> > firingdep
Marking-dependent firing-rate multiplier g_m(marking); an empty entry is the unit multiplier.
std::vector< Matrix< T > > inhibiting
inhibiting[m](p,r): class-r tokens of p that BLOCK mode m (Inf = never).
std::vector< std::size_t > firingphases
phase count per mode, 0 when non-Markovian