diff --git a/.gitignore b/.gitignore index ac796da..7fb050f 100644 --- a/.gitignore +++ b/.gitignore @@ -24,6 +24,3 @@ x86/ *.vcxproj *.vcxproj.user *.vcxproj.filters - -*.pdf -*.pptx \ No newline at end of file diff --git a/algorithm/tarjan.h b/algorithm/tarjan.h new file mode 100644 index 0000000..3a72da6 --- /dev/null +++ b/algorithm/tarjan.h @@ -0,0 +1,74 @@ +#ifndef TARJAN_H_ +#define TARJAN_H_ + +#include "graph/graph.h" +using namespace graph; + +#include +#include +#include +#include +#include + +namespace algorithm { + +template +class Tarjan { +public: + Tarjan(Graph G) : G(G) {} + + void findSCC(); + + void strongConnect(Vertex& v); + + std::uint16_t index = 0; + std::stack> S; +private: + Graph G; +}; + +template +void Tarjan::strongConnect(Vertex& v) { + v.index, v.lowlink = index++; + v.onStack = true; + S.push(v); + + for (auto& w : v.edges) { + if (w.index == -1) { + // successor w has not yet been visited, recurse on it + strongConnect(w); + v.lowlink = std::min(v.lowlink, w.lowlink); + } else if (w.onStack) { + // successor w is in stack S and hence in the current SCC + // if w is not on stack, then (v, w) is an edge pointing to an SCC + // already found and must be ignored + v.lowlink = std::min(v.lowlink, w.index); + } + } + + // if v is a root node, pop the stack and generate an SCC + if (v.lowlink = v.index) { + // start a new SCC + Vertex w; + do { + w = S.top(); + S.pop(); + // add w to current SCC + + } while (w != v); + } +} + +template +void Tarjan::findSCC() { + + for (auto& vertex : G.vertices) { + if (vertex.index == -1) { + strongConnect(vertex); + } + } +} + +} // namespace algorithm + +#endif \ No newline at end of file diff --git a/doc/IMPROVED DYNAMIC REACHABILITY ALGORITHMS.pdf b/doc/IMPROVED DYNAMIC REACHABILITY ALGORITHMS.pdf new file mode 100644 index 0000000..797cbdd Binary files /dev/null and b/doc/IMPROVED DYNAMIC REACHABILITY ALGORITHMS.pdf differ diff --git a/graph/graph.h b/graph/graph.h new file mode 100644 index 0000000..a661953 --- /dev/null +++ b/graph/graph.h @@ -0,0 +1,65 @@ +#ifndef GRAPH_H_ +#define GRAPH_H_ + +#include "vertex.h" + +#include +#include +#include +#include + +namespace graph { + +template +class Graph { +public: + Graph() = default; + + // Add vertex v + void insert(Vertex& v); + + // Add edge between v and u + void insert(Vertex v, Vertex u); + + // Delete vertex v + void erase(Vertex& v); + + // Delete edge between v and u + void erase(Vertex& v, Vertex& u); + + // Return true if v and u are connected + bool connected(const Vertex& v, const Vertex& u) const; + + // Adjacency matrix representation + std::vector> vertices; +}; + +template +inline void Graph::insert(Vertex& v) { + vertices.push_back(v); +} + +template +inline void Graph::insert(Vertex v, Vertex u) { + v.edges.push_back(u); + vertices.push_back(v); +} + +template +inline void Graph::erase(Vertex& v) { + // +} + +template +inline void Graph::erase(Vertex& v, Vertex& u) { + // +} + +template +inline bool Graph::connected(const Vertex& v, const Vertex& u) const { + return false; +} + +} // namespace graph + +#endif \ No newline at end of file diff --git a/graph/vertex.h b/graph/vertex.h new file mode 100644 index 0000000..9d447ee --- /dev/null +++ b/graph/vertex.h @@ -0,0 +1,36 @@ +#ifndef VERTEX_H_ +#define VERTEX_H_ + +#include +#include +#include +#include + +namespace graph { + +template +class Vertex { +public: + Vertex() = default; + Vertex(T v) : v(v) {} + + T v; + std::uint16_t index = -1; + std::uint16_t lowlink = -1; + bool onStack = false; + std::vector> edges; + + auto operator<=>(const Vertex&) const = default; + + template + friend inline std::ostream& operator<<(std::ostream& os, const Vertex& v); +}; + +template +inline std::ostream& operator<<(std::ostream& os, const Vertex& vout) { + return os << vout.v; +} + +} // namespace graph + +#endif \ No newline at end of file diff --git a/include/graph.h b/include/graph.h deleted file mode 100644 index a90bd60..0000000 --- a/include/graph.h +++ /dev/null @@ -1,61 +0,0 @@ -#ifndef GRAPH_H_ -#define GRAPH_H_ - -#include -#include -#include -#include - -namespace graph { - -template -class Graph { -public: - Graph() = default; - - // Add vertex v - void insert(const V& v); - - // Add edge between v and u - void insert(const V& v, const V& u); - - // Delete vertex v - void erase(const V& v); - - // Delete edge between v and u - void erase(const V& v, const V& u); - - // Return true if v and u are connected - bool connected(const V& v, const V& u); -private: - std::map> adjacency; -}; - -template -inline void Graph::insert(const V& v) { - adjacency[v]; -} - -template -inline void Graph::insert(const V& v, const V& u) { - adjacency[v].insert(u); -} - -template -inline void Graph::erase(const V& v) { - adjacency.erase(v); -} - -template -inline void Graph::erase(const V& v, const V& u) { - adjacency[v].erase(u); -} - -template -inline bool Graph::connected(const V& v, const V& u) { - return true; -} - -} // namespace graph - -#endif \ No newline at end of file diff --git a/test/graph_test.cc b/test/graph_test.cc index 7ec5bb4..7720b65 100644 --- a/test/graph_test.cc +++ b/test/graph_test.cc @@ -1,11 +1,13 @@ #include -#include +#include "graph/graph.h" +using namespace graph; +#include "algorithm/tarjan.h" -#include "include/graph.h" +#include +#include TEST_SUITE("Testing Graph.") { - using namespace graph; TEST_CASE("Insert vertices/edges.") { Graph G; @@ -19,6 +21,12 @@ TEST_SUITE("Testing Graph.") { G.insert(3, 6); G.insert(4, 6); G.insert(5, 6); + + Vertex v1(1); + Vertex v2(3); + Vertex v3(5); + algorithm::Tarjan tarjan(G); + tarjan.findSCC(); // CHECK_EQ(G.connected(1, 5), true);