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