/**
  * Finds connected components in the provided directed graph.
  *
  * @param DirectedGraph $graph
  *   The DirectedGraph to search for connected components.
  * @param TarjanSCCVisitor $visitor
  *   The visitor that will collect and store the connected components. One
  *   will be created if not provided.
  *
  * @return TarjanSCCVisitor
  *   The finalized visitor.
  */
 public static function tarjan_scc(DirectedGraph $graph, TarjanSCCVisitor $visitor = NULL)
 {
     $visitor = $visitor ?: new TarjanSCCVisitor();
     $counter = 0;
     $stack = array();
     $indices = new \SplObjectStorage();
     $lowlimits = new \SplObjectStorage();
     $visit = function ($vertex) use(&$visit, &$counter, $graph, &$stack, $indices, $lowlimits, $visitor) {
         $indices->attach($vertex, $counter);
         $lowlimits->attach($vertex, $counter);
         $stack[] = $vertex;
         $counter++;
         $graph->eachAdjacent($vertex, function ($to) use(&$visit, $vertex, $indices, $lowlimits, &$stack) {
             if (!$indices->contains($to)) {
                 $visit($to);
                 $lowlimits[$vertex] = min($lowlimits[$vertex], $lowlimits[$to]);
             } else {
                 if (in_array($to, $stack)) {
                     $lowlimits[$vertex] = min($lowlimits[$vertex], $indices[$to]);
                 }
             }
         });
         if ($lowlimits[$vertex] === $indices[$vertex]) {
             $visitor->newComponent();
             do {
                 $other = array_pop($stack);
                 $visitor->addToCurrentComponent($other);
             } while ($other != $vertex);
         }
     };
     $graph->eachVertex(function ($vertex) use(&$visit, $indices) {
         if (!$indices->contains($vertex)) {
             $visit($vertex);
         }
     });
     return $visitor;
 }
 /**
  * Finds source vertices in a DirectedGraph, then enqueues them.
  *
  * @param DirectedGraph $graph
  * @param DepthFirstVisitorInterface $visitor
  *
  * @return \SplQueue
  */
 public static function find_sources(DirectedGraph $graph, DepthFirstVisitorInterface $visitor)
 {
     $incomings = new \SplObjectStorage();
     $queue = new \SplQueue();
     $graph->eachEdge(function ($edge) use(&$incomings) {
         if (!isset($incomings[$edge[1]])) {
             $incomings[$edge[1]] = new \SplObjectStorage();
         }
         $incomings[$edge[1]]->attach($edge[0]);
     });
     // Prime the queue with vertices that have no incoming edges.
     $graph->eachVertex(function ($vertex) use($queue, $incomings, $visitor) {
         if (!$incomings->contains($vertex)) {
             $queue->push($vertex);
             // TRUE second param indicates source vertex
             $visitor->onInitializeVertex($vertex, TRUE, $queue);
         } else {
             $visitor->onInitializeVertex($vertex, FALSE, $queue);
         }
     });
     return $queue;
 }