21#include <unordered_map>
22#include <unordered_set>
37template <
class Vertex>
39 using AdjacencyMap = std::unordered_map<Vertex, std::unordered_set<Vertex>>;
58 using BaseIterator =
typename AdjacencyMap::const_iterator;
73 return iterator_->first;
78 return &iterator_->first;
102 BaseIterator iterator_;
116 using OuterIterator =
typename AdjacencyMap::const_iterator;
117 using InnerIterator =
typename NeighborSet::const_iterator;
134 return EdgeType{outer_->first, *inner_};
158 if (outer_ != last_) {
159 inner_ = outer_->second.cbegin();
170 while (outer_ != last_) {
171 if (inner_ == outer_->second.cend()) {
173 if (outer_ == last_) {
176 inner_ = outer_->second.cbegin();
177 }
else if (outer_->first < *inner_) {
183 inner_ = InnerIterator{};
186 OuterIterator outer_;
188 InnerIterator inner_;
202 explicit Graph(
const std::vector<std::array<Vertex, 2>>&
edges) {
203 for (
const auto& [u, v] :
edges) {
214 adjacency_.try_emplace(
vertex);
225 void addEdge(
const Vertex& u,
const Vertex& v) {
227 adjacency_[u].insert(v);
228 adjacency_[v].insert(u);
239 return adjacency_.contains(
vertex);
249 [[nodiscard]]
bool containsEdge(
const Vertex& u,
const Vertex& v)
const {
250 const auto uIt = adjacency_.find(u);
251 return uIt != adjacency_.end() && uIt->second.contains(v);
261 const auto vertexIt = adjacency_.find(
vertex);
262 if (vertexIt == adjacency_.end()) {
265 return static_cast<int>(vertexIt->second.size());
275 for (
const auto& entry : adjacency_) {
276 result = std::max(result,
static_cast<int>(entry.second.size()));
283 return static_cast<int>(adjacency_.size());
288 std::size_t directedEdgeCount = 0;
289 for (
const auto& entry : adjacency_) {
290 directedEdgeCount += entry.second.size();
292 assert(directedEdgeCount % 2 == 0);
293 return static_cast<int>(directedEdgeCount / 2);
305 const auto uIt = adjacency_.find(u);
306 if (uIt == adjacency_.end() || !uIt->second.contains(v)) {
309 uIt->second.erase(v);
310 adjacency_.at(v).erase(u);
319 const auto vertexIt = adjacency_.find(
vertex);
320 if (vertexIt == adjacency_.end()) {
326 for (
const Vertex& neighbor :
neighbors) {
327 adjacency_.at(neighbor).erase(
vertex);
329 adjacency_.erase(vertexIt);
348 return std::ranges::subrange(
begin(),
end());
366 requires std::totally_ordered<Vertex>
368 return std::ranges::subrange(
382 return adjacency_.at(
vertex);
407 [[nodiscard]] std::vector<Vertex>
bfs(
const Vertex&
vertex,
int maxVertices = 0)
const {
412 const std::size_t limit = maxVertices == 0
414 :
static_cast<std::size_t
>(maxVertices);
417 std::vector<Vertex> result;
418 std::queue<Vertex> queue;
422 while (!queue.empty() && result.size() < limit) {
423 const Vertex current = queue.front();
425 result.push_back(current);
427 for (
const Vertex& neighbor :
neighbors(current)) {
428 if (visited.insert(neighbor).second) {
429 queue.push(neighbor);
446 [[nodiscard]] std::vector<std::vector<Vertex>>
components()
const {
448 std::vector<std::vector<Vertex>> result;
450 for (
const auto& entry : adjacency_) {
451 if (visited.contains(entry.first)) {
455 result.push_back(
bfs(entry.first));
456 visited.insert(result.back().begin(), result.back().end());
459 std::sort(result.begin(), result.end(), [](
const auto& a,
const auto& b) {
460 return a.size() > b.size();
487 std::optional<Vertex> parent;
488 typename NeighborSet::const_iterator nextNeighbor;
489 typename NeighborSet::const_iterator endNeighbor;
492 std::size_t timer = 0;
493 std::unordered_map<Vertex, SearchData> searchData;
494 std::vector<std::pair<Vertex, Vertex>> edgeStack;
495 std::vector<std::vector<Vertex>> result;
497 for (
const auto& entry : adjacency_) {
498 const Vertex& start = entry.first;
499 if (searchData.contains(start)) {
503 searchData.emplace(start, SearchData{timer, timer});
506 std::stack<Frame> stack;
507 stack.push(Frame{start, std::nullopt, entry.second.cbegin(), entry.second.cend()});
509 while (!stack.empty()) {
510 Frame& frame = stack.top();
511 const Vertex
vertex = frame.vertex;
513 if (frame.nextNeighbor != frame.endNeighbor) {
514 const Vertex neighbor = *frame.nextNeighbor;
515 ++frame.nextNeighbor;
517 if (frame.parent.has_value() && neighbor == *frame.parent) {
521 const auto neighborData = searchData.find(neighbor);
522 if (neighborData == searchData.end()) {
523 edgeStack.emplace_back(
vertex, neighbor);
524 searchData.emplace(neighbor, SearchData{timer, timer});
527 const NeighborSet& nextNeighbors = adjacency_.at(neighbor);
531 nextNeighbors.cbegin(),
532 nextNeighbors.cend(),
534 }
else if (neighborData->second.index < searchData.at(
vertex).index) {
535 SearchData& vertexData = searchData.at(
vertex);
536 vertexData.low = std::min(vertexData.low, neighborData->second.index);
537 edgeStack.emplace_back(
vertex, neighbor);
542 const std::optional<Vertex> parent = frame.parent;
544 if (!parent.has_value()) {
548 SearchData& parentData = searchData.at(*parent);
549 const SearchData& vertexData = searchData.at(
vertex);
550 parentData.low = std::min(parentData.low, vertexData.low);
552 if (vertexData.low >= parentData.index) {
554 std::vector<Vertex> component;
555 bool foundTreeEdge =
false;
558 assert(!edgeStack.empty());
559 const auto edge = std::move(edgeStack.back());
560 edgeStack.pop_back();
562 if (addedVertices.insert(
edge.first).second) {
563 component.push_back(
edge.first);
565 if (addedVertices.insert(
edge.second).second) {
566 component.push_back(
edge.second);
569 }
while (!foundTreeEdge);
571 result.push_back(std::move(component));
576 std::sort(result.begin(), result.end(), [](
const auto& a,
const auto& b) {
577 return a.size() > b.size();
597 [[nodiscard]] std::vector<std::vector<Vertex>>
cliqueCover()
const {
600 const std::vector<Vertex> graphVertices(
begin(),
end());
601 const std::size_t
vertexCount = graphVertices.size();
604 std::vector<std::size_t> colors(
vertexCount, uncolored);
605 std::vector<std::size_t> complementDegrees(
vertexCount);
606 std::vector<std::unordered_set<std::size_t>> neighborColors(
vertexCount);
607 std::vector<std::vector<Vertex>> result;
610 complementDegrees[i] =
vertexCount - 1 - adjacency_.at(graphVertices[i]).size();
613 for (std::size_t coloredCount = 0; coloredCount <
vertexCount; ++coloredCount) {
614 std::size_t selected = uncolored;
616 if (colors[i] != uncolored) {
620 if (selected == uncolored ||
621 neighborColors[i].size() > neighborColors[selected].size() ||
622 (neighborColors[i].size() == neighborColors[selected].size() &&
623 complementDegrees[i] > complementDegrees[selected])) {
627 assert(selected != uncolored);
629 std::size_t color = 0;
630 while (neighborColors[selected].contains(color)) {
633 colors[selected] = color;
635 if (color == result.size()) {
636 result.emplace_back();
638 result[color].push_back(graphVertices[selected]);
640 const NeighborSet& selectedNeighbors = adjacency_.at(graphVertices[selected]);
642 if (colors[i] == uncolored && i != selected &&
643 !selectedNeighbors.contains(graphVertices[i])) {
644 neighborColors[i].insert(color);
649 std::sort(result.begin(), result.end(), [](
const auto& a,
const auto& b) {
650 return a.size() > b.size();
668 std::vector<Vertex> orderedVertices(
begin(),
end());
669 std::sort(orderedVertices.begin(), orderedVertices.end(), [
this](
673 return adjacency_.at(a).size() < adjacency_.at(b).size();
677 std::vector<Vertex> result;
678 for (
const Vertex&
vertex : orderedVertices) {
680 if (std::ranges::none_of(vertexNeighbors, [&selected](
const Vertex& neighbor) {
681 return selected.contains(neighbor);
712 template <
class WeightFunction>
714 using Weight = std::invoke_result_t<WeightFunction&, const Vertex&, const Vertex&>;
724 const auto heavier = [](
const Candidate& a,
const Candidate& b) {
725 return b.weight < a.weight;
730 std::priority_queue<Candidate, std::vector<Candidate>,
decltype(heavier)> frontier(heavier);
732 const auto pushIncidentEdges = [&](
const Vertex&
vertex) {
733 for (
const Vertex& neighbor : adjacency_.at(
vertex)) {
734 if (!visited.contains(neighbor)) {
735 frontier.push(Candidate{weight(
vertex, neighbor),
vertex, neighbor});
740 for (
const auto& entry : adjacency_) {
741 if (visited.contains(entry.first)) {
747 visited.insert(entry.first);
749 pushIncidentEdges(entry.first);
751 while (!frontier.empty()) {
752 const Candidate best = frontier.top();
754 if (!visited.insert(best.to).second) {
757 result.
addEdge(best.from, best.to);
758 pushIncidentEdges(best.to);
793 template <
class WeightFunction>
795 const Vertex& source,
796 const Vertex& target,
797 WeightFunction weight
799 using Weight = std::invoke_result_t<WeightFunction&, const Vertex&, const Vertex&>;
810 if (source == target) {
816 const auto farther = [](
const Candidate& a,
const Candidate& b) {
817 return b.weight < a.weight;
821 std::unordered_map<Vertex, Vertex> parent;
822 std::priority_queue<Candidate, std::vector<Candidate>,
decltype(farther)> frontier(farther);
824 const auto pushIncidentEdges = [&](
const Vertex&
vertex,
const Candidate& candidate) {
825 for (
const Vertex& neighbor : adjacency_.at(
vertex)) {
826 if (!settled.contains(neighbor)) {
827 frontier.push(Candidate{
828 candidate.weight + weight(
vertex, neighbor),
839 settled.insert(source);
840 for (
const Vertex& neighbor : adjacency_.at(source)) {
841 frontier.push(Candidate{weight(source, neighbor), source, neighbor});
844 while (!frontier.empty()) {
845 const Candidate best = frontier.top();
847 if (!settled.insert(best.to).second) {
850 parent.emplace(best.to, best.from);
852 if (best.to == target) {
853 std::vector<Vertex> result{target};
854 while (result.back() != source) {
855 result.push_back(parent.at(result.back()));
857 std::reverse(result.begin(), result.end());
861 pushIncidentEdges(best.to, best);
899 template <
class WeightFunction,
class LowerBoundFunction>
901 const Vertex& source,
902 const Vertex& target,
903 WeightFunction weight,
904 LowerBoundFunction lowerBound
907 std::invoke_result_t<WeightFunction&, const Vertex&, const Vertex&>;
918 if (source == target) {
925 const auto farther = [](
const Candidate& a,
const Candidate& b) {
926 return b.estimate < a.estimate;
929 std::unordered_map<Vertex, Weight> distance;
930 std::unordered_map<Vertex, Vertex> parent;
931 std::priority_queue<Candidate, std::vector<Candidate>,
decltype(farther)>
934 const auto relax = [&](
const Vertex& from,
936 const Weight& fromDistance) {
941 const Weight newDistance = fromDistance + weight(from, to);
942 const auto known = distance.find(to);
943 if (known != distance.end() && !(newDistance < known->second)) {
947 distance.insert_or_assign(to, newDistance);
948 parent.insert_or_assign(to, from);
949 frontier.push(Candidate{
951 newDistance + lowerBound(to, target),
958 for (
const Vertex& neighbor : adjacency_.at(source)) {
959 const Weight neighborDistance = weight(source, neighbor);
960 distance.emplace(neighbor, neighborDistance);
961 parent.emplace(neighbor, source);
962 frontier.push(Candidate{
964 neighborDistance + lowerBound(neighbor, target),
969 while (!frontier.empty()) {
970 const Candidate best = frontier.top();
973 const auto known = distance.find(best.vertex);
974 if (known == distance.end() || known->second < best.distance) {
978 if (best.vertex == target) {
979 std::vector<Vertex> result{target};
980 while (result.back() != source) {
981 result.push_back(parent.at(result.back()));
983 std::reverse(result.begin(), result.end());
987 for (
const Vertex& neighbor : adjacency_.at(best.vertex)) {
988 relax(best.vertex, neighbor, best.distance);
997 return iterator(adjacency_.cbegin());
1002 return iterator(adjacency_.cend());
1026 AdjacencyMap adjacency_;
Forward iterator over the undirected edges of a graph.
Definition graph.hpp:115
EdgeType value_type
Definition graph.hpp:126
EdgeIterator & operator++()
Advances to the next edge.
Definition graph.hpp:138
std::ptrdiff_t difference_type
Definition graph.hpp:125
friend bool operator==(const EdgeIterator &, const EdgeIterator &)=default
reference operator*() const
Returns the current edge, smaller endpoint first.
Definition graph.hpp:133
EdgeType reference
Definition graph.hpp:127
std::input_iterator_tag iterator_category
Definition graph.hpp:123
std::forward_iterator_tag iterator_concept
Definition graph.hpp:124
EdgeIterator()=default
Creates an iterator with no associated graph.
EdgeIterator operator++(int)
Advances to the next edge and returns the previous position.
Definition graph.hpp:145
friend class Graph
Definition graph.hpp:154
Forward iterator over the vertices of a graph.
Definition graph.hpp:57
reference operator*() const
Returns the current vertex.
Definition graph.hpp:72
Iterator & operator++()
Advances to the next vertex.
Definition graph.hpp:82
pointer operator->() const
Returns a pointer to the current vertex.
Definition graph.hpp:77
std::forward_iterator_tag iterator_concept
Definition graph.hpp:62
Iterator operator++(int)
Advances to the next vertex and returns the previous position.
Definition graph.hpp:88
std::forward_iterator_tag iterator_category
Definition graph.hpp:61
const Vertex * pointer
Definition graph.hpp:65
const Vertex & reference
Definition graph.hpp:66
friend bool operator==(const Iterator &, const Iterator &)=default
Iterator()=default
Creates an iterator with no associated graph.
Vertex value_type
Definition graph.hpp:64
friend class Graph
Definition graph.hpp:97
std::ptrdiff_t difference_type
Definition graph.hpp:63
void removeVertex(const Vertex &vertex)
Removes a vertex and every incident edge.
Definition graph.hpp:318
bool containsVertex(const Vertex &vertex) const
Tests whether a vertex is present.
Definition graph.hpp:238
const_iterator begin() const
Returns a const iterator to the first vertex.
Definition graph.hpp:1006
void addVertex(const Vertex &vertex)
Adds a vertex if it is not already present.
Definition graph.hpp:213
int vertexCount() const
Returns the number of vertices.
Definition graph.hpp:282
const_iterator cend() const
Returns the const end iterator.
Definition graph.hpp:1021
std::vector< Vertex > independentSet() const
Computes a maximal independent set greedily from low-degree vertices.
Definition graph.hpp:667
std::vector< Vertex > shortestPath(const Vertex &source, const Vertex &target, WeightFunction weight, LowerBoundFunction lowerBound) const
Computes a shortest path between two vertices using the A* algorithm.
Definition graph.hpp:900
std::vector< std::vector< Vertex > > components() const
Returns the graph's connected components.
Definition graph.hpp:446
const_iterator end() const
Returns the const end iterator.
Definition graph.hpp:1011
std::unordered_set< Vertex > NeighborSet
Definition graph.hpp:46
Graph spanningTree(WeightFunction weight) const
Computes a minimum spanning forest using Prim's algorithm.
Definition graph.hpp:713
Graph(const std::vector< std::array< Vertex, 2 > > &edges)
Creates a graph from a list of undirected edges.
Definition graph.hpp:202
iterator begin()
Returns an iterator to the first vertex.
Definition graph.hpp:996
std::vector< std::vector< Vertex > > biconnectedComponents() const
Returns the vertex-biconnected blocks of the graph.
Definition graph.hpp:479
Vertex VertexType
Definition graph.hpp:43
std::vector< Vertex > bfs(const Vertex &vertex, int maxVertices=0) const
Traverses a connected component in breadth-first order.
Definition graph.hpp:407
int degree(const Vertex &vertex) const
Returns the degree of a vertex.
Definition graph.hpp:260
std::vector< std::vector< Vertex > > cliqueCover() const
Computes a vertex clique cover using the DSATUR heuristic.
Definition graph.hpp:597
Iterator const_iterator
Definition graph.hpp:192
void clear()
Removes every vertex and edge.
Definition graph.hpp:333
std::vector< Vertex > shortestPath(const Vertex &source, const Vertex &target, WeightFunction weight) const
Computes a shortest path between two vertices using Dijkstra's algorithm.
Definition graph.hpp:794
const NeighborSet & neighbors(const Vertex &vertex) const
Returns the neighbors of a vertex.
Definition graph.hpp:381
NeighborSet closedNeighbors(const Vertex &vertex) const
Returns a vertex together with all of its neighbors.
Definition graph.hpp:392
int edgeCount() const
Returns the number of undirected edges.
Definition graph.hpp:287
iterator end()
Returns the end iterator.
Definition graph.hpp:1001
auto edges() const
Returns a lazy view over the undirected edges.
Definition graph.hpp:365
void addEdge(const Vertex &u, const Vertex &v)
Adds an undirected edge and its endpoints.
Definition graph.hpp:225
std::array< Vertex, 2 > EdgeType
Definition graph.hpp:49
bool containsEdge(const Vertex &u, const Vertex &v) const
Tests whether an undirected edge is present.
Definition graph.hpp:249
void removeEdge(const Vertex &u, const Vertex &v)
Removes an undirected edge if it is present.
Definition graph.hpp:304
Graph()=default
Creates an empty graph.
auto vertices() const
Returns a lazy view over the vertices.
Definition graph.hpp:347
const_iterator cbegin() const
Returns a const iterator to the first vertex.
Definition graph.hpp:1016
Iterator iterator
Definition graph.hpp:191
int maxDegree() const
Returns the largest vertex degree.
Definition graph.hpp:273
Enumeration of the integer grid points a shape contains.
Definition arrangement.hpp:67
@ edge
Definition bitmatrix.hpp:37
@ vertex
Definition bitmatrix.hpp:37