16#ifndef UTIL_GRAPH_UTIL_H_
17#define UTIL_GRAPH_UTIL_H_
27#include "absl/container/btree_map.h"
28#include "absl/container/flat_hash_map.h"
29#include "absl/container/inlined_vector.h"
30#include "absl/log/check.h"
31#include "absl/types/span.h"
74 absl::Span<const int> new_node_index);
88 absl::Span<const int> nodes);
101template <
class Graph>
105 "for forward graphs, directly use `Graph::operator[]`");
110 typedef typename Graph::OutgoingOrOppositeIncomingArcIterator
ArcIterator;
117 return graph_.Head(ArcIterator::operator*());
126 const auto& arc_range = graph_.OutgoingOrOppositeIncomingArcs(node);
136template <
class Graph>
143template <
class Graph>
160template <
class Graph>
173template <
class Graph>
177template <
class Graph>
195template <
class Graph>
197 bool die_if_not_symmetric);
201template <
class Graph>
203 for (
const auto arc :
graph.AllForwardArcs()) {
204 if (
graph.Tail(arc) ==
graph.Head(arc))
return true;
209template <
class Graph>
213 std::vector<bool> tmp_node_mask(
graph.num_nodes(),
false);
214 for (
const NodeIndex tail :
graph.AllNodes()) {
215 for (
const ArcIndex arc :
graph.OutgoingArcs(tail)) {
216 const NodeIndex head =
graph.Head(arc);
217 if (tmp_node_mask[head])
return true;
218 tmp_node_mask[head] =
true;
220 for (
const ArcIndex arc :
graph.OutgoingArcs(tail)) {
221 tmp_node_mask[
graph.Head(arc)] =
false;
227template <
class Graph>
234 for (
const NodeIndex node :
graph.AllNodes()) {
235 for (
const ArcIndex arc :
graph.OutgoingArcs(node)) {
239 reverse_graph.
Build();
241 std::vector<ArcIndex> count(
graph.num_nodes(), 0);
242 for (
const NodeIndex node :
graph.AllNodes()) {
243 for (
const ArcIndex arc :
graph.OutgoingArcs(node)) {
244 ++count[
graph.Head(arc)];
246 for (
const ArcIndex arc : reverse_graph.
OutgoingArcs(node)) {
247 if (--count[reverse_graph.
Head(arc)] < 0)
return false;
249 for (
const ArcIndex arc :
graph.OutgoingArcs(node)) {
250 if (count[
graph.Head(arc)] != 0)
return false;
256template <
class Graph>
259 static_assert(std::numeric_limits<NodeIndex>::max() <= INT_MAX,
260 "GraphIsWeaklyConnected() isn't yet implemented for graphs"
261 " that support more than INT_MAX nodes. Reach out to"
262 " or-core-team@ if you need this.");
263 if (
graph.num_nodes() == 0)
return true;
272template <
class Graph>
274 std::unique_ptr<Graph> new_graph(
276 for (
const auto node :
graph.AllNodes()) {
277 for (
const auto arc :
graph.OutgoingArcs(node)) {
278 new_graph->AddArc(node,
graph.Head(arc));
285template <
class Graph>
287 absl::Span<const int> new_node_index) {
289 const int num_nodes = old_graph.
num_nodes();
290 CHECK_EQ(new_node_index.size(), num_nodes);
291 std::unique_ptr<Graph> new_graph(
new Graph(num_nodes, old_graph.
num_arcs()));
294 for (
const NodeIndex node : old_graph.
AllNodes()) {
295 for (
const ArcIndex arc : old_graph.
OutgoingArcs(node)) {
296 new_graph->AddArc(new_node_index[node],
297 new_node_index[old_graph.
Head(arc)]);
304template <
class Graph>
306 absl::Span<const int> nodes) {
310 std::vector<NodeIndex> new_node_index(old_graph.
num_nodes(), -1);
311 for (NodeIndex new_index = 0; new_index < nodes.size(); ++new_index) {
312 new_node_index[nodes[new_index]] = new_index;
316 ArcIndex num_arcs = 0;
317 for (
const NodeIndex node : nodes) {
318 for (
const ArcIndex arc : old_graph.
OutgoingArcs(node)) {
319 if (new_node_index[old_graph.
Head(arc)] != -1) ++num_arcs;
326 std::unique_ptr<Graph> new_graph(
new Graph(nodes.size(), num_arcs));
327 for (NodeIndex new_tail = 0; new_tail < nodes.size(); ++new_tail) {
328 const NodeIndex old_tail = nodes[new_tail];
329 for (
const ArcIndex arc : old_graph.
OutgoingArcs(old_tail)) {
330 const NodeIndex new_head = new_node_index[old_graph.
Head(arc)];
331 if (new_head != -1) new_graph->AddArc(new_tail, new_head);
338template <
class Graph>
340 std::unique_ptr<Graph> g(
new Graph(
graph.num_nodes(),
graph.num_arcs()));
343 std::vector<bool> tmp_node_mask(
graph.num_nodes(),
false);
344 for (
const NodeIndex tail :
graph.AllNodes()) {
345 for (
const ArcIndex arc :
graph.OutgoingArcs(tail)) {
346 const NodeIndex head =
graph.Head(arc);
347 if (head != tail && !tmp_node_mask[head]) {
348 tmp_node_mask[head] =
true;
349 g->AddArc(tail, head);
352 for (
const ArcIndex arc :
graph.OutgoingArcs(tail)) {
353 tmp_node_mask[
graph.Head(arc)] =
false;
360template <
class Graph>
362 if (arc_path->empty())
return;
365 absl::btree_map<int, int> last_arc_leaving_node;
366 for (
const int arc : *arc_path) last_arc_leaving_node[
graph.Tail(arc)] = arc;
370 last_arc_leaving_node[
graph.Head(arc_path->back())] = -1;
374 int node =
graph.Tail(arc_path->front());
376 while (new_size < arc_path->size()) {
378 if (arc == -1)
break;
379 (*arc_path)[new_size++] = arc;
380 node =
graph.Head(arc);
382 arc_path->resize(new_size);
385template <
class Graph>
387 if (arc_path.empty())
return false;
389 seen.insert(
graph.Tail(arc_path.front()));
390 for (
const int arc : arc_path) {
396template <
class Graph>
398 const Graph&
graph,
bool die_if_not_symmetric) {
399 std::vector<int> reverse_arc(
graph.num_arcs(), -1);
403 absl::flat_hash_map<std::pair< int,
int>,
404 absl::InlinedVector<int, 4>>
407 for (
int arc = 0; arc <
graph.num_arcs(); ++arc) {
408 const int tail =
graph.Tail(arc);
409 const int head =
graph.Head(arc);
412 reverse_arc[arc] = arc;
416 auto it = arc_map.find({head, tail});
417 if (it != arc_map.end()) {
420 reverse_arc[arc] = it->second.back();
421 reverse_arc[it->second.back()] = arc;
422 if (it->second.size() > 1) {
423 it->second.pop_back();
429 arc_map[{tail, head}].push_back(arc);
434 int64_t num_unmapped_arcs = 0;
435 for (
const auto& p : arc_map) {
436 num_unmapped_arcs += p.second.size();
438 DCHECK_EQ(std::count(reverse_arc.begin(), reverse_arc.end(), -1),
441 if (die_if_not_symmetric) {
442 CHECK_EQ(arc_map.size(), 0)
443 <<
"The graph is not symmetric: " << arc_map.size() <<
" of "
444 <<
graph.num_arcs() <<
" arcs did not have a reverse.";
A connected components finder that only works on dense ints.
bool AddEdge(int node1, int node2)
void SetNumberOfNodes(int num_nodes)
int GetNumberOfComponents() const
NodeIndexType num_nodes() const
static constexpr bool kHasNegativeReverseArcs
ArcIndexType num_arcs() const
Returns the number of valid arcs in the graph.
IntegerRange< NodeIndex > AllNodes() const
BaseGraph implementation -------------------------------------------------—.
BeginEndWrapper< OutgoingArcIterator > OutgoingArcs(NodeIndexType node) const
NodeIndexType Head(ArcIndexType arc) const
ArcIndexType AddArc(NodeIndexType tail, NodeIndexType head)
IntegerRange< ArcIndexType > OutgoingArcs(NodeIndexType node) const
NodeIndexType Head(ArcIndexType arc) const
AdjacencyListIterator(const Graph &graph, ArcIterator &&arc_it)
Graph::NodeIndex operator*() const
Overwrite operator* to return the heads of the arcs.
Graph::OutgoingOrOppositeIncomingArcIterator ArcIterator
UndirectedAdjacencyListsOfDirectedGraph(const Graph &graph)
BeginEndWrapper< AdjacencyListIterator > operator[](int node) const
Returns a pseudo-container of all the nodes adjacent to "node".
bool InsertIfNotPresent(Collection *const collection, const typename Collection::value_type &value)
const Collection::value_type::second_type & FindOrDie(const Collection &collection, const typename Collection::value_type::first_type &key)
A collections of i/o utilities for the Graph classes in ./graph.h.
void RemoveCyclesFromPath(const Graph &graph, std::vector< int > *arc_path)
bool IsValidPermutation(absl::Span< const int > v)
Returns true iff the given vector is a permutation of [0..size()-1].
std::unique_ptr< Graph > CopyGraph(const Graph &graph)
Returns a fresh copy of a given graph.
std::vector< int > GetConnectedComponents(int num_nodes, const UndirectedGraph &graph)
UndirectedAdjacencyListsOfDirectedGraph(const Graph &) -> UndirectedAdjacencyListsOfDirectedGraph< Graph >
CTAD for UndirectedAdjacencyListsOfDirectedGraph.
bool PathHasCycle(const Graph &graph, absl::Span< const int > arc_path)
Returns true iff the given path contains a cycle.
bool GraphHasDuplicateArcs(const Graph &graph)
bool GraphIsSymmetric(const Graph &graph)
std::unique_ptr< Graph > RemapGraph(const Graph &graph, absl::Span< const int > new_node_index)
std::unique_ptr< Graph > RemoveSelfArcsAndDuplicateArcs(const Graph &graph)
Returns a copy of "graph", without self-arcs and duplicate arcs.
std::vector< int > GetWeaklyConnectedComponents(const Graph &graph)
bool GraphIsWeaklyConnected(const Graph &graph)
bool GraphHasSelfArcs(const Graph &graph)
Implementations of the templated methods.
bool IsSubsetOf0N(absl::Span< const int > v, int n)
std::unique_ptr< Graph > GetSubgraphOfNodes(const Graph &graph, absl::Span< const int > nodes)
std::vector< int > ComputeOnePossibleReverseArcMapping(const Graph &graph, bool die_if_not_symmetric)
ListGraph Graph
Defining the simplest Graph interface as Graph for convenience.