16#ifndef UTIL_GRAPH_UTIL_H_
17#define UTIL_GRAPH_UTIL_H_
28#include "absl/container/btree_map.h"
29#include "absl/container/flat_hash_map.h"
30#include "absl/container/inlined_vector.h"
31#include "absl/types/span.h"
75 absl::Span<const int> new_node_index);
89 absl::Span<const int>
nodes);
102template <
class Graph>
108 typedef typename Graph::OutgoingOrOppositeIncomingArcIterator
ArcIterator;
115 return graph_.
Head(ArcIterator::operator*());
124 const auto& arc_range = graph_.OutgoingOrOppositeIncomingArcs(node);
136template <
class Graph>
153template <
class Graph>
166template <
class Graph>
170template <
class Graph>
188template <
class Graph>
190 bool die_if_not_symmetric);
194template <
class Graph>
196 for (
const auto arc :
graph.AllForwardArcs()) {
202template <
class Graph>
206 std::vector<bool> tmp_node_mask(
graph.num_nodes(),
false);
207 for (
const NodeIndex
tail :
graph.AllNodes()) {
210 if (tmp_node_mask[
head])
return true;
211 tmp_node_mask[
head] =
true;
214 tmp_node_mask[
graph.Head(
arc)] =
false;
220template <
class Graph>
227 for (
const NodeIndex node :
graph.AllNodes()) {
228 for (
const ArcIndex
arc :
graph.OutgoingArcs(node)) {
232 reverse_graph.
Build();
234 std::vector<ArcIndex> count(
graph.num_nodes(), 0);
235 for (
const NodeIndex node :
graph.AllNodes()) {
236 for (
const ArcIndex
arc :
graph.OutgoingArcs(node)) {
240 if (--count[reverse_graph.
Head(
arc)] < 0)
return false;
242 for (
const ArcIndex
arc :
graph.OutgoingArcs(node)) {
243 if (count[
graph.Head(
arc)] != 0)
return false;
249template <
class Graph>
252 static_assert(std::numeric_limits<NodeIndex>::max() <= INT_MAX,
253 "GraphIsWeaklyConnected() isn't yet implemented for graphs"
254 " that support more than INT_MAX nodes. Reach out to"
255 " or-core-team@ if you need this.");
256 if (
graph.num_nodes() == 0)
return true;
265template <
class Graph>
267 std::unique_ptr<Graph> new_graph(
269 for (
const auto node :
graph.AllNodes()) {
270 for (
const auto arc :
graph.OutgoingArcs(node)) {
271 new_graph->AddArc(node,
graph.Head(
arc));
278template <
class Graph>
280 absl::Span<const int> new_node_index) {
282 const int num_nodes = old_graph.
num_nodes();
283 CHECK_EQ(new_node_index.size(), num_nodes);
284 std::unique_ptr<Graph> new_graph(
new Graph(num_nodes, old_graph.
num_arcs()));
287 for (
const NodeIndex node : old_graph.
AllNodes()) {
289 new_graph->AddArc(new_node_index[node],
290 new_node_index[old_graph.
Head(
arc)]);
297template <
class Graph>
299 absl::Span<const int>
nodes) {
303 std::vector<NodeIndex> new_node_index(old_graph.
num_nodes(), -1);
304 for (NodeIndex new_index = 0; new_index <
nodes.size(); ++new_index) {
305 new_node_index[
nodes[new_index]] = new_index;
309 ArcIndex num_arcs = 0;
310 for (
const NodeIndex node :
nodes) {
312 if (new_node_index[old_graph.
Head(
arc)] != -1) ++num_arcs;
319 std::unique_ptr<Graph> new_graph(
new Graph(
nodes.size(), num_arcs));
320 for (NodeIndex new_tail = 0; new_tail <
nodes.size(); ++new_tail) {
321 const NodeIndex old_tail =
nodes[new_tail];
323 const NodeIndex new_head = new_node_index[old_graph.
Head(
arc)];
324 if (new_head != -1) new_graph->AddArc(new_tail, new_head);
331template <
class Graph>
333 std::unique_ptr<Graph> g(
new Graph(
graph.num_nodes(),
graph.num_arcs()));
336 std::vector<bool> tmp_node_mask(
graph.num_nodes(),
false);
337 for (
const NodeIndex
tail :
graph.AllNodes()) {
341 tmp_node_mask[
head] =
true;
346 tmp_node_mask[
graph.Head(
arc)] =
false;
353template <
class Graph>
355 if (arc_path->empty())
return;
358 absl::btree_map<int, int> last_arc_leaving_node;
359 for (
const int arc : *arc_path) last_arc_leaving_node[
graph.Tail(
arc)] =
arc;
363 last_arc_leaving_node[
graph.Head(arc_path->back())] = -1;
367 int node =
graph.Tail(arc_path->front());
369 while (new_size < arc_path->
size()) {
371 if (
arc == -1)
break;
372 (*arc_path)[new_size++] =
arc;
375 arc_path->resize(new_size);
378template <
class Graph>
380 if (arc_path.empty())
return false;
382 seen.insert(
graph.Tail(arc_path.front()));
383 for (
const int arc : arc_path) {
389template <
class Graph>
391 const Graph& graph,
bool die_if_not_symmetric) {
392 std::vector<int> reverse_arc(
graph.num_arcs(), -1);
396 absl::flat_hash_map<std::pair< int,
int>,
397 absl::InlinedVector<int, 4>>
409 auto it = arc_map.find({
head,
tail});
410 if (it != arc_map.end()) {
413 reverse_arc[
arc] = it->second.back();
414 reverse_arc[it->second.back()] =
arc;
415 if (it->second.size() > 1) {
416 it->second.pop_back();
427 int64_t num_unmapped_arcs = 0;
428 for (
const auto& p : arc_map) {
429 num_unmapped_arcs += p.second.size();
431 DCHECK_EQ(std::count(reverse_arc.begin(), reverse_arc.end(), -1),
434 if (die_if_not_symmetric) {
435 CHECK_EQ(arc_map.size(), 0)
436 <<
"The graph is not symmetric: " << arc_map.size() <<
" of "
437 <<
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
IntegerRange< NodeIndex > AllNodes() const
BaseGraph implementation -------------------------------------------------—.
ArcIndexType num_arcs() const
Returns the number of valid arcs in the graph.
BeginEndWrapper< OutgoingArcIterator > OutgoingArcs(NodeIndexType node) const
NodeIndexType Head(ArcIndexType arc) const
ArcIndexType AddArc(NodeIndexType tail, NodeIndexType head)
BeginEndWrapper< OutgoingArcIterator > 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.
UndirectedAdjacencyListsOfDirectedGraph(const Graph &graph)
Graph::OutgoingOrOppositeIncomingArcIterator ArcIterator
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)
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.