Giter VIP home page Giter VIP logo

php-tarjan's People

Contributors

vacilando avatar

Stargazers

 avatar  avatar  avatar  avatar

Watchers

 avatar

Forkers

k127

php-tarjan's Issues

Convert to class

Hello. Nice one :) I used your algorithm and converted it into a class and it seems to fork well. I would like to suggest to put your code into a class which would be more handy for real life usage I think. See my example below (I am not sure why $G is modified so hopefully my class is working correctly)

Update: I also modified how the $G array is used - You expect indices to be continous 0-N while my situation was different. My indices are random IDs from DB. This is the only difference I forgot to mention.

Update2: I also converted internal variable $maxlooplength and hardcoded string '|' into private attributes with setters and getters so they can be configured. See example below.

PS2: I would also like to ask for enhancement of linked article - I was missing graphical representation of the graph whose "Adjacency Matrix" is used.
https://www.vacilando.org/article/php-implementation-tarjans-cycle-detection-algorithm

Thank you for your contribution.


// Class usage:
// $tarjanLoopDetector = new TarjanLoopDetector($adjacencyMatrix);
// $tarjanLoopDetector->setLoopVertexSeparator('-');  // unnecessary
// $tarjanLoopDetector->setMaxLoopLength(3); // unnecessary
// $loops = $tarjanLoopDetector->php_tarjan_entry();
// $result = [];
// foreach ($loops as $loop) {
//  $result []= explode($tarjanLoopDetector->getLoopVertexSeparator(), $loop);
// }

<?php

/**
 * Code origin:
 * https://www.vacilando.org/article/php-implementation-tarjans-cycle-detection-algorithm
 * https://github.com/Vacilando/php-tarjan
 *
 * Adjacency Matrix:
 * https://www.geeksforgeeks.org/graph-and-its-representations/
 */
class TarjanLoopDetector
{

  private $cycles = [];
  private $marked = [];
  private $marked_stack = [];
  private $point_stack = [];
  private $G = [];
  private $loopVertexSeparator = '|';
  private $maxLoopLength = null; // For example 3

  public function __construct($adjacencyMatrix)
  {
    $this->G = $adjacencyMatrix;
  }

  public function setLoopVertexSeparator($loopVertexSeparator)
  {
    $this->loopVertexSeparator = $loopVertexSeparator;
  }

  public function getLoopVertexSeparator()
  {
    return $this->loopVertexSeparator;
  }

  /**
   * Set a value to Limit the length of loops to keep in the results
   * @param $maxLoopLength
   * @return void
   */
  public function setMaxLoopLength($maxLoopLength)
  {
    $this->maxLoopLength = (int)$maxLoopLength;
  }

  public function getMaxLoopLength()
  {
    return $this->maxLoopLength;
  }

  public function php_tarjan_entry()
  {
    foreach ($this->G as $x => $data) {
      $this->marked[$x] = FALSE;
    }

    foreach ($this->G as $i => $data) {
      $this->php_tarjan($i, $i);
      while (!empty($this->marked_stack)) {
        $this->marked[array_pop($this->marked_stack)] = FALSE;
      }
      //echo '<br>'.($i+1).' / '.count($this->G); // Enable if you wish to follow progression through the array rows.
    }

    $this->cycles = array_keys($this->cycles);

    return $this->cycles;
  }

  /*
   * Recursive function to detect strongly connected components (cycles, loops).
   */
  private function php_tarjan($s, $v)
  {

    $f = FALSE;
    $this->point_stack[] = $v;
    $this->marked[$v] = TRUE;
    $this->marked_stack[] = $v;

    foreach ($this->G[$v] as $w) {
      if ($w < $s) {
        $this->G[$w] = array(); // Users note: Why is this array modified?
      } else if ($w == $s) {
        if ($this->maxLoopLength == null || count($this->point_stack) == $this->maxLoopLength) {
          // Collect cycles of a given length only.
          // Add new cycles as array keys to avoid duplication. Way faster than using array_search.
          $this->cycles[implode($this->loopVertexSeparator, $this->point_stack)] = TRUE;
        }
        $f = TRUE;
      } else if ($this->marked[$w] === FALSE) {
        if ($this->maxLoopLength == null || count($this->point_stack) < $this->maxLoopLength) {
          // Collect cycles up to $this->maxLoopLength.
          $g = $this->php_tarjan($s, $w);
        }
        if (!empty($f) or !empty($g)) {
          $f = TRUE;
        }
      }
    }

    if ($f === TRUE) {
      while (end($this->marked_stack) != $v) {
        $this->marked[array_pop($this->marked_stack)] = FALSE;
      }
      array_pop($this->marked_stack);
      $this->marked[$v] = FALSE;
    }

    array_pop($this->point_stack);
    return $f;
  }

}

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.