From e7fd88f82cd1284e56b32e59e4e9574c26aeb1a0 Mon Sep 17 00:00:00 2001 From: stefiosif Date: Sat, 15 Oct 2022 10:40:08 +0300 Subject: [PATCH] Refactor: Change reachability interfaces to handle multiple removals/insertions --- include/algorithm/decremental_reachability.h | 2 +- include/algorithm/dynamic_reachability.h | 2 +- include/algorithm/frigioni.h | 10 +-------- include/algorithm/henzinger_king.h | 22 +++----------------- include/algorithm/italiano.h | 11 +++++++++- include/algorithm/king.h | 18 ++++++++++++---- include/algorithm/roditty_zwick.h | 11 +++++++++- test/dynamic_reachability_test.cc | 2 +- 8 files changed, 41 insertions(+), 37 deletions(-) diff --git a/include/algorithm/decremental_reachability.h b/include/algorithm/decremental_reachability.h index 8853b2f..1258a6c 100644 --- a/include/algorithm/decremental_reachability.h +++ b/include/algorithm/decremental_reachability.h @@ -18,7 +18,7 @@ public: 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 T& u, const T& v) =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 0d44799..2ce7cb8 100644 --- a/include/algorithm/dynamic_reachability.h +++ b/include/algorithm/dynamic_reachability.h @@ -9,7 +9,7 @@ template class DynamicReachability : public DecrementalReachability { // Insert edge e(u,v) and maintain the transitive closure matrix - virtual void insert(const T& u, const T& v) =0; + virtual void insert(const T& c, const std::vector& vertices) =0; }; diff --git a/include/algorithm/frigioni.h b/include/algorithm/frigioni.h index fdd0e44..bd5102f 100644 --- a/include/algorithm/frigioni.h +++ b/include/algorithm/frigioni.h @@ -24,11 +24,8 @@ public: // in O(1) using the transitive closure matrix bool query(const T& u, const T& v) override; - // Delete edge e(u, v) - void remove(const T& u, const T& v) override; - // Delete set of edges and explicitely maintain the transitive closure - void remove(const std::vector>& edges); + void remove(const std::vector>& edges) override; private: // Transitive closure matrix, used to answer reachability queries in O(1) std::unordered_map> TC; @@ -84,11 +81,6 @@ bool Frigioni::query(const T& u, const T& v) { return TC[u][v]; } -template -void Frigioni::remove(const T& u, const T& v) { - -} - template void Frigioni::remove(const std::vector>& edges) { std::vector> Eint; diff --git a/include/algorithm/henzinger_king.h b/include/algorithm/henzinger_king.h index aa9516e..2fd5c2d 100644 --- a/include/algorithm/henzinger_king.h +++ b/include/algorithm/henzinger_king.h @@ -25,16 +25,10 @@ public: // and then if necessary check the set S bool query(const T& u, const T& v) override; - // Delete edge e(u, v) - void remove(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); - // Add edge e(u, v) - void insert(const T& u, const T& v) 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 @@ -70,15 +64,10 @@ bool HenzingerKing::query(const T& u, const T& v) { }); } -template -void HenzingerKing::remove(const T& u, const T& v) { - this->G.remove(u, v); -} - template void HenzingerKing::remove(const std::vector>& edges) { - for (const auto& [u, v]: edges) { - remove(u, v); + for (const auto& [u, v] : edges) { + this->G.remove(u, v); } frigioni.remove(edges); @@ -88,15 +77,10 @@ void HenzingerKing::remove(const std::vector>& edges) { } } -template -void HenzingerKing::insert(const T& u, const T& v) { - this->G.insert(u, v); -} - template void HenzingerKing::insert(const T& c, const std::vector& vertices) { for (const auto& w : vertices) - insert(c, w); + this->G.insert(c, w); S.insert(c); if (S.size() > threshold) { diff --git a/include/algorithm/italiano.h b/include/algorithm/italiano.h index ab1b40b..fc16aa0 100644 --- a/include/algorithm/italiano.h +++ b/include/algorithm/italiano.h @@ -24,8 +24,11 @@ public: // in O(1) using the transitive closure matrix bool query(const T& u, const T& v) override; + // Delete collection of edges + void remove(const std::vector>& edges) override; + // Delete edge e(u, v) and explicitely maintain the transitive closure - void remove(const T& u, const T& v) override; + void remove(const T& u, const T& v); private: // Transitive closure matrix std::unordered_map> TC; @@ -64,6 +67,12 @@ 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) + remove(u, v); +} + template void Italiano::remove(const T& u, const T& v) { if (!this->G.adjList[u].contains(v)) return; diff --git a/include/algorithm/king.h b/include/algorithm/king.h index a41286a..12040d3 100644 --- a/include/algorithm/king.h +++ b/include/algorithm/king.h @@ -23,12 +23,15 @@ public: // in O(n) using the stored decremental maintenance data structure for DAGs bool query(const T& u, const T& v) override; + // Delete collection of edges + 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) override; + void remove(const T& u, const T& v); // Insert edge e(u, v) by reconstructing all reachability trees - void insert(const T& u, const T& v) 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; @@ -53,6 +56,12 @@ bool King::query(const T& u, const T& v) { }); } +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) { this->G.remove(u, v); @@ -63,8 +72,9 @@ void King::remove(const T& u, const T& v) { } template -void King::insert(const T& u, const T& v) { - this->G.insert(u, v); +void King::insert(const T& c, const std::vector& vertices) { + for (const auto& v : vertices) + this->G.insert(c, v); init(); } diff --git a/include/algorithm/roditty_zwick.h b/include/algorithm/roditty_zwick.h index 4595df9..7e71e33 100644 --- a/include/algorithm/roditty_zwick.h +++ b/include/algorithm/roditty_zwick.h @@ -25,8 +25,11 @@ public: // Return true if u and v are in the same SCC bool query(const T& u, const T& v) override; + // Delete collection of edges + 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) override; + void remove(const T& u, const T& v); std::unordered_map> getSCCs() { return C; } private: @@ -68,6 +71,12 @@ 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) + remove(u, v); +} + template void RodittyZwick::remove(const T& u, const T& v) { const auto& w = A[u]; diff --git a/test/dynamic_reachability_test.cc b/test/dynamic_reachability_test.cc index 818c15f..6b3020e 100644 --- a/test/dynamic_reachability_test.cc +++ b/test/dynamic_reachability_test.cc @@ -60,7 +60,7 @@ TEST_SUITE("Dynamic Reachability Test") { } SUBCASE("King::insert") { - king.insert(3, 10); + king.insert(3, { 10 }); CHECK_EQ(king.query(1, 10), true); CHECK_EQ(king.query(2, 10), false);