64 const std::size_t M =
sn.nstations, K =
sn.nclasses;
67 std::vector<std::vector<bool>> stalled(M, std::vector<bool>(K,
false));
68 bool anystalled =
false;
69 for (std::size_t i = 0; i < M; ++i)
70 for (std::size_t r = 0; r < K; ++r) {
71 const bool zr = !
sn.disabled[i][r] &&
73 stalled[i][r] = zr ||
sn.stations[i].nservers == 0.0;
74 anystalled = anystalled || stalled[i][r];
76 if (!anystalled)
return out;
78 const std::vector<double> st2sf =
sn.station_to_stateful();
79 const std::vector<double> njobs =
sn.njobs();
81 auto visited = [&](std::size_t c, std::size_t i, std::size_t r) {
82 const double sf = st2sf[i];
83 if (std::isnan(sf) || c >=
sn.visits.size())
return false;
84 const std::size_t row =
static_cast<std::size_t
>(sf) - 1;
85 if (row >=
sn.visits[c].rows() || r >=
sn.visits[c].cols())
return false;
88 for (std::size_t c = 0; c <
sn.nchains; ++c) {
89 std::vector<std::size_t> hit;
91 for (std::size_t r = 0; r < K; ++r)
92 if (
sn.chains[c][r] && std::isinf(njobs[r])) open =
true;
93 for (std::size_t i = 0; i < M; ++i) {
95 for (std::size_t r = 0; r < K && !h; ++r)
96 h =
sn.chains[c][r] && stalled[i][r] && visited(c, i, r);
97 if (h) hit.push_back(i);
99 if (hit.empty())
continue;
101 out.
reason =
"Station " +
sn.stations[hit[0]].name +
102 " has zero capacity and is visited by an open class, which accumulates "
103 "there without bound: the model has no steady state.";
106 if (hit.size() > 1) {
108 for (std::size_t k = 0; k < hit.size(); ++k)
109 names += (k ?
", " :
"") +
sn.stations[hit[k]].name;
110 out.
reason =
"Chain " + std::to_string(c + 1) +
" visits " +
111 std::to_string(hit.size()) +
" stations with zero capacity (" + names +
112 "): its jobs are trapped at all of them and how they divide depends on "
113 "the initial state.";
118 for (std::size_t i = 0; i < M; ++i) {
120 for (std::size_t s : out.
deadstat) dead = dead || s == i + 1;
121 const double ns =
sn.stations[i].nservers;
122 if (!dead || ns == 0.0 || std::isinf(ns))
continue;
123 for (std::size_t c = 0; c <
sn.nchains; ++c) {
124 if (out.
deadstat[c] == i + 1)
continue;
125 for (std::size_t r = 0; r < K; ++r)
126 if (
sn.chains[c][r] && visited(c, i, r)) {
127 out.
reason =
"Station " +
sn.stations[i].name +
128 " serves a class at rate zero and is shared with a chain that "
129 "is not trapped there: the stalled jobs would hold its servers "