5#ifndef LINE_API_WF_WF_LOOP_DETECTOR_H
6#define LINE_API_WF_WF_LOOP_DETECTOR_H
75bool wf_in_simple_loop(
int serviceNode,
const std::map<
int, std::vector<std::pair<int, T>>>& adj,
76 const std::set<int>& routerSet) {
77 typename std::map<int, std::vector<std::pair<int, T>>>::const_iterator it = adj.find(serviceNode);
78 if (it == adj.end())
return false;
79 for (std::size_t a = 0; a < it->second.size(); ++a) {
80 const int router = it->second[a].first;
81 if (!routerSet.count(router))
continue;
82 typename std::map<int, std::vector<std::pair<int, T>>>::const_iterator jt = adj.find(router);
83 if (jt == adj.end())
continue;
84 for (std::size_t b = 0; b < jt->second.size(); ++b)
85 if (jt->second[b].first == serviceNode)
return true;
91 std::map<int, int> index;
92 std::map<int, int> lowlink;
93 std::set<int> onStack;
94 std::vector<int> stack;
95 std::vector<std::vector<int>> sccs;
99inline void wf_strong_connect(
int node,
const std::map<
int, std::set<int>>& graph, TarjanState& st) {
100 st.index[node] = st.counter;
101 st.lowlink[node] = st.counter;
103 st.stack.push_back(node);
104 st.onStack.insert(node);
106 std::map<int, std::set<int>>::const_iterator it = graph.find(node);
107 if (it != graph.end()) {
108 for (std::set<int>::const_iterator nb = it->second.begin(); nb != it->second.end(); ++nb) {
109 if (!st.index.count(*nb)) {
110 wf_strong_connect(*nb, graph, st);
111 if (st.lowlink[*nb] < st.lowlink[node]) st.lowlink[node] = st.lowlink[*nb];
112 }
else if (st.onStack.count(*nb)) {
113 if (st.index[*nb] < st.lowlink[node]) st.lowlink[node] = st.index[*nb];
118 if (st.lowlink[node] == st.index[node]) {
119 std::vector<int> scc;
127 st.sccs.push_back(scc);
143 const std::vector<int>& routerNodes,
144 const std::vector<int>& joinNodes = std::vector<int>()) {
145 detail::wf_check(linkMatrix);
146 const std::set<int> routerSet(routerNodes.begin(), routerNodes.end());
147 const std::map<int, std::vector<std::pair<int, T>>> adj = detail::wf_adjacency_prob(linkMatrix);
149 std::vector<int> loopNodes;
150 for (std::size_t i = 0; i < serviceNodes.size(); ++i)
151 if (detail::wf_in_simple_loop(serviceNodes[i], adj, routerSet))
152 loopNodes.push_back(serviceNodes[i]);
154 if (!joinNodes.empty()) {
155 const std::set<int> serviceSet(serviceNodes.begin(), serviceNodes.end());
156 const std::set<int> joinSet(joinNodes.begin(), joinNodes.end());
158 std::map<int, std::set<int>> graph;
159 for (std::size_t i = 0; i < linkMatrix.
rows(); ++i)
160 graph[detail::wf_id(linkMatrix, i, 0)].insert(detail::wf_id(linkMatrix, i, 1));
162 detail::TarjanState st;
163 for (std::map<
int, std::set<int>>::const_iterator it = graph.begin(); it != graph.end(); ++it)
164 if (!st.index.count(it->first)) detail::wf_strong_connect(it->first, graph, st);
166 for (std::size_t s = 0; s < st.sccs.size(); ++s) {
167 if (st.sccs[s].size() <= 1)
continue;
168 std::vector<int> inScc;
169 bool hasRouterOrJoin =
false;
170 for (std::size_t k = 0; k < st.sccs[s].size(); ++k) {
171 const int n = st.sccs[s][k];
172 if (serviceSet.count(n)) inScc.push_back(n);
173 if (routerSet.count(n) || joinSet.count(n)) hasRouterOrJoin =
true;
175 if (!inScc.empty() && hasRouterOrJoin)
176 loopNodes.insert(loopNodes.end(), inScc.begin(), inScc.end());
180 std::vector<int> distinct;
182 for (std::size_t i = 0; i < loopNodes.size(); ++i)
183 if (seen.insert(loopNodes[i]).second) distinct.push_back(loopNodes[i]);
193 const std::vector<int>& routerNodes) {
194 detail::wf_check(linkMatrix);
195 const std::set<int> routerSet(routerNodes.begin(), routerNodes.end());
196 for (std::size_t i = 0; i < linkMatrix.
rows(); ++i) {
197 const int start = detail::wf_id(linkMatrix, i, 0);
198 const int end = detail::wf_id(linkMatrix, i, 1);
199 if (start != serviceNode || !routerSet.count(end))
continue;
200 for (std::size_t j = 0; j < linkMatrix.
rows(); ++j)
201 if (detail::wf_id(linkMatrix, j, 0) == end &&
202 detail::wf_id(linkMatrix, j, 1) == serviceNode)
203 return linkMatrix(j, 2);
211 const std::vector<int>& routerNodes) {
212 detail::wf_check(linkMatrix);
213 const std::set<int> routerSet(routerNodes.begin(), routerNodes.end());
214 return detail::wf_in_simple_loop(loopNode, detail::wf_adjacency_prob(linkMatrix), routerSet);
222 if (loopProbability >= one) {
226 r.
value = one / (one - loopProbability);
233 const std::vector<int>& routerNodes) {
237 std::vector<T> probs;
238 for (std::size_t i = 0; i < loopNodes.size(); ++i)
241 if (!probs.empty()) {
245 for (std::size_t i = 0; i < probs.size(); ++i) {
247 if (probs[i] > mx) mx = probs[i];
248 if (probs[i] < mn) mn = probs[i];
255 std::vector<T> iters;
256 for (std::size_t i = 0; i < probs.size(); ++i) {
260 if (!iters.empty()) {
263 for (std::size_t i = 0; i < iters.size(); ++i) {
265 if (iters[i] > mx) mx = iters[i];
The exception types the port throws.
Dense matrix and non-owning view.
std::vector< int > detect_loops(const Matrix< T > &linkMatrix, const std::vector< int > &serviceNodes, const std::vector< int > &routerNodes, const std::vector< int > &joinNodes=std::vector< int >())
ExpectedIterations< T > get_expected_loop_iterations(const T &loopProbability)
Mean number of visits of a geometric loop, 1/(1-p).
bool validate_loop_pattern(int loopNode, const Matrix< T > &linkMatrix, const std::vector< int > &routerNodes)
True when the node still has the service -> router -> service structure.
T get_loop_probability(int serviceNode, const Matrix< T > &linkMatrix, const std::vector< int > &routerNodes)
Probability on the router-to-service edge that closes the loop, 0 when the node is not on a simple lo...
LoopStats< T > get_loop_stats(const std::vector< int > &loopNodes, const Matrix< T > &linkMatrix, const std::vector< int > &routerNodes)
Count and moments of the loop probabilities and iteration counts.
Number-type abstraction for the templated API port.
1/(1-p), with the p >= 1 divergence reported rather than encoded.
Mirrors the Java getLoopStats map.
Shared conventions of the workflow pattern detectors.