5#ifndef LINE_API_WF_WF_SEQUENCE_DETECTOR_H
6#define LINE_API_WF_WF_SEQUENCE_DETECTOR_H
73inline std::vector<int> wf_build_sequence_chain(std::vector<std::pair<int, int>>& connections) {
74 std::vector<int> sequence;
75 if (connections.empty())
return sequence;
77 std::vector<std::size_t> used;
78 int first = connections[0].first;
79 int last = connections[0].second;
80 sequence.push_back(first);
81 sequence.push_back(last);
84 bool foundExtension =
true;
85 while (foundExtension) {
86 foundExtension =
false;
87 const std::size_t currentSize = sequence.size();
88 for (std::size_t i = 1; i < connections.size(); ++i) {
89 if (std::find(used.begin(), used.end(), i) != used.end())
continue;
90 const int start = connections[i].first;
91 const int end = connections[i].second;
94 sequence.push_back(end);
96 foundExtension =
true;
97 }
else if (end == first) {
99 sequence.insert(sequence.begin(), start);
101 foundExtension =
true;
104 foundExtension = foundExtension && sequence.size() > currentSize;
107 std::sort(used.begin(), used.end(), std::greater<std::size_t>());
108 for (std::size_t idx : used) connections.erase(connections.begin() +
static_cast<long>(idx));
121 const std::vector<int>& serviceNodes) {
122 detail::wf_check(linkMatrix);
123 std::vector<std::vector<int>> chains;
124 const std::set<int> serviceSet(serviceNodes.begin(), serviceNodes.end());
126 std::vector<std::pair<int, int>> connections;
127 for (std::size_t i = 0; i < linkMatrix.
rows(); ++i) {
128 const int s = detail::wf_id(linkMatrix, i, 0);
129 const int e = detail::wf_id(linkMatrix, i, 1);
130 if (serviceSet.count(s) && serviceSet.count(e))
131 connections.push_back(std::make_pair(s, e));
133 if (connections.empty())
return chains;
135 std::map<int, std::size_t> counts;
136 for (std::size_t i = 0; i < connections.size(); ++i) {
137 counts[connections[i].first] += 1;
138 counts[connections[i].second] += 1;
140 std::size_t countOnce = 0;
141 for (std::map<int, std::size_t>::const_iterator it = counts.begin(); it != counts.end(); ++it)
142 if (it->second == 1) ++countOnce;
143 const std::size_t numSequences = countOnce / 2;
145 for (std::size_t seq = 0; seq < numSequences; ++seq) {
146 if (connections.empty())
break;
147 std::vector<int> chain = detail::wf_build_sequence_chain(connections);
148 if (!chain.empty()) chains.push_back(chain);
156 detail::wf_check(linkMatrix);
157 if (sequence.size() < 2)
return false;
158 std::set<std::pair<int, int>> edges;
159 for (std::size_t i = 0; i < linkMatrix.
rows(); ++i)
160 edges.insert(std::make_pair(detail::wf_id(linkMatrix, i, 0),
161 detail::wf_id(linkMatrix, i, 1)));
162 for (std::size_t i = 0; i + 1 < sequence.size(); ++i)
163 if (!edges.count(std::make_pair(sequence[i], sequence[i + 1])))
return false;
172 std::size_t total = 0;
173 for (std::size_t i = 0; i < sequences.size(); ++i) total += sequences[i].size();
175 if (sequences.empty())
return stats;
181 for (std::size_t i = 1; i < sequences.size(); ++i) {
The exception types the port throws.
Dense matrix and non-owning view.
bool validate_sequence(const std::vector< int > &sequence, const Matrix< T > &linkMatrix)
Every consecutive pair of the chain must be an edge of the workflow.
std::vector< std::vector< int > > detect_sequences(const Matrix< T > &linkMatrix, const std::vector< int > &serviceNodes)
SequenceStats< T > get_sequence_stats(const std::vector< std::vector< int > > &sequences)
Count, total, mean, maximum and minimum chain length.
Number-type abstraction for the templated API port.
Mirrors the Java getSequenceStats map.
Shared conventions of the workflow pattern detectors.