From 6f090e22c0da75e7447edafc82adaec5d123e263 Mon Sep 17 00:00:00 2001 From: Antonin Portelli Date: Wed, 2 Dec 2015 19:33:34 +0000 Subject: [PATCH] Hadrons: graph topological sort --- programs/Hadrons/Application.cc | 29 +++-- programs/Hadrons/Global.hpp | 1 + programs/Hadrons/Graph.hpp | 203 +++++++++++++++++++++++++++++--- 3 files changed, 205 insertions(+), 28 deletions(-) diff --git a/programs/Hadrons/Application.cc b/programs/Hadrons/Application.cc index 5cbd1baa..923bd0eb 100644 --- a/programs/Hadrons/Application.cc +++ b/programs/Hadrons/Application.cc @@ -57,29 +57,32 @@ void Application::run(void) { Graph g; - cout << g << endl; g.addEdge("A", "B"); g.addEdge("B", "D"); g.addEdge("D", "E"); g.addEdge("E", "C"); - g.addEdge("C", "A"); g.addEdge("Z", "Y"); g.addEdge("Z", "W"); g.addEdge("Z", "R"); g.addEdge("W", "R"); - auto v = g.getAdjacentVertices("B"); - for (auto &s: v) + g.addEdge("U", "I"); + + cout << g << endl; + auto vec = g.getConnectedComponents(); + for (auto &h: vec) { - cout << s << " "; + cout << h << endl; + } + for (auto &h: vec) + { + auto top = h.topoSort(); + while (!top.empty()) + { + cout << top.top() << " "; + top.pop(); + } + cout << endl; } - cout << endl; - cout << g << endl; - g.depthFirstSearch(); - g.removedMarked(); - cout << g << endl; - g.depthFirstSearch(); - g.removedMarked(); - cout << g << endl; } // parse parameter file //////////////////////////////////////////////////////// diff --git a/programs/Hadrons/Global.hpp b/programs/Hadrons/Global.hpp index 44c395db..3b90b7ed 100644 --- a/programs/Hadrons/Global.hpp +++ b/programs/Hadrons/Global.hpp @@ -22,6 +22,7 @@ #include #include +#include #define BEGIN_HADRONS_NAMESPACE \ namespace Hadrons {\ diff --git a/programs/Hadrons/Graph.hpp b/programs/Hadrons/Graph.hpp index 802812c7..e96c22b9 100644 --- a/programs/Hadrons/Graph.hpp +++ b/programs/Hadrons/Graph.hpp @@ -48,17 +48,22 @@ public: // destructor virtual ~Graph(void) = default; // access - void addVertex(const T &value); - void addEdge(const Edge &e); - void addEdge(const T &start, const T &end); - void removeVertex(const T &value); - void removeEdge(const Edge &e); - void removeEdge(const T &start, const T &end); + void addVertex(const T &value); + void addEdge(const Edge &e); + void addEdge(const T &start, const T &end); + void removeVertex(const T &value); + void removeEdge(const Edge &e); + void removeEdge(const T &start, const T &end); + unsigned int size(void) const; // tests bool gotValue(const T &value) const; // graph topological manipulations std::vector getAdjacentVertices(const T &value) const; + std::vector getChildren(const T &value) const; + std::vector getParents(const T &value) const; + std::vector getRoots(void) const; std::vector> getConnectedComponents(void) const; + std::stack topoSort(void); // I/O friend std::ostream & operator<<(std::ostream &out, const Graph &g) { @@ -75,14 +80,18 @@ public: return out; } -public: +private: // vertex marking - void mark(const T &value, const bool doMark = true); - void unmark(const T &value); - bool isMarked(const T &value) const; + void mark(const T &value, const bool doMark = true); + void markAll(const bool doMark = true); + void unmark(const T &value); + void unmarkAll(void); + bool isMarked(const T &value) const; + const T * getFirstMarked(const bool isMarked = true) const; + const T * getFirstUnmarked(void) const; // prune marked/unmarked vertices - void removedMarked(const bool isMarked = true); - void removedUnmarked(void); + void removeMarked(const bool isMarked = true); + void removeUnmarked(void); // depth-first search marking void depthFirstSearch(void); void depthFirstSearch(const T &root); @@ -165,6 +174,12 @@ void Graph::removeEdge(const T &start, const T &end) removeEdge(Edge(start, end)); } +template +unsigned int Graph::size(void) const +{ + return isMarked_.size(); +} + // tests /////////////////////////////////////////////////////////////////////// template bool Graph::gotValue(const T &value) const @@ -195,12 +210,27 @@ void Graph::mark(const T &value, const bool doMark) } } +template +void Graph::markAll(const bool doMark) +{ + for (auto &v: isMarked_) + { + mark(v.first, doMark); + } +} + template void Graph::unmark(const T &value) { mark(value, false); } +template +void Graph::unmarkAll(void) +{ + markAll(false); +} + template bool Graph::isMarked(const T &value) const { @@ -216,9 +246,34 @@ bool Graph::isMarked(const T &value) const } } +template +const T * Graph::getFirstMarked(const bool isMarked) const +{ + auto pred = [&isMarked](const std::pair &v) + { + return (v.second == isMarked); + }; + auto vIt = std::find_if(isMarked_.begin(), isMarked_.end(), pred); + + if (vIt != isMarked_.end()) + { + return &(vIt->first); + } + else + { + return nullptr; + } +} + +template +const T * Graph::getFirstUnmarked(void) const +{ + return getFirstMarked(false); +} + // prune marked/unmarked vertices ////////////////////////////////////////////// template -void Graph::removedMarked(const bool isMarked) +void Graph::removeMarked(const bool isMarked) { auto isMarkedCopy = isMarked_; @@ -232,9 +287,9 @@ void Graph::removedMarked(const bool isMarked) } template -void Graph::removedUnmarked(void) +void Graph::removeUnmarked(void) { - removedMarked(false); + removeMarked(false); } // depth-first search marking ////////////////////////////////////////////////// @@ -288,10 +343,128 @@ std::vector Graph::getAdjacentVertices(const T &value) const return adjacentVertex; } +template +std::vector Graph::getChildren(const T &value) const +{ + std::vector child; + + auto pred = [&value](const Edge &e) + { + return (e.first == value); + }; + auto eIt = find_if(edgeSet_.begin(), edgeSet_.end(), pred); + + while (eIt != edgeSet_.end()) + { + child.push_back((*eIt).second); + eIt = find_if(++eIt, edgeSet_.end(), pred); + } + + return child; +} + +template +std::vector Graph::getParents(const T &value) const +{ + std::vector parent; + + auto pred = [&value](const Edge &e) + { + return (e.second == value); + }; + auto eIt = find_if(edgeSet_.begin(), edgeSet_.end(), pred); + + while (eIt != edgeSet_.end()) + { + parent.push_back((*eIt).first); + eIt = find_if(++eIt, edgeSet_.end(), pred); + } + + return parent; +} + +template +std::vector Graph::getRoots(void) const +{ + std::vector root; + + for (auto &v: isMarked_) + { + auto parent = getParents(v.first); + + if (parent.size() == 0) + { + root.push_back(v.first); + } + } + + return root; +} + template std::vector> Graph::getConnectedComponents(void) const { + std::vector> res; + Graph copy(*this); + while (copy.size() > 0) + { + copy.depthFirstSearch(); + res.push_back(copy); + res.back().removeUnmarked(); + res.back().unmarkAll(); + copy.removeMarked(); + copy.unmarkAll(); + } + + return res; +} + +// topological sort using Kahn's algorithm +template +std::stack Graph::topoSort(void) +{ + std::stack res; + const T *vPt; + std::map tmpMarked(isMarked_); + + // visit function + std::function visit = [&](const T &v) + { + if (tmpMarked.at(v)) + { + HADRON_ERROR("cannot topologically sort a cyclic graph"); + } + if (!this->isMarked(v)) + { + std::vector child = this->getChildren(v); + + tmpMarked[v] = true; + for (auto &c: child) + { + visit(c); + } + this->mark(v); + tmpMarked[v] = false; + res.push(v); + } + }; + + // reset temporary marks + for (auto &v: tmpMarked) + { + tmpMarked.at(v.first) = false; + } + // loop on unmarked vertices + vPt = getFirstUnmarked(); + while (vPt) + { + visit(*vPt); + vPt = getFirstUnmarked(); + } + unmarkAll(); + + return res; } END_HADRONS_NAMESPACE