// // Created by max on 01.08.22. // #include #include "pds.hpp" #include "graphml/graphml.hpp" #include namespace pds { PowerGrid import_graphml(const std::string& filename, bool all_zero_injection) { PowerGrid graph; boost::dynamic_properties attr(boost::ignore_other_properties); map zero_injection_data; boost::associative_property_map zero_injection(zero_injection_data); auto id_map = [&graph](const PowerGrid::vertex_descriptor& vertex) -> long& { return graph[vertex].id;}; auto name_map = [&graph](PowerGrid::vertex_descriptor vertex) -> std::string& { return graph[vertex].name; }; boost::function_property_map id(id_map); boost::function_property_map name(name_map); attr.property("zero_injection", zero_injection);//make_vector_property_map(long_zi, graph)); attr.property("name", name); attr.property("id", id); std::ifstream graph_in(filename); pds::read_graphml(graph_in, graph, attr); graph_in.close(); for (auto v: graph.vertices()) { graph[v].zero_injection = zero_injection[v] || all_zero_injection; } return graph; } set observationNeighborhood(const PowerGrid &graph, const set &starts) { set observed; for (auto v: starts) { observed.insert(v); for (auto w: graph.neighbors(v)) { observed.insert(w); } } propagate(graph, observed); return observed; } void PdsState::addEdge(Vertex source, Vertex target) { if (!m_graph.edge(source, target)) { m_graph.addEdge(source, target); if (!isObserved(source)) { m_unobserved_degree[target] += 1; } if (!isObserved(target)) { m_unobserved_degree[source] += 1; } } } void PdsState::removeVertex(Vertex v) { if (!isObserved(v)) { for (auto w: m_graph.neighbors(v)) { m_unobserved_degree[w] -= 1; propagate(w); } } m_graph.removeVertex(v); } void PdsState::propagate(PdsState::Vertex vertex) { if (isObserved(vertex) && isZeroInjection(vertex) && m_unobserved_degree[vertex] == 1) { for (auto w: m_graph.neighbors(vertex)) { observe(w); } } } void PdsState::observe(PdsState::Vertex vertex) { if (!isObserved(vertex)) { m_observed.insert(vertex); for (auto w: m_graph.neighbors(vertex)) { m_unobserved_degree[w] -= 1; assert(m_unobserved_degree[w] >= 0); propagate(w); } propagate(vertex); } } bool PdsState::disableLowDegreeRecursive(PdsState::Vertex start, set &seen) { auto hasBlankNeighbor = [this] (auto v) { return ranges::any_of(m_graph.neighbors(v), [this](auto w) { return isActive(w) || isBlank(w);} ); }; bool changed = false; seen.insert(start); if (m_graph.degree(start) <= 2 && hasBlankNeighbor(start) && isZeroInjection(start) && isBlank(start)) { setInactive(start); changed = true; } for (auto w: m_graph.neighbors(start)) { if (!seen.contains(w)) { changed |= disableLowDegreeRecursive(w, seen); } } return changed; } bool PdsState::setBlank(PdsState::Vertex vertex) { assert(!isActive(vertex)); m_active[vertex] = PmuState::Blank; return m_observed.size() == m_graph.numVertices(); } bool PdsState::setActive(PdsState::Vertex vertex) { m_active[vertex] = PmuState::Active; observe(vertex); for (auto w: m_graph.neighbors(vertex)) { observe(w); } return m_observed.size() == m_graph.numVertices(); } bool PdsState::setInactive(PdsState::Vertex vertex) { assert(!isActive(vertex)); if (!isInactive(vertex)) { m_active[vertex] = PmuState::Inactive; assert(activeState(vertex) == PmuState::Inactive); return true; } else { return false; } } bool PdsState::collapseLeaves() { bool changed = false; auto vertices = m_graph.vertices() | ranges::to(); for (auto v: vertices) { if (m_graph.degree(v) == 1 && !isActive(v) ) { Vertex neighbor; for (auto w: m_graph.neighbors(v)) { neighbor = w; } if (m_graph.degree(neighbor) == 2 && m_graph[neighbor].zero_injection) { if (!isZeroInjection(v)) { m_graph[neighbor].zero_injection = false; } } else { if (m_graph[neighbor].zero_injection) { m_graph[neighbor].zero_injection = false; } else { setActive(neighbor); } } removeVertex(v); changed = true; } else if (m_unobserved_degree.at(v) == 0 && isBlank(v) && isObserved(v)) { setInactive(v); changed = true; } } return changed; } bool PdsState::disableLowDegree() { bool changed = false; set seen; for (auto v: m_graph.vertices()) { if (m_graph.degree(v) >= 3) { changed = disableLowDegreeRecursive(v, seen); } } return changed; } bool PdsState::reduceObservedNonZi() { bool changed = false; auto vertices = m_graph.vertices() | ranges::to(); for (auto v: vertices) { if (isObserved(v) && isInactive(v) && !isZeroInjection(v)) { removeVertex(v); changed = true; } } return changed; } bool PdsState::collapseDegreeTwo() { bool changed = false; auto vertices = m_graph.vertices() | ranges::to(); for (auto v: vertices) { if (m_graph.degree(v) == 2 && isZeroInjection(v)) { std::vector neighbors = m_graph.neighbors(v) | ranges::to(); auto [x, y] = std::tie(neighbors[0], neighbors[1]); { } if (!m_graph.edge(x, y)) { if (isInactive(v)) { if((isZeroInjection(x) && m_graph.degree(x) <= 2) || (isZeroInjection(y) && m_graph.degree(y) <= 2)) { addEdge(x, y); removeVertex(v); changed = true; } } for (auto [s, t]: {std::tie(x, y), std::tie(y, x)}) { if (!isZeroInjection(s) && isInactive(s) && !isZeroInjection(t) && isBlank(t)) { setActive(t); changed = true; } } } else { if (m_graph.degree(x) == 2 && isBlank(y)) { setActive(y); changed = true; } else if (m_graph.degree(y) == 2 && isBlank(x)) { setActive(x); changed = true; } } } } return changed; } bool PdsState::disableObservationNeighborhood() { bool changed = false; map> cachedNeighborhood; set active; for (auto v: m_graph.vertices()) { if (isActive(v)) active.insert(v); } auto activeNeighborhood = observationNeighborhood(m_graph, active); for (auto v: m_graph.vertices()) { if (isBlank(v)) { if (isSuperset(activeNeighborhood, m_graph.neighbors(v))) { setInactive(v); changed = true; } } } auto vertices = m_graph.vertices() | ranges::to(); ranges::sort(vertices, [this](auto left, auto right) -> bool { return m_graph.degree(left) > m_graph.degree(right);}); for (auto v: vertices) { if (isBlank(v)) { active.insert(v); auto observation = observationNeighborhood(m_graph, active); active.erase(v); for (auto w: observation) { if (v != w && isBlank(w)) { if (isSuperset(observation, m_graph.neighbors(w))) { setInactive(w); changed = true; } } } } } return changed; } bool PdsState::activateNecessaryNodes() { bool changed = false; set blankActive; for (auto v: m_graph.vertices()) { if (!isInactive(v)) blankActive.insert(v); } for (auto v: m_graph.vertices()) { if (isBlank(v)) { blankActive.erase(v); auto observed = observationNeighborhood(m_graph, blankActive); if (ranges::any_of(m_graph.vertices(), [&observed](auto v) -> bool { return !observed.contains(v);})) { setActive(v); changed = true; } blankActive.insert(v); } } return changed; } map findClosestActive(const PdsState& state) { using Vertex = PdsState::Vertex; std::deque queue; map closestActive; for (auto v: state.graph().vertices()) { if (state.isActive(v)) { closestActive.emplace(v, v); queue.push_back(v); } } while (!queue.empty()) { auto v = queue.front(); queue.pop_front(); for (auto w: state.graph().neighbors(v)) { if (!closestActive.contains(w)) { closestActive.emplace(w, closestActive[v]); queue.push_back(w); } } } return closestActive; } bool PdsState::collapseObservedEdges() { bool changed = false; auto isObservedEdge = [this](PowerGrid::edge_descriptor e) { auto [s, t] = m_graph.endpoints(e); return isObserved(s) && isObserved(t); }; auto edges = m_graph.edges() | ranges::views::filter(isObservedEdge) | ranges::to(); if (edges.empty()) return false; auto closestActive = findClosestActive(*this); for (auto e: edges) { auto [s, t] = m_graph.endpoints(e); if (s == closestActive.at(t) || t == closestActive.at(s)) continue; m_graph.removeEdge(e); changed = true; auto hasObservedNeighbor = [this](Vertex v) -> bool { return ranges::any_of(m_graph.neighbors(v), [this](auto w) { return isActive(w);});}; if (!isActive(s)) { if (!hasObservedNeighbor(s)) addEdge(s, closestActive.at(s)); } if (!isActive(t)) { if (!hasObservedNeighbor(t)) addEdge(t, closestActive.at(t)); } } return changed; } bool isBlockingVertex(const PdsState& state, PdsState::Vertex vertex) { return !state.isZeroInjection(vertex) && state.isObserved(vertex) && state.isInactive(vertex); } inline bool isBlockedEdge(const PdsState& state, PdsState::Vertex source, PdsState::Vertex target) { return state.isObserved(source) && state.isObserved(target) && !state.isActive(source) && !state.isActive(target) && !(state.isZeroInjection(source) && state.isZeroInjection(target)); } void recurseComponent( PdsState::Vertex start, const PdsState& state, set& seen, set& currentComponent, bool nonZiSeparators ) { if (seen.contains(start)) return; seen.insert(start); currentComponent.insert(start); for (auto w: state.graph().neighbors(start)) { if (!state.isActive(w)) { if (!seen.contains(w) && (!nonZiSeparators || !isBlockedEdge(state, start, w))) { recurseComponent(w, state, seen, currentComponent, nonZiSeparators); } } else { currentComponent.insert(w); } } } bool PdsState::solveTrivial() { if (!allObserved()) { auto blank_filter = [this] (Vertex v) -> bool { return isBlank(v); }; auto possibleLocations = m_graph.vertices() | ranges::views::filter(blank_filter) | ranges::to(); if (possibleLocations.size() == 1) { setActive(possibleLocations[0]); } } return allObserved(); } std::vector PdsState::subproblems(bool nonZiSeparators) const { std::vector components; set seen; for (auto v: m_graph.vertices()) { if (!isActive(v) && !seen.contains(v)) { set currentComponent; recurseComponent(v, *this, seen, currentComponent, nonZiSeparators); PowerGrid subgraph{graph()}; for (auto x: subgraph.vertices()) { if (!currentComponent.contains(x)) { subgraph.removeVertex(x); } } auto dummy = subgraph.addVertex(); auto oneActive = dummy; PdsState subproblem(std::move(subgraph)); for (auto x: subproblem.graph().vertices()) { if (x == dummy) continue; if (isActive(x)) { subproblem.setActive(x); oneActive = x; } else if (isInactive(x)) { subproblem.setInactive(x); } } bool dummyNeeded = false; for (auto x: subproblem.graph().vertices()) { if (x == dummy) continue; if (isObserved(x) && !subproblem.isObserved(x)) { subproblem.addEdge(x, oneActive); dummyNeeded = true; } } subproblem.setActive(oneActive); if (oneActive != dummy || !dummyNeeded) { subproblem.removeVertex(dummy); } components.emplace_back(std::move(subproblem)); } } return components; } void dominate(const PowerGrid &graph, const map &active, set &observed) { for (auto v: graph.vertices()) { if (active.at(v) == PmuState::Active) { observed.insert(v); for (auto w: graph.neighbors(v)) { observed.insert(w); } } } } bool propagate(const PowerGrid &graph, set &observed, size_t max_unobserved) { pds::map unobserved_degree; std::vector queue; for (const auto& v: graph.vertices()) { unobserved_degree[v] = 0; for (const auto& w: graph.neighbors(v)) { unobserved_degree[v] += !observed.contains(w); } if (graph[v].zero_injection && observed.contains(v) && unobserved_degree.at(v) > 0 && unobserved_degree.at(v) <= max_unobserved) { queue.push_back(v); } } while (!queue.empty()) { auto v = queue.back(); queue.pop_back(); for (const auto& w: graph.neighbors(v)) { if (!observed.contains(w)) { observed.insert(w); if (graph[w].zero_injection && observed.contains(w) && unobserved_degree.at(w) > 0 && unobserved_degree.at(w) <= max_unobserved) { queue.push_back(w); } for (const auto& u: graph.neighbors(w)) { unobserved_degree[u] -= 1; auto deg = unobserved_degree.at(u); if (graph[u].zero_injection && observed.contains(u) && deg > 0 && deg == max_unobserved) { queue.push_back(u); } } } } } return true; } bool observed(const PowerGrid &graph, const set &observed) { return ranges::all_of(graph.vertices(), [&] (const auto& v) { return observed.contains(v); }); } }