19 #include "boost/graph/graph_traits.hpp"
20 #include "boost/graph/adjacency_list.hpp"
21 #include "boost/graph/depth_first_search.hpp"
22 #include "boost/graph/visitors.hpp"
66 typedef std::pair<unsigned int, unsigned int>
SimpleEdge;
67 typedef std::map<SimpleEdge, std::vector<unsigned int>>
EdgeToPathMap;
69 typedef boost::adjacency_list<boost::vecS, boost::vecS, boost::bidirectionalS>
Graph;
71 typedef boost::graph_traits<Graph>::edge_descriptor Edge;
74 std::unordered_set<T> intersect(std::unordered_set<T>
const& iLHS, std::unordered_set<T>
const& iRHS) {
75 std::unordered_set<T>
result;
76 if (iLHS.size() < iRHS.size()) {
77 result.reserve(iLHS.size());
78 for (
auto const&
l : iLHS) {
79 if (iRHS.find(
l) != iRHS.end()) {
85 result.reserve(iRHS.size());
86 for (
auto const&
r : iRHS) {
87 if (iLHS.find(
r) != iLHS.end()) {
94 struct cycle_detector :
public boost::dfs_visitor<> {
95 static const unsigned int kRootVertexIndex = 0;
98 std::vector<std::vector<unsigned int>>
const& iPathIndexToModuleIndexOrder,
99 std::vector<std::string>
const& iPathNames,
100 std::unordered_map<unsigned int, std::string>
const& iModuleIndexToNames)
101 : m_edgeToPathMap(iEdgeToPathMap),
102 m_pathIndexToModuleIndexOrder(iPathIndexToModuleIndexOrder),
103 m_pathNames(iPathNames),
104 m_indexToNames(iModuleIndexToNames) {}
106 bool compare(Edge
const& iLHS, Edge
const& iRHS)
const;
108 void tree_edge(Edge
const& iEdge,
Graph const& iGraph) {
109 auto const&
index =
get(boost::vertex_index, iGraph);
112 for (
auto it = m_stack.begin(); it != m_stack.end(); ++it) {
116 m_stack.erase(it, m_stack.end());
121 m_stack.push_back(iEdge);
124 void finish_vertex(
unsigned int iVertex,
Graph const& iGraph) {
125 if (not m_stack.empty()) {
126 auto const&
index =
get(boost::vertex_index, iGraph);
128 if (iVertex ==
index[
source(m_stack.back(), iGraph)]) {
135 void back_edge(Edge
const& iEdge,
Graph const& iGraph) {
136 auto const&
index =
get(boost::vertex_index, iGraph);
138 if (kRootVertexIndex !=
index[
source(m_stack.front(), iGraph)]) {
143 m_stack.push_back(iEdge);
145 auto pop_stack = [](std::vector<Edge>*
stack) {
stack->pop_back(); };
146 std::unique_ptr<std::vector<Edge>, decltype(pop_stack)> guard(&m_stack, pop_stack);
151 std::vector<Edge> tempStack;
153 tempStack = findMinimumCycle(m_stack, iGraph);
154 checkCycleForProblem(tempStack, iGraph);
155 for (
auto const& edge : tempStack) {
159 m_verticiesInFundamentalCycles.insert(
in);
160 m_verticiesInFundamentalCycles.insert(
out);
165 m_fundamentalCycles.emplace_back(
std::move(tempStack));
168 void forward_or_cross_edge(Edge iEdge,
Graph const& iGraph) {
170 IndexMap
const&
index =
get(boost::vertex_index, iGraph);
172 if (kRootVertexIndex !=
index[
source(m_stack.front(), iGraph)]) {
181 if (m_verticiesInFundamentalCycles.end() == m_verticiesInFundamentalCycles.find(
out)) {
185 for (
auto const& cycle : m_fundamentalCycles) {
187 auto itStartMatch = cycle.end();
188 for (
auto it = cycle.begin(); it != cycle.end(); ++it) {
191 if (
out == inCycle) {
196 if (itStartMatch == cycle.end()) {
203 m_stack.push_back(iEdge);
204 auto pop_stack = [](std::vector<Edge>*
stack) {
stack->pop_back(); };
205 std::unique_ptr<std::vector<Edge>, decltype(pop_stack)> guard(&m_stack, pop_stack);
206 auto tempStack = findMinimumCycle(m_stack, iGraph);
210 std::set<unsigned int> verticiesInStack;
211 for (
auto const& edge : tempStack) {
212 verticiesInStack.insert(
index[
source(edge, iGraph)]);
217 auto itLastMatch = cycle.end();
218 for (
auto it = itStartMatch; it != cycle.end(); ++it) {
219 unsigned int outCycle =
index[
target(*it, iGraph)];
220 if (verticiesInStack.end() != verticiesInStack.find(outCycle)) {
225 if (itLastMatch == cycle.end()) {
227 tempStack.insert(tempStack.end(), itStartMatch, cycle.end());
228 for (
auto it = cycle.begin(); it != itStartMatch; ++it) {
229 unsigned int outCycle =
index[
target(*it, iGraph)];
230 if (verticiesInStack.end() != verticiesInStack.find(outCycle)) {
235 if (itLastMatch == cycle.end()) {
242 tempStack.insert(tempStack.end(), cycle.begin(), itStartMatch);
244 tempStack.insert(tempStack.end(), cycle.begin(), itLastMatch + 1);
247 if ((itStartMatch == cycle.begin()) and (cycle.end() == (itLastMatch + 1))) {
252 tempStack.insert(tempStack.end(), itStartMatch, itLastMatch + 1);
255 tempStack = findMinimumCycle(tempStack, iGraph);
256 checkCycleForProblem(tempStack, iGraph);
264 auto itFound = m_indexToNames.find(iIndex);
265 assert(itFound != m_indexToNames.end());
266 return itFound->second;
269 void throwOnError(std::vector<Edge>
const& iEdges,
271 Graph const& iGraph)
const {
272 std::stringstream oStream;
273 oStream <<
"Module run order problem found: \n";
274 bool first_edge =
true;
275 for (
auto const& edge : iEdges) {
276 unsigned int in = iIndex[
source(edge, iGraph)];
277 unsigned int out = iIndex[
target(edge, iGraph)];
287 bool pathDependencyOnly =
true;
288 for (
auto dependency : iFound->second) {
290 pathDependencyOnly =
false;
294 if (pathDependencyOnly) {
300 oStream <<
"\n Running in the threaded framework would lead to indeterminate results."
301 "\n Please change order of modules in mentioned Path(s) to avoid inconsistent module ordering.";
306 std::vector<Edge> findMinimumCycle(std::vector<Edge>
const& iCycleEdges,
Graph const& iGraph)
const {
316 IndexMap
const&
index =
get(boost::vertex_index, iGraph);
318 std::vector<Edge> reducedEdges;
319 reducedEdges.reserve(iCycleEdges.size());
320 reducedEdges.push_back(iCycleEdges.back());
321 unsigned int lastIn =
index[
source(iCycleEdges.back(), iGraph)];
322 const unsigned int finalVertex =
index[
target(iCycleEdges.back(), iGraph)];
323 for (
auto it = iCycleEdges.rbegin() + 1; it != iCycleEdges.rend(); ++it) {
327 reducedEdges.push_back(*it);
329 if (
in == finalVertex) {
339 void checkCycleForProblem(std::vector<Edge>
const& iCycleEdges,
Graph const& iGraph) {
343 bool hasDataDependency =
false;
346 IndexMap
const&
index =
get(boost::vertex_index, iGraph);
348 unsigned int lastIn =
index[
source(iCycleEdges.back(), iGraph)];
349 unsigned int lastOut =
index[
target(iCycleEdges.back(), iGraph)];
350 bool lastEdgeHasDataDepencency =
false;
352 std::unordered_set<unsigned int> lastPathsSeen;
357 std::unordered_multimap<unsigned int, unsigned int> pathToModulesWhichMustAppearLater;
358 bool moduleAppearedEarlierInPath =
false;
360 for (
auto dependency : m_edgeToPathMap.find(
SimpleEdge(lastIn, lastOut))->second) {
362 lastPathsSeen.insert(dependency);
364 lastEdgeHasDataDepencency =
true;
368 bool minimumInitialPathsSet =
false;
369 std::unordered_set<unsigned int> initialPaths(lastPathsSeen);
370 std::unordered_set<unsigned int> sharedPaths;
371 for (
auto const& edge : iCycleEdges) {
376 std::unordered_set<unsigned int> pathsOnEdge;
377 bool edgeHasDataDependency =
false;
378 for (
auto dependency : iFound->second) {
381 hasDataDependency =
true;
382 edgeHasDataDependency =
true;
384 pathsOnEdge.insert(dependency);
386 auto const& pathIndicies = m_pathIndexToModuleIndexOrder[dependency];
387 auto pathToCheckRange = pathToModulesWhichMustAppearLater.equal_range(dependency);
388 for (
auto it = pathToCheckRange.first; it != pathToCheckRange.second;) {
389 auto moduleIDToCheck = it->second;
390 if (moduleIDToCheck ==
in or moduleIDToCheck ==
out) {
393 pathToModulesWhichMustAppearLater.erase(toErase);
396 bool alreadyAdvanced =
false;
397 for (
auto pathIndex : pathIndicies) {
398 if (pathIndex ==
out) {
403 alreadyAdvanced =
true;
404 pathToModulesWhichMustAppearLater.erase(toErase);
407 if (pathIndex == moduleIDToCheck) {
412 if (not alreadyAdvanced) {
418 sharedPaths = intersect(pathsOnEdge, lastPathsSeen);
419 if (sharedPaths.empty()) {
420 minimumInitialPathsSet =
true;
421 if ((not edgeHasDataDependency) and (not lastEdgeHasDataDepencency) and (not lastPathsSeen.empty())) {
427 if (edgeHasDataDependency and not lastPathsSeen.empty()) {
430 bool atLeastOnePathFailed =
false;
431 std::vector<unsigned int> pathsToWatch;
432 pathsToWatch.reserve(lastPathsSeen.size());
433 for (
auto seenPath : lastPathsSeen) {
434 if (pathsOnEdge.end() == pathsOnEdge.find(seenPath)) {
437 bool foundOut =
false;
438 for (
auto seenPathIndex : m_pathIndexToModuleIndexOrder[seenPath]) {
439 if (seenPathIndex ==
out) {
441 pathsToWatch.push_back(seenPath);
443 if (seenPathIndex == lastOut) {
445 atLeastOnePathFailed =
true;
449 if (atLeastOnePathFailed) {
458 if (not atLeastOnePathFailed) {
459 moduleAppearedEarlierInPath =
true;
460 for (
auto p : pathsToWatch) {
461 pathToModulesWhichMustAppearLater.emplace(
p,
out);
465 lastPathsSeen = pathsOnEdge;
467 lastPathsSeen = sharedPaths;
468 if (not minimumInitialPathsSet) {
469 initialPaths = sharedPaths;
473 lastEdgeHasDataDepencency = edgeHasDataDependency;
475 if (moduleAppearedEarlierInPath and not pathToModulesWhichMustAppearLater.empty()) {
478 if (not hasDataDependency) {
481 if ((not initialPaths.empty()) and intersect(initialPaths, sharedPaths).empty()) {
487 throwOnError(iCycleEdges,
index, iGraph);
491 std::vector<std::vector<unsigned int>>
const& m_pathIndexToModuleIndexOrder;
492 std::vector<std::string>
const& m_pathNames;
493 std::unordered_map<unsigned int, std::string> m_indexToNames;
494 std::unordered_map<unsigned int, std::vector<unsigned int>> m_pathToModuleIndex;
496 std::vector<Edge> m_stack;
497 std::vector<std::vector<Edge>> m_fundamentalCycles;
498 std::set<unsigned int> m_verticiesInFundamentalCycles;
503 std::vector<std::vector<unsigned int>>
const& iPathIndexToModuleIndexOrder,
504 std::vector<std::string>
const& iPathNames,
505 std::unordered_map<unsigned int, std::string>
const& iModuleIndexToNames) {
507 std::vector<SimpleEdge> outList;
508 outList.reserve(iEdgeToPathMap.size());
509 for (
auto const& edgeInfo : iEdgeToPathMap) {
510 outList.push_back(edgeInfo.first);
513 Graph g(outList.begin(), outList.end(), iModuleIndexToNames.size());
515 cycle_detector
detector(iEdgeToPathMap, iPathIndexToModuleIndexOrder, iPathNames, iModuleIndexToNames);
516 boost::depth_first_search(
g, boost::visitor(
detector));