From fee5b8d0ab2d368ba61c3c270a75f43caeaad161 Mon Sep 17 00:00:00 2001 From: stefiosif Date: Thu, 29 Sep 2022 23:33:54 +0300 Subject: [PATCH] Add edge removal method and tree repair, TODO: handle Eext --- algorithm/frigioni.h | 114 +++++++++++++++++++++++++++++++++++-------- 1 file changed, 95 insertions(+), 19 deletions(-) diff --git a/algorithm/frigioni.h b/algorithm/frigioni.h index 849b253..e782d53 100644 --- a/algorithm/frigioni.h +++ b/algorithm/frigioni.h @@ -17,26 +17,26 @@ public: Frigioni(Digraph G) { this->G = G; } - // + // Initialize the decremental maintenance data structure for general graphs void init() override; - // + // 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; - // + // 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); private: // Transitive closure matrix, used to answer reachability queries in O(1) std::map> TC; - // Connect each vertex with its representative SCC - std::map> C; - - // Each scc's representative vertex reachability tree + // For each SCC, store a reachability tree created as a BFS tree std::map> RT; - // Incoming / Outgoing / Internal edges of each SCC - // Maps each SCC representative with struct Edges + // For each SCC, store collections of incoming, outgoing and internal edges struct Edges { std::set> in; std::set> inc; @@ -45,20 +45,19 @@ private: std::map E; // Decremental maintenance of strongly connected components - RodittyZwick decremental; + RodittyZwick rodittyZwick; }; template void Frigioni::init() { auto SCCs = Tarjan(this->G.adjMatrix).execute(); - decremental = RodittyZwick(this->G); - decremental.init(); - + rodittyZwick = RodittyZwick(this->G); + rodittyZwick.init(); + for (auto& scc : SCCs) { RT[scc.id] = BreadthFirstTree(this->G, scc.id); for (const auto& u : this->G.vertices()) { for (const auto& v : this->G.adjMatrix[u]) { - TC[u][v] = false; if (scc.member(u)) { if (scc.member(v)) E[scc.id].in.insert(std::make_pair(u, v)); @@ -67,15 +66,14 @@ void Frigioni::init() { } else if (scc.member(v)) { E[scc.id].inc.insert(std::make_pair(u, v)); } + TC[u][v] = false; } } } for (auto& scc : SCCs) { - for (const auto& u : this->G.vertices()) { - if (scc.member(u)) { - for (const auto& v : RT[scc.id].vertices()) { - TC[u][v] = true; - } + for (const auto& u : scc.vertices()) { + for (const auto& v : RT[scc.id].vertices()) { + TC[u][v] = true; } } } @@ -88,7 +86,85 @@ bool Frigioni::query(const T& u, const T& v) { template void Frigioni::remove(const T& u, const T& v) { + +} +template +void Frigioni::remove(const std::vector>& edges) { + std::vector> Eint; + std::vector> Eext; + + // Put incoming edge removal requests in the corresponding collection + for (const auto& [u, v] : edges) { + if (rodittyZwick.query(u, v)) + Eint.push_back({ u, v }); + else + Eext.push_back({ u, v }); + } + + std::map> H; + + // Handle SCC internal edge removals + for (const auto& [u, v] : Eint) { + this->G.remove(u, v); + rodittyZwick.remove(u, v); + + if (!rodittyZwick.query(u, v)) { + auto C = rodittyZwick.getSCCs(); + auto D = E[u]; // or E[v], the component that's been split + E.erase(u); + + for (const auto& [w, z] : D.inc) { + E[C[z].id].inc.insert({ w, z }); + // check if scc needs hook + } + + for (const auto& [w, z] : D.out) { + E[C[z].id].out.insert({ w, z }); + // check if scc needs hook + } + + for (const auto& [w, z] : D.in) { + if (C[w] == C[z]) + E[C[w].id].in.insert({ w, z }); + else { + E[C[w].id].out.insert({ w, z }); + E[C[z].id].in.insert({ w, z }); + } + } + } else { + E[u].in.erase({ u, v }); + } + } + + // Handle SCC external edge removals + for (const auto& [u, v] : Eext) { + this->G.remove(u, v); + // TODO + } + + // Repair the trees + for (const auto& id : std::views::keys(rodittyZwick.getSCCs())) { + while (H[id].size() > 0) { + const auto& h = H[id].top(); + bool found = false; + + for (const auto& [u, v] : E[h].inc) { + if (RT[id].contains(id, u)) { + RT[id].adjMatrix[u].insert(h); + found = true; + break; + } + } + H[id].pop(); + if (!found) { + TC[id][h] = false; + for (const auto& [u, v] : E[h].out) { + H[id].push(v); + } + } + } + } } } // namespace algo