001/* 002 * Copyright (C) 2014 The Guava Authors 003 * 004 * Licensed under the Apache License, Version 2.0 (the "License"); 005 * you may not use this file except in compliance with the License. 006 * You may obtain a copy of the License at 007 * 008 * http://www.apache.org/licenses/LICENSE-2.0 009 * 010 * Unless required by applicable law or agreed to in writing, software 011 * distributed under the License is distributed on an "AS IS" BASIS, 012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 013 * See the License for the specific language governing permissions and 014 * limitations under the License. 015 */ 016 017package com.google.common.graph; 018 019import static com.google.common.base.Preconditions.checkArgument; 020import static com.google.common.graph.GraphConstants.NODE_NOT_IN_GRAPH; 021 022import com.google.common.annotations.Beta; 023import com.google.common.base.Objects; 024import com.google.common.collect.Iterables; 025import com.google.common.collect.Maps; 026import com.google.errorprone.annotations.CanIgnoreReturnValue; 027import java.util.ArrayDeque; 028import java.util.Collections; 029import java.util.HashSet; 030import java.util.LinkedHashSet; 031import java.util.Map; 032import java.util.Queue; 033import java.util.Set; 034import javax.annotation.Nullable; 035 036/** 037 * Static utility methods for {@link Graph}, {@link ValueGraph}, and {@link Network} instances. 038 * 039 * @author James Sexton 040 * @author Joshua O'Madadhain 041 * @since 20.0 042 */ 043@Beta 044public final class Graphs { 045 046 private Graphs() {} 047 048 // Graph query methods 049 050 /** 051 * Returns true if {@code graph} has at least one cycle. A cycle is defined as a non-empty subset 052 * of edges in a graph arranged to form a path (a sequence of adjacent outgoing edges) starting 053 * and ending with the same node. 054 * 055 * <p>This method will detect any non-empty cycle, including self-loops (a cycle of length 1). 056 */ 057 public static <N> boolean hasCycle(Graph<N> graph) { 058 int numEdges = graph.edges().size(); 059 if (numEdges == 0) { 060 return false; // An edge-free graph is acyclic by definition. 061 } 062 if (!graph.isDirected() && numEdges >= graph.nodes().size()) { 063 return true; // Optimization for the undirected case: at least one cycle must exist. 064 } 065 066 Map<Object, NodeVisitState> visitedNodes = 067 Maps.newHashMapWithExpectedSize(graph.nodes().size()); 068 for (N node : graph.nodes()) { 069 if (subgraphHasCycle(graph, visitedNodes, node, null)) { 070 return true; 071 } 072 } 073 return false; 074 } 075 076 /** 077 * Returns true if {@code network} has at least one cycle. A cycle is defined as a non-empty 078 * subset of edges in a graph arranged to form a path (a sequence of adjacent outgoing edges) 079 * starting and ending with the same node. 080 * 081 * <p>This method will detect any non-empty cycle, including self-loops (a cycle of length 1). 082 */ 083 public static boolean hasCycle(Network<?, ?> network) { 084 // In a directed graph, parallel edges cannot introduce a cycle in an acyclic graph. 085 // However, in an undirected graph, any parallel edge induces a cycle in the graph. 086 if (!network.isDirected() 087 && network.allowsParallelEdges() 088 && network.edges().size() > network.asGraph().edges().size()) { 089 return true; 090 } 091 return hasCycle(network.asGraph()); 092 } 093 094 /** 095 * Performs a traversal of the nodes reachable from {@code node}. If we ever reach a node we've 096 * already visited (following only outgoing edges and without reusing edges), we know there's a 097 * cycle in the graph. 098 */ 099 private static <N> boolean subgraphHasCycle( 100 Graph<N> graph, Map<Object, NodeVisitState> visitedNodes, N node, @Nullable N previousNode) { 101 NodeVisitState state = visitedNodes.get(node); 102 if (state == NodeVisitState.COMPLETE) { 103 return false; 104 } 105 if (state == NodeVisitState.PENDING) { 106 return true; 107 } 108 109 visitedNodes.put(node, NodeVisitState.PENDING); 110 for (N nextNode : graph.successors(node)) { 111 if (canTraverseWithoutReusingEdge(graph, nextNode, previousNode) 112 && subgraphHasCycle(graph, visitedNodes, nextNode, node)) { 113 return true; 114 } 115 } 116 visitedNodes.put(node, NodeVisitState.COMPLETE); 117 return false; 118 } 119 120 /** 121 * Determines whether an edge has already been used during traversal. In the directed case a cycle 122 * is always detected before reusing an edge, so no special logic is required. In the undirected 123 * case, we must take care not to "backtrack" over an edge (i.e. going from A to B and then going 124 * from B to A). 125 */ 126 private static boolean canTraverseWithoutReusingEdge( 127 Graph<?> graph, Object nextNode, @Nullable Object previousNode) { 128 if (graph.isDirected() || !Objects.equal(previousNode, nextNode)) { 129 return true; 130 } 131 // This falls into the undirected A->B->A case. The Graph interface does not support parallel 132 // edges, so this traversal would require reusing the undirected AB edge. 133 return false; 134 } 135 136 /** 137 * Returns the transitive closure of {@code graph}. The transitive closure of a graph is another 138 * graph with an edge connecting node A to node B if node B is {@link #reachableNodes(Graph, 139 * Object) reachable} from node A. 140 * 141 * <p>This is a "snapshot" based on the current topology of {@code graph}, rather than a live view 142 * of the transitive closure of {@code graph}. In other words, the returned {@link Graph} will not 143 * be updated after modifications to {@code graph}. 144 */ 145 // TODO(b/31438252): Consider potential optimizations for this algorithm. 146 public static <N> Graph<N> transitiveClosure(Graph<N> graph) { 147 MutableGraph<N> transitiveClosure = GraphBuilder.from(graph).allowsSelfLoops(true).build(); 148 // Every node is, at a minimum, reachable from itself. Since the resulting transitive closure 149 // will have no isolated nodes, we can skip adding nodes explicitly and let putEdge() do it. 150 151 if (graph.isDirected()) { 152 // Note: works for both directed and undirected graphs, but we only use in the directed case. 153 for (N node : graph.nodes()) { 154 for (N reachableNode : reachableNodes(graph, node)) { 155 transitiveClosure.putEdge(node, reachableNode); 156 } 157 } 158 } else { 159 // An optimization for the undirected case: for every node B reachable from node A, 160 // node A and node B have the same reachability set. 161 Set<N> visitedNodes = new HashSet<N>(); 162 for (N node : graph.nodes()) { 163 if (!visitedNodes.contains(node)) { 164 Set<N> reachableNodes = reachableNodes(graph, node); 165 visitedNodes.addAll(reachableNodes); 166 int pairwiseMatch = 1; // start at 1 to include self-loops 167 for (N nodeU : reachableNodes) { 168 for (N nodeV : Iterables.limit(reachableNodes, pairwiseMatch++)) { 169 transitiveClosure.putEdge(nodeU, nodeV); 170 } 171 } 172 } 173 } 174 } 175 176 return transitiveClosure; 177 } 178 179 /** 180 * Returns the set of nodes that are reachable from {@code node}. Node B is defined as reachable 181 * from node A if there exists a path (a sequence of adjacent outgoing edges) starting at node A 182 * and ending at node B. Note that a node is always reachable from itself via a zero-length path. 183 * 184 * <p>This is a "snapshot" based on the current topology of {@code graph}, rather than a live view 185 * of the set of nodes reachable from {@code node}. In other words, the returned {@link Set} will 186 * not be updated after modifications to {@code graph}. 187 * 188 * @throws IllegalArgumentException if {@code node} is not present in {@code graph} 189 */ 190 public static <N> Set<N> reachableNodes(Graph<N> graph, N node) { 191 checkArgument(graph.nodes().contains(node), NODE_NOT_IN_GRAPH, node); 192 Set<N> visitedNodes = new LinkedHashSet<N>(); 193 Queue<N> queuedNodes = new ArrayDeque<N>(); 194 visitedNodes.add(node); 195 queuedNodes.add(node); 196 // Perform a breadth-first traversal rooted at the input node. 197 while (!queuedNodes.isEmpty()) { 198 N currentNode = queuedNodes.remove(); 199 for (N successor : graph.successors(currentNode)) { 200 if (visitedNodes.add(successor)) { 201 queuedNodes.add(successor); 202 } 203 } 204 } 205 return Collections.unmodifiableSet(visitedNodes); 206 } 207 208 /** 209 * @deprecated Use {@link Graph#equals(Object)} instead. This method will be removed in late 2017. 210 */ 211 // TODO(user): Delete this method. 212 @Deprecated 213 public static boolean equivalent(@Nullable Graph<?> graphA, @Nullable Graph<?> graphB) { 214 return Objects.equal(graphA, graphB); 215 } 216 217 /** 218 * @deprecated Use {@link ValueGraph#equals(Object)} instead. This method will be removed in late 219 * 2017. 220 */ 221 // TODO(user): Delete this method. 222 @Deprecated 223 public static boolean equivalent( 224 @Nullable ValueGraph<?, ?> graphA, @Nullable ValueGraph<?, ?> graphB) { 225 return Objects.equal(graphA, graphB); 226 } 227 228 /** 229 * @deprecated Use {@link Network#equals(Object)} instead. This method will be removed in late 230 * 2017. 231 */ 232 // TODO(user): Delete this method. 233 @Deprecated 234 public static boolean equivalent( 235 @Nullable Network<?, ?> networkA, @Nullable Network<?, ?> networkB) { 236 return Objects.equal(networkA, networkB); 237 } 238 239 // Graph mutation methods 240 241 // Graph view methods 242 243 /** 244 * Returns a view of {@code graph} with the direction (if any) of every edge reversed. All other 245 * properties remain intact, and further updates to {@code graph} will be reflected in the view. 246 */ 247 public static <N> Graph<N> transpose(Graph<N> graph) { 248 if (!graph.isDirected()) { 249 return graph; // the transpose of an undirected graph is an identical graph 250 } 251 252 if (graph instanceof TransposedGraph) { 253 return ((TransposedGraph<N>) graph).graph; 254 } 255 256 return new TransposedGraph<N>(graph); 257 } 258 259 private static class TransposedGraph<N> extends AbstractGraph<N> { 260 private final Graph<N> graph; 261 262 TransposedGraph(Graph<N> graph) { 263 this.graph = graph; 264 } 265 266 @Override 267 public Set<N> nodes() { 268 return graph.nodes(); 269 } 270 271 /** 272 * Defer to {@link AbstractGraph#edges()} (based on {@link #successors(Object)}) for full 273 * edges() implementation. 274 */ 275 @Override 276 protected long edgeCount() { 277 return graph.edges().size(); 278 } 279 280 @Override 281 public boolean isDirected() { 282 return graph.isDirected(); 283 } 284 285 @Override 286 public boolean allowsSelfLoops() { 287 return graph.allowsSelfLoops(); 288 } 289 290 @Override 291 public ElementOrder<N> nodeOrder() { 292 return graph.nodeOrder(); 293 } 294 295 @Override 296 public Set<N> adjacentNodes(N node) { 297 return graph.adjacentNodes(node); 298 } 299 300 @Override 301 public Set<N> predecessors(N node) { 302 return graph.successors(node); // transpose 303 } 304 305 @Override 306 public Set<N> successors(N node) { 307 return graph.predecessors(node); // transpose 308 } 309 } 310 311 /** 312 * Returns a view of {@code graph} with the direction (if any) of every edge reversed. All other 313 * properties remain intact, and further updates to {@code graph} will be reflected in the view. 314 */ 315 public static <N, V> ValueGraph<N, V> transpose(ValueGraph<N, V> graph) { 316 if (!graph.isDirected()) { 317 return graph; // the transpose of an undirected graph is an identical graph 318 } 319 320 if (graph instanceof TransposedValueGraph) { 321 return ((TransposedValueGraph<N, V>) graph).graph; 322 } 323 324 return new TransposedValueGraph<N, V>(graph); 325 } 326 327 private static class TransposedValueGraph<N, V> extends AbstractValueGraph<N, V> { 328 private final ValueGraph<N, V> graph; 329 330 TransposedValueGraph(ValueGraph<N, V> graph) { 331 this.graph = graph; 332 } 333 334 @Override 335 public Set<N> nodes() { 336 return graph.nodes(); 337 } 338 339 /** 340 * Defer to {@link AbstractGraph#edges()} (based on {@link #successors(Object)}) for full 341 * edges() implementation. 342 */ 343 @Override 344 protected long edgeCount() { 345 return graph.edges().size(); 346 } 347 348 @Override 349 public boolean isDirected() { 350 return graph.isDirected(); 351 } 352 353 @Override 354 public boolean allowsSelfLoops() { 355 return graph.allowsSelfLoops(); 356 } 357 358 @Override 359 public ElementOrder<N> nodeOrder() { 360 return graph.nodeOrder(); 361 } 362 363 @Override 364 public Set<N> adjacentNodes(N node) { 365 return graph.adjacentNodes(node); 366 } 367 368 @Override 369 public Set<N> predecessors(N node) { 370 return graph.successors(node); // transpose 371 } 372 373 @Override 374 public Set<N> successors(N node) { 375 return graph.predecessors(node); // transpose 376 } 377 378 @Override 379 public V edgeValue(N nodeU, N nodeV) { 380 return graph.edgeValue(nodeV, nodeU); // transpose 381 } 382 383 @Override 384 public V edgeValueOrDefault(N nodeU, N nodeV, @Nullable V defaultValue) { 385 return graph.edgeValueOrDefault(nodeV, nodeU, defaultValue); // transpose 386 } 387 } 388 389 /** 390 * Returns a view of {@code network} with the direction (if any) of every edge reversed. All other 391 * properties remain intact, and further updates to {@code network} will be reflected in the view. 392 */ 393 public static <N, E> Network<N, E> transpose(Network<N, E> network) { 394 if (!network.isDirected()) { 395 return network; // the transpose of an undirected network is an identical network 396 } 397 398 if (network instanceof TransposedNetwork) { 399 return ((TransposedNetwork<N, E>) network).network; 400 } 401 402 return new TransposedNetwork<N, E>(network); 403 } 404 405 private static class TransposedNetwork<N, E> extends AbstractNetwork<N, E> { 406 private final Network<N, E> network; 407 408 TransposedNetwork(Network<N, E> network) { 409 this.network = network; 410 } 411 412 @Override 413 public Set<N> nodes() { 414 return network.nodes(); 415 } 416 417 @Override 418 public Set<E> edges() { 419 return network.edges(); 420 } 421 422 @Override 423 public boolean isDirected() { 424 return network.isDirected(); 425 } 426 427 @Override 428 public boolean allowsParallelEdges() { 429 return network.allowsParallelEdges(); 430 } 431 432 @Override 433 public boolean allowsSelfLoops() { 434 return network.allowsSelfLoops(); 435 } 436 437 @Override 438 public ElementOrder<N> nodeOrder() { 439 return network.nodeOrder(); 440 } 441 442 @Override 443 public ElementOrder<E> edgeOrder() { 444 return network.edgeOrder(); 445 } 446 447 @Override 448 public Set<N> adjacentNodes(N node) { 449 return network.adjacentNodes(node); 450 } 451 452 @Override 453 public Set<N> predecessors(N node) { 454 return network.successors(node); // transpose 455 } 456 457 @Override 458 public Set<N> successors(N node) { 459 return network.predecessors(node); // transpose 460 } 461 462 @Override 463 public Set<E> incidentEdges(N node) { 464 return network.incidentEdges(node); 465 } 466 467 @Override 468 public Set<E> inEdges(N node) { 469 return network.outEdges(node); // transpose 470 } 471 472 @Override 473 public Set<E> outEdges(N node) { 474 return network.inEdges(node); // transpose 475 } 476 477 @Override 478 public EndpointPair<N> incidentNodes(E edge) { 479 EndpointPair<N> endpointPair = network.incidentNodes(edge); 480 return EndpointPair.of(network, endpointPair.nodeV(), endpointPair.nodeU()); // transpose 481 } 482 483 @Override 484 public Set<E> adjacentEdges(E edge) { 485 return network.adjacentEdges(edge); 486 } 487 488 @Override 489 public Set<E> edgesConnecting(N nodeU, N nodeV) { 490 return network.edgesConnecting(nodeV, nodeU); // transpose 491 } 492 } 493 494 // Graph copy methods 495 496 /** 497 * Returns the subgraph of {@code graph} induced by {@code nodes}. This subgraph is a new graph 498 * that contains all of the nodes in {@code nodes}, and all of the {@link Graph#edges() edges} 499 * from {@code graph} for which both nodes are contained by {@code nodes}. 500 * 501 * @throws IllegalArgumentException if any element in {@code nodes} is not a node in the graph 502 */ 503 public static <N> MutableGraph<N> inducedSubgraph(Graph<N> graph, Iterable<? extends N> nodes) { 504 MutableGraph<N> subgraph = GraphBuilder.from(graph).build(); 505 for (N node : nodes) { 506 subgraph.addNode(node); 507 } 508 for (N node : subgraph.nodes()) { 509 for (N successorNode : graph.successors(node)) { 510 if (subgraph.nodes().contains(successorNode)) { 511 subgraph.putEdge(node, successorNode); 512 } 513 } 514 } 515 return subgraph; 516 } 517 518 /** 519 * Returns the subgraph of {@code graph} induced by {@code nodes}. This subgraph is a new graph 520 * that contains all of the nodes in {@code nodes}, and all of the {@link Graph#edges() edges} 521 * (and associated edge values) from {@code graph} for which both nodes are contained by {@code 522 * nodes}. 523 * 524 * @throws IllegalArgumentException if any element in {@code nodes} is not a node in the graph 525 */ 526 public static <N, V> MutableValueGraph<N, V> inducedSubgraph( 527 ValueGraph<N, V> graph, Iterable<? extends N> nodes) { 528 MutableValueGraph<N, V> subgraph = ValueGraphBuilder.from(graph).build(); 529 for (N node : nodes) { 530 subgraph.addNode(node); 531 } 532 for (N node : subgraph.nodes()) { 533 for (N successorNode : graph.successors(node)) { 534 if (subgraph.nodes().contains(successorNode)) { 535 subgraph.putEdgeValue(node, successorNode, graph.edgeValue(node, successorNode)); 536 } 537 } 538 } 539 return subgraph; 540 } 541 542 /** 543 * Returns the subgraph of {@code network} induced by {@code nodes}. This subgraph is a new graph 544 * that contains all of the nodes in {@code nodes}, and all of the {@link Network#edges() edges} 545 * from {@code network} for which the {@link Network#incidentNodes(Object) incident nodes} are 546 * both contained by {@code nodes}. 547 * 548 * @throws IllegalArgumentException if any element in {@code nodes} is not a node in the graph 549 */ 550 public static <N, E> MutableNetwork<N, E> inducedSubgraph( 551 Network<N, E> network, Iterable<? extends N> nodes) { 552 MutableNetwork<N, E> subgraph = NetworkBuilder.from(network).build(); 553 for (N node : nodes) { 554 subgraph.addNode(node); 555 } 556 for (N node : subgraph.nodes()) { 557 for (E edge : network.outEdges(node)) { 558 N successorNode = network.incidentNodes(edge).adjacentNode(node); 559 if (subgraph.nodes().contains(successorNode)) { 560 subgraph.addEdge(node, successorNode, edge); 561 } 562 } 563 } 564 return subgraph; 565 } 566 567 /** Creates a mutable copy of {@code graph} with the same nodes and edges. */ 568 public static <N> MutableGraph<N> copyOf(Graph<N> graph) { 569 MutableGraph<N> copy = GraphBuilder.from(graph).expectedNodeCount(graph.nodes().size()).build(); 570 for (N node : graph.nodes()) { 571 copy.addNode(node); 572 } 573 for (EndpointPair<N> edge : graph.edges()) { 574 copy.putEdge(edge.nodeU(), edge.nodeV()); 575 } 576 return copy; 577 } 578 579 /** Creates a mutable copy of {@code graph} with the same nodes, edges, and edge values. */ 580 public static <N, V> MutableValueGraph<N, V> copyOf(ValueGraph<N, V> graph) { 581 MutableValueGraph<N, V> copy = 582 ValueGraphBuilder.from(graph).expectedNodeCount(graph.nodes().size()).build(); 583 for (N node : graph.nodes()) { 584 copy.addNode(node); 585 } 586 for (EndpointPair<N> edge : graph.edges()) { 587 copy.putEdgeValue(edge.nodeU(), edge.nodeV(), graph.edgeValue(edge.nodeU(), edge.nodeV())); 588 } 589 return copy; 590 } 591 592 /** Creates a mutable copy of {@code network} with the same nodes and edges. */ 593 public static <N, E> MutableNetwork<N, E> copyOf(Network<N, E> network) { 594 MutableNetwork<N, E> copy = 595 NetworkBuilder.from(network) 596 .expectedNodeCount(network.nodes().size()) 597 .expectedEdgeCount(network.edges().size()) 598 .build(); 599 for (N node : network.nodes()) { 600 copy.addNode(node); 601 } 602 for (E edge : network.edges()) { 603 EndpointPair<N> endpointPair = network.incidentNodes(edge); 604 copy.addEdge(endpointPair.nodeU(), endpointPair.nodeV(), edge); 605 } 606 return copy; 607 } 608 609 @CanIgnoreReturnValue 610 static int checkNonNegative(int value) { 611 checkArgument(value >= 0, "Not true that %s is non-negative.", value); 612 return value; 613 } 614 615 @CanIgnoreReturnValue 616 static int checkPositive(int value) { 617 checkArgument(value > 0, "Not true that %s is positive.", value); 618 return value; 619 } 620 621 @CanIgnoreReturnValue 622 static long checkNonNegative(long value) { 623 checkArgument(value >= 0, "Not true that %s is non-negative.", value); 624 return value; 625 } 626 627 @CanIgnoreReturnValue 628 static long checkPositive(long value) { 629 checkArgument(value > 0, "Not true that %s is positive.", value); 630 return value; 631 } 632 633 /** 634 * An enum representing the state of a node during DFS. {@code PENDING} means that the node is on 635 * the stack of the DFS, while {@code COMPLETE} means that the node and all its successors have 636 * been already explored. Any node that has not been explored will not have a state at all. 637 */ 638 private enum NodeVisitState { 639 PENDING, 640 COMPLETE 641 } 642}