C++ Reference

C++ Reference: Graph

util.h
Go to the documentation of this file.
1 // Copyright 2010-2018 Google LLC
2 // Licensed under the Apache License, Version 2.0 (the "License");
3 // you may not use this file except in compliance with the License.
4 // You may obtain a copy of the License at
5 //
6 // http://www.apache.org/licenses/LICENSE-2.0
7 //
8 // Unless required by applicable law or agreed to in writing, software
9 // distributed under the License is distributed on an "AS IS" BASIS,
10 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11 // See the License for the specific language governing permissions and
12 // limitations under the License.
13 
14 // A collections of utilities for the Graph classes in ./graph.h.
15 
16 #ifndef UTIL_GRAPH_UTIL_H_
17 #define UTIL_GRAPH_UTIL_H_
18 
19 #include <algorithm>
20 #include <map>
21 #include <memory>
22 #include <set>
23 #include <string>
24 #include <unordered_map>
25 #include <vector>
26 
27 #include "ortools/base/hash.h"
28 #include "ortools/base/map_util.h"
30 #include "ortools/graph/graph.h"
32 
33 namespace util {
34 
35 // Here's a set of simple diagnosis tools. Notes:
36 // - A self-arc is an arc from a node to itself.
37 // - We say that an arc A->B is duplicate when there is another arc A->B in the
38 // same graph.
39 // - A graph is said "weakly connected" if it is connected when considering all
40 // arcs as undirected edges.
41 // - A graph is said "symmetric" iff for all (a, b), the number of arcs a->b
42 // is equal to the number of arcs b->a.
43 //
44 // All these diagnosis work in O(graph size), since the inverse Ackerman
45 // function is <= 5 for all practical instances, and are very fast.
46 //
47 // If the graph is a "static" kind, they must be finalized, except for
48 // GraphHasSelfArcs() and GraphIsWeaklyConnected() which also support
49 // non-finalized StaticGraph<>.
50 template <class Graph>
51 bool GraphHasSelfArcs(const Graph& graph);
52 template <class Graph>
53 bool GraphHasDuplicateArcs(const Graph& graph);
54 template <class Graph>
55 bool GraphIsSymmetric(const Graph& graph);
56 template <class Graph>
57 bool GraphIsWeaklyConnected(const Graph& graph);
58 
59 // Returns a fresh copy of a given graph.
60 template <class Graph>
61 std::unique_ptr<Graph> CopyGraph(const Graph& graph);
62 
63 // Creates a remapped copy of graph "graph", where node i becomes node
64 // new_node_index[i].
65 // "new_node_index" must be a valid permutation of [0..num_nodes-1] or the
66 // behavior is undefined (it may die).
67 // Note that you can call IsValidPermutation() to check it yourself.
68 template <class Graph>
69 std::unique_ptr<Graph> RemapGraph(const Graph& graph,
70  const std::vector<int>& new_node_index);
71 
72 // Gets the induced subgraph of "graph" restricted to the nodes in "nodes":
73 // the resulting graph will have exactly nodes.size() nodes, and its
74 // node #0 will be the former graph's node #nodes[0], etc.
75 // See https://en.wikipedia.org/wiki/Induced_subgraph .
76 // The "nodes" must be a valid subset (no repetitions) of
77 // [0..graph.num_nodes()-1], or the behavior is undefined (it may die).
78 // Note that you can call IsSubsetOf0N() to check it yourself.
79 //
80 // Current complexity: O(num old nodes + num new arcs). It could easily
81 // be done in O(num new nodes + num new arcs) but with a higher constant.
82 template <class Graph>
83 std::unique_ptr<Graph> GetSubgraphOfNodes(const Graph& graph,
84  const std::vector<int>& nodes);
85 
86 // This can be used to view a directed graph (that supports reverse arcs)
87 // from graph.h as un undirected graph: operator[](node) returns a
88 // pseudo-container that iterates over all nodes adjacent to "node" (from
89 // outgoing or incoming arcs).
90 // CAVEAT: Self-arcs (aka loops) will appear twice.
91 //
92 // Example:
93 // ReverseArcsStaticGraph<> dgraph;
94 // ...
95 // UndirectedAdjacencyListsOfDirectedGraph<decltype(dgraph)> ugraph(dgraph);
96 // for (int neighbor_of_node_42 : ugraph[42]) { ... }
97 template <class Graph>
99  public:
101  : graph_(graph) {}
102 
103  typedef typename Graph::OutgoingOrOppositeIncomingArcIterator ArcIterator;
105  public:
106  explicit AdjacencyListIterator(const Graph& graph, ArcIterator&& arc_it)
107  : ArcIterator(arc_it), graph_(graph) {}
108  // Overwrite operator* to return the heads of the arcs.
109  typename Graph::NodeIndex operator*() const {
110  return graph_.Head(ArcIterator::operator*());
111  }
112 
113  private:
114  const Graph& graph_;
115  };
116 
117  // Returns a pseudo-container of all the nodes adjacent to "node".
119  const auto& arc_range = graph_.OutgoingOrOppositeIncomingArcs(node);
120  return {AdjacencyListIterator(graph_, arc_range.begin()),
121  AdjacencyListIterator(graph_, arc_range.end())};
122  }
123 
124  private:
125  const Graph& graph_;
126 };
127 
128 // Computes the weakly connected components of a directed graph that
129 // provides the OutgoingOrOppositeIncomingArcs() API, and returns them
130 // as a mapping from node to component index. See GetConnectedComponens().
131 template <class Graph>
132 std::vector<int> GetWeaklyConnectedComponents(const Graph& graph) {
133  return GetConnectedComponents(
135 }
136 
137 // Returns true iff the given vector is a subset of [0..n-1], i.e.
138 // all elements i are such that 0 <= i < n and no two elements are equal.
139 // "n" must be >= 0 or the result is undefined.
140 bool IsSubsetOf0N(const std::vector<int>& v, int n);
141 
142 // Returns true iff the given vector is a permutation of [0..size()-1].
143 inline bool IsValidPermutation(const std::vector<int>& v) {
144  return IsSubsetOf0N(v, v.size());
145 }
146 
147 // Returns a copy of "graph", without self-arcs and duplicate arcs.
148 template <class Graph>
149 std::unique_ptr<Graph> RemoveSelfArcsAndDuplicateArcs(const Graph& graph);
150 
151 // Given an arc path, changes it to a sub-path with the same source and
152 // destination but without any cycle. Nothing happen if the path was already
153 // without cycle.
154 //
155 // The graph class should support Tail(arc) and Head(arc). They should both
156 // return an integer representing the corresponding tail/head of the passed arc.
157 //
158 // TODO(user): In some cases, there is more than one possible solution. We could
159 // take some arc costs and return the cheapest path instead. Or return the
160 // shortest path in term of number of arcs.
161 template <class Graph>
162 void RemoveCyclesFromPath(const Graph& graph, std::vector<int>* arc_path);
163 
164 // Returns true iff the given path contains a cycle.
165 template <class Graph>
166 bool PathHasCycle(const Graph& graph, const std::vector<int>& arc_path);
167 
168 // Returns a vector representing a mapping from arcs to arcs such that each arc
169 // is mapped to another arc with its (tail, head) flipped, if such an arc
170 // exists (otherwise it is mapped to -1).
171 // If the graph is symmetric, the returned mapping is bijective and reflexive,
172 // i.e. out[out[arc]] = arc for all "arc", where "out" is the returned vector.
173 // If "die_if_not_symmetric" is true, this function CHECKs() that the graph
174 // is symmetric.
175 //
176 // Self-arcs are always mapped to themselves.
177 //
178 // Note that since graphs may have multi-arcs, the mapping isn't necessarily
179 // unique, hence the function name.
180 template <class Graph>
181 std::vector<int> ComputeOnePossibleReverseArcMapping(const Graph& graph,
182  bool die_if_not_symmetric);
183 
184 // Implementations of the templated methods.
185 
186 template <class Graph>
187 bool GraphHasSelfArcs(const Graph& graph) {
188  for (const auto arc : graph.AllForwardArcs()) {
189  if (graph.Tail(arc) == graph.Head(arc)) return true;
190  }
191  return false;
192 }
193 
194 template <class Graph>
195 bool GraphHasDuplicateArcs(const Graph& graph) {
196  typedef typename Graph::ArcIndex ArcIndex;
197  typedef typename Graph::NodeIndex NodeIndex;
198  std::vector<bool> tmp_node_mask(graph.num_nodes(), false);
199  for (const NodeIndex tail : graph.AllNodes()) {
200  for (const ArcIndex arc : graph.OutgoingArcs(tail)) {
201  const NodeIndex head = graph.Head(arc);
202  if (tmp_node_mask[head]) return true;
203  tmp_node_mask[head] = true;
204  }
205  for (const ArcIndex arc : graph.OutgoingArcs(tail)) {
206  tmp_node_mask[graph.Head(arc)] = false;
207  }
208  }
209  return false;
210 }
211 
212 template <class Graph>
213 bool GraphIsSymmetric(const Graph& graph) {
214  typedef typename Graph::NodeIndex NodeIndex;
215  typedef typename Graph::ArcIndex ArcIndex;
216  // Create a reverse copy of the graph.
217  StaticGraph<NodeIndex, ArcIndex> reverse_graph(graph.num_nodes(),
218  graph.num_arcs());
219  for (const NodeIndex node : graph.AllNodes()) {
220  for (const ArcIndex arc : graph.OutgoingArcs(node)) {
221  reverse_graph.AddArc(graph.Head(arc), node);
222  }
223  }
224  reverse_graph.Build();
225  // Compare the graph to its reverse, one adjacency list at a time.
226  std::vector<ArcIndex> count(graph.num_nodes(), 0);
227  for (const NodeIndex node : graph.AllNodes()) {
228  for (const ArcIndex arc : graph.OutgoingArcs(node)) {
229  ++count[graph.Head(arc)];
230  }
231  for (const ArcIndex arc : reverse_graph.OutgoingArcs(node)) {
232  if (--count[reverse_graph.Head(arc)] < 0) return false;
233  }
234  for (const ArcIndex arc : graph.OutgoingArcs(node)) {
235  if (count[graph.Head(arc)] != 0) return false;
236  }
237  }
238  return true;
239 }
240 
241 template <class Graph>
242 bool GraphIsWeaklyConnected(const Graph& graph) {
243  typedef typename Graph::NodeIndex NodeIndex;
244  static_assert(std::numeric_limits<NodeIndex>::max() <= INT_MAX,
245  "GraphIsWeaklyConnected() isn't yet implemented for graphs"
246  " that support more than INT_MAX nodes. Reach out to"
247  " or-core-team@ if you need this.");
248  if (graph.num_nodes() == 0) return true;
250  union_find.SetNumberOfNodes(graph.num_nodes());
251  for (typename Graph::ArcIndex arc = 0; arc < graph.num_arcs(); ++arc) {
252  union_find.AddEdge(graph.Tail(arc), graph.Head(arc));
253  }
254  return union_find.GetNumberOfComponents() == 1;
255 }
256 
257 template <class Graph>
258 std::unique_ptr<Graph> CopyGraph(const Graph& graph) {
259  std::unique_ptr<Graph> new_graph(
260  new Graph(graph.num_nodes(), graph.num_arcs()));
261  for (const auto node : graph.AllNodes()) {
262  for (const auto arc : graph.OutgoingArcs(node)) {
263  new_graph->AddArc(node, graph.Head(arc));
264  }
265  }
266  new_graph->Build();
267  return new_graph;
268 }
269 
270 template <class Graph>
271 std::unique_ptr<Graph> RemapGraph(const Graph& old_graph,
272  const std::vector<int>& new_node_index) {
273  DCHECK(IsValidPermutation(new_node_index)) << "Invalid permutation";
274  const int num_nodes = old_graph.num_nodes();
275  CHECK_EQ(new_node_index.size(), num_nodes);
276  std::unique_ptr<Graph> new_graph(new Graph(num_nodes, old_graph.num_arcs()));
277  typedef typename Graph::NodeIndex NodeIndex;
278  typedef typename Graph::ArcIndex ArcIndex;
279  for (const NodeIndex node : old_graph.AllNodes()) {
280  for (const ArcIndex arc : old_graph.OutgoingArcs(node)) {
281  new_graph->AddArc(new_node_index[node],
282  new_node_index[old_graph.Head(arc)]);
283  }
284  }
285  new_graph->Build();
286  return new_graph;
287 }
288 
289 template <class Graph>
290 std::unique_ptr<Graph> GetSubgraphOfNodes(const Graph& old_graph,
291  const std::vector<int>& nodes) {
292  typedef typename Graph::NodeIndex NodeIndex;
293  typedef typename Graph::ArcIndex ArcIndex;
294  DCHECK(IsSubsetOf0N(nodes, old_graph.num_nodes())) << "Invalid subset";
295  std::vector<NodeIndex> new_node_index(old_graph.num_nodes(), -1);
296  for (NodeIndex new_index = 0; new_index < nodes.size(); ++new_index) {
297  new_node_index[nodes[new_index]] = new_index;
298  }
299  // Do a first pass to count the arcs, so that we don't allocate more memory
300  // than needed.
301  ArcIndex num_arcs = 0;
302  for (const NodeIndex node : nodes) {
303  for (const ArcIndex arc : old_graph.OutgoingArcs(node)) {
304  if (new_node_index[old_graph.Head(arc)] != -1) ++num_arcs;
305  }
306  }
307  // A second pass where we actually copy the subgraph.
308  // NOTE(user): there might seem to be a bit of duplication with RemapGraph(),
309  // but there is a key difference: the loop below only iterates on "nodes",
310  // which could be much smaller than all the graph's nodes.
311  std::unique_ptr<Graph> new_graph(new Graph(nodes.size(), num_arcs));
312  for (NodeIndex new_tail = 0; new_tail < nodes.size(); ++new_tail) {
313  const NodeIndex old_tail = nodes[new_tail];
314  for (const ArcIndex arc : old_graph.OutgoingArcs(old_tail)) {
315  const NodeIndex new_head = new_node_index[old_graph.Head(arc)];
316  if (new_head != -1) new_graph->AddArc(new_tail, new_head);
317  }
318  }
319  new_graph->Build();
320  return new_graph;
321 }
322 
323 template <class Graph>
324 std::unique_ptr<Graph> RemoveSelfArcsAndDuplicateArcs(const Graph& graph) {
325  std::unique_ptr<Graph> g(new Graph(graph.num_nodes(), graph.num_arcs()));
326  typedef typename Graph::ArcIndex ArcIndex;
327  typedef typename Graph::NodeIndex NodeIndex;
328  std::vector<bool> tmp_node_mask(graph.num_nodes(), false);
329  for (const NodeIndex tail : graph.AllNodes()) {
330  for (const ArcIndex arc : graph.OutgoingArcs(tail)) {
331  const NodeIndex head = graph.Head(arc);
332  if (head != tail && !tmp_node_mask[head]) {
333  tmp_node_mask[head] = true;
334  g->AddArc(tail, head);
335  }
336  }
337  for (const ArcIndex arc : graph.OutgoingArcs(tail)) {
338  tmp_node_mask[graph.Head(arc)] = false;
339  }
340  }
341  g->Build();
342  return g;
343 }
344 
345 template <class Graph>
346 void RemoveCyclesFromPath(const Graph& graph, std::vector<int>* arc_path) {
347  if (arc_path->empty()) return;
348 
349  // This maps each node to the latest arc in the given path that leaves it.
350  std::map<int, int> last_arc_leaving_node;
351  for (const int arc : *arc_path) last_arc_leaving_node[graph.Tail(arc)] = arc;
352 
353  // Special case for the destination.
354  // Note that this requires that -1 is not a valid arc of Graph.
355  last_arc_leaving_node[graph.Head(arc_path->back())] = -1;
356 
357  // Reconstruct the path by starting at the source and then following the
358  // "next" arcs. We override the given arc_path at the same time.
359  int node = graph.Tail(arc_path->front());
360  int new_size = 0;
361  while (new_size < arc_path->size()) { // To prevent cycle on bad input.
362  const int arc = gtl::FindOrDie(last_arc_leaving_node, node);
363  if (arc == -1) break;
364  (*arc_path)[new_size++] = arc;
365  node = graph.Head(arc);
366  }
367  arc_path->resize(new_size);
368 }
369 
370 template <class Graph>
371 bool PathHasCycle(const Graph& graph, const std::vector<int>& arc_path) {
372  if (arc_path.empty()) return false;
373  std::set<int> seen;
374  seen.insert(graph.Tail(arc_path.front()));
375  for (const int arc : arc_path) {
376  if (!gtl::InsertIfNotPresent(&seen, graph.Head(arc))) return true;
377  }
378  return false;
379 }
380 
381 template <class Graph>
383  const Graph& graph, bool die_if_not_symmetric) {
384  std::vector<int> reverse_arc(graph.num_arcs(), -1);
385  std::unordered_multimap<std::pair</*tail*/ int, /*head*/ int>,
386  /*arc index*/ int>
387  arc_map;
388  for (int arc = 0; arc < graph.num_arcs(); ++arc) {
389  const int tail = graph.Tail(arc);
390  const int head = graph.Head(arc);
391  if (tail == head) {
392  // Special case: directly map any self-arc to itself.
393  reverse_arc[arc] = arc;
394  continue;
395  }
396  // Lookup for the reverse arc of the current one...
397  auto it = arc_map.find({head, tail});
398  if (it != arc_map.end()) {
399  // Found a reverse arc! Store the mapping and remove the
400  // reverse arc from the map.
401  reverse_arc[arc] = it->second;
402  reverse_arc[it->second] = arc;
403  arc_map.erase(it);
404  } else {
405  // Reverse arc not in the map. Add the current arc to the map.
406  arc_map.insert({{tail, head}, arc});
407  }
408  }
409  // Algorithm check, for debugging.
410  DCHECK_EQ(std::count(reverse_arc.begin(), reverse_arc.end(), -1),
411  arc_map.size());
412  if (die_if_not_symmetric) {
413  CHECK_EQ(arc_map.size(), 0)
414  << "The graph is not symmetric: " << arc_map.size() << " of "
415  << graph.num_arcs() << " arcs did not have a reverse.";
416  }
417  return reverse_arc;
418 }
419 
420 } // namespace util
421 
422 #endif // UTIL_GRAPH_UTIL_H_
IntegerRange< NodeIndex > AllNodes() const
Definition: graph.h:929
bool GraphHasDuplicateArcs(const Graph &graph)
Definition: util.h:195
int32 NodeIndex
Definition: graph.h:189
bool IsSubsetOf0N(const std::vector< int > &v, int n)
NodeIndexType Tail(ArcIndexType arc) const
Definition: graph.h:1105
std::unique_ptr< Graph > CopyGraph(const Graph &graph)
Definition: util.h:258
ListGraph Graph
Definition: graph.h:2356
void AddEdge(int node1, int node2)
UndirectedAdjacencyListsOfDirectedGraph(const Graph &graph)
Definition: util.h:100
int GetNumberOfComponents() const
bool GraphIsSymmetric(const Graph &graph)
Definition: util.h:213
std::unique_ptr< Graph > RemoveSelfArcsAndDuplicateArcs(const Graph &graph)
Definition: util.h:324
NodeIndexType Head(ArcIndexType arc) const
Definition: graph.h:1309
Graph::NodeIndex operator*() const
Definition: util.h:109
bool GraphIsWeaklyConnected(const Graph &graph)
Definition: util.h:242
BeginEndWrapper< AdjacencyListIterator > operator[](int node) const
Definition: util.h:118
ArcIndexType num_arcs() const
Definition: graph.h:204
BeginEndWrapper< OutgoingArcIterator > OutgoingArcs(NodeIndexType node) const
NodeIndexType Head(ArcIndexType arc) const
Definition: graph.h:1112
std::unique_ptr< Graph > RemapGraph(const Graph &graph, const std::vector< int > &new_node_index)
Definition: util.h:271
IntegerRange< ArcIndex > AllForwardArcs() const
Definition: graph.h:935
void Build()
Definition: graph.h:434
std::vector< int > ComputeOnePossibleReverseArcMapping(const Graph &graph, bool die_if_not_symmetric)
Definition: util.h:382
bool IsValidPermutation(const std::vector< int > &v)
Definition: util.h:143
ArcIndexType AddArc(NodeIndexType tail, NodeIndexType head)
Definition: graph.h:1281
Definition: graph.h:396
int32 ArcIndex
Definition: graph.h:190
std::vector< int > GetConnectedComponents(int num_nodes, const UndirectedGraph &graph)
int32 ArcIndex
Definition: ebert_graph.h:201
BeginEndWrapper< OutgoingArcIterator > OutgoingArcs(NodeIndexType node) const
void SetNumberOfNodes(int num_nodes)
std::unique_ptr< Graph > GetSubgraphOfNodes(const Graph &graph, const std::vector< int > &nodes)
Definition: util.h:290
void RemoveCyclesFromPath(const Graph &graph, std::vector< int > *arc_path)
Definition: util.h:346
int32 NodeIndex
Definition: ebert_graph.h:192
bool PathHasCycle(const Graph &graph, const std::vector< int > &arc_path)
Definition: util.h:371
Definition: iterators.h:38
Graph::OutgoingOrOppositeIncomingArcIterator ArcIterator
Definition: util.h:103
Definition: graph.h:297
NodeIndexType num_nodes() const
Definition: graph.h:201
AdjacencyListIterator(const Graph &graph, ArcIterator &&arc_it)
Definition: util.h:106
Definition: util.h:104
std::vector< int > GetWeaklyConnectedComponents(const Graph &graph)
Definition: util.h:132
bool GraphHasSelfArcs(const Graph &graph)
Definition: util.h:187
Definition: util.h:98