5#ifndef LINE_API_SN_SN_ROUTING_ERGODIC_H
6#define LINE_API_SN_SN_ROUTING_ERGODIC_H
66 const std::size_t I =
sn.nodes.size();
69 for (
typename std::map<std::pair<std::size_t, std::size_t>,
Matrix<T>>::const_iterator it =
71 it !=
sn.P.end(); ++it) {
73 const std::size_t nr = std::min(blk.
rows(), I);
74 const std::size_t
nc = std::min(blk.
cols(), I);
75 for (std::size_t i = 0; i < nr; ++i)
76 for (std::size_t j = 0; j <
nc; ++j)
77 if (blk(i, j) > zero) adj(i, j) = one;
86 for (
typename std::map<std::pair<std::size_t, std::size_t>,
Matrix<T>>::const_iterator it =
88 it !=
sn.P.end(); ++it) {
90 if (idx >= blk.
rows())
continue;
91 for (std::size_t j = 0; j < blk.
cols(); ++j)
92 if (blk(idx, j) > zero)
return true;
99std::string default_target(
const qn::NetworkStruct<T>& sn,
100 const std::vector<std::string>& absorbing) {
101 for (std::size_t i = 0; i < sn.nodes.size(); ++i)
104 for (std::size_t i = 0; i < sn.nodes.size(); ++i) {
105 if (sn.nodes[i].station == 0)
continue;
106 if (first.empty()) first = sn.nodes[i].name;
107 if (std::find(absorbing.begin(), absorbing.end(), sn.nodes[i].name) == absorbing.end())
108 return sn.nodes[i].name;
119 if (
sn.P.empty())
return info;
121 const Matrix<T> adj = detail::routing_adjacency(
sn);
126 for (std::size_t i = 0; i <
sn.nodes.size(); ++i) {
127 if (
sn.nodes[i].station == 0)
continue;
128 bool outgoing =
false;
129 for (std::size_t j = 0; j <
sn.nodes.size(); ++j)
130 if (j != i && adj(i, j) > zero) {
134 if (!outgoing && detail::has_any_routing(
sn, i))
138 for (std::size_t i = 0; i <
sn.nodes.size(); ++i)
146 std::size_t recurrentCount = 0;
147 for (std::size_t c = 1; c <= info.
numSCCs; ++c) {
152 for (std::size_t v = 0; v < scc.
scc.size(); ++v) {
153 if (scc.
scc[v] != c ||
sn.nodes[v].station == 0)
continue;
154 const std::string& nm =
sn.nodes[v].name;
174 if (!target.empty() && target != abs)
175 info.
suggestedFixes.push_back(
"Route jobs from " + abs +
" back to " + target +
176 " (e.g., P{class}(" + abs +
", " + target +
") = 1.0)");
185 std::vector<std::size_t> out;
187 for (std::size_t i = 0; i <
sn.nodes.size(); ++i)
204 std::map<std::pair<std::size_t, std::size_t>,
Matrix<T>> P =
sn.P;
208 const std::string target =
210 if (target.empty())
throw InputError(
"sn_make_ergodic: no suitable target node for routing");
211 std::size_t targetIdx =
sn.nodes.size();
212 for (std::size_t i = 0; i <
sn.nodes.size(); ++i)
213 if (
sn.nodes[i].name == target) targetIdx = i;
214 if (targetIdx ==
sn.nodes.size())
215 throw InputError(
"sn_make_ergodic: target node \"" + target +
"\" not found");
219 std::size_t absIdx =
sn.nodes.size();
220 for (std::size_t i = 0; i <
sn.nodes.size(); ++i)
222 if (absIdx ==
sn.nodes.size() || absIdx == targetIdx)
continue;
223 for (
typename std::map<std::pair<std::size_t, std::size_t>,
Matrix<T>>::iterator it =
225 it != P.end(); ++it) {
226 if (absIdx >= it->second.rows())
continue;
227 for (std::size_t j = 0; j < it->second.cols(); ++j) it->second(absIdx, j) = zero;
229 for (std::size_t r = 1; r <=
sn.nclasses; ++r) {
230 typename std::map<std::pair<std::size_t, std::size_t>,
Matrix<T>>::iterator it =
231 P.find(std::make_pair(r, r));
232 if (it != P.end() && absIdx < it->second.rows() && targetIdx < it->second.cols())
233 it->second(absIdx, targetIdx) = one;
A network plus its refreshed NetworkStruct.
The exception types the port throws.
Dense matrix and non-owning view.
SccResult stronglyconncomp(const Matrix< T > &A)
Strongly connected components of a directed graph, and which of them are recurrent (closed under the ...
std::map< std::pair< std::size_t, std::size_t >, Matrix< T > > sn_make_ergodic(const qn::NetworkStruct< T > &sn, const std::string &targetName=std::string())
A routing map that makes the network ergodic, by redirecting every absorbing station to TARGETNAME (e...
RoutingErgodicityInfo sn_reducibility_info(const qn::NetworkStruct< T > &sn)
The reducibility structure plus a suggested repair per absorbing station.
std::vector< std::size_t > sn_absorbing_stations(const qn::NetworkStruct< T > &sn)
NODE indices, 1-based, of the absorbing stations.
RoutingErgodicityInfo sn_is_routing_ergodic(const qn::NetworkStruct< T > &sn)
Ergodicity of the routing, with the structure behind the verdict.
A queueing network and its refreshed NetworkStruct.
Strongly connected components of a directed graph, and which of them are recurrent (closed under the ...
std::size_t numSCC() const
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).
The reducibility structure of a routing matrix, the MATLAB info struct.
bool isReducible
the routing is reducible
std::vector< std::string > absorbingStations
names, the Sink excluded
std::size_t numSCCs
strongly connected components
std::vector< std::string > transientStations
names in a transient component
bool isRoutingErgodic
the routing is irreducible
std::vector< std::string > suggestedFixes
one repair per absorbing station