From 3951db7ff9c062f1542936cfe28611297eafefea Mon Sep 17 00:00:00 2001 From: stefiosif Date: Sat, 3 Aug 2024 13:14:42 +0300 Subject: [PATCH] Use clang-format --- benchmark/algorithm_bench.cc | 2 + include/algorithm/breadth_first_search.h | 34 +++-- include/algorithm/decremental_reachability.h | 11 +- include/algorithm/dynamic_reachability.h | 6 +- include/algorithm/frigioni.h | 143 ++++++++++--------- include/algorithm/henzinger_king.h | 38 +++-- include/algorithm/italiano.h | 59 ++++---- include/algorithm/king.h | 44 +++--- include/algorithm/roditty_zwick.h | 47 +++--- include/algorithm/tarjan.h | 27 ++-- include/graph/breadth_first_tree.h | 16 +-- include/graph/digraph.h | 48 +++---- include/graph/graph.h | 34 ++--- include/graph/scc.h | 32 ++--- include/roditty_zwick.h | 4 +- test/decremental_reachability_test.cc | 2 + test/dynamic_reachability_test.cc | 2 + 17 files changed, 262 insertions(+), 287 deletions(-) diff --git a/benchmark/algorithm_bench.cc b/benchmark/algorithm_bench.cc index 09b3a75..ee2e7fe 100644 --- a/benchmark/algorithm_bench.cc +++ b/benchmark/algorithm_bench.cc @@ -1,3 +1,4 @@ + #include #include @@ -8,6 +9,7 @@ #include #include #include +#include using namespace graph; diff --git a/include/algorithm/breadth_first_search.h b/include/algorithm/breadth_first_search.h index c82441d..66e4b43 100644 --- a/include/algorithm/breadth_first_search.h +++ b/include/algorithm/breadth_first_search.h @@ -1,35 +1,38 @@ #ifndef BREADTH_FIRST_SEARCH_H_ #define BREADTH_FIRST_SEARCH_H_ +#include "graph/graph.h" #include -#include #include +#include using namespace graph; namespace algo { -template -class BreadthFirstSearch { +template class BreadthFirstSearch { public: BreadthFirstSearch() = default; - explicit BreadthFirstSearch(std::unordered_map> adjList) - : adjList(adjList) {} + explicit BreadthFirstSearch( + std::unordered_map> adjList) + : adjList(adjList) {} // Traverse whole graph using the BFS search, and save the tree graph // which is created when visiting new vertices (Breadth First Tree) - std::unordered_map> execute(const T& root); + std::unordered_map> execute(const T &root); // Search if target vertex exists in graph - bool query(const T& root, const T& target); + bool query(const T &root, const T &target); + private: // Represents the graph on which the algorithm will be executed std::unordered_map> adjList; -}; +}; -template -std::unordered_map> BreadthFirstSearch::execute(const T& root) { +template +std::unordered_map> +BreadthFirstSearch::execute(const T &root) { std::unordered_map> tree; std::unordered_map visited; std::queue Q; @@ -40,7 +43,7 @@ std::unordered_map> BreadthFirstSearch::execute(cons const auto v = Q.front(); Q.pop(); - for (const auto& u : adjList[v]) { + for (const auto &u : adjList[v]) { if (!visited[u]) { visited[u] = true; tree[v].insert(u); @@ -52,8 +55,8 @@ std::unordered_map> BreadthFirstSearch::execute(cons return tree; } -template -bool BreadthFirstSearch::query(const T& root, const T& target) { +template +bool BreadthFirstSearch::query(const T &root, const T &target) { std::unordered_map visited; std::queue Q; Q.push(root); @@ -63,9 +66,10 @@ bool BreadthFirstSearch::query(const T& root, const T& target) { const auto v = Q.front(); Q.pop(); - if (v == target) return true; + if (v == target) + return true; - for (const auto& u : adjList[v]) { + for (const auto &u : adjList[v]) { if (!visited[u]) { visited[u] = true; Q.push(u); diff --git a/include/algorithm/decremental_reachability.h b/include/algorithm/decremental_reachability.h index c09ffcb..2792f53 100644 --- a/include/algorithm/decremental_reachability.h +++ b/include/algorithm/decremental_reachability.h @@ -4,21 +4,20 @@ #include "graph/digraph.h" namespace algo { - -template -class DecrementalReachability { +template class DecrementalReachability { public: virtual ~DecrementalReachability() = default; // This method is implemented and executed by all roditty and zwick // algorithms, it constructs the data structures used in other operations - virtual void init() =0; + virtual void init() = 0; // Answer if vertex v is reachable from vertex u - virtual bool query(const T& u, const T& v) =0; + virtual bool query(const T &u, const T &v) = 0; // Remove edge e(u,v) and maintain the transitive closure matrix - virtual void remove(const std::vector>& edges) =0; + virtual void remove(const std::vector> &edges) = 0; + protected: Digraph G; }; diff --git a/include/algorithm/dynamic_reachability.h b/include/algorithm/dynamic_reachability.h index 2ce7cb8..54bb356 100644 --- a/include/algorithm/dynamic_reachability.h +++ b/include/algorithm/dynamic_reachability.h @@ -4,15 +4,13 @@ #include "algorithm/decremental_reachability.h" namespace algo { - -template +template class DynamicReachability : public DecrementalReachability { // Insert edge e(u,v) and maintain the transitive closure matrix - virtual void insert(const T& c, const std::vector& vertices) =0; + virtual void insert(const T &c, const std::vector &vertices) = 0; }; - } // namespace algo #endif \ No newline at end of file diff --git a/include/algorithm/frigioni.h b/include/algorithm/frigioni.h index 90e4c49..3adf39a 100644 --- a/include/algorithm/frigioni.h +++ b/include/algorithm/frigioni.h @@ -8,8 +8,7 @@ namespace algo { -template -class Frigioni : public DecrementalReachability { +template class Frigioni : public DecrementalReachability { public: Frigioni() = default; @@ -20,10 +19,11 @@ public: // Execute reachability query q(u, v) from vertex u to vertex v // in O(1) using the transitive closure matrix - bool query(const T& u, const T& v) override; + bool query(const T &u, const T &v) override; // Delete set of edges and explicitely maintain the transitive closure - void remove(const std::vector>& edges) override; + void remove(const std::vector> &edges) override; + private: // Transitive closure matrix, used to answer reachability queries in O(1) std::unordered_map> TC; @@ -46,161 +46,162 @@ private: RodittyZwick rodittyZwick; // Delete internal edge e(u, v) - void removeInternal(const T& u, const T& v); + void removeInternal(const T &u, const T &v); // Delete external edge e(u, v) - void removeExternal(const T& u, const T& v); + void removeExternal(const T &u, const T &v); // Repair reachability trees void repairTrees(); - // - void splitEdges(std::unordered_map>& L, std::unordered_map> C, const T& w); + // + void splitEdges(std::unordered_map> &L, + std::unordered_map> C, const T &w); }; -template -void Frigioni::init() { +template void Frigioni::init() { rodittyZwick = RodittyZwick(this->G); rodittyZwick.init(); auto C = rodittyZwick.getComponentMap(); - for (const auto& w : std::views::keys(C)) { + for (const auto &w : std::views::keys(C)) { RT[C[w]] = BreadthFirstTree(this->G, w); - for (const auto& u : this->G.vertices()) { - for (const auto& v : this->G.adjList[u]) { + for (const auto &u : this->G.vertices()) { + for (const auto &v : this->G.adjList[u]) { if (!C[w].contains(u) && C[w].contains(v)) - E[C[w]].inc.insert({ u, v }); + E[C[w]].inc.insert({u, v}); else if (C[w].contains(u) && !C[w].contains(v)) - E[C[w]].out.insert({ u, v }); + E[C[w]].out.insert({u, v}); else - E[C[w]].in.insert({ u, v }); + E[C[w]].in.insert({u, v}); TC[u][v] = false; } } } - for (const auto& w : std::views::keys(C)) { - for (const auto& u : C[w].vertices()) { - for (const auto& v : RT[C[w]].vertices()) { + for (const auto &w : std::views::keys(C)) { + for (const auto &u : C[w].vertices()) { + for (const auto &v : RT[C[w]].vertices()) { TC[u][v] = true; } } } } -template -bool Frigioni::query(const T& u, const T& v) { +template bool Frigioni::query(const T &u, const T &v) { return TC[u][v]; } -template -void Frigioni::remove(const std::vector>& edges) { +template +void Frigioni::remove(const std::vector> &edges) { std::vector> Eint; std::vector> Eext; - for (const auto& [u, v] : edges) { - if (!this->G.adjList[u].contains(v)) continue; + for (const auto &[u, v] : edges) { + if (!this->G.adjList[u].contains(v)) + continue; if (rodittyZwick.query(u, v)) - Eint.push_back({ u, v }); + Eint.push_back({u, v}); else - Eext.push_back({ u, v }); + Eext.push_back({u, v}); } - for (const auto& [u, v] : Eint) removeInternal(u, v); - for (const auto& [u, v] : Eext) removeExternal(u, v); + for (const auto &[u, v] : Eint) + removeInternal(u, v); + for (const auto &[u, v] : Eext) + removeExternal(u, v); repairTrees(); } -template -void Frigioni::removeInternal(const T& u, const T& v) { +template void Frigioni::removeInternal(const T &u, const T &v) { this->G.remove(u, v); auto L = rodittyZwick.getComponentMap(); rodittyZwick.remove(u, v); auto C = rodittyZwick.getComponentMap(); if (rodittyZwick.query(u, v)) { - E[C[u]].in.erase({ u, v }); + E[C[u]].in.erase({u, v}); return; } if (L[u] == C[u]) { - E[L[u]].out.erase({ u, v }); + E[L[u]].out.erase({u, v}); E.erase(L[v]); splitEdges(L, C, v); - } - else { - E[L[v]].inc.erase({ u, v }); + } else { + E[L[v]].inc.erase({u, v}); E.erase(L[u]); splitEdges(L, C, u); } - for (const auto& w : std::views::keys(C)) { - if (!RT[C[w]].contains(v)) continue; + for (const auto &w : std::views::keys(C)) { + if (!RT[C[w]].contains(v)) + continue; RT[C[w]].removeEdgeTo(v); if (E[C[v]].inc.size() > 0) { H[C[w]].push(v); /*h mipos C[v].id?*/ continue; } - for (const auto& x : C[w].vertices()) { - for (const auto& y : C[v].vertices()) { + for (const auto &x : C[w].vertices()) { + for (const auto &y : C[v].vertices()) { TC[x][y] = false; } } - for (const auto& [a, b] : E[C[v]].out) + for (const auto &[a, b] : E[C[v]].out) H[C[w]].push(b); } } -template -void Frigioni::removeExternal(const T& u, const T& v) { +template void Frigioni::removeExternal(const T &u, const T &v) { this->G.remove(u, v); auto C = rodittyZwick.getComponentMap(); - E[C[v]].inc.erase({ u, v }); - E[C[u]].out.erase({ u, v }); + E[C[v]].inc.erase({u, v}); + E[C[u]].out.erase({u, v}); - for (const auto& w : std::views::keys(C)) { - if (!RT[C[w]].contains(v)) continue; + for (const auto &w : std::views::keys(C)) { + if (!RT[C[w]].contains(v)) + continue; RT[C[w]].removeEdgeTo(v); if (E[C[v]].inc.size() > 0) { H[C[w]].push(v); continue; } - for (const auto& x : C[w].vertices()) { - for (const auto& y : C[v].vertices()) { + for (const auto &x : C[w].vertices()) { + for (const auto &y : C[v].vertices()) { TC[x][y] = false; } } - for (const auto& [a, b] : E[C[v]].out) + for (const auto &[a, b] : E[C[v]].out) H[C[w]].push(b); } } -template -void Frigioni::repairTrees() { +template void Frigioni::repairTrees() { auto C = rodittyZwick.getComponentMap(); - for (const auto& w : std::views::keys(C)) { + for (const auto &w : std::views::keys(C)) { while (H[C[w]].size() > 0) { - const auto& h = H[C[w]].top(); + const auto &h = H[C[w]].top(); H[C[w]].pop(); bool foundHook = false; - for (const auto& [a, b] : E[C[h]].inc) { + for (const auto &[a, b] : E[C[h]].inc) { if (RT[C[w]].adjList[w].contains(a)) { RT[C[w]].insert(a, h); foundHook = true; break; } } - if (foundHook) continue; + if (foundHook) + continue; - for (const auto& x : C[w].vertices()) { - for (const auto& y : C[h].vertices()) { + for (const auto &x : C[w].vertices()) { + for (const auto &y : C[h].vertices()) { TC[x][y] = false; } } - for (const auto& [a, b] : E[C[h]].out) { + for (const auto &[a, b] : E[C[h]].out) { if (RT[C[w]].adjList[h].contains(a)) { H[C[w]].push(b); } @@ -209,21 +210,21 @@ void Frigioni::repairTrees() { } } -template -void Frigioni::splitEdges(std::unordered_map>& L, std::unordered_map> C, const T& w) { - for (const auto& [a, b] : E[L[w]].inc) - E[C[b]].inc.insert({ a, b }); +template +void Frigioni::splitEdges(std::unordered_map> &L, + std::unordered_map> C, const T &w) { + for (const auto &[a, b] : E[L[w]].inc) + E[C[b]].inc.insert({a, b}); - for (const auto& [a, b] : E[L[w]].out) - E[C[a]].out.insert({ a, b }); + for (const auto &[a, b] : E[L[w]].out) + E[C[a]].out.insert({a, b}); - for (const auto& [a, b] : E[L[w]].in) { + for (const auto &[a, b] : E[L[w]].in) { if (C[a] == C[b]) { - E[C[a]].in.insert({ a, b }); - } - else { - E[C[a]].out.insert({ a, b }); - E[C[b]].in.insert({ a, b }); + E[C[a]].in.insert({a, b}); + } else { + E[C[a]].out.insert({a, b}); + E[C[b]].in.insert({a, b}); } } } diff --git a/include/algorithm/henzinger_king.h b/include/algorithm/henzinger_king.h index 95031a8..bfb6e0d 100644 --- a/include/algorithm/henzinger_king.h +++ b/include/algorithm/henzinger_king.h @@ -8,8 +8,7 @@ constexpr int threshold = 5; namespace algo { -template -class HenzingerKing : public DynamicReachability { +template class HenzingerKing : public DynamicReachability { public: HenzingerKing() = default; @@ -21,16 +20,17 @@ public: // Execute query q(u, v) from vertex u to vertex v by querying the // decremental reachability data structure at the start of the phase // and then if necessary check the set S - bool query(const T& u, const T& v) override; + bool query(const T &u, const T &v) override; // Remove collection of edges from the decremental maintenance data structure // and for every vertex in set S, rebuilt reachability trees from scratch - void remove(const std::vector>& edges); + void remove(const std::vector> &edges) override; // Insert collection of edges in set S, if threshold is reached re-initialize // algorithm, otherwise construct reachability trees for the vertex that is // the center-of-insertions - void insert(const T& c, const std::vector& vertices); + void insert(const T &c, const std::vector &vertices) override; + private: // Decremental maintenance data structure Frigioni frigioni; @@ -43,41 +43,37 @@ private: std::unordered_map> Out; }; -template -void HenzingerKing::init() { +template void HenzingerKing::init() { S.clear(); frigioni = Frigioni(this->G); frigioni.init(); } -template -bool HenzingerKing::query(const T& u, const T& v) { +template bool HenzingerKing::query(const T &u, const T &v) { if (frigioni.query(u, v)) return true; - return std::ranges::any_of(S.begin(), S.end(), - [&](const T& w) { - return In[w].adjList.contains(u) && - Out[w].adjList.contains(v); - }); + return std::ranges::any_of(S.begin(), S.end(), [&](const T &w) { + return In[w].adjList.contains(u) && Out[w].adjList.contains(v); + }); } -template -void HenzingerKing::remove(const std::vector>& edges) { - for (const auto& [u, v] : edges) { +template +void HenzingerKing::remove(const std::vector> &edges) { + for (const auto &[u, v] : edges) { this->G.remove(u, v); } frigioni.remove(edges); - for (const auto& w : S) { + for (const auto &w : S) { In[w] = BreadthFirstTree(this->G.reverse(), w); Out[w] = BreadthFirstTree(this->G, w); } } -template -void HenzingerKing::insert(const T& c, const std::vector& vertices) { - for (const auto& w : vertices) +template +void HenzingerKing::insert(const T &c, const std::vector &vertices) { + for (const auto &w : vertices) this->G.insert(c, w); S.insert(c); diff --git a/include/algorithm/italiano.h b/include/algorithm/italiano.h index af78723..e9eda89 100644 --- a/include/algorithm/italiano.h +++ b/include/algorithm/italiano.h @@ -7,8 +7,7 @@ namespace algo { -template -class Italiano : public DecrementalReachability { +template class Italiano : public DecrementalReachability { public: Italiano() = default; @@ -19,17 +18,18 @@ public: // Execute reachability query q(u, v) from vertex u to vertex v // in O(1) using the transitive closure matrix - bool query(const T& u, const T& v) override; + bool query(const T &u, const T &v) override; // Delete collection of edges - void remove(const std::vector>& edges) override; + void remove(const std::vector> &edges) override; // Delete edge e(u, v) and explicitly maintain the transitive closure - void remove(const T& u, const T& v); + void remove(const T &u, const T &v); + private: // Transitive closure matrix std::unordered_map> TC; - + // For each vertex, store a reachability tree created as a BFS tree std::unordered_map> RT; @@ -47,42 +47,41 @@ private: void repairTrees(); }; -template -void Italiano::init() { - for (const auto& u : this->G.vertices()) { - for (const auto& v : this->G.adjList[u]) { +template void Italiano::init() { + for (const auto &u : this->G.vertices()) { + for (const auto &v : this->G.adjList[u]) { E[v].inc.insert(u); E[u].out.insert(v); TC[u][v] = false; } RT[u] = BreadthFirstTree(this->G, u); TC[u][u] = true; - for (const auto& v : RT[u].vertices()) + for (const auto &v : RT[u].vertices()) TC[u][v] = true; } } -template -bool Italiano::query(const T& u, const T& v) { +template bool Italiano::query(const T &u, const T &v) { return TC[u][v]; } -template -void Italiano::remove(const std::vector>& edges) { - for (const auto& [u, v] : edges) { - if (!this->G.adjList[u].contains(v)) continue; +template +void Italiano::remove(const std::vector> &edges) { + for (const auto &[u, v] : edges) { + if (!this->G.adjList[u].contains(v)) + continue; remove(u, v); } } -template -void Italiano::remove(const T& u, const T& v) { +template void Italiano::remove(const T &u, const T &v) { this->G.remove(u, v); E[u].out.erase(v); E[v].inc.erase(u); - - for (const auto& w : this->G.vertices()) { - if (!RT[w].adjList[u].contains(v)) continue; + + for (const auto &w : this->G.vertices()) { + if (!RT[w].adjList[u].contains(v)) + continue; RT[w].adjList[u].erase(v); if (E[v].inc.size() > 0) { @@ -90,31 +89,31 @@ void Italiano::remove(const T& u, const T& v) { continue; } TC[w][v] = false; - for (const auto& c : E[v].out) + for (const auto &c : E[v].out) H[w].push(c); } repairTrees(); } -template -void Italiano::repairTrees() { - for (const auto& w : this->G.vertices()) { +template void Italiano::repairTrees() { + for (const auto &w : this->G.vertices()) { while (H[w].size() > 0) { - const auto& h = H[w].top(); + const auto &h = H[w].top(); H[w].pop(); bool foundHook = false; - for (const auto& i : E[h].inc) { + for (const auto &i : E[h].inc) { if (RT[w].adjList[w].contains(i)) { RT[w].adjList[i].insert(h); foundHook = true; break; } } - if (foundHook) continue; + if (foundHook) + continue; TC[w][h] = false; - for (const auto& o : E[h].out) { + for (const auto &o : E[h].out) { if (RT[w].adjList[h].contains(o)) { H[w].push(o); } diff --git a/include/algorithm/king.h b/include/algorithm/king.h index 3ffd863..a2256fd 100644 --- a/include/algorithm/king.h +++ b/include/algorithm/king.h @@ -6,8 +6,7 @@ namespace algo { -template -class King : public DynamicReachability { +template class King : public DynamicReachability { public: King() = default; @@ -19,26 +18,26 @@ public: // Execute reachability query q(u, v) from vertex u to vertex v // in O(n) using the stored decremental maintenance data structure for DAGs - bool query(const T& u, const T& v) override; + bool query(const T &u, const T &v) override; // Delete collection of edges - void remove(const std::vector>& edges) override; + void remove(const std::vector> &edges) override; // Delete edge e(u, v) from all reachability trees and update each one of // them using the decremental reachability algorithm for DAGs - void remove(const T& u, const T& v); + void remove(const T &u, const T &v); // Insert edge e(u, v) by reconstructing all reachability trees - void insert(const T& c, const std::vector& vertices) override; + void insert(const T &c, const std::vector &vertices) override; + private: // Connect each reachabiliy tree with decremental maintenance data structure std::unordered_map> In; std::unordered_map> Out; }; -template -void King::init() { - for (const auto& u : this->G.vertices()) { +template void King::init() { + for (const auto &u : this->G.vertices()) { In[u] = Italiano(BreadthFirstTree(this->G.reverse(), u)); In[u].init(); Out[u] = Italiano(BreadthFirstTree(this->G, u)); @@ -46,32 +45,29 @@ void King::init() { } } -template -bool King::query(const T& u, const T& v) { - return std::ranges::any_of(this->G.vertices().begin(), this->G.vertices().end(), - [&](const T& w) { - return In[w].query(w, u) && Out[w].query(w, v); - }); +template bool King::query(const T &u, const T &v) { + return std::any_of( + this->G.vertices().begin(), this->G.vertices().end(), + [&](const T &w) { return In[w].query(w, u) && Out[w].query(w, v); }); } -template -void King::remove(const std::vector>& edges) { - for (const auto& [u, v] : edges) +template +void King::remove(const std::vector> &edges) { + for (const auto &[u, v] : edges) remove(u, v); } -template -void King::remove(const T& u, const T& v) { +template void King::remove(const T &u, const T &v) { this->G.remove(u, v); - for (const auto& w : this->G.vertices()) { + for (const auto &w : this->G.vertices()) { In[w].remove(v, u); Out[w].remove(u, v); } } -template -void King::insert(const T& c, const std::vector& vertices) { - for (const auto& v : vertices) { +template +void King::insert(const T &c, const std::vector &vertices) { + for (const auto &v : vertices) { this->G.insert(c, v); } In[c] = Italiano(BreadthFirstTree(this->G.reverse(), c)); diff --git a/include/algorithm/roditty_zwick.h b/include/algorithm/roditty_zwick.h index 4b83c2c..d957729 100644 --- a/include/algorithm/roditty_zwick.h +++ b/include/algorithm/roditty_zwick.h @@ -7,8 +7,7 @@ namespace algo { -template -class RodittyZwick : public DecrementalReachability { +template class RodittyZwick : public DecrementalReachability { public: RodittyZwick() = default; @@ -21,15 +20,16 @@ public: void findSCC(graph::Digraph G); // Return true if u and v are in the same SCC - bool query(const T& u, const T& v) override; + bool query(const T &u, const T &v) override; // Delete collection of edges - void remove(const std::vector>& edges) override; + void remove(const std::vector> &edges) override; // Remove edge (u,v) and update A accordingly for fast checking query - void remove(const T& u, const T& v); + void remove(const T &u, const T &v); std::unordered_map> getComponentMap() { return C; } + private: // Array used to answer strong connectivity queries in O(1) time std::unordered_map A; @@ -42,21 +42,17 @@ private: std::unordered_map> Out; }; -template -void RodittyZwick::init() { - findSCC(this->G); -} +template void RodittyZwick::init() { findSCC(this->G); } -template -void RodittyZwick::findSCC(graph::Digraph G) { +template void RodittyZwick::findSCC(graph::Digraph G) { auto SCCs = Tarjan(G.adjList).execute(); - - for (auto& c : SCCs) { - const auto& w = c.id; - for (const auto& v : c.vertices()) + for (auto &c : SCCs) { + const auto &w = c.id; + + for (const auto &v : c.vertices()) A[v] = w; - + Out[w] = BreadthFirstTree(c, w); In[w] = BreadthFirstTree(c.reverse(), w); @@ -64,20 +60,18 @@ void RodittyZwick::findSCC(graph::Digraph G) { } } -template -bool RodittyZwick::query(const T& u, const T& v) { +template bool RodittyZwick::query(const T &u, const T &v) { return A[u] == A[v]; } -template -void RodittyZwick::remove(const std::vector>& edges) { - for (const auto& [u, v] : edges) +template +void RodittyZwick::remove(const std::vector> &edges) { + for (const auto &[u, v] : edges) remove(u, v); } -template -void RodittyZwick::remove(const T& u, const T& v) { - const auto& w = A[u]; +template void RodittyZwick::remove(const T &u, const T &v) { + const auto &w = A[u]; C[w].remove(u, v); this->G.remove(u, v); @@ -85,8 +79,9 @@ void RodittyZwick::remove(const T& u, const T& v) { if (A[u] != A[v]) return; - // If edge (u,v) is not contained in both inTree and outTree do nothing TODO:remove useless comments - // is this not better if i utilize A matrix, since we are going traversing between components.. ? TODO + // If edge (u,v) is not contained in both inTree and outTree do nothing + // TODO:remove useless comments is this not better if i utilize A matrix, + // since we are going traversing between components.. ? TODO if (!In[w].adjList[u].contains(v) && !Out[w].adjList[u].contains(v)) return; diff --git a/include/algorithm/tarjan.h b/include/algorithm/tarjan.h index a3452bb..ff047c9 100644 --- a/include/algorithm/tarjan.h +++ b/include/algorithm/tarjan.h @@ -3,24 +3,25 @@ #include "graph/scc.h" +#include #include #include -#include namespace algo { -template -class Tarjan { +template class Tarjan { public: Tarjan() = default; - explicit Tarjan(std::unordered_map> adjList) : adjList(adjList) {} + explicit Tarjan(std::unordered_map> adjList) + : adjList(adjList) {} // auto execute(); - + // - void strongConnect(const T& u); + void strongConnect(const T &u); + private: std::unordered_map> adjList; std::stack S; @@ -36,13 +37,12 @@ private: std::unordered_map V; }; -template -void Tarjan::strongConnect(const T& u) { +template void Tarjan::strongConnect(const T &u) { V[u].index = V[u].lowlink = index++; S.push(u); V[u].onStack = true; - for (const auto& w : adjList[u]) { + for (const auto &w : adjList[u]) { if (V[w].index == -1) { strongConnect(w); V[u].lowlink = std::min(V[u].lowlink, V[w].lowlink); @@ -64,14 +64,13 @@ void Tarjan::strongConnect(const T& u) { scc[w] = adjList[w]; finished = (w == u); } while (!finished); - - SCCs.push_back({ scc, static_cast(cid) }); + + SCCs.push_back({scc, static_cast(cid)}); } } -template -auto Tarjan::execute() { - for (const auto& u : std::views::keys(adjList)) { +template auto Tarjan::execute() { + for (const auto &u : std::views::keys(adjList)) { if (V[u].index == -1) strongConnect(u); } diff --git a/include/graph/breadth_first_tree.h b/include/graph/breadth_first_tree.h index 197157c..cabfb56 100644 --- a/include/graph/breadth_first_tree.h +++ b/include/graph/breadth_first_tree.h @@ -5,30 +5,28 @@ namespace graph { -template -class BreadthFirstTree : public Digraph { +template class BreadthFirstTree : public Digraph { public: BreadthFirstTree() = default; BreadthFirstTree(std::unordered_map> G, T root) - : BreadthFirstTree(Digraph(G), root) {} + : BreadthFirstTree(Digraph(G), root) {} BreadthFirstTree(Digraph G, T root); - void removeEdgeTo(const T& u); + void removeEdgeTo(const T &u); T root{}; }; -template +template BreadthFirstTree::BreadthFirstTree(Digraph G, T root) { this->adjList = algo::BreadthFirstSearch(G.adjList).execute(root); } -template -void BreadthFirstTree::removeEdgeTo(const T& u) { - for (const auto& x : this->vertices()) { - for (const auto& y : this->adjList[x]) { +template void BreadthFirstTree::removeEdgeTo(const T &u) { + for (const auto &x : this->vertices()) { + for (const auto &y : this->adjList[x]) { if (y == u) { this->remove(x, u); return; diff --git a/include/graph/digraph.h b/include/graph/digraph.h index 9a88d98..00119bf 100644 --- a/include/graph/digraph.h +++ b/include/graph/digraph.h @@ -1,64 +1,59 @@ #ifndef DIGRAPH_H_ #define DIGRAPH_H_ -#include "graph.h" #include "algorithm/breadth_first_search.h" +#include "graph.h" namespace graph { -template -class Digraph : public Graph { +template class Digraph : public Graph { public: Digraph() = default; explicit Digraph(std::unordered_map> G); // Return true if there is a path from u to v - bool contains(const T& u, const T& v); + bool contains(const T &u, const T &v); // Add edge e(u,v) - void insert(const T& u, const T& v); + void insert(const T &u, const T &v); // Remove edge e(u,v) - void remove(const T& u, const T& v); + void remove(const T &u, const T &v); // Reverse graph directions auto reverse(); // - auto contains(const T& u); - - friend std::ostream& operator<<<>(std::ostream& os, Digraph& G); + auto contains(const T &u); + template + friend std::ostream &operator<<(std::ostream &os, const Digraph &G); }; -template +template Digraph::Digraph(std::unordered_map> G) { this->adjList = G; } -template -bool Digraph::contains(const T& u, const T& v) { +template bool Digraph::contains(const T &u, const T &v) { return algo::BreadthFirstSearch(this->adjList).query(u, v); } -template -void Digraph::insert(const T& u, const T& v) { +template void Digraph::insert(const T &u, const T &v) { this->adjList[u].insert(v); this->adjList[v]; } -template -void Digraph::remove(const T& u, const T& v) { +template void Digraph::remove(const T &u, const T &v) { this->adjList[u].erase(v); } -template -auto Digraph::reverse() { +template auto Digraph::reverse() { std::unordered_map> revMatrix; - - for (const auto& u : this->vertices()) { - for (const auto& v : this->adjList[u]) { + + for (const auto &u : this->vertices()) { + for (const auto &v : this->adjList[u]) { revMatrix[v].insert(u); } } @@ -66,17 +61,16 @@ auto Digraph::reverse() { return revMatrix; } -template -auto Digraph::contains(const T& u) { +template auto Digraph::contains(const T &u) { return this->adjList.count(u); } -template -std::ostream& operator<<(std::ostream& os, Digraph& G) { +template +std::ostream &operator<<(std::ostream &os, Digraph &G) { os << "V: " << G.V() << " E: " << G.E() << '\n'; - for (const auto& u : G.vertices()) { + for (const auto &u : G.vertices()) { if (!G.adjList[u].empty()) { - for (const auto& v : G.adjList[u]) { + for (const auto &v : G.adjList[u]) { os << u << "->" << v << ' '; } os << '\n'; diff --git a/include/graph/graph.h b/include/graph/graph.h index 1058bfd..fca956a 100644 --- a/include/graph/graph.h +++ b/include/graph/graph.h @@ -1,30 +1,29 @@ #ifndef GRAPH_H_ #define GRAPH_H_ -#include -#include #include #include +#include +#include namespace graph { // Forward declerations -template class Graph; -template std::ostream& operator<<(std::ostream& os, Graph& G); +template class Graph; +template std::ostream &operator<<(std::ostream &os, Graph &G); -template -class Graph { +template class Graph { public: virtual ~Graph() = default; - + // Return true if there is a path from u to v - virtual bool contains(const T& u, const T& v) =0; + virtual bool contains(const T &u, const T &v) = 0; // Add edge e(u,v) - virtual void insert(const T& u, const T& v) =0; + virtual void insert(const T &u, const T &v) = 0; // Remove edge e(u,v) - virtual void remove(const T& u, const T& v) =0; + virtual void remove(const T &u, const T &v) = 0; // Return graph vertices auto vertices() const; @@ -37,31 +36,24 @@ public: // Adjacency matrix representation std::unordered_map> adjList; - }; -template -auto Graph::vertices() const{ +template auto Graph::vertices() const { return std::views::keys(adjList); } -template -std::uint16_t Graph::V() { +template std::uint16_t Graph::V() { return static_cast(adjList.size()); } -template -std::uint16_t Graph::E() { +template std::uint16_t Graph::E() { std::uint16_t edges = 0; - for (const auto& u : vertices()) { + for (const auto &u : vertices()) { edges += static_cast(adjList[u].size()); } return edges; } - - } // namespace graph - #endif \ No newline at end of file diff --git a/include/graph/scc.h b/include/graph/scc.h index d1878a2..bb45afd 100644 --- a/include/graph/scc.h +++ b/include/graph/scc.h @@ -8,35 +8,36 @@ namespace graph { -template -class SCC : public Digraph { +template class SCC : public Digraph { public: SCC() = default; SCC(std::unordered_map> G, T id) - : Digraph(G), id(id) { normalize(); } + : Digraph(G), id(id) { + normalize(); + } SCC(Digraph G, T id) : id(id) { normalize(); } // Return true if u is part of this SCC - bool contains(const T& u) const; + bool contains(const T &u) const; // Representative vertex of this SCC T id{}; - // + // std::unordered_map> neighboorList; - bool operator==(const SCC& o) const; + bool operator==(const SCC &o) const; + private: // Erase all edges that include vertices outside this SCC void normalize(); }; -template -void SCC::normalize() { - for (const auto& u : this->vertices()) { - for (const auto& v : this->adjList[u]) { +template void SCC::normalize() { + for (const auto &u : this->vertices()) { + for (const auto &v : this->adjList[u]) { if (!this->contains(v)) { this->adjList[u].erase(v); this->adjList.erase(v); @@ -46,19 +47,16 @@ void SCC::normalize() { } } -template -bool SCC::contains(const T& u) const { +template bool SCC::contains(const T &u) const { return this->adjList.count(u); } -template -bool SCC::operator==(const SCC& o) const { +template bool SCC::operator==(const SCC &o) const { return id == o.id; } -template -struct HashSCC { - std::size_t operator()(const SCC& C) const { +template struct HashSCC { + std::size_t operator()(const SCC &C) const { return static_cast(C.id); } }; diff --git a/include/roditty_zwick.h b/include/roditty_zwick.h index b95e149..b03786b 100644 --- a/include/roditty_zwick.h +++ b/include/roditty_zwick.h @@ -1,9 +1,9 @@ #ifndef RODITTY_ZWICK_H_ #define RODITTY_ZWICK_H_ -#include "algorithm/italiano.h" #include "algorithm/frigioni.h" -#include "algorithm/king.h" #include "algorithm/henzinger_king.h" +#include "algorithm/italiano.h" +#include "algorithm/king.h" #endif diff --git a/test/decremental_reachability_test.cc b/test/decremental_reachability_test.cc index d7a4992..de436e1 100644 --- a/test/decremental_reachability_test.cc +++ b/test/decremental_reachability_test.cc @@ -4,6 +4,8 @@ #include "algorithm/frigioni.h" #include "algorithm/italiano.h" +#include + using namespace graph; TEST_SUITE("Decremental Reachability Test") { diff --git a/test/dynamic_reachability_test.cc b/test/dynamic_reachability_test.cc index d045619..36c63df 100644 --- a/test/dynamic_reachability_test.cc +++ b/test/dynamic_reachability_test.cc @@ -3,6 +3,8 @@ #include "algorithm/henzinger_king.h" #include "algorithm/king.h" +#include + using namespace graph; TEST_SUITE("Dynamic Reachability Test") {