001/*
002 * Copyright (C) 2017 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.base.Preconditions.checkNotNull;
021
022import com.google.common.annotations.Beta;
023import com.google.common.collect.AbstractIterator;
024import com.google.common.collect.ImmutableSet;
025import com.google.common.collect.Iterables;
026import com.google.common.collect.UnmodifiableIterator;
027import java.util.ArrayDeque;
028import java.util.Deque;
029import java.util.HashSet;
030import java.util.Iterator;
031import java.util.Queue;
032import java.util.Set;
033import org.checkerframework.checker.nullness.compatqual.NullableDecl;
034
035/**
036 * An object that can traverse the nodes that are reachable from a specified (set of) start node(s)
037 * using a specified {@link SuccessorsFunction}.
038 *
039 * <p>There are two entry points for creating a {@code Traverser}: {@link
040 * #forTree(SuccessorsFunction)} and {@link #forGraph(SuccessorsFunction)}. You should choose one
041 * based on your answers to the following questions:
042 *
043 * <ol>
044 *   <li>Is there only one path to any node that's reachable from any start node? (If so, the
045 *       graph to be traversed is a tree or forest even if it is a subgraph of a graph which is
046 *       neither.)
047 *   <li>Are the node objects' implementations of {@code equals()}/{@code hashCode()} <a
048 *       href="https://github.com/google/guava/wiki/GraphsExplained#non-recursiveness">recursive</a>?
049 * </ol>
050 *
051 * <p>If your answers are:
052 *
053 * <ul>
054 *   <li>(1) "no" and (2) "no", use {@link #forGraph(SuccessorsFunction)}.
055 *   <li>(1) "yes" and (2) "yes", use {@link #forTree(SuccessorsFunction)}.
056 *   <li>(1) "yes" and (2) "no", you can use either, but {@code forTree()} will be more efficient.
057 *   <li>(1) "no" and (2) "yes", <b><i>neither will work</i></b>, but if you transform your node
058 *       objects into a non-recursive form, you can use {@code forGraph()}.
059 * </ul>
060 *
061 * @author Jens Nyman
062 * @param <N> Node parameter type
063 * @since 23.1
064 */
065@Beta
066public abstract class Traverser<N> {
067
068  /**
069   * Creates a new traverser for the given general {@code graph}.
070   *
071   * <p>Traversers created using this method are guaranteed to visit each node reachable from the
072   * start node(s) at most once.
073   *
074   * <p>If you know that no node in {@code graph} is reachable by more than one path from the start
075   * node(s), consider using {@link #forTree(SuccessorsFunction)} instead.
076   *
077   * <p><b>Performance notes</b>
078   *
079   * <ul>
080   *   <li>Traversals require <i>O(n)</i> time (where <i>n</i> is the number of nodes reachable from
081   *       the start node), assuming that the node objects have <i>O(1)</i> {@code equals()} and
082   *       {@code hashCode()} implementations. (See the <a
083   *       href="https://github.com/google/guava/wiki/GraphsExplained#elements-must-be-useable-as-map-keys">
084   *       notes on element objects</a> for more information.)
085   *   <li>While traversing, the traverser will use <i>O(n)</i> space (where <i>n</i> is the number
086   *       of nodes that have thus far been visited), plus <i>O(H)</i> space (where <i>H</i> is the
087   *       number of nodes that have been seen but not yet visited, that is, the "horizon").
088   * </ul>
089   *
090   * @param graph {@link SuccessorsFunction} representing a general graph that may have cycles.
091   */
092  public static <N> Traverser<N> forGraph(SuccessorsFunction<N> graph) {
093    checkNotNull(graph);
094    return new GraphTraverser<>(graph);
095  }
096
097  /**
098   * Creates a new traverser for a directed acyclic graph that has at most one path from the start
099   * node(s) to any node reachable from the start node(s), and has no paths from any start node to
100   * any other start node, such as a tree or forest.
101   *
102   * <p>{@code forTree()} is especially useful (versus {@code forGraph()}) in cases where the data
103   * structure being traversed is, in addition to being a tree/forest, also defined <a
104   * href="https://github.com/google/guava/wiki/GraphsExplained#non-recursiveness">recursively</a>.
105   * This is because the {@code forTree()}-based implementations don't keep track of visited nodes,
106   * and therefore don't need to call `equals()` or `hashCode()` on the node objects; this saves
107   * both time and space versus traversing the same graph using {@code forGraph()}.
108   *
109   * <p>Providing a graph to be traversed for which there is more than one path from the start
110   * node(s) to any node may lead to:
111   *
112   * <ul>
113   *   <li>Traversal not terminating (if the graph has cycles)
114   *   <li>Nodes being visited multiple times (if multiple paths exist from any start node to any
115   *       node reachable from any start node)
116   * </ul>
117   *
118   * <p><b>Performance notes</b>
119   *
120   * <ul>
121   *   <li>Traversals require <i>O(n)</i> time (where <i>n</i> is the number of nodes reachable from
122   *       the start node).
123   *   <li>While traversing, the traverser will use <i>O(H)</i> space (where <i>H</i> is the number
124   *       of nodes that have been seen but not yet visited, that is, the "horizon").
125   * </ul>
126   *
127   * <p><b>Examples</b> (all edges are directed facing downwards)
128   *
129   * <p>The graph below would be valid input with start nodes of {@code a, f, c}. However, if {@code
130   * b} were <i>also</i> a start node, then there would be multiple paths to reach {@code e} and
131   * {@code h}.
132   *
133   * <pre>{@code
134   *    a     b      c
135   *   / \   / \     |
136   *  /   \ /   \    |
137   * d     e     f   g
138   *       |
139   *       |
140   *       h
141   * }</pre>
142   *
143   * <p>.
144   *
145   * <p>The graph below would be a valid input with start nodes of {@code a, f}. However, if {@code
146   * b} were a start node, there would be multiple paths to {@code f}.
147   *
148   * <pre>{@code
149   *    a     b
150   *   / \   / \
151   *  /   \ /   \
152   * c     d     e
153   *        \   /
154   *         \ /
155   *          f
156   * }</pre>
157   *
158   * <p><b>Note on binary trees</b>
159   *
160   * <p>This method can be used to traverse over a binary tree. Given methods {@code
161   * leftChild(node)} and {@code rightChild(node)}, this method can be called as
162   *
163   * <pre>{@code
164   * Traverser.forTree(node -> ImmutableList.of(leftChild(node), rightChild(node)));
165   * }</pre>
166   *
167   * @param tree {@link SuccessorsFunction} representing a directed acyclic graph that has at most
168   *     one path between any two nodes
169   */
170  public static <N> Traverser<N> forTree(SuccessorsFunction<N> tree) {
171    checkNotNull(tree);
172    if (tree instanceof BaseGraph) {
173      checkArgument(((BaseGraph<?>) tree).isDirected(), "Undirected graphs can never be trees.");
174    }
175    if (tree instanceof Network) {
176      checkArgument(((Network<?, ?>) tree).isDirected(), "Undirected networks can never be trees.");
177    }
178    return new TreeTraverser<>(tree);
179  }
180
181  /**
182   * Returns an unmodifiable {@code Iterable} over the nodes reachable from {@code startNode}, in
183   * the order of a breadth-first traversal. That is, all the nodes of depth 0 are returned, then
184   * depth 1, then 2, and so on.
185   *
186   * <p><b>Example:</b> The following graph with {@code startNode} {@code a} would return nodes in
187   * the order {@code abcdef} (assuming successors are returned in alphabetical order).
188   *
189   * <pre>{@code
190   * b ---- a ---- d
191   * |      |
192   * |      |
193   * e ---- c ---- f
194   * }</pre>
195   *
196   * <p>The behavior of this method is undefined if the nodes, or the topology of the graph, change
197   * while iteration is in progress.
198   *
199   * <p>The returned {@code Iterable} can be iterated over multiple times. Every iterator will
200   * compute its next element on the fly. It is thus possible to limit the traversal to a certain
201   * number of nodes as follows:
202   *
203   * <pre>{@code
204   * Iterables.limit(Traverser.forGraph(graph).breadthFirst(node), maxNumberOfNodes);
205   * }</pre>
206   *
207   * <p>See <a href="https://en.wikipedia.org/wiki/Breadth-first_search">Wikipedia</a> for more
208   * info.
209   *
210   * @throws IllegalArgumentException if {@code startNode} is not an element of the graph
211   */
212  public abstract Iterable<N> breadthFirst(N startNode);
213
214  /**
215   * Returns an unmodifiable {@code Iterable} over the nodes reachable from any of the {@code
216   * startNodes}, in the order of a breadth-first traversal. This is equivalent to a breadth-first
217   * traversal of a graph with an additional root node whose successors are the listed {@code
218   * startNodes}.
219   *
220   * @throws IllegalArgumentException if any of {@code startNodes} is not an element of the graph
221   * @see #breadthFirst(Object)
222   * @since 24.1
223   */
224  public abstract Iterable<N> breadthFirst(Iterable<? extends N> startNodes);
225
226  /**
227   * Returns an unmodifiable {@code Iterable} over the nodes reachable from {@code startNode}, in
228   * the order of a depth-first pre-order traversal. "Pre-order" implies that nodes appear in the
229   * {@code Iterable} in the order in which they are first visited.
230   *
231   * <p><b>Example:</b> The following graph with {@code startNode} {@code a} would return nodes in
232   * the order {@code abecfd} (assuming successors are returned in alphabetical order).
233   *
234   * <pre>{@code
235   * b ---- a ---- d
236   * |      |
237   * |      |
238   * e ---- c ---- f
239   * }</pre>
240   *
241   * <p>The behavior of this method is undefined if the nodes, or the topology of the graph, change
242   * while iteration is in progress.
243   *
244   * <p>The returned {@code Iterable} can be iterated over multiple times. Every iterator will
245   * compute its next element on the fly. It is thus possible to limit the traversal to a certain
246   * number of nodes as follows:
247   *
248   * <pre>{@code
249   * Iterables.limit(
250   *     Traverser.forGraph(graph).depthFirstPreOrder(node), maxNumberOfNodes);
251   * }</pre>
252   *
253   * <p>See <a href="https://en.wikipedia.org/wiki/Depth-first_search">Wikipedia</a> for more info.
254   *
255   * @throws IllegalArgumentException if {@code startNode} is not an element of the graph
256   */
257  public abstract Iterable<N> depthFirstPreOrder(N startNode);
258
259  /**
260   * Returns an unmodifiable {@code Iterable} over the nodes reachable from any of the {@code
261   * startNodes}, in the order of a depth-first pre-order traversal. This is equivalent to a
262   * depth-first pre-order traversal of a graph with an additional root node whose successors are
263   * the listed {@code startNodes}.
264   *
265   * @throws IllegalArgumentException if any of {@code startNodes} is not an element of the graph
266   * @see #depthFirstPreOrder(Object)
267   * @since 24.1
268   */
269  public abstract Iterable<N> depthFirstPreOrder(Iterable<? extends N> startNodes);
270
271  /**
272   * Returns an unmodifiable {@code Iterable} over the nodes reachable from {@code startNode}, in
273   * the order of a depth-first post-order traversal. "Post-order" implies that nodes appear in the
274   * {@code Iterable} in the order in which they are visited for the last time.
275   *
276   * <p><b>Example:</b> The following graph with {@code startNode} {@code a} would return nodes in
277   * the order {@code fcebda} (assuming successors are returned in alphabetical order).
278   *
279   * <pre>{@code
280   * b ---- a ---- d
281   * |      |
282   * |      |
283   * e ---- c ---- f
284   * }</pre>
285   *
286   * <p>The behavior of this method is undefined if the nodes, or the topology of the graph, change
287   * while iteration is in progress.
288   *
289   * <p>The returned {@code Iterable} can be iterated over multiple times. Every iterator will
290   * compute its next element on the fly. It is thus possible to limit the traversal to a certain
291   * number of nodes as follows:
292   *
293   * <pre>{@code
294   * Iterables.limit(
295   *     Traverser.forGraph(graph).depthFirstPostOrder(node), maxNumberOfNodes);
296   * }</pre>
297   *
298   * <p>See <a href="https://en.wikipedia.org/wiki/Depth-first_search">Wikipedia</a> for more info.
299   *
300   * @throws IllegalArgumentException if {@code startNode} is not an element of the graph
301   */
302  public abstract Iterable<N> depthFirstPostOrder(N startNode);
303
304  /**
305   * Returns an unmodifiable {@code Iterable} over the nodes reachable from any of the {@code
306   * startNodes}, in the order of a depth-first post-order traversal. This is equivalent to a
307   * depth-first post-order traversal of a graph with an additional root node whose successors are
308   * the listed {@code startNodes}.
309   *
310   * @throws IllegalArgumentException if any of {@code startNodes} is not an element of the graph
311   * @see #depthFirstPostOrder(Object)
312   * @since 24.1
313   */
314  public abstract Iterable<N> depthFirstPostOrder(Iterable<? extends N> startNodes);
315
316  // Avoid subclasses outside of this class
317  private Traverser() {}
318
319  private static final class GraphTraverser<N> extends Traverser<N> {
320    private final SuccessorsFunction<N> graph;
321
322    GraphTraverser(SuccessorsFunction<N> graph) {
323      this.graph = checkNotNull(graph);
324    }
325
326    @Override
327    public Iterable<N> breadthFirst(final N startNode) {
328      checkNotNull(startNode);
329      return breadthFirst(ImmutableSet.of(startNode));
330    }
331
332    @Override
333    public Iterable<N> breadthFirst(final Iterable<? extends N> startNodes) {
334      checkNotNull(startNodes);
335      if (Iterables.isEmpty(startNodes)) {
336        return ImmutableSet.of();
337      }
338      for (N startNode : startNodes) {
339        checkThatNodeIsInGraph(startNode);
340      }
341      return new Iterable<N>() {
342        @Override
343        public Iterator<N> iterator() {
344          return new BreadthFirstIterator(startNodes);
345        }
346      };
347    }
348
349    @Override
350    public Iterable<N> depthFirstPreOrder(final N startNode) {
351      checkNotNull(startNode);
352      return depthFirstPreOrder(ImmutableSet.of(startNode));
353    }
354
355    @Override
356    public Iterable<N> depthFirstPreOrder(final Iterable<? extends N> startNodes) {
357      checkNotNull(startNodes);
358      if (Iterables.isEmpty(startNodes)) {
359        return ImmutableSet.of();
360      }
361      for (N startNode : startNodes) {
362        checkThatNodeIsInGraph(startNode);
363      }
364      return new Iterable<N>() {
365        @Override
366        public Iterator<N> iterator() {
367          return new DepthFirstIterator(startNodes, Order.PREORDER);
368        }
369      };
370    }
371
372    @Override
373    public Iterable<N> depthFirstPostOrder(final N startNode) {
374      checkNotNull(startNode);
375      return depthFirstPostOrder(ImmutableSet.of(startNode));
376    }
377
378    @Override
379    public Iterable<N> depthFirstPostOrder(final Iterable<? extends N> startNodes) {
380      checkNotNull(startNodes);
381      if (Iterables.isEmpty(startNodes)) {
382        return ImmutableSet.of();
383      }
384      for (N startNode : startNodes) {
385        checkThatNodeIsInGraph(startNode);
386      }
387      return new Iterable<N>() {
388        @Override
389        public Iterator<N> iterator() {
390          return new DepthFirstIterator(startNodes, Order.POSTORDER);
391        }
392      };
393    }
394
395    @SuppressWarnings("CheckReturnValue")
396    private void checkThatNodeIsInGraph(N startNode) {
397      // successors() throws an IllegalArgumentException for nodes that are not an element of the
398      // graph.
399      graph.successors(startNode);
400    }
401
402    private final class BreadthFirstIterator extends UnmodifiableIterator<N> {
403      private final Queue<N> queue = new ArrayDeque<>();
404      private final Set<N> visited = new HashSet<>();
405
406      BreadthFirstIterator(Iterable<? extends N> roots) {
407        for (N root : roots) {
408          // add all roots to the queue, skipping duplicates
409          if (visited.add(root)) {
410            queue.add(root);
411          }
412        }
413      }
414
415      @Override
416      public boolean hasNext() {
417        return !queue.isEmpty();
418      }
419
420      @Override
421      public N next() {
422        N current = queue.remove();
423        for (N neighbor : graph.successors(current)) {
424          if (visited.add(neighbor)) {
425            queue.add(neighbor);
426          }
427        }
428        return current;
429      }
430    }
431
432    private final class DepthFirstIterator extends AbstractIterator<N> {
433      private final Deque<NodeAndSuccessors> stack = new ArrayDeque<>();
434      private final Set<N> visited = new HashSet<>();
435      private final Order order;
436
437      DepthFirstIterator(Iterable<? extends N> roots, Order order) {
438        stack.push(new NodeAndSuccessors(null, roots));
439        this.order = order;
440      }
441
442      @Override
443      protected N computeNext() {
444        while (true) {
445          if (stack.isEmpty()) {
446            return endOfData();
447          }
448          NodeAndSuccessors nodeAndSuccessors = stack.getFirst();
449          boolean firstVisit = visited.add(nodeAndSuccessors.node);
450          boolean lastVisit = !nodeAndSuccessors.successorIterator.hasNext();
451          boolean produceNode =
452              (firstVisit && order == Order.PREORDER) || (lastVisit && order == Order.POSTORDER);
453          if (lastVisit) {
454            stack.pop();
455          } else {
456            // we need to push a neighbor, but only if we haven't already seen it
457            N successor = nodeAndSuccessors.successorIterator.next();
458            if (!visited.contains(successor)) {
459              stack.push(withSuccessors(successor));
460            }
461          }
462          if (produceNode && nodeAndSuccessors.node != null) {
463            return nodeAndSuccessors.node;
464          }
465        }
466      }
467
468      NodeAndSuccessors withSuccessors(N node) {
469        return new NodeAndSuccessors(node, graph.successors(node));
470      }
471
472      /** A simple tuple of a node and a partially iterated {@link Iterator} of its successors. */
473      private final class NodeAndSuccessors {
474        @NullableDecl final N node;
475        final Iterator<? extends N> successorIterator;
476
477        NodeAndSuccessors(@NullableDecl N node, Iterable<? extends N> successors) {
478          this.node = node;
479          this.successorIterator = successors.iterator();
480        }
481      }
482    }
483  }
484
485  private static final class TreeTraverser<N> extends Traverser<N> {
486    private final SuccessorsFunction<N> tree;
487
488    TreeTraverser(SuccessorsFunction<N> tree) {
489      this.tree = checkNotNull(tree);
490    }
491
492    @Override
493    public Iterable<N> breadthFirst(final N startNode) {
494      checkNotNull(startNode);
495      return breadthFirst(ImmutableSet.of(startNode));
496    }
497
498    @Override
499    public Iterable<N> breadthFirst(final Iterable<? extends N> startNodes) {
500      checkNotNull(startNodes);
501      if (Iterables.isEmpty(startNodes)) {
502        return ImmutableSet.of();
503      }
504      for (N startNode : startNodes) {
505        checkThatNodeIsInTree(startNode);
506      }
507      return new Iterable<N>() {
508        @Override
509        public Iterator<N> iterator() {
510          return new BreadthFirstIterator(startNodes);
511        }
512      };
513    }
514
515    @Override
516    public Iterable<N> depthFirstPreOrder(final N startNode) {
517      checkNotNull(startNode);
518      return depthFirstPreOrder(ImmutableSet.of(startNode));
519    }
520
521    @Override
522    public Iterable<N> depthFirstPreOrder(final Iterable<? extends N> startNodes) {
523      checkNotNull(startNodes);
524      if (Iterables.isEmpty(startNodes)) {
525        return ImmutableSet.of();
526      }
527      for (N node : startNodes) {
528        checkThatNodeIsInTree(node);
529      }
530      return new Iterable<N>() {
531        @Override
532        public Iterator<N> iterator() {
533          return new DepthFirstPreOrderIterator(startNodes);
534        }
535      };
536    }
537
538    @Override
539    public Iterable<N> depthFirstPostOrder(final N startNode) {
540      checkNotNull(startNode);
541      return depthFirstPostOrder(ImmutableSet.of(startNode));
542    }
543
544    @Override
545    public Iterable<N> depthFirstPostOrder(final Iterable<? extends N> startNodes) {
546      checkNotNull(startNodes);
547      if (Iterables.isEmpty(startNodes)) {
548        return ImmutableSet.of();
549      }
550      for (N startNode : startNodes) {
551        checkThatNodeIsInTree(startNode);
552      }
553      return new Iterable<N>() {
554        @Override
555        public Iterator<N> iterator() {
556          return new DepthFirstPostOrderIterator(startNodes);
557        }
558      };
559    }
560
561    @SuppressWarnings("CheckReturnValue")
562    private void checkThatNodeIsInTree(N startNode) {
563      // successors() throws an IllegalArgumentException for nodes that are not an element of the
564      // graph.
565      tree.successors(startNode);
566    }
567
568    private final class BreadthFirstIterator extends UnmodifiableIterator<N> {
569      private final Queue<N> queue = new ArrayDeque<>();
570
571      BreadthFirstIterator(Iterable<? extends N> roots) {
572        for (N root : roots) {
573          queue.add(root);
574        }
575      }
576
577      @Override
578      public boolean hasNext() {
579        return !queue.isEmpty();
580      }
581
582      @Override
583      public N next() {
584        N current = queue.remove();
585        Iterables.addAll(queue, tree.successors(current));
586        return current;
587      }
588    }
589
590    private final class DepthFirstPreOrderIterator extends UnmodifiableIterator<N> {
591      private final Deque<Iterator<? extends N>> stack = new ArrayDeque<>();
592
593      DepthFirstPreOrderIterator(Iterable<? extends N> roots) {
594        stack.addLast(roots.iterator());
595      }
596
597      @Override
598      public boolean hasNext() {
599        return !stack.isEmpty();
600      }
601
602      @Override
603      public N next() {
604        Iterator<? extends N> iterator = stack.getLast(); // throws NoSuchElementException if empty
605        N result = checkNotNull(iterator.next());
606        if (!iterator.hasNext()) {
607          stack.removeLast();
608        }
609        Iterator<? extends N> childIterator = tree.successors(result).iterator();
610        if (childIterator.hasNext()) {
611          stack.addLast(childIterator);
612        }
613        return result;
614      }
615    }
616
617    private final class DepthFirstPostOrderIterator extends AbstractIterator<N> {
618      private final ArrayDeque<NodeAndChildren> stack = new ArrayDeque<>();
619
620      DepthFirstPostOrderIterator(Iterable<? extends N> roots) {
621        stack.addLast(new NodeAndChildren(null, roots));
622      }
623
624      @Override
625      protected N computeNext() {
626        while (!stack.isEmpty()) {
627          NodeAndChildren top = stack.getLast();
628          if (top.childIterator.hasNext()) {
629            N child = top.childIterator.next();
630            stack.addLast(withChildren(child));
631          } else {
632            stack.removeLast();
633            if (top.node != null) {
634              return top.node;
635            }
636          }
637        }
638        return endOfData();
639      }
640
641      NodeAndChildren withChildren(N node) {
642        return new NodeAndChildren(node, tree.successors(node));
643      }
644
645      /** A simple tuple of a node and a partially iterated {@link Iterator} of its children. */
646      private final class NodeAndChildren {
647        @NullableDecl final N node;
648        final Iterator<? extends N> childIterator;
649
650        NodeAndChildren(@NullableDecl N node, Iterable<? extends N> children) {
651          this.node = node;
652          this.childIterator = children.iterator();
653        }
654      }
655    }
656  }
657
658  private enum Order {
659    PREORDER,
660    POSTORDER
661  }
662}