[
  {
    "path": ".gitattributes",
    "content": "/.gitattributes export-ignore\n/.github/workflows/ export-ignore\n/.gitignore export-ignore\n/phpunit.xml.dist export-ignore\n/phpunit.xml.legacy export-ignore\n/tests export-ignore\n"
  },
  {
    "path": ".github/workflows/ci.yml",
    "content": "name: CI\n\non:\n  push:\n  pull_request:\n\njobs:\n  PHPUnit:\n    runs-on: ubuntu-20.04\n    strategy:\n      matrix:\n        php:\n          - 7.4\n          - 7.3\n          - 7.2\n          - 7.1\n          - 7.0\n          - 5.6\n          - 5.5\n          - 5.4\n          - 5.3\n    steps:\n      - uses: actions/checkout@v2\n      - name: Setup PHP\n        uses: shivammathur/setup-php@v2\n        with:\n          php-version: ${{ matrix.php }}\n      - run: composer install\n      - run: vendor/bin/phpunit --coverage-text\n        if: ${{ matrix.php >= 7.3 }}\n      - run: vendor/bin/phpunit --coverage-text -c phpunit.xml.legacy\n        if: ${{ matrix.php < 7.3 }}\n"
  },
  {
    "path": ".gitignore",
    "content": "/vendor\n/composer.lock\n"
  },
  {
    "path": "CHANGELOG.md",
    "content": "# Changelog\n\n## 0.8.2 (2020-02-20)\n\n*   Feature: Add max depth parameter to breadth first search.\n    (#27 by @phyrwork)\n\n*   Feature: Replace recursive topological sort with iterative algorithm.\n    (#25 by @phyrwork)\n\n*   Fix: Fix option to merge parallel edges when creating residual graph.\n    (#39 by @clue)\n\n*   Fix: Fix setting upper limit for TSP bruteforce via MST algorithm.\n    (#36 by @clue)\n\n*   Minor code style improvements to make PHPStan happy,\n    clean up dead code for depth first search and\n    automated native_function_invocation fixes.\n    (#35 and #40 by @clue and #37 by @draco2003)\n\n*   Improve test suite to support PHPUnit 6 and PHPUnit 5 and\n    support running on legacy PHP 5.3 through PHP 7.2 and HHVM.\n    (#32 by @clue)\n\n## 0.8.1 (2015-03-08)\n\n*   Support graph v0.9 (while keeping BC)\n    ([#16](https://github.com/graphp/algorithms/pull/16))\n\n*   Deprecate internal algorithm base classes\n    ([#15](https://github.com/graphp/algorithms/pull/15))\n\n## 0.8.0 (2015-02-25)\n\n*   First tagged release, split off from [clue/graph](https://github.com/clue/graph) v0.8.0\n    ([#1](https://github.com/graphp/algorithms/issues/1))\n"
  },
  {
    "path": "LICENSE",
    "content": "The MIT License (MIT)\n\nCopyright (c) 2015 Christian Lück\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is furnished\nto do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\nTHE SOFTWARE.\n"
  },
  {
    "path": "README.md",
    "content": "# graphp/algorithms\n\n[![CI status](https://github.com/graphp/algorithms/workflows/CI/badge.svg)](https://github.com/graphp/algorithms/actions)\n\nCommon mathematical graph algorithms implemented in PHP\n\n> **Development version:** This branch contains the code for the upcoming\n> version 0.9. For the code of the current version 0.8, check out the\n> [`0.8.x` branch](https://github.com/graphp/algorithms/tree/0.8.x).\n>\n> The upcoming version 0.9 will be the way forward for this package. However,\n> we will still actively support version 0.8 for those not yet on the latest\n> version. See also [installation instructions](#install) for more details.\n\n## Install\n\nThe recommended way to install this library is [through Composer](https://getcomposer.org/).\n[New to Composer?](https://getcomposer.org/doc/00-intro.md)\n\nOnce released, this project will follow [SemVer](https://semver.org/).\nAt the moment, this will install the latest development version:\n\n```bash\ncomposer require graphp/algorithms:^0.9@dev\n```\n\nSee also the [CHANGELOG](CHANGELOG.md) for details about version upgrades.\n\nThis project aims to run on any platform and thus does not require any PHP\nextensions and supports running on legacy PHP 5.3 through current PHP 7+.\nIt's *highly recommended to use PHP 7+* for this project.\n\n## Tests\n\nTo run the test suite, you first need to clone this repo and then install all\ndependencies [through Composer](https://getcomposer.org/):\n\n```bash\ncomposer install\n```\n\nTo run the test suite, go to the project root and run:\n\n```bash\nvendor/bin/phpunit\n```\n\n## License\n\nThis project is released under the permissive [MIT license](LICENSE).\n"
  },
  {
    "path": "composer.json",
    "content": "{\n    \"name\": \"graphp/algorithms\",\n    \"description\": \"Common mathematical graph algorithms implemented in PHP\",\n    \"keywords\": [\"Graph algorithms\", \"shortest path\", \"dijkstra\", \"moore-bellman-ford\", \"minimum spanning tree\", \"kruskal\", \"prim\"],\n    \"homepage\": \"https://github.com/graphp/algorithms\",\n    \"license\": \"MIT\",\n    \"authors\": [\n        {\n            \"name\": \"Christian Lück\",\n            \"email\": \"christian@clue.engineering\"\n        }\n    ],\n    \"require\": {\n        \"php\": \">=5.3\",\n        \"graphp/graph\": \"1.x-dev#fb198e4 as 1.0.0\"\n    },\n    \"require-dev\": {\n        \"phpunit/phpunit\": \"^9.3 || ^5.7 || ^4.8.35\"\n    },\n    \"autoload\": {\n        \"psr-4\": {\"Graphp\\\\Algorithms\\\\\": \"src/\"}\n    },\n    \"autoload-dev\": {\n        \"psr-4\": { \"Graphp\\\\Tests\\\\Algorithms\\\\\": \"tests/\" }\n    }\n}\n"
  },
  {
    "path": "phpunit.xml.dist",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n\n<!-- PHPUnit configuration file with new format for PHPUnit 9.3+ -->\n<phpunit xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" \n         xsi:noNamespaceSchemaLocation=\"https://schema.phpunit.de/9.3/phpunit.xsd\"\n         bootstrap=\"vendor/autoload.php\" \n         colors=\"true\" \n         cacheResult=\"false\">\n    <testsuites>\n        <testsuite name=\"Algorithm Test Suite\">\n            <directory>./tests/</directory>\n        </testsuite>\n    </testsuites>\n    <coverage>\n        <include>\n            <directory>./src/</directory>\n        </include>\n    </coverage>\n</phpunit>\n"
  },
  {
    "path": "phpunit.xml.legacy",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n\n<!-- PHPUnit configuration file with old format for PHPUnit 9.2 or older-->\n<phpunit xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n         xsi:noNamespaceSchemaLocation=\"https://schema.phpunit.de/4.8/phpunit.xsd\"\n         bootstrap=\"vendor/autoload.php\" \n         colors=\"true\">\n    <testsuites>\n        <testsuite name=\"Algorithm Test Suite\">\n            <directory>./tests/</directory>\n        </testsuite>\n    </testsuites>\n    <filter>\n        <whitelist>\n            <directory>./src/</directory>\n        </whitelist>\n    </filter>\n</phpunit>\n"
  },
  {
    "path": "src/Base.php",
    "content": "<?php\n\nnamespace Graphp\\Algorithms;\n\n/**\n * @deprecated\n */\nabstract class Base{ }\n"
  },
  {
    "path": "src/BaseDual.php",
    "content": "<?php\n\nnamespace Graphp\\Algorithms;\n\nuse Graphp\\Graph\\Graph;\nuse Graphp\\Graph\\Set\\DualAggregate;\nuse Graphp\\Graph\\Walk;\n\n/**\n * Abstract base class for algorithms that operate on a given Set instance\n *\n * @see Set\n * @deprecated\n */\nabstract class BaseDual extends Base\n{\n    /**\n     * Set to operate on\n     *\n     * @var DualAggregate\n     */\n    protected $set;\n\n    /**\n     * instantiate new algorithm\n     *\n     * @param Graph|Walk|DualAggregate $graphOrWalk either the Graph or Walk to operate on (or the common base class Set)\n     */\n    public function __construct(DualAggregate $graphOrWalk)\n    {\n        $this->set = $graphOrWalk;\n    }\n}\n"
  },
  {
    "path": "src/BaseGraph.php",
    "content": "<?php\n\nnamespace Graphp\\Algorithms;\n\nuse Graphp\\Graph\\Graph;\n\n/**\n * Abstract base class for algorithms that operate on a given Graph instance\n *\n * @deprecated\n */\nabstract class BaseGraph extends Base\n{\n    /**\n     * Graph to operate on\n     *\n     * @var Graph\n     */\n    protected $graph;\n\n    /**\n     * instantiate new algorithm\n     *\n     * @param Graph $graph Graph to operate on\n     */\n    public function __construct(Graph $graph)\n    {\n        $this->graph = $graph;\n    }\n}\n"
  },
  {
    "path": "src/BaseVertex.php",
    "content": "<?php\n\nnamespace Graphp\\Algorithms;\n\nuse Graphp\\Graph\\Vertex;\n\n/**\n * Abstract base class for algorithms that operate on a given Vertex instance\n *\n * @deprecated\n */\nabstract class BaseVertex extends Base\n{\n    /**\n     * Vertex to operate on\n     *\n     * @var Vertex\n     */\n    protected $vertex;\n\n    /**\n     * instantiate new algorithm\n     *\n     * @param Vertex $vertex Vertex to operate on\n     */\n    public function __construct(Vertex $vertex)\n    {\n        $this->vertex = $vertex;\n    }\n}\n"
  },
  {
    "path": "src/Bipartit.php",
    "content": "<?php\n\nnamespace Graphp\\Algorithms;\n\nuse Graphp\\Graph\\Exception\\UnexpectedValueException;\nuse Graphp\\Graph\\Graph;\n\nclass Bipartit extends BaseGraph\n{\n    /**\n     * check whether this graph is bipartit\n     *\n     * @return bool\n     * @uses AlgorithmBipartit::getColors()\n     */\n    public function isBipartit()\n    {\n        try {\n            $this->getColors();\n\n            return true;\n        } catch (UnexpectedValueException $ignore) { }\n\n        return false;\n    }\n\n    /**\n     * checks whether the input graph's vertex groups are a valid bipartition\n     *\n     * @return bool\n     * @uses AlgorithmGroups::isBipartit()\n     */\n    public function isBipartitGroups()\n    {\n        $alg = new Groups($this->graph);\n\n        return $alg->isBipartit();\n    }\n\n    /**\n     * get map of vertex ID to vertex color\n     *\n     * @return int[]\n     * @throws UnexpectedValueException if graph is not bipartit\n     * @uses AlgorithmBipartit::checkVertex() for every vertex not already colored\n     */\n    public function getColors()\n    {\n        $colors = array();\n\n        // get color for each vertex\n        foreach ($this->graph->getVertices()->getMap() as $vid => $startVertex) {\n            if (!isset($colors[$vid])) {\n                $queue = array($startVertex);\n                // initialize each components color\n                $colors[$vid] = 0;\n\n                // breadth search all vertices in same component\n                do {\n                    // next vertex in color\n                    $vertex = \\array_shift($queue);\n                    $color = $colors[$vertex->getId()];\n                    $nextColor = 1-$color;\n\n                    // scan all vertices connected to this vertex\n                    foreach ($vertex->getVerticesEdge()->getMap() as $vid => $nextVertex) {\n                        // color unknown, so expect next color for this vertex\n                        if (!isset($colors[$vid])) {\n                            $colors[$vid] = $nextColor;\n                            $queue[] = $nextVertex;\n                        // color is known but differs => can not be bipartit\n                        } elseif ($colors[$vid] !== $nextColor) {\n                            throw new UnexpectedValueException('Graph is not bipartit');\n                        }\n                    }\n                } while ($queue);\n            }\n        }\n\n        return $colors;\n    }\n\n    /**\n     * get groups of vertices per color\n     *\n     * @return array[] array of arrays of vertices\n     */\n    public function getColorVertices()\n    {\n        $colors = $this->getColors();\n        $ret = array(0 => array(), 1 => array());\n\n        foreach ($this->graph->getVertices()->getMap() as $vid => $vertex) {\n            $ret[$colors[$vid]][$vid] = $vertex;\n        }\n\n        return $ret;\n    }\n\n    /**\n     * create new graph with valid groups set according to bipartition colors\n     *\n     * @return Graph\n     * @throws UnexpectedValueException if graph is not bipartit\n     * @uses AlgorithmBipartit::getColors()\n     * @uses Graph::createGraphClone()\n     * @uses Vertex::setGroup()\n     */\n    public function createGraphGroups()\n    {\n        $colors = $this->getColors();\n\n        $graph = $this->graph->createGraphClone();\n        foreach ($graph->getVertices()->getMap() as $vid => $vertex) {\n            $vertex->setGroup($colors[$vid]);\n        }\n\n        return $graph;\n    }\n}\n"
  },
  {
    "path": "src/Complete.php",
    "content": "<?php\n\nnamespace Graphp\\Algorithms;\n\n/**\n * Basic algorithms for working with complete graphs\n *\n * A complete graph is a graph in which every pair of vertices is connected\n * by an edge.\n *\n * @link http://en.wikipedia.org/wiki/Complete_graph\n * @link http://mathworld.wolfram.com/CompleteGraph.html\n */\nclass Complete extends BaseGraph\n{\n    /**\n     * checks whether this graph is complete (every vertex has an edge to any other vertex)\n     *\n     * @return bool\n     * @uses Graph::getVertices()\n     * @uses Vertex::hasEdgeTo()\n     */\n    public function isComplete()\n    {\n        // copy of array (separate iterator but same vertices)\n        $c = $vertices = $this->graph->getVertices()->getVector();\n        // from each vertex\n        foreach ($vertices as $vertex) {\n            // to each vertex\n            foreach ($c as $other) {\n                // missing edge => fail\n                if ($other !== $vertex && !$vertex->hasEdgeTo($other)) {\n                    return false;\n                }\n            }\n        }\n\n        return true;\n    }\n}\n"
  },
  {
    "path": "src/ConnectedComponents.php",
    "content": "<?php\n\nnamespace Graphp\\Algorithms;\n\nuse Graphp\\Algorithms\\Search\\BreadthFirst as SearchBreadthFirst;\nuse Graphp\\Graph\\Exception\\InvalidArgumentException;\nuse Graphp\\Graph\\Exception\\UnderflowException;\nuse Graphp\\Graph\\Graph;\nuse Graphp\\Graph\\Vertex;\n\n/**\n * Algorithm for working with connected components\n *\n * @link http://en.wikipedia.org/wiki/Connected_component_%28graph_theory%29\n * @link http://mathworld.wolfram.com/ConnectedGraph.html\n * @link http://math.stackexchange.com/questions/50551/is-the-empty-graph-connected\n */\nclass ConnectedComponents extends BaseGraph\n{\n    /**\n     * create subgraph with all vertices connected to given vertex (i.e. the connected component of ths given vertex)\n     *\n     * @param  Vertex                   $vertex\n     * @return Graph\n     * @throws InvalidArgumentException if given vertex is not from same graph\n     * @uses AlgorithmSearchBreadthFirst::getVertices()\n     * @uses Graph::createGraphCloneVertices()\n     */\n    public function createGraphComponentVertex(Vertex $vertex)\n    {\n        if ($vertex->getGraph() !== $this->graph) {\n            throw new InvalidArgumentException('This graph does not contain the given vertex');\n        }\n\n        return $this->graph->createGraphCloneVertices($this->createSearch($vertex)->getVertices());\n    }\n\n    /**\n     *\n     * @param Vertex $vertex\n     * @return SearchBreadthFirst\n     */\n    private function createSearch(Vertex $vertex)\n    {\n        $alg = new SearchBreadthFirst($vertex);\n\n        // follow into both directions (loosely connected)\n        return $alg->setDirection(SearchBreadthFirst::DIRECTION_BOTH);\n    }\n\n    /**\n     * check whether this graph consists of only a single component\n     *\n     * If a Graph consists of only a single component, it is said to be a\n     * connected Graph, otherwise it's called a disconnected Graph.\n     *\n     * This method returns exactly the same result as checking\n     * <pre>($this->getNumberOfComponents() === 1)</pre>. However, using this\n     * method is faster than calling getNumberOfComponents(), as it only has to\n     * count all vertices in one component to see if the graph consists of only\n     * a single component.\n     *\n     * As such, a null Graph (a Graph with no vertices) is not considered\n     * connected here.\n     *\n     * @return bool\n     * @see self::getNumberOfComponents()\n     */\n    public function isSingle()\n    {\n        try {\n            $vertex = $this->graph->getVertices()->getVertexFirst();\n        } catch (UnderflowException $e) {\n            // no first vertex => empty graph => has zero components\n            return false;\n        }\n        $alg = $this->createSearch($vertex);\n\n        return (\\count($this->graph->getVertices()) === \\count($alg->getVertices()));\n    }\n\n    /**\n     * count number of connected components\n     *\n     * A null Graph (a Graph with no vertices) will return 0 components.\n     *\n     * @return int number of components\n     * @uses Graph::getVertices()\n     * @uses AlgorithmSearchBreadthFirst::getVertices()\n     */\n    public function getNumberOfComponents()\n    {\n        $visitedVertices = array();\n        $components = 0;\n\n        // for each vertices\n        foreach ($this->graph->getVertices()->getMap() as $vid => $vertex) {\n            // did I visit this vertex before?\n            if (!isset($visitedVertices[$vid])) {\n\n                // get all vertices of this component\n                $newVertices = $this->createSearch($vertex)->getVertices()->getIds();\n\n                ++$components;\n\n                // mark the vertices of this component as visited\n                foreach ($newVertices as $vid) {\n                    $visitedVertices[$vid] = true;\n                }\n            }\n        }\n\n        // return number of components\n        return $components;\n    }\n\n    /**\n     * separate input graph into separate independant and unconnected graphs\n     *\n     * @return Graph[]\n     * @uses Graph::getVertices()\n     * @uses AlgorithmSearchBreadthFirst::getVertices()\n     */\n    public function createGraphsComponents()\n    {\n        $visitedVertices = array();\n        $graphs = array();\n\n        // for each vertices\n        foreach ($this->graph->getVertices()->getMap() as $vid => $vertex) {\n            // did I visit this vertex before?\n            if (!isset($visitedVertices[$vid])) {\n\n                $alg = $this->createSearch($vertex);\n                // get all vertices of this component\n                $newVertices = $alg->getVertices();\n\n                // mark the vertices of this component as visited\n                foreach ($newVertices->getIds() as $vid) {\n                    $visitedVertices[$vid] = true;\n                }\n\n                $graphs[] = $this->graph->createGraphCloneVertices($newVertices);\n            }\n        }\n\n        return $graphs;\n    }\n}\n"
  },
  {
    "path": "src/Degree.php",
    "content": "<?php\n\nnamespace Graphp\\Algorithms;\n\nuse Graphp\\Graph\\Exception\\UnderflowException;\nuse Graphp\\Graph\\Exception\\UnexpectedValueException;\nuse Graphp\\Graph\\Vertex;\n\n/**\n * Basic algorithms for working with the degrees of Graphs.\n *\n * The degree (or valency) of a Vertex of a Graph is the number of Edges\n * incident to the Vertex, with Loops counted twice.\n *\n * @link http://en.wikipedia.org/wiki/Degree_%28graph_theory%29\n * @link http://en.wikipedia.org/wiki/Regular_graph\n */\nclass Degree extends BaseGraph\n{\n    /**\n     * get degree for k-regular-graph (only if each vertex has the same degree)\n     *\n     * @return int\n     * @throws UnderflowException       if graph is empty\n     * @throws UnexpectedValueException if graph is not regular (i.e. vertex degrees are not equal)\n     * @uses self::getDegreeVertex()\n     * @see self::isRegular()\n     */\n    public function getDegree()\n    {\n        // get initial degree of any start vertex to compare others to\n        $degree = $this->getDegreeVertex($this->graph->getVertices()->getVertexFirst());\n\n        foreach ($this->graph->getVertices() as $vertex) {\n            assert($vertex instanceof Vertex);\n            $i = $this->getDegreeVertex($vertex);\n\n            if ($i !== $degree) {\n                throw new UnexpectedValueException('Graph is not k-regular (vertex degrees differ)');\n            }\n        }\n\n        return $degree;\n    }\n\n    /**\n     * get minimum degree of vertices\n     *\n     * @return int\n     * @throws UnderflowException       if graph is empty\n     * @uses Vertices::getVertexOrder()\n     * @uses self::getDegreeVertex()\n     */\n    public function getDegreeMin()\n    {\n        return $this->getDegreeVertex($this->graph->getVertices()->getVertexOrder(array($this, 'getDegreeVertex')));\n    }\n\n    /**\n     * get maximum degree of vertices\n     *\n     * @return int\n     * @throws UnderflowException       if graph is empty\n     * @uses Vertices::getVertexOrder()\n     * @uses self::getDegreeVertex()\n     */\n    public function getDegreeMax()\n    {\n        return $this->getDegreeVertex($this->graph->getVertices()->getVertexOrder(array($this, 'getDegreeVertex'), true));\n    }\n\n    /**\n     * checks whether this graph is regular, i.e. each vertex has the same indegree/outdegree\n     *\n     * @return bool\n     * @uses self::getDegree()\n     */\n    public function isRegular()\n    {\n        // an empty graph is considered regular\n        if ($this->graph->getVertices()->isEmpty()) {\n            return true;\n        }\n        try {\n            $this->getDegree();\n\n            return true;\n        } catch (UnexpectedValueException $ignore) { }\n\n        return false;\n    }\n\n    /**\n     * checks whether the indegree of every vertex equals its outdegree\n     *\n     * @return bool\n     * @uses self::getDegreeInVertex()\n     * @uses self::getDegreeOutVertex()\n     */\n    public function isBalanced()\n    {\n        foreach ($this->graph->getVertices() as $vertex) {\n            if ($this->getDegreeInVertex($vertex) !== $this->getDegreeOutVertex($vertex)) {\n                return false;\n            }\n        }\n\n        return true;\n    }\n\n    /**\n     * checks whether this vertex is a source, i.e. its indegree is zero\n     *\n     * @param Vertex $vertex\n     * @return bool\n     * @uses Edge::hasVertexTarget()\n     * @see self::getDegreeInVertex()\n     */\n    public function isVertexSource(Vertex $vertex)\n    {\n        foreach ($vertex->getEdges() as $edge) {\n            if ($edge->hasVertexTarget($vertex)) {\n                return false;\n            }\n        }\n\n        // reach this point: no edge to this vertex\n        return true;\n    }\n\n    /**\n     * checks whether this vertex is a sink, i.e. its outdegree is zero\n     *\n     * @param Vertex $vertex\n     * @return bool\n     * @uses Edge::hasVertexStart()\n     * @see self::getDegreeOutVertex()\n     */\n    public function isVertexSink(Vertex $vertex)\n    {\n        foreach ($vertex->getEdges() as $edge) {\n            if ($edge->hasVertexStart($vertex)) {\n                return false;\n            }\n        }\n\n        // reach this point: no edge away from this vertex\n        return true;\n    }\n\n    /**\n     * get degree of this vertex (total number of edges)\n     *\n     * vertex degree counts the total number of edges attached to this vertex\n     * regardless of whether they're directed or not. loop edges are counted\n     * twice as both start and end form a 'line' to the same vertex.\n     *\n     * @param Vertex $vertex\n     * @return int\n     * @see self::getDegreeInVertex()\n     * @see self::getDegreeOutVertex()\n     */\n    public function getDegreeVertex(Vertex $vertex)\n    {\n        return \\count($vertex->getEdges());\n    }\n\n    /**\n     * check whether this vertex is isolated (i.e. has no edges attached)\n     *\n     * @param Vertex $vertex\n     * @return bool\n     */\n    public function isVertexIsolated(Vertex $vertex)\n    {\n        return $vertex->getEdges()->isEmpty();\n    }\n\n    /**\n     * get indegree of this vertex (number of edges TO this vertex)\n     *\n     * @param Vertex $vertex\n     * @return int\n     * @uses Edge::hasVertexTarget()\n     * @see self::getDegreeVertex()\n     */\n    public function getDegreeInVertex($vertex)\n    {\n        $n = 0;\n        foreach ($vertex->getEdges() as $edge) {\n            if ($edge->hasVertexTarget($vertex)) {\n                ++$n;\n            }\n        }\n\n        return $n;\n    }\n\n    /**\n     * get outdegree of this vertex (number of edges FROM this vertex TO other vertices)\n     *\n     * @param Vertex $vertex\n     * @return int\n     * @uses Edge::hasVertexStart()\n     * @see self::getDegreeVertex()\n     */\n    public function getDegreeOutVertex(Vertex $vertex)\n    {\n        $n = 0;\n        foreach ($vertex->getEdges() as $edge) {\n            if ($edge->hasVertexStart($vertex)) {\n                ++$n;\n            }\n        }\n\n        return $n;\n    }\n}\n"
  },
  {
    "path": "src/DetectNegativeCycle.php",
    "content": "<?php\n\nnamespace Graphp\\Algorithms;\n\nuse Graphp\\Algorithms\\ShortestPath\\MooreBellmanFord as SpMooreBellmanFord;\nuse Graphp\\Graph\\Exception\\NegativeCycleException;\nuse Graphp\\Graph\\Exception\\UnderflowException;\nuse Graphp\\Graph\\Graph;\nuse Graphp\\Graph\\Walk;\n\nclass DetectNegativeCycle extends BaseGraph\n{\n    /**\n     * check if the input graph has any negative cycles\n     *\n     * @return bool\n     * @uses AlgorithmDetectNegativeCycle::getCycleNegative()\n     */\n    public function hasCycleNegative()\n    {\n        try {\n            $this->getCycleNegative();\n\n            // cycle was found => okay\n            return true;\n        // no cycle found\n        } catch (UnderflowException $ignore) {}\n\n        return false;\n    }\n\n    /**\n     * Searches all vertices for the first negative cycle\n     *\n     * @return Walk\n     * @throws UnderflowException if there's no negative cycle\n     * @uses AlgorithmSpMooreBellmanFord::getVertices()\n     */\n    public function getCycleNegative()\n    {\n        // remember vertices already visited, as they can not lead to a new cycle\n        $verticesVisited = array();\n        // check for all vertices\n        foreach ($this->graph->getVertices()->getMap() as $vid => $vertex) {\n            // skip vertices already visited\n            if (!isset($verticesVisited[$vid])) {\n                // start MBF algorithm on current vertex\n                $alg = new SpMooreBellmanFord($vertex);\n\n                try {\n                    // try to get all connected vertices (or throw new cycle)\n                    foreach ($alg->getVertices()->getIds() as $vid) {\n                        // getting connected vertices succeeded, so skip over all of them\n                        $verticesVisited[$vid] = true;\n                    // no cycle found, check next vertex...\n                    }\n                // yey, negative cycle encountered => return\n                } catch (NegativeCycleException $e) {\n                    return $e->getCycle();\n                }\n            }\n        // no more vertices to check => abort\n        }\n        throw new UnderflowException('No negative cycle found');\n    }\n\n    /**\n     * create new graph clone with only vertices and edges in negative cycle\n     *\n     * @return Graph\n     * @throws UnderflowException if there's no negative cycle\n     * @uses AlgorithmDetectNegativeCycle::getCycleNegative()\n     * @uses Walk::createGraph()\n     */\n    public function createGraph()\n    {\n        return $this->getCycleNegative()->createGraph();\n    }\n}\n"
  },
  {
    "path": "src/Directed.php",
    "content": "<?php\n\nnamespace Graphp\\Algorithms;\n\nuse Graphp\\Graph\\EdgeDirected;\nuse Graphp\\Graph\\EdgeUndirected;\n\n/**\n * Basic algorithms for working with the undirected or directed Graphs (digraphs) / Walks.\n *\n * @link http://en.wikipedia.org/wiki/Glossary_of_graph_theory#Direction\n * @link http://en.wikipedia.org/wiki/Digraph_%28mathematics%29\n */\nclass Directed extends BaseDual\n{\n    /**\n     * checks whether the graph has any directed edges\n     *\n     * This method is intentionally not named \"isDirected()\" (aka digraph),\n     * because that might be misleading in regards to empty and/or mixed graphs.\n     *\n     * @return bool\n     */\n    public function hasDirected()\n    {\n        foreach ($this->set->getEdges() as $edge) {\n            if ($edge instanceof EdgeDirected) {\n                return true;\n            }\n        }\n\n        return false;\n    }\n\n    /**\n     * checks whether the graph has any undirected edges\n     *\n     * This method is intentionally not named \"isUndirected()\",\n     * because that might be misleading in regards to empty and/or mixed graphs.\n     *\n     * @return bool\n     */\n    public function hasUndirected()\n    {\n        foreach ($this->set->getEdges() as $edge) {\n            if ($edge instanceof EdgeUndirected) {\n                return true;\n            }\n        }\n\n        return false;\n    }\n\n    /**\n     * checks whether this is a mixed graph (contains both directed and undirected edges)\n     *\n     * @return bool\n     * @uses self::hasDirected()\n     * @uses self::hasUndirected()\n     */\n    public function isMixed()\n    {\n        return ($this->hasDirected() && $this->hasUndirected());\n    }\n}\n"
  },
  {
    "path": "src/Eulerian.php",
    "content": "<?php\n\nnamespace Graphp\\Algorithms;\n\nclass Eulerian extends BaseGraph\n{\n    /**\n     * check whether this graph has an eulerian cycle\n     *\n     * @return bool\n     * @uses ConnectedComponents::isSingle()\n     * @uses Degree::getDegreeVertex()\n     * @todo isolated vertices should be ignored\n     * @todo definition is only valid for undirected graphs\n     */\n    public function hasCycle()\n    {\n        $components = new ConnectedComponents($this->graph);\n        if ($components->isSingle()) {\n            $alg = new Degree($this->graph);\n\n            foreach ($this->graph->getVertices() as $vertex) {\n                // uneven degree => fail\n                if ($alg->getDegreeVertex($vertex) & 1) {\n                    return false;\n                }\n            }\n\n            return true;\n        }\n\n        return false;\n    }\n}\n"
  },
  {
    "path": "src/Flow.php",
    "content": "<?php\n\nnamespace Graphp\\Algorithms;\n\nuse Graphp\\Graph\\EdgeDirected;\nuse Graphp\\Graph\\Exception\\UnexpectedValueException;\nuse Graphp\\Graph\\Vertex;\n\n/**\n * Basic algorithms for working with flow graphs\n *\n * A flow network (also known as a transportation network) is a directed graph\n * where each edge has a capacity and each edge receives a flow.\n *\n * @link http://en.wikipedia.org/wiki/Flow_network\n * @see Algorithm\\Balance\n */\nclass Flow extends BaseDual\n{\n    /**\n     * check if this graph has any flow set (any edge has a non-NULL flow)\n     *\n     * @return bool\n     * @uses Edge::getFlow()\n     */\n    public function hasFlow()\n    {\n        foreach ($this->set->getEdges() as $edge) {\n            if ($edge->getFlow() !== NULL) {\n                return true;\n            }\n        }\n\n        return false;\n    }\n\n    /**\n     * Calculates the flow for this Vertex: sum(outflow) - sum(inflow)\n     *\n     * Usually, vertices should have a resulting flow of 0: The sum of flows\n     * entering a vertex must equal the sum of flows leaving a vertex. If the\n     * resulting flow is < 0, this vertex is considered a sink (i.e. there's\n     * more flow into this vertex). If the resulting flow is > 0, this vertex\n     * is considered a \"source\" (i.e. there's more flow leaving this vertex).\n     *\n     * @param Vertex $vertex\n     * @return float\n     * @throws UnexpectedValueException if they are undirected edges\n     * @see Vertex::getBalance()\n     * @uses Vertex::getEdges()\n     * @uses Edge::getFlow()\n     */\n    public function getFlowVertex(Vertex $vertex)\n    {\n        $sumOfFlow = 0;\n\n        foreach ($vertex->getEdges() as $edge) {\n            if (!($edge instanceof EdgeDirected)) {\n                throw new UnexpectedValueException(\"TODO: undirected edges not suported yet\");\n            }\n\n            // edge is an outgoing edge of this vertex\n            if ($edge->hasVertexStart($vertex)) {\n                // flowing out (flow is \"pointing away\")\n                $sumOfFlow += $edge->getFlow();\n                // this is an ingoing edge\n            } else {\n                // flowing in\n                $sumOfFlow -= $edge->getFlow();\n            }\n        }\n\n        return $sumOfFlow;\n    }\n\n    public function getBalance()\n    {\n        $balance = 0;\n        // Sum for all vertices of value\n        foreach ($this->set->getVertices() as $vertex) {\n            $balance += $vertex->getBalance();\n        }\n\n        return $balance;\n    }\n\n    /**\n     * check if the current flow is balanced (aka \"balanced flow\" or \"b-flow\")\n     *\n     * a flow is considered balanced if each edge's current flow does not exceed its\n     * maximum capacity (which is always guaranteed due to the implementation\n     * of Edge::setFlow()) and each vertices' flow (i.e. outflow-inflow) equals\n     * its balance.\n     *\n     * checking whether the FLOW is balanced is not to be confused with checking\n     * whether the GRAPH is balanced (see Graph::isBalanced() instead)\n     *\n     * @return bool\n     * @see Degree::isBalanced() if you merely want to check indegree=outdegree\n     * @uses self::getFlowVertex()\n     * @uses Vertex::getBalance()\n     */\n    public function isBalancedFlow()\n    {\n        // no need to check for each edge: flow <= capacity (setters already check that)\n        // check for each vertex: outflow-inflow = balance\n        foreach ($this->set->getVertices() as $vertex) {\n            if ($this->getFlowVertex($vertex) !== $vertex->getBalance()) {\n                return false;\n            }\n        }\n\n        return true;\n    }\n}\n"
  },
  {
    "path": "src/Groups.php",
    "content": "<?php\n\nnamespace Graphp\\Algorithms;\n\nuse Graphp\\Graph\\Set\\Vertices;\nuse Graphp\\Graph\\Vertex;\n\nclass Groups extends BaseGraph\n{\n    /**\n     * count total number of different groups assigned to vertices\n     *\n     * @return int\n     * @uses AlgorithmGroups::getGroups()\n     */\n    public function getNumberOfGroups()\n    {\n        return \\count($this->getGroups());\n    }\n\n    /**\n     * checks whether the input graph's vertex groups are a valid bipartition\n     *\n     * @return bool\n     * @see AlgorithmBipartit() if you do NOT want to take vertex groups into consideration\n     * @uses AlgorithmGroups::getNumberOfGroups()\n     * @uses Vertex::getGroup()\n     */\n    public function isBipartit()\n    {\n        // graph has to contain exactly 2 groups\n        if ($this->getNumberOfGroups() !== 2) {\n            return false;\n        }\n\n        // for each vertex\n        foreach ($this->graph->getVertices() as $vertex) {\n            // get current group\n            $group = $vertex->getGroup();\n            // for every neighbor vertex\n            foreach ($vertex->getVerticesEdge() as $vertexNeighbor) {\n                // vertex group must be other group\n                if ($vertexNeighbor->getGroup() === $group) {\n                    return false;\n                }\n            }\n        }\n\n        return true;\n    }\n\n    /**\n     * get vector of all group numbers\n     *\n     * @return int[]\n     * @uses Vertex::getGroup()\n     */\n    public function getGroups()\n    {\n        $groups = array();\n        foreach ($this->graph->getVertices() as $vertex) {\n            assert($vertex instanceof Vertex);\n            $groups[$vertex->getGroup()] = true;\n        }\n\n        return \\array_keys($groups);\n    }\n\n    /**\n     * get set of all Vertices in the given group\n     *\n     * @param  int      $group\n     * @return Vertices\n     * @uses Vertex::getGroup()\n     */\n    public function getVerticesGroup($group)\n    {\n        $vertices = array();\n        foreach ($this->graph->getVertices()->getMap() as $vid => $vertex) {\n            if ($vertex->getGroup() === $group) {\n                $vertices[$vid] = $vertex;\n            }\n        }\n\n        return new Vertices($vertices);\n    }\n}\n"
  },
  {
    "path": "src/Loop.php",
    "content": "<?php\n\nnamespace Graphp\\Algorithms;\n\nuse Graphp\\Graph\\Vertex;\n\n/**\n * Basic algorithms for working with loop edges\n *\n * A loop (also called a self-loop or a \"buckle\") is an edge that connects a\n * Vertex to itself. A simple graph contains no loops.\n *\n * @link http://en.wikipedia.org/wiki/Loop_%28graph_theory%29\n */\nclass Loop extends BaseDual\n{\n    /**\n     * checks whether this graph has any loops (edges from vertex to itself)\n     *\n     * @return bool\n     * @uses Edge::isLoop()\n     */\n    public function hasLoop()\n    {\n        foreach ($this->set->getEdges() as $edge) {\n            if ($edge->isLoop()) {\n                return true;\n            }\n        }\n\n        return false;\n    }\n\n    /**\n     * checks whether this vertex has a loop (edge to itself)\n     *\n     * @return bool\n     * @uses Edge::isLoop()\n     */\n    public function hasLoopVertex(Vertex $vertex)\n    {\n        foreach ($vertex->getEdges() as $edge) {\n            if ($edge->isLoop()) {\n                return true;\n            }\n        }\n\n        return false;\n    }\n}\n"
  },
  {
    "path": "src/MaxFlow/EdmondsKarp.php",
    "content": "<?php\n\nnamespace Graphp\\Algorithms\\MaxFlow;\n\nuse Graphp\\Algorithms\\Base;\nuse Graphp\\Algorithms\\ResidualGraph;\nuse Graphp\\Algorithms\\ShortestPath\\BreadthFirst;\nuse Graphp\\Graph\\EdgeDirected;\nuse Graphp\\Graph\\Exception\\InvalidArgumentException;\nuse Graphp\\Graph\\Exception\\OutOfBoundsException;\nuse Graphp\\Graph\\Exception\\UnderflowException;\nuse Graphp\\Graph\\Exception\\UnexpectedValueException;\nuse Graphp\\Graph\\Graph;\nuse Graphp\\Graph\\Set\\Edges;\nuse Graphp\\Graph\\Vertex;\n\nclass EdmondsKarp extends Base\n{\n    /**\n     * @var Vertex\n     */\n    private $startVertex;\n\n    /**\n     * @var Vertex\n     */\n    private $destinationVertex;\n\n    /**\n     * @param Vertex $startVertex       the vertex where the flow search starts\n     * @param Vertex $destinationVertex the vertex where the flow search ends (destination)\n     */\n    public function __construct(Vertex $startVertex, Vertex $destinationVertex)\n    {\n        if ($startVertex === $destinationVertex) {\n            throw new InvalidArgumentException('Start and destination must not be the same vertex');\n        }\n        if ($startVertex->getGraph() !== $destinationVertex->getGraph()) {\n            throw new InvalidArgumentException('Start and target vertex have to be in the same graph instance');\n        }\n        $this->startVertex = $startVertex;\n        $this->destinationVertex = $destinationVertex;\n    }\n\n    /**\n     * Returns max flow graph\n     *\n     * @return Graph\n     * @throws UnexpectedValueException for undirected edges\n     */\n    public function createGraph()\n    {\n        $graphResult = $this->startVertex->getGraph()->createGraphClone();\n\n        // initialize null flow and check edges\n        foreach ($graphResult->getEdges() as $edge) {\n            if (!($edge instanceof EdgeDirected)) {\n                throw new UnexpectedValueException('Undirected edges not supported for edmonds karp');\n            }\n            $edge->setFlow(0);\n        }\n\n        $idA = $this->startVertex->getId();\n        $idB = $this->destinationVertex->getId();\n\n        do {\n            // Generate new residual graph and repeat\n            $residualAlgorithm = new ResidualGraph($graphResult);\n            $graphResidual = $residualAlgorithm->createGraph();\n\n            // 1. Search _shortest_ (number of hops and cheapest) path from s -> t\n            $alg = new BreadthFirst($graphResidual->getVertex($idA));\n            try {\n                $pathFlow = $alg->getWalkTo($graphResidual->getVertex($idB));\n            } catch (OutOfBoundsException $e) {\n                $pathFlow = NULL;\n            }\n\n            // If path exists add the new flow to graph\n            if ($pathFlow) {\n                // 2. get max flow from path\n                $maxFlowValue = $pathFlow->getEdges()->getEdgeOrder(Edges::ORDER_CAPACITY)->getCapacity();\n\n                // 3. add flow to path\n                foreach ($pathFlow->getEdges() as $edge) {\n                    // try to look for forward edge to increase flow\n                    try {\n                        $originalEdge = $graphResult->getEdgeClone($edge);\n                        $originalEdge->setFlow($originalEdge->getFlow() + $maxFlowValue);\n                    // forward edge not found, look for back edge to decrease flow\n                    } catch (UnderflowException $e) {\n                        $originalEdge = $graphResult->getEdgeCloneInverted($edge);\n                        $originalEdge->setFlow($originalEdge->getFlow() - $maxFlowValue);\n                    }\n                }\n            }\n\n        // repeat while we still finds paths with residual capacity to add flow to\n        } while ($pathFlow);\n\n        return $graphResult;\n    }\n\n    /**\n     * Returns max flow value\n     *\n     * @return float\n     */\n    public function getFlowMax()\n    {\n        $resultGraph = $this->createGraph();\n\n        $start = $resultGraph->getVertex($this->startVertex->getId());\n        $maxFlow = 0;\n        foreach ($start->getEdgesOut() as $edge) {\n            $maxFlow = $maxFlow + $edge->getFlow();\n        }\n\n        return $maxFlow;\n    }\n}\n"
  },
  {
    "path": "src/MaximumMatching/Base.php",
    "content": "<?php\n\nnamespace Graphp\\Algorithms\\MaximumMatching;\n\nuse Graphp\\Algorithms\\BaseGraph;\nuse Graphp\\Graph\\Exception\\UnexpectedValueException;\nuse Graphp\\Graph\\Graph;\nuse Graphp\\Graph\\Set\\Edges;\n\nabstract class Base extends BaseGraph\n{\n    /**\n     * Get the count of edges that are in the match\n     *\n     * @return int\n     * @throws UnexpectedValueException if graph is directed or is not bipartit\n     * @uses Base::getEdges()\n     */\n    public function getNumberOfMatches()\n    {\n        return \\count($this->getEdges());\n    }\n\n    /**\n     * create new resulting graph with only edges from maximum matching\n     *\n     * @return Graph\n     * @uses Base::getEdges()\n     * @uses Graph::createGraphCloneEdges()\n     */\n    public function createGraph()\n    {\n        return $this->graph->createGraphCloneEdges($this->getEdges());\n    }\n\n    /**\n     * create new resulting graph with minimum-cost flow on edges\n     *\n     * @return Edges\n     */\n    abstract public function getEdges();\n}\n"
  },
  {
    "path": "src/MaximumMatching/Flow.php",
    "content": "<?php\n\nnamespace Graphp\\Algorithms\\MaximumMatching;\n\nuse Graphp\\Algorithms\\Directed;\nuse Graphp\\Algorithms\\Groups;\nuse Graphp\\Algorithms\\MaxFlow\\EdmondsKarp as MaxFlowEdmondsKarp;\nuse Graphp\\Graph\\Exception\\UnexpectedValueException;\nuse Graphp\\Graph\\Set\\Edges;\nuse Graphp\\Graph\\Vertex;\n\nclass Flow extends Base\n{\n    public function getEdges()\n    {\n        $alg = new Directed($this->graph);\n        if ($alg->hasDirected()) {\n            throw new UnexpectedValueException('Input graph contains directed edges');\n        }\n\n        $alg = new Groups($this->graph);\n        if (!$alg->isBipartit()) {\n            throw new UnexpectedValueException('Input graph does not have bipartit groups assigned to each vertex. Consider Using \"AlgorithmBipartit::createGraph()\" first');\n        }\n\n        // create temporary flow graph with supersource and supersink\n        $graphFlow = $this->graph->createGraphCloneEdgeless();\n\n        $superSource = $graphFlow->createVertex();\n        $superSink   = $graphFlow->createVertex();\n\n        $groups = $alg->getGroups();\n        $groupA = $groups[0];\n\n        // connect supersource s* to set A and supersink t* to set B\n        foreach ($graphFlow->getVertices() as $vertex) {\n            assert($vertex instanceof Vertex);\n            // we want to skip over supersource & supersink as they do not have a partition assigned\n            if ($vertex === $superSource || $vertex === $superSink) continue;\n\n            $group = $vertex->getGroup();\n\n            if ($group === $groupA) {\n                // group A: source\n                $graphFlow->createEdgeDirected($superSource, $vertex)->setCapacity(1)->setFlow(0);\n\n                // temporarily create edges from A->B for flow graph\n                $originalVertex = $this->graph->getVertex($vertex->getId());\n                foreach ($originalVertex->getVerticesEdgeTo() as $vertexTarget) {\n                    $graphFlow->createEdgeDirected($vertex, $graphFlow->getVertex($vertexTarget->getId()))->setCapacity(1)->setFlow(0);\n                }\n            } else {\n                // group B: sink\n                $graphFlow->createEdgeDirected($vertex, $superSink)->setCapacity(1)->setFlow(0);\n            }\n        }\n\n        // visualize($resultGraph);\n\n        // calculate (s*, t*)-flow\n        $algMaxFlow = new MaxFlowEdmondsKarp($superSource, $superSink);\n        $resultGraph = $algMaxFlow->createGraph();\n\n        // destroy temporary supersource and supersink again\n        $resultGraph->getVertex($superSink->getId())->destroy();\n        $resultGraph->getVertex($superSource->getId())->destroy();\n\n        $returnEdges = array();\n        foreach ($resultGraph->getEdges() as $edge) {\n            // only keep matched edges\n            if ($edge->getFlow() > 0) {\n                $originalEdge = $this->graph->getEdgeClone($edge);\n                $returnEdges[] = $originalEdge;\n            }\n        }\n\n        return new Edges($returnEdges);\n    }\n}\n"
  },
  {
    "path": "src/MinimumCostFlow/Base.php",
    "content": "<?php\n\nnamespace Graphp\\Algorithms\\MinimumCostFlow;\n\nuse Graphp\\Algorithms\\BaseGraph;\nuse Graphp\\Algorithms\\Weight as AlgorithmWeight;\nuse Graphp\\Algorithms\\Flow as AlgorithmFlow;\nuse Graphp\\Graph\\Exception\\UnderflowException;\nuse Graphp\\Graph\\Exception\\UnexpectedValueException;\nuse Graphp\\Graph\\Graph;\nuse Graphp\\Graph\\Set\\Edges;\n\nabstract class Base extends BaseGraph\n{\n    /**\n     * check if balance is okay and throw exception otherwise\n     *\n     * @return $this (chainable)\n     * @throws UnexpectedValueException\n     */\n    protected function checkBalance()\n    {\n        $alg = new AlgorithmFlow($this->graph);\n        $balance = $alg->getBalance();\n\n        $tolerance = 0.000001;\n        if ($balance >= $tolerance || $balance <= -$tolerance) {\n            throw new UnexpectedValueException('The given graph is not balanced value is: ' . $balance);\n        }\n\n        return $this;\n    }\n\n    /**\n     * helper used to add $newFlow to original edges of $clonedEdges in graph $resultGraph\n     *\n     * @param Graph  $resultGraph graph to look for original edges\n     * @param Edges  $clonedEdges set of cloned edges to be modified\n     * @param number $newFlow     flow to add\n     * @uses Graph::getEdgeClone()\n     * @uses Graph::getEdgeCloneInverted()\n     * @uses Edge::getFlow()\n     * @uses Edge::setFlow()\n     */\n    protected function addFlow(Graph $resultGraph, Edges $clonedEdges, $newFlow)\n    {\n        foreach ($clonedEdges as $clonedEdge) {\n            try {\n                // get edge from clone\n                $edge = $resultGraph->getEdgeClone($clonedEdge);\n                // add flow\n                $edge->setFlow($edge->getFlow() + $newFlow);\n            } catch (UnderflowException $ignore) {\n                // if the edge doesn't exist => use the residual edge\n                $edge = $resultGraph->getEdgeCloneInverted($clonedEdge);\n                // remove flow\n                $edge->setFlow($edge->getFlow() - $newFlow);\n            }\n        }\n    }\n\n    /**\n     * calculate total weight along minimum-cost flow\n     *\n     * @return float\n     * @uses self::createGraph()\n     * @uses AlgorithmWeight::getWeightFlow()\n     */\n    public function getWeightFlow()\n    {\n        $alg = new AlgorithmWeight($this->createGraph());\n        return $alg->getWeightFlow();\n    }\n\n    /**\n     * create new resulting graph with minimum-cost flow on edges\n     *\n     * @return Graph\n     * @throws UnexpectedValueException for undirected edges\n     * @throws UnexpectedValueException if the graph has not enough capacity for the minimum-cost flow\n     */\n    abstract public function createGraph();\n}\n"
  },
  {
    "path": "src/MinimumCostFlow/CycleCanceling.php",
    "content": "<?php\n\nnamespace Graphp\\Algorithms\\MinimumCostFlow;\n\nuse Graphp\\Algorithms\\DetectNegativeCycle;\nuse Graphp\\Algorithms\\MaxFlow\\EdmondsKarp as MaxFlowEdmondsKarp;\nuse Graphp\\Algorithms\\ResidualGraph;\nuse Graphp\\Graph\\Exception\\UnderflowException;\nuse Graphp\\Graph\\Exception\\UnexpectedValueException;\nuse Graphp\\Graph\\Set\\Edges;\n\nclass CycleCanceling extends Base\n{\n    public function createGraph()\n    {\n        $this->checkBalance();\n\n        // create resulting graph with supersource and supersink\n        $resultGraph = $this->graph->createGraphClone();\n\n        $superSource = $resultGraph->createVertex();\n        $superSink   = $resultGraph->createVertex();\n\n        $sumBalance = 0;\n\n        // connect supersource s* and supersink t* with all \"normal\" sources and sinks\n        foreach ($resultGraph->getVertices() as $vertex) {\n            $balance = $vertex->getBalance();\n\n            if ($balance > 0) {\n                // positive balance => source capacity\n                $resultGraph->createEdgeDirected($superSource, $vertex)->setCapacity($balance);\n\n                $sumBalance += $balance;\n            } elseif ($balance < 0) {\n                // negative balance => sink capacity (positive)\n                $resultGraph->createEdgeDirected($vertex, $superSink)->setCapacity(-$balance);\n            }\n        }\n\n        // calculate (s*, t*)-flow\n        $algMaxFlow = new MaxFlowEdmondsKarp($superSource, $superSink);\n        $flowMax = $algMaxFlow->getFlowMax();\n\n        if ($flowMax !== $sumBalance) {\n            throw new UnexpectedValueException('Network does not support required flow of ' . $sumBalance . ' (maximum possible flow limited to ' . $flowMax . ')');\n        }\n\n        $resultGraph = $algMaxFlow->createGraph();\n\n        while (true) {\n            // create residual graph\n            $algRG = new ResidualGraph($resultGraph);\n            $residualGraph = $algRG->createGraph();\n\n            // get negative cycle\n            $alg = new DetectNegativeCycle($residualGraph);\n            try {\n                $clonedEdges = $alg->getCycleNegative()->getEdges();\n            } catch (UnderflowException $ignore) {\n                // no negative cycle found => end algorithm\n                break;\n            }\n\n            // calculate maximal possible flow = minimum capacity remaining for all edges\n            $newFlow = $clonedEdges->getEdgeOrder(Edges::ORDER_CAPACITY_REMAINING)->getCapacityRemaining();\n\n            // set flow on original graph\n            assert($newFlow !== null);\n            $this->addFlow($resultGraph, $clonedEdges, $newFlow);\n        }\n\n        // destroy temporary supersource and supersink again\n        $resultGraph->getVertex($superSink->getId())->destroy();\n        $resultGraph->getVertex($superSource->getId())->destroy();\n\n        return $resultGraph;\n    }\n}\n"
  },
  {
    "path": "src/MinimumCostFlow/SuccessiveShortestPath.php",
    "content": "<?php\n\nnamespace Graphp\\Algorithms\\MinimumCostFlow;\n\nuse Graphp\\Algorithms\\ResidualGraph;\nuse Graphp\\Algorithms\\ShortestPath\\MooreBellmanFord as SpMooreBellmanFord;\nuse Graphp\\Algorithms\\Search\\BreadthFirst as SearchBreadthFirst;\nuse Graphp\\Graph\\EdgeDirected;\nuse Graphp\\Graph\\Exception\\UnderflowException;\nuse Graphp\\Graph\\Exception\\UnexpectedValueException;\nuse Graphp\\Graph\\Graph;\nuse Graphp\\Graph\\Set\\Edges;\nuse Graphp\\Graph\\Vertex;\n\nclass SuccessiveShortestPath extends Base\n{\n    /**\n     * @uses Graph::createGraphClone()\n     * @uses ResidualGraph::createGraph()\n     * @uses SpMooreBellmanFord::getEdgesTo(Vertex $targetVertex)\n     * @see Base::createGraph()\n     */\n    public function createGraph()\n    {\n        $this->checkBalance();\n        $resultGraph = $this->graph->createGraphClone();\n\n        // initial balance to 0\n        $vertices = $resultGraph->getVertices();\n        foreach ($vertices as $vertex) {\n            $vertex->setBalance(0);\n        }\n\n        // initial flow of edges\n        $edges = $resultGraph->getEdges();\n        foreach ($edges as $edge) {\n            if (!($edge instanceof EdgeDirected)) {\n                throw new UnexpectedValueException('Undirected edges are not supported for SuccessiveShortestPath');\n            }\n\n            // 0 if weight of edge is positive\n            $flow = 0;\n\n            // maximal flow if weight of edge is negative\n            if ($edge->getWeight() < 0) {\n                $flow = $edge->getCapacity();\n\n                $startVertex = $edge->getVertexStart();\n                $endVertex = $edge->getVertexEnd();\n\n                // add balance to start- and end-vertex\n                $this->addBalance($startVertex, $flow);\n                $this->addBalance($endVertex, - $flow);\n            }\n\n            $edge->setFlow($flow);\n        }\n\n        // return or Exception inside this while\n        while (true) {\n            // create residual graph\n            $algRG = new ResidualGraph($resultGraph);\n            $residualGraph = $algRG->createGraph();\n\n            // search for a source\n            try {\n                $sourceVertex = $this->getVertexSource($residualGraph);\n            } catch (UnderflowException $ignore) {\n                // no source is found => minimum-cost flow is found\n                break;\n            }\n\n            // search for reachable target sink from this source\n            try {\n                $targetVertex = $this->getVertexSink($sourceVertex);\n            } catch (UnderflowException $e) {\n                // no target found => network does not have enough capacity\n                throw new UnexpectedValueException('The graph has not enough capacity for the minimum-cost flow', 0, $e);\n            }\n\n            // calculate shortest path between source- and target-vertex\n            $algSP = new SpMooreBellmanFord($sourceVertex);\n            $edgesOnFlow = $algSP->getEdgesTo($targetVertex);\n\n            // calculate the maximal possible flow\n            // new flow is the maximal possible flow for this path\n            $newflow    =    $this->graph->getVertex($sourceVertex->getId())->getBalance() - $sourceVertex->getBalance();\n            $targetFlow = - ($this->graph->getVertex($targetVertex->getId())->getBalance() - $targetVertex->getBalance());\n\n            // get minimum of source and target\n            if ($targetFlow < $newflow) {\n                $newflow = $targetFlow;\n            }\n\n            // get minimum of capacity remaining on path\n            $minCapacity = $edgesOnFlow->getEdgeOrder(Edges::ORDER_CAPACITY_REMAINING)->getCapacityRemaining();\n            if ($minCapacity < $newflow) {\n                $newflow = $minCapacity;\n            }\n\n            // add the new flow to the path\n            assert($newflow !== null);\n            $this->addFlow($resultGraph, $edgesOnFlow, $newflow);\n\n            // add balance to source and remove for the target sink\n            $oriSourceVertex = $resultGraph->getVertex($sourceVertex->getId());\n            $oriTargetVertex = $resultGraph->getVertex($targetVertex->getId());\n\n            $this->addBalance($oriSourceVertex, $newflow);\n            $this->addBalance($oriTargetVertex, - $newflow);\n        }\n\n        return $resultGraph;\n    }\n\n    /**\n     * @param  Graph     $graph\n     * @return Vertex a source vertex in the given graph\n     * @throws UnderflowException if there is no left source vertex\n     */\n    private function getVertexSource(Graph $graph)\n    {\n        foreach ($graph->getVertices()->getMap() as $vid => $vertex) {\n            if ($this->graph->getVertex($vid)->getBalance() - $vertex->getBalance() > 0) {\n                return $vertex;\n            }\n        }\n        throw new UnderflowException('No source vertex found in graph');\n    }\n\n    /**\n     * @param  Vertex    $source\n     * @return Vertex a sink-vertex that is reachable from the source\n     * @throws UnderflowException if there is no reachable sink vertex\n     * @uses BreadthFirst::getVertices()\n     */\n    private function getVertexSink(Vertex $source)\n    {\n        // search for reachable Vertices\n        $algBFS = new SearchBreadthFirst($source);\n\n        foreach ($algBFS->getVertices()->getMap() as $vid => $vertex) {\n            if ($this->graph->getVertex($vid)->getBalance() - $vertex->getBalance() < 0) {\n                return $vertex;\n            }\n        }\n        throw new UnderflowException('No sink vertex connected to given source vertex found');\n    }\n\n    private function addBalance(Vertex $vertex, $balance)\n    {\n        $vertex->setBalance($vertex->getBalance() + $balance);\n    }\n}\n"
  },
  {
    "path": "src/MinimumSpanningTree/Base.php",
    "content": "<?php\n\nnamespace Graphp\\Algorithms\\MinimumSpanningTree;\n\nuse Graphp\\Algorithms\\Base as AlgorithmBase;\nuse Graphp\\Graph\\Edge;\nuse Graphp\\Graph\\Graph;\nuse Graphp\\Graph\\Set\\Edges;\nuse SplPriorityQueue;\n\n/**\n * Abstract base class for minimum spanning tree (MST) algorithms\n *\n * A minimum spanning tree of a graph is a subgraph that is a tree and connects\n * all the vertices together while minimizing the total sum of all edges'\n * weights.\n *\n * A spanning tree thus requires a connected graph (single connected component),\n * otherwise we can span multiple trees (spanning forest) within each component.\n * Because a null graph (a Graph with no vertices) is not considered connected,\n * it also can not contain a spanning tree.\n *\n * Most authors demand that the input graph has to be undirected, whereas this\n * library supports also directed and mixed graphs. The actual direction of the\n * edge will be ignored, only its incident vertices will be checked. This is\n * done in order to be consistent to how ConnectedComponents are checked.\n *\n * @link http://en.wikipedia.org/wiki/Minimum_Spanning_Tree\n * @link http://en.wikipedia.org/wiki/Spanning_Tree\n * @link http://mathoverflow.net/questions/120536/is-the-empty-graph-a-tree\n */\nabstract class Base extends AlgorithmBase\n{\n    /**\n     * create new resulting graph with only edges on minimum spanning tree\n     *\n     * @return Graph\n     * @uses self::getGraph()\n     * @uses self::getEdges()\n     * @uses Graph::createGraphCloneEdges()\n     */\n    public function createGraph()\n    {\n        return $this->getGraph()->createGraphCloneEdges($this->getEdges());\n    }\n\n    /**\n     * get all edges on minimum spanning tree\n     *\n     * @return Edges\n     */\n    abstract public function getEdges();\n\n    /**\n     * return reference to current Graph\n     *\n     * @return Graph\n     */\n    abstract protected function getGraph();\n\n    /**\n     * get total weight of minimum spanning tree\n     *\n     * @return float\n     */\n    public function getWeight()\n    {\n        return $this->getEdges()->getSumCallback(function (Edge $edge) {\n            return $edge->getWeight();\n        });\n    }\n\n    /**\n     * helper method to add a set of Edges to the given set of sorted edges\n     *\n     * @param Edges            $edges\n     * @param SplPriorityQueue $sortedEdges\n     */\n    protected function addEdgesSorted(Edges $edges, SplPriorityQueue $sortedEdges)\n    {\n        // For all edges\n        foreach ($edges as $edge) {\n            assert($edge instanceof Edge);\n            // ignore loops (a->a)\n            if (!$edge->isLoop()) {\n                // Add edges with negative weight because of order in stl\n                $sortedEdges->insert($edge, -$edge->getWeight());\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "src/MinimumSpanningTree/Kruskal.php",
    "content": "<?php\n\nnamespace Graphp\\Algorithms\\MinimumSpanningTree;\n\nuse Graphp\\Graph\\Edge;\nuse Graphp\\Graph\\Exception\\UnexpectedValueException;\nuse Graphp\\Graph\\Graph;\nuse Graphp\\Graph\\Set\\Edges;\nuse SplPriorityQueue;\n\nclass Kruskal extends Base\n{\n    /**\n     * @var Graph\n     */\n    private $graph;\n\n    public function __construct(Graph $inputGraph)\n    {\n        $this->graph = $inputGraph;\n    }\n\n    protected function getGraph()\n    {\n        return $this->graph;\n    }\n\n    /**\n     * @return Edges\n     */\n    public function getEdges()\n    {\n        // Sortiere Kanten im Graphen\n\n        $sortedEdges = new SplPriorityQueue();\n\n        // For all edges\n        $this->addEdgesSorted($this->graph->getEdges(), $sortedEdges);\n\n        $returnEdges = array();\n\n        // next color to assign\n        $colorNext = 0;\n        // array(color1 => array(vid1, vid2, ...), color2=>...)\n        $colorVertices = array();\n        // array(vid1 => color1, vid2 => color1, ...)\n        $colorOfVertices = array();\n\n        // Füge billigste Kanten zu neuen Graphen hinzu und verschmelze teilgragen wenn es nötig ist (keine Kreise)\n        // solange ich mehr als einen Graphen habe mit weniger als n-1 kanten (bei n knoten im original)\n        foreach ($sortedEdges as $edge) {\n            assert($edge instanceof Edge);\n            // Gucke Kante an:\n\n            $vertices = $edge->getVertices()->getIds();\n\n            $aId = $vertices[0];\n            $bId = $vertices[1];\n\n            $aColor = isset($colorOfVertices[$aId]) ? $colorOfVertices[$aId] : NULL;\n            $bColor = isset($colorOfVertices[$bId]) ? $colorOfVertices[$bId] : NULL;\n\n            // 1. weder start noch end gehört zu einem graphen\n                // => neuer Graph mit kanten\n            if ($aColor === NULL && $bColor === NULL) {\n                $colorOfVertices[$aId] = $colorNext;\n                $colorOfVertices[$bId] = $colorNext;\n\n                $colorVertices[$colorNext] = array($aId, $bId);\n\n                ++$colorNext;\n\n                // connect both vertices\n                $returnEdges[] = $edge;\n            }\n            // 4. start xor end gehören zu einem graphen\n                // => erweitere diesesn Graphen\n            // Only b has color\n            else if ($aColor === NULL && $bColor !== NULL) {\n                // paint a in b's color\n                $colorOfVertices[$aId] = $bColor;\n                $colorVertices[$bColor][]=$aId;\n\n                $returnEdges[] = $edge;\n            // Only a has color\n            } elseif ($aColor !== NULL && $bColor === NULL) {\n                // paint b in a's color\n                $colorOfVertices[$bId] = $aColor;\n                $colorVertices[$aColor][]=$bId;\n\n                $returnEdges[] = $edge;\n            }\n            // 3. start und end gehören zu unterschiedlichen graphen\n                // => vereinigung\n            // Different color\n            else if ($aColor !== $bColor) {\n                $betterColor = $aColor;\n                $worseColor  = $bColor;\n\n                // more vertices with color a => paint all in b in a's color\n                if (\\count($colorVertices[$bColor]) > \\count($colorVertices[$aColor])) {\n                    $betterColor = $bColor;\n                    $worseColor = $aColor;\n                }\n\n                // search all vertices with color b\n                foreach ($colorVertices[$worseColor] as $vid) {\n                    $colorOfVertices[$vid] = $betterColor;\n                    // repaint in a's color\n                    $colorVertices[$betterColor][]=$vid;\n                }\n                // delete old color\n                unset($colorVertices[$worseColor]);\n\n                $returnEdges[] = $edge;\n            }\n            // 2. start und end gehören zum gleichen graphen => zirkel\n            // => nichts machen\n        }\n\n        // definition of spanning tree: number of edges = number of vertices - 1\n        // above algorithm does not check isolated edges or may otherwise return multiple connected components => force check\n        if (\\count($returnEdges) !== (\\count($this->graph->getVertices()) - 1)) {\n            throw new UnexpectedValueException('Graph is not connected');\n        }\n\n        return new Edges($returnEdges);\n    }\n}\n"
  },
  {
    "path": "src/MinimumSpanningTree/Prim.php",
    "content": "<?php\n\nnamespace Graphp\\Algorithms\\MinimumSpanningTree;\n\nuse Graphp\\Graph\\Edge;\nuse Graphp\\Graph\\Exception\\UnexpectedValueException;\nuse Graphp\\Graph\\Set\\Edges;\nuse Graphp\\Graph\\Vertex;\nuse SplPriorityQueue;\n\nclass Prim extends Base\n{\n    /**\n     * @var Vertex\n     */\n    private $startVertex;\n\n    public function __construct(Vertex $startVertex)\n    {\n        $this->startVertex = $startVertex;\n    }\n\n    /**\n     * @return Edges\n     */\n    public function getEdges()\n    {\n        // Initialize algorithm\n        $edgeQueue = new SplPriorityQueue();\n        $vertexCurrent = $this->startVertex;\n\n        $markInserted = array();\n        $returnEdges = array();\n\n        // iterate n-1 times (per definition, resulting MST MUST have n-1 edges)\n        for ($i = 0, $n = \\count($this->startVertex->getGraph()->getVertices()) - 1; $i < $n; ++$i) {\n            $markInserted[$vertexCurrent->getId()] = true;\n\n            // get unvisited vertex of the edge and add edges from new vertex\n            // Add all edges from $currentVertex to priority queue\n            $this->addEdgesSorted($vertexCurrent->getEdges(), $edgeQueue);\n\n            do {\n                if ($edgeQueue->isEmpty()) {\n                    throw new UnexpectedValueException('Graph has more than one component');\n                }\n\n                // Get next cheapest edge\n                $cheapestEdge = $edgeQueue->extract();\n                assert($cheapestEdge instanceof Edge);\n\n                // Check if edge is between unmarked and marked edge\n                $vertices = $cheapestEdge->getVertices();\n                $vertexA  = $vertices->getVertexFirst();\n                $vertexB  = $vertices->getVertexLast();\n            } while (!(isset($markInserted[$vertexA->getId()]) XOR isset($markInserted[$vertexB->getId()])));\n\n            // Cheapest Edge found, add edge to returnGraph\n            $returnEdges[] = $cheapestEdge;\n\n            // set current vertex for next iteration in order to add its edges to queue\n            if (isset($markInserted[$vertexA->getId()])) {\n                $vertexCurrent = $vertexB;\n            } else {\n                $vertexCurrent = $vertexA;\n            }\n        }\n\n        return new Edges($returnEdges);\n    }\n\n    protected function getGraph()\n    {\n        return $this->startVertex->getGraph();\n    }\n}\n"
  },
  {
    "path": "src/Parallel.php",
    "content": "<?php\n\nnamespace Graphp\\Algorithms;\n\nuse Graphp\\Graph\\Edge;\nuse Graphp\\Graph\\EdgeDirected as EdgeDirected;\nuse Graphp\\Graph\\Set\\Edges;\n\n/**\n * Basic algorithms for working with parallel edges\n *\n * Parallel edges (also called multiple edges or a multi-edge), are two or more\n * edges that are incident to the same two vertices. A simple graph has no\n * multiple edges.\n *\n * @link http://en.wikipedia.org/wiki/Multiple_edges\n */\nclass Parallel extends BaseGraph\n{\n    /**\n     * checks whether this graph has any parallel edges (aka multigraph)\n     *\n     * @return bool\n     * @uses Edge::hasEdgeParallel() for every edge\n     */\n    public function hasEdgeParallel()\n    {\n        foreach ($this->graph->getEdges() as $edge) {\n            if ($this->hasEdgeParallelEdge($edge)) {\n                return true;\n            }\n        }\n\n        return false;\n    }\n\n\n    /**\n     * checks whether this edge has any parallel edges\n     *\n     * @return bool\n     * @uses Edge::getEdgesParallel()\n     */\n    public function hasEdgeParallelEdge(Edge $edge)\n    {\n        return !$this->getEdgesParallelEdge($edge)->isEmpty();\n    }\n\n    /**\n     * get set of all Edges parallel to this edge (excluding self)\n     *\n     * @param Edge $edge\n     * @return Edges\n     */\n    public function getEdgesParallelEdge(Edge $edge)\n    {\n        if ($edge instanceof EdgeDirected) {\n            // get all edges between this edge's endpoints\n            $edges = $edge->getVertexStart()->getEdgesTo($edge->getVertexEnd())->getVector();\n        } else {\n            // edge points into both directions (undirected/bidirectional edge)\n            // also get all edges in other direction\n            $ends  = $edge->getVertices();\n            $edges = $ends->getVertexFirst()->getEdges()->getEdgesIntersection($ends->getVertexLast()->getEdges())->getVector();\n        }\n\n        $pos = \\array_search($edge, $edges, true);\n        assert($pos !== false);\n\n        // exclude current edge from parallel edges\n        unset($edges[$pos]);\n\n        return new Edges(\\array_values($edges));\n    }\n}\n"
  },
  {
    "path": "src/Property/GraphProperty.php",
    "content": "<?php\n\nnamespace Graphp\\Algorithms\\Property;\n\nuse Graphp\\Algorithms\\BaseGraph;\n\n/**\n * Simple algorithms for working with Graph properties\n *\n * @link https://en.wikipedia.org/wiki/Graph_property\n */\nclass GraphProperty extends BaseGraph\n{\n    /**\n     * checks whether this graph has no edges\n     *\n     * Also known as empty Graph. An empty Graph contains no edges, but can\n     * possibly contain any number of isolated vertices.\n     *\n     * @return bool\n     */\n    public function isEdgeless()\n    {\n        return $this->graph->getEdges()->isEmpty();\n    }\n\n    /**\n     * checks whether this graph is a null graph (no vertex - and thus no edges)\n     *\n     * Each Edge is incident to two Vertices, or in case of an loop Edge,\n     * incident to the same Vertex twice. As such an Edge can not exist when\n     * no Vertices exist. So if we check we have no Vertices, we can also be\n     * sure that no Edges exist either.\n     *\n     * @return bool\n     */\n    public function isNull()\n    {\n        return $this->graph->getVertices()->isEmpty();\n    }\n\n    /**\n     * checks whether this graph is trivial (one vertex and no edges)\n     *\n     * @return bool\n     */\n    public function isTrivial()\n    {\n        return ($this->graph->getEdges()->isEmpty() && \\count($this->graph->getVertices()) === 1);\n    }\n}\n"
  },
  {
    "path": "src/Property/WalkProperty.php",
    "content": "<?php\n\nnamespace Graphp\\Algorithms\\Property;\n\nuse Graphp\\Algorithms\\Base as BaseAlgorithm;\nuse Graphp\\Algorithms\\Loop as AlgorithmLoop;\nuse Graphp\\Graph\\Walk;\n\n/**\n * Simple algorithms for working with Walk properties\n *\n * @see GraphProperty\n */\nclass WalkProperty extends BaseAlgorithm\n{\n    /**\n     * the Walk to operate on\n     *\n     * @var Walk\n     */\n    protected $walk;\n\n    /**\n     * instantiate new WalkProperty algorithm\n     *\n     * @param Walk $walk\n     */\n    public function __construct(Walk $walk)\n    {\n        $this->walk = $walk;\n    }\n\n    /**\n     * checks whether walk is a cycle (i.e. source vertex = target vertex)\n     *\n     * A cycle is also known as a closed path, a walk that is NOT a cycle is\n     * also known as an open path.\n     *\n     * A walk with no edges is not considered a cycle. The shortest possible\n     * cycle is a single loop edge:\n     *\n     * 1--\\\n     * ^  |\n     * \\--/\n     *\n     * The following Walk is also considered a valid cycle:\n     *\n     *      /->3--\\\n     *      |     |\n     * 1 -> 2 -\\  |\n     * ^    ^  |  |\n     * |    \\--/  |\n     * |          |\n     * \\----------/\n     *\n     * @return bool\n     * @link http://en.wikipedia.org/wiki/Cycle_%28graph_theory%29\n     * @see self::isCircuit()\n     * @see self::isLoop()\n     */\n    public function isCycle()\n    {\n        $vertices = $this->walk->getVertices();\n        return ($vertices->getVertexFirst() === $vertices->getVertexLast() && !$this->walk->getEdges()->isEmpty());\n    }\n\n    /**\n     * checks whether this walk is a circuit (i.e. a cycle with no duplicate edges)\n     *\n     * A circuit is also known as a closed (=cycle) trail (=path), that has at\n     * least one edge.\n     *\n     * The following Walk is considered both a valid cycle and a valid circuit:\n     *\n     * 1 -> 2 -> 3 -\\\n     * ^            |\n     * |            |\n     * \\------------/\n     *\n     * The following Walk is also considered both a valid cycle and a valid circuit:\n     *\n     *      /->3--\\\n     *      |     |\n     * 1 -> 2 -\\  |\n     * ^    ^  |  |\n     * |    \\--/  |\n     * |          |\n     * \\----------/\n     *\n     * The later circuit walk can be expressed by its Vertex IDs as\n     * \"1, 2, 2, 3, 1\". If however, the inner loop would be \"walked along\"\n     * several times, the resulting walk would be expressed as\n     * \"1, 2, 2, 2, 3, 1\", which would still be a valid cycle, but NOT a valid\n     * circuit anymore.\n     *\n     * @return bool\n     * @link http://www.proofwiki.org/wiki/Definition:Circuit\n     * @uses self::isCycle()\n     * @uses self::isPath()\n     */\n    public function isCircuit()\n    {\n        return ($this->isCycle() && $this->isPath());\n    }\n\n    /**\n     * checks whether walk is a path (i.e. does not contain any duplicate edges)\n     *\n     * A path Walk is also known as a trail.\n     *\n     * @return bool\n     * @uses self::hasArrayDuplicates()\n     * @link http://www.proofwiki.org/wiki/Definition:Trail\n     */\n    public function isPath()\n    {\n        return !$this->hasArrayDuplicates($this->walk->getEdges()->getVector());\n    }\n\n    /**\n     * checks whether walk contains a cycle (i.e. contains a duplicate vertex)\n     *\n     * A walk that CONTAINS a cycle does not neccessarily have to BE a cycle.\n     * Conversely, a Walk that *is* a cycle, automatically always *contains* a\n     * cycle.\n     *\n     * The following Walk is NOT a cycle, but it *contains* a valid cycle:\n     *\n     *      /->4\n     *      |\n     * 1 -> 2 -> 3 -\\\n     *      ^       |\n     *      \\-------/\n     *\n     * @return bool\n     * @uses self::hasArrayDuplicates()\n     * @see self::isCycle()\n     */\n    public function hasCycle()\n    {\n        return $this->hasArrayDuplicates($this->walk->getVertices()->getVector());\n    }\n\n    /**\n     * checks whether this walk IS a loop (single edge connecting vertex A with vertex A again)\n     *\n     * A loop is the simplest possible cycle. As such, each loop is also a\n     * cycle. Accordingly, every Walk that *is* a loop, automatically also *is*\n     * a cycle and automatically *contains* a loop and automatically *contains*\n     * a cycle.\n     *\n     * The following Walk represents a simple (directed) loop:\n     *\n     * 1--\\\n     * ^  |\n     * \\--/\n     *\n     * @return bool\n     * @uses self::isCycle()\n     * @see self::hasLoop()\n     */\n    public function isLoop()\n    {\n        return (\\count($this->walk->getEdges()) === 1 && $this->isCycle());\n    }\n\n    /**\n     * checks whether this walk HAS a loop (single edge connecting vertex A with vertex A again)\n     *\n     * The following Walk is NOT a valid loop, but it contains a valid loop:\n     *\n     *      /->3\n     *      |\n     * 1 -> 2 -\\\n     *      ^  |\n     *      \\--/\n     *\n     * @return bool\n     * @uses AlgorithmLoop::hasLoop()\n     * @see self::isLoop()\n     */\n    public function hasLoop()\n    {\n        $alg = new AlgorithmLoop($this->walk);\n\n        return $alg->hasLoop();\n    }\n\n    /**\n     * checks whether this walk is a digon (a pair of parallel edges in a multigraph or a pair of antiparallel edges in a digraph)\n     *\n     * A digon is a cycle connecting exactly two distinct vertices with exactly\n     * two distinct edges.\n     *\n     * The following Graph represents a digon in an undirected Graph:\n     *\n     *  /--\\\n     * 1    2\n     *  \\--/\n     *\n     * The following Graph represents a digon as a set of antiparallel directed\n     * Edges in a directed Graph:\n     *\n     * 1 -> 2\n     * ^    |\n     * |    |\n     * \\----/\n     *\n     * @return bool\n     * @uses self::hasArrayDuplicates()\n     * @uses self::isCycle()\n     */\n    public function isDigon()\n    {\n        // exactly 2 edges\n        return (\\count($this->walk->getEdges()) === 2 &&\n                // no duplicate edges\n                !$this->hasArrayDuplicates($this->walk->getEdges()->getVector()) &&\n                // exactly two distinct vertices\n                \\count($this->walk->getVertices()->getVerticesDistinct()) === 2 &&\n                // this is actually a cycle\n                $this->isCycle());\n    }\n\n    /**\n     * checks whether this walk is a triangle (a simple cycle with exactly three distinct vertices)\n     *\n     * The following Graph is a valid directed triangle:\n     *\n     * 1->2->3\n     * ^     |\n     * \\-----/\n     *\n     * @return bool\n     * @uses self::isCycle()\n     */\n    public function isTriangle()\n    {\n        // exactly 3 (implicitly distinct) edges\n        return (\\count($this->walk->getEdges()) === 3 &&\n                // exactly three distinct vertices\n                \\count($this->walk->getVertices()->getVerticesDistinct()) === 3 &&\n                // this is actually a cycle\n                $this->isCycle());\n    }\n\n    /**\n     * check whether this walk is simple\n     *\n     * contains no duplicate/repeated vertices (and thus no duplicate edges either)\n     * other than the starting and ending vertices of cycles.\n     *\n     * A simple Walk is also known as a chain.\n     *\n     * The term \"simple walk\" is somewhat related to a walk with no cycles. If\n     * a Walk has a cycle, it is not simple - with one single exception: a Walk\n     * that IS a cycle automatically also contains a cycle, but if it contains\n     * no \"further\" additional cycles, it is considered a simple cycle.\n     *\n     * The following Graph represents a (very) simple Walk:\n     *\n     * 1 -- 2\n     *\n     * The following Graph IS a cycle and is simple:\n     *\n     * 1 -> 2\n     * ^    |\n     * \\----/\n     *\n     * The following Graph contains a cycle and is NOT simple:\n     *\n     *      /->4\n     *      |\n     * 1 -> 2 -> 3 -\\\n     *      ^       |\n     *      \\-------/\n     *\n     * The following Graph IS a cycle and thus automatically contains a cycle.\n     * Due to the additional \"inner\" cycle (loop at vertex 2), it is NOT simple:\n     *\n     *      /->3--\\\n     *      |     |\n     * 1 -> 2 -\\  |\n     * ^    ^  |  |\n     * |    \\--/  |\n     * |          |\n     * \\----------/\n     *\n     * @return bool\n     * @uses self::isCycle()\n     * @uses self::hasArrayDuplicates()\n     * @see self::hasCycle()\n     */\n    public function isSimple()\n    {\n        $vertices = $this->walk->getVertices()->getVector();\n        // ignore starting vertex for cycles as it's always the same as ending vertex\n        if ($this->isCycle()) {\n            unset($vertices[0]);\n        }\n\n        return !$this->hasArrayDuplicates($vertices);\n    }\n\n    /**\n     * checks whether walk is hamiltonian (i.e. walk over ALL VERTICES of the graph)\n     *\n     * A hamiltonian Walk is also known as a spanning walk.\n     *\n     * @return bool\n     * @see self::isEulerian() if you want to check for all EDGES instead of VERTICES\n     * @uses self::isArrayContentsEqual()\n     * @link http://en.wikipedia.org/wiki/Hamiltonian_path\n     */\n    public function isHamiltonian()\n    {\n        $vertices = $this->walk->getVertices()->getVector();\n        // ignore starting vertex for cycles as it's always the same as ending vertex\n        if ($this->isCycle()) {\n            unset($vertices[0]);\n        }\n        return $this->isArrayContentsEqual($vertices, $this->walk->getGraph()->getVertices()->getVector());\n    }\n\n    /**\n     * checks whether walk is eulerian (i.e. a walk over ALL EDGES of the graph)\n     *\n     * @return bool\n     * @see self::isHamiltonian() if you want to check for all VERTICES instead of EDGES\n     * @uses self::isArrayContentsEqual()\n     * @link http://en.wikipedia.org/wiki/Eulerian_path\n     */\n    public function isEulerian()\n    {\n        return $this->isArrayContentsEqual($this->walk->getEdges()->getVector(), $this->walk->getGraph()->getEdges()->getVector());\n    }\n\n    /**\n     * checks whether ths given array contains duplicate identical entries\n     *\n     * @param  array $array\n     * @return bool\n     */\n    private function hasArrayDuplicates($array)\n    {\n        $compare = array();\n        foreach ($array as $element) {\n            // duplicate element found\n            if (\\in_array($element, $compare, true)) {\n                return true;\n            } else {\n                // add element to temporary array to check for duplicates\n                $compare [] = $element;\n            }\n        }\n\n        return false;\n    }\n\n    /**\n     * checks whether the contents of array a equals those of array b (ignore keys and order but otherwise strict check)\n     *\n     * @param  array   $a\n     * @param  array   $b\n     * @return bool\n     */\n    private function isArrayContentsEqual($a, $b)\n    {\n        foreach ($b as $one) {\n            $pos = \\array_search($one, $a, true);\n            if ($pos === false) {\n                return false;\n            } else {\n                unset($a[$pos]);\n            }\n        }\n\n        return $a ? false : true;\n    }\n}\n"
  },
  {
    "path": "src/ResidualGraph.php",
    "content": "<?php\n\nnamespace Graphp\\Algorithms;\n\nuse Graphp\\Graph\\Edge;\nuse Graphp\\Graph\\EdgeDirected;\nuse Graphp\\Graph\\Exception\\UnexpectedValueException;\nuse Graphp\\Graph\\Graph;\n\nclass ResidualGraph extends BaseGraph\n{\n    private $keepNullCapacity = false;\n    private $mergeParallelEdges = false;\n\n    public function setKeepNullCapacity($toggle)\n    {\n        $this->keepNullCapacity = !!$toggle;\n\n        return $this;\n    }\n\n    public function setMergeParallelEdges($toggle)\n    {\n        $this->mergeParallelEdges = !!$toggle;\n\n        return $this;\n    }\n\n    /**\n     * create residual graph\n     *\n     * @throws UnexpectedValueException if input graph has undirected edges or flow/capacity is not set\n     * @return Graph\n     * @uses Graph::createGraphCloneEdgeless()\n     * @uses Graph::createEdgeClone()\n     * @uses Graph::createEdgeCloneInverted()\n     */\n    public function createGraph()\n    {\n        $newgraph = $this->graph->createGraphCloneEdgeless();\n\n        foreach ($this->graph->getEdges() as $edge) {\n            if (!($edge instanceof EdgeDirected)) {\n                throw new UnexpectedValueException('Edge is undirected');\n            }\n\n            $flow = $edge->getFlow();\n            if ($flow === NULL) {\n                throw new UnexpectedValueException('Flow not set');\n            }\n\n            $capacity = $edge->getCapacity();\n            if ($capacity === NULL) {\n                throw new UnexpectedValueException('Capacity not set');\n            }\n\n            // capacity is still available, clone remaining capacity into new edge\n            if ($this->keepNullCapacity || $flow < $capacity) {\n                $newEdge = $newgraph->createEdgeClone($edge)->setFlow(0)->setCapacity($capacity - $flow);\n\n                if ($this->mergeParallelEdges) {\n                    $this->mergeParallelEdges($newEdge);\n                }\n            }\n\n            // flow is set, clone current flow as capacity for back-flow into new inverted edge (opposite direction)\n            if ($this->keepNullCapacity || $flow > 0) {\n                $newEdge = $newgraph->createEdgeCloneInverted($edge)->setFlow(0)->setCapacity($flow);\n\n                // if weight is set, use negative weight for back-edges\n                if ($newEdge->getWeight() !== NULL) {\n                    $newEdge->setWeight(-$newEdge->getWeight());\n                }\n\n                if ($this->mergeParallelEdges) {\n                    $this->mergeParallelEdges($newEdge);\n                }\n            }\n        }\n\n        return $newgraph;\n    }\n\n    /**\n     * Will merge all edges that are parallel to to given edge\n     *\n     * @param Edge $newEdge\n     */\n    private function mergeParallelEdges(Edge $newEdge)\n    {\n        $alg = new Parallel($this->graph);\n        $parallelEdges = $alg->getEdgesParallelEdge($newEdge)->getVector();\n\n        if (!$parallelEdges) {\n            return;\n        }\n\n        $mergedCapacity = 0;\n        foreach ($parallelEdges as $parallelEdge) {\n            $mergedCapacity += $parallelEdge->getCapacity();\n        }\n\n        $newEdge->setCapacity($newEdge->getCapacity() + $mergedCapacity);\n\n        foreach ($parallelEdges as $parallelEdge) {\n            $parallelEdge->destroy();\n        }\n    }\n}\n"
  },
  {
    "path": "src/Search/Base.php",
    "content": "<?php\n\nnamespace Graphp\\Algorithms\\Search;\n\nuse Graphp\\Algorithms\\BaseVertex;\nuse Graphp\\Graph\\Exception\\InvalidArgumentException;\nuse Graphp\\Graph\\Set\\Vertices;\nuse Graphp\\Graph\\Vertex;\n\nabstract class Base extends BaseVertex\n{\n    const DIRECTION_FORWARD = 0;\n    const DIRECTION_REVERSE = 1;\n    const DIRECTION_BOTH = 2;\n\n    private $direction = self::DIRECTION_FORWARD;\n\n    /**\n     * set direction in which to follow adjacent vertices\n     *\n     * @param  int             $direction\n     * @return $this (chainable)\n     * @throws InvalidArgumentException\n     * @see self::getVerticesAdjacent()\n     */\n    public function setDirection($direction)\n    {\n        if ($direction !== self::DIRECTION_FORWARD && $direction !== self::DIRECTION_REVERSE && $direction !== self::DIRECTION_BOTH) {\n            throw new InvalidArgumentException('Invalid direction given');\n        }\n        $this->direction = $direction;\n\n        return $this;\n    }\n\n    protected function getVerticesAdjacent(Vertex $vertex)\n    {\n        if ($this->direction === self::DIRECTION_FORWARD) {\n            return $vertex->getVerticesEdgeTo();\n        } elseif ($this->direction === self::DIRECTION_REVERSE) {\n            return $vertex->getVerticesEdgeFrom();\n        } else {\n            return $vertex->getVerticesEdge();\n        }\n    }\n\n    /**\n     * get set of all Vertices that can be reached from start vertex\n     *\n     * @return Vertices\n     */\n    abstract public function getVertices();\n}\n"
  },
  {
    "path": "src/Search/BreadthFirst.php",
    "content": "<?php\n\nnamespace Graphp\\Algorithms\\Search;\n\nuse Graphp\\Graph\\Set\\Vertices;\n\nclass BreadthFirst extends Base\n{\n    /**\n     * @param int $maxDepth\n     * @return Vertices\n     */\n    public function getVertices($maxDepth = PHP_INT_MAX)\n    {\n        $queue = array($this->vertex);\n        // to not add vertices twice in array visited\n        $mark = array($this->vertex->getId() => true);\n        // visited vertices\n        $visited = array();\n\n        // keep track of depth\n        $currentDepth = 0;\n        $nodesThisLevel = 1;\n        $nodesNextLevel = 0;\n\n        do {\n            // get first from queue\n            $t = \\array_shift($queue);\n            // save as visited\n            $visited[$t->getId()] = $t;\n\n            // get next vertices\n            $children = $this->getVerticesAdjacent($t);\n\n            // track depth\n            $nodesNextLevel = $children->count();\n            if (--$nodesThisLevel === 0) {\n                if (++$currentDepth > $maxDepth) {\n                    return new Vertices($visited);\n                }\n                $nodesThisLevel = $nodesNextLevel;\n                $nodesNextLevel = 0;\n            }\n\n            // process next vertices\n            foreach ($children->getMap() as $id => $vertex) {\n                // if not \"touched\" before\n                if (!isset($mark[$id])) {\n                    // add to queue\n                    $queue[] = $vertex;\n                    // and mark\n                    $mark[$id] = true;\n                }\n            }\n\n            // until queue is empty\n        } while ($queue);\n\n        return new Vertices($visited);\n    }\n}\n"
  },
  {
    "path": "src/Search/DepthFirst.php",
    "content": "<?php\n\nnamespace Graphp\\Algorithms\\Search;\n\nuse Graphp\\Graph\\Set\\Vertices;\n\nclass DepthFirst extends Base\n{\n    /**\n     * calculates an iterative depth-first search\n     *\n     * @return Vertices\n     */\n    public function getVertices()\n    {\n        $visited = array();\n        $todo = array($this->vertex);\n        while ($vertex = \\array_shift($todo)) {\n            if (!isset($visited[$vertex->getId()])) {\n                $visited[$vertex->getId()] = $vertex;\n\n                foreach (\\array_reverse($this->getVerticesAdjacent($vertex)->getMap(), true) as $nextVertex) {\n                    $todo[] = $nextVertex;\n                }\n            }\n        }\n\n        return new Vertices($visited);\n    }\n}\n"
  },
  {
    "path": "src/ShortestPath/Base.php",
    "content": "<?php\n\nnamespace Graphp\\Algorithms\\ShortestPath;\n\nuse Graphp\\Algorithms\\BaseVertex;\nuse Graphp\\Graph\\Edge;\nuse Graphp\\Graph\\Exception\\InvalidArgumentException;\nuse Graphp\\Graph\\Exception\\OutOfBoundsException;\nuse Graphp\\Graph\\Graph;\nuse Graphp\\Graph\\Set\\Edges;\nuse Graphp\\Graph\\Set\\Vertices;\nuse Graphp\\Graph\\Vertex;\nuse Graphp\\Graph\\Walk;\n\n/**\n * Abstract base class for shortest path algorithms\n *\n * This abstract base class provides the base interface for working with\n * single-source shortest paths (SSSP).\n *\n * The shortest path problem is the problem of finding a path between two\n * vertices such that the sum of the weights of its constituent edges is\n * minimized. The weight of the shortest path is referred to as distance.\n *\n *    A--[10]-------------B---E<--F\n *     \\                 /\n *      \\--[4]--C--[2]--D\n *\n * In the above pictured graph, the distance (weight of the shortest path)\n * between A and C is 4, and the shortest path between A and B is \"A->C->D->B\"\n * with a distance (total weight) of 6.\n *\n * In graph theory, it is usually assumed that a path to an unreachable vertex\n * has infinite distance. In the above pictured graph, there's no way path\n * from A to F, i.e. vertex F is unreachable from vertex A because of the\n * directed edge \"E <- F\" pointing in the opposite direction. This library\n * considers this an Exception instead. So if you're asking for the distance\n * between A and F, you'll receive an OutOfBoundsException instead.\n *\n * In graph theory, it is usually assumed that each vertex has a (pseudo-)path\n * to itself with a distance of 0. In order to produce reliable, consistent\n * results, this library considers this (pseudo-)path to be non-existant, i.e.\n * there's NO \"magic\" path between A and A. So if you're asking for the distance\n * between A and A, you'll receive an OutOfBoundsException instead. This allows\n * us to check hether there's a real path between A and A (cycle via other\n * vertices) as well as working with loop edges.\n *\n * @link http://en.wikipedia.org/wiki/Shortest_path_problem\n * @link http://en.wikipedia.org/wiki/Tree_%28data_structure%29\n * @see ShortestPath\\Dijkstra\n * @see ShortestPath\\MooreBellmanFord which also supports negative Edge weights\n * @see ShortestPath\\BreadthFirst with does not consider Edge weights, but only the number of hops\n */\nabstract class Base extends BaseVertex\n{\n    /**\n     * get walk (path) from start vertex to given end vertex\n     *\n     * @param  Vertex    $endVertex\n     * @return Walk\n     * @throws OutOfBoundsException if there's no path to the given end vertex\n     * @uses self::getEdgesTo()\n     * @uses Walk::factoryFromEdges()\n     */\n    public function getWalkTo(Vertex $endVertex)\n    {\n        return Walk::factoryFromEdges($this->getEdgesTo($endVertex), $this->vertex);\n    }\n\n    /**\n     * get array of edges (path) from start vertex to given end vertex\n     *\n     * @param  Vertex    $endVertex\n     * @throws OutOfBoundsException if there's no path to the given end vertex\n     * @return Edges\n     * @uses self::getEdges()\n     * @uses self::getEdgesToInternal()\n     */\n    public function getEdgesTo(Vertex $endVertex)\n    {\n        return $this->getEdgesToInternal($endVertex, $this->getEdges());\n    }\n\n    /**\n     * get array of edges (path) from start vertex to given end vertex\n     *\n     * @param  Vertex       $endVertex\n     * @param  Edges|Edge[] $edges     set or array of all input edges to operate on\n     * @throws OutOfBoundsException if there's no path to the given vertex\n     * @return Edges\n     * @uses self::getEdges() if no edges were given\n     */\n    protected function getEdgesToInternal(Vertex $endVertex, $edges)\n    {\n        $currentVertex = $endVertex;\n        $path = array();\n        do {\n            $pre = NULL;\n            // check all edges to search for edge that points TO current vertex\n            foreach ($edges as $edge) {\n                try {\n                    // get start point of this edge (fails if current vertex is not its end point)\n                    $pre = $edge->getVertexFromTo($currentVertex);\n                    $path[] = $edge;\n                    $currentVertex = $pre;\n                    break;\n                } catch (InvalidArgumentException $ignore) {\n                } // ignore: this edge does not point TO current vertex\n            }\n            if ($pre === NULL) {\n                throw new OutOfBoundsException('No edge leading to vertex');\n            }\n        } while ($currentVertex !== $this->vertex);\n\n        return new Edges(\\array_reverse($path));\n    }\n\n    /**\n     * get sum of weight of given edges\n     *\n     * @param  Edges $edges\n     * @return float\n     * @uses Edge::getWeight()\n     */\n    private function sumEdges(Edges $edges)\n    {\n        $sum = 0;\n        foreach ($edges as $edge) {\n            $sum += $edge->getWeight();\n        }\n\n        return $sum;\n    }\n\n    /**\n     * get set of all Vertices the given start vertex has a path to\n     *\n     * @return Vertices\n     * @uses self::getDistanceMap()\n     */\n    public function getVertices()\n    {\n        $vertices = array();\n        $map = $this->getDistanceMap();\n        foreach ($this->vertex->getGraph()->getVertices()->getMap() as $vid => $vertex) {\n            if (isset($map[$vid])) {\n                $vertices[$vid] = $vertex;\n            }\n        }\n\n        return new Vertices($vertices);\n    }\n\n    /**\n     * checks whether there's a path from this start vertex to given end vertex\n     *\n     * @param  Vertex  $vertex\n     * @return bool\n     * @uses self::getEdgesTo()\n     */\n    public function hasVertex(Vertex $vertex)\n    {\n        try {\n            $this->getEdgesTo($vertex);\n        } catch (OutOfBoundsException $e) {\n            return false;\n        }\n        return true;\n    }\n\n    /**\n     * get map of vertex IDs to distance\n     *\n     * @return float[]\n     * @uses self::getEdges()\n     * @uses self::getEdgesToInternal()\n     * @uses self::sumEdges()\n     */\n    public function getDistanceMap()\n    {\n        $edges = $this->getEdges();\n        $ret = array();\n        foreach ($this->vertex->getGraph()->getVertices()->getMap() as $vid => $vertex) {\n            try {\n                $ret[$vid] = $this->sumEdges($this->getEdgesToInternal($vertex, $edges));\n            } catch (OutOfBoundsException $ignore) {\n            } // ignore vertices that can not be reached\n        }\n\n        return $ret;\n    }\n\n    /**\n     * get distance (sum of weights) between start vertex and given end vertex\n     *\n     * @param  Vertex    $endVertex\n     * @return float\n     * @throws OutOfBoundsException if there's no path to the given end vertex\n     * @uses self::getEdgesTo()\n     * @uses self::sumEdges()\n     */\n    public function getDistance(Vertex $endVertex)\n    {\n        return $this->sumEdges($this->getEdgesTo($endVertex));\n    }\n\n    /**\n     * create new resulting graph with only edges on shortest path\n     *\n     * The resulting Graph will always represent a tree with the start vertex\n     * being the root vertex.\n     *\n     * For example considering the following input Graph with equal weights on\n     * each edge:\n     *\n     *     A----->F\n     *    / \\     ^\n     *   /   \\   /\n     *  /     \\ /\n     *  |      E\n     *  |       \\\n     *  |        \\\n     *  B--->C<---D\n     *\n     * The resulting shortest path tree Graph will look like this:\n     *\n     *     A----->F\n     *    / \\\n     *   /   \\\n     *  /     \\\n     *  |      E\n     *  |       \\\n     *  |        \\\n     *  B--->C    D\n     *\n     * Or by just arranging the Vertices slightly different:\n     *\n     *          A\n     *         /|\\\n     *        / | \\\n     *       B  E  \\->F\n     *      /   |\n     *  C<-/    D\n     *\n     * @return Graph\n     * @uses self::getEdges()\n     * @uses Graph::createGraphCloneEdges()\n     */\n    public function createGraph()\n    {\n        return $this->vertex->getGraph()->createGraphCloneEdges($this->getEdges());\n    }\n\n    /**\n     * get cheapest edges (lowest weight) for given map of vertex predecessors\n     *\n     * @param  Vertex[] $predecessor\n     * @return Edges\n     * @uses Graph::getVertices()\n     * @uses Vertex::getEdgesTo()\n     * @uses Edges::getEdgeOrder()\n     */\n    protected function getEdgesCheapestPredecesor(array $predecessor)\n    {\n        $vertices = $this->vertex->getGraph()->getVertices()->getMap();\n\n        $edges = array();\n        foreach ($vertices as $vid => $vertex) {\n            if (isset($predecessor[$vid])) {\n                // get predecor\n                $predecesVertex = $predecessor[$vid];\n\n                // get cheapest edge\n                $edges[] = $predecesVertex->getEdgesTo($vertex)->getEdgeOrder(Edges::ORDER_WEIGHT);\n            }\n        }\n\n        return new Edges($edges);\n    }\n\n    /**\n     * get all edges on shortest path for this vertex\n     *\n     * @return Edges\n     */\n    abstract public function getEdges();\n}\n"
  },
  {
    "path": "src/ShortestPath/BreadthFirst.php",
    "content": "<?php\n\nnamespace Graphp\\Algorithms\\ShortestPath;\n\nuse Graphp\\Graph\\Vertex;\nuse Graphp\\Graph\\Exception\\OutOfBoundsException;\nuse Graphp\\Graph\\Set\\Edges;\nuse Graphp\\Graph\\Set\\Vertices;\n\n/**\n * Simple breadth-first shortest path algorithm\n *\n * This algorithm ignores edge weights and operates as a level-order algorithm\n * on the number of hops. As such, it considers the path with the least number\n * of hops to be shortest.\n *\n * This is particularly useful your Graph doesn't have Edge weights assigned to\n * begin with or if you're merely interested in knowing which Vertices can be\n * reached at all (path finding). This avoids running expensive operations to\n * determine the actual weight (distance) of a path.\n */\nclass BreadthFirst extends Base\n{\n    /**\n     * get distance between start vertex and given end vertex\n     *\n     * @param  Vertex               $endVertex\n     * @throws OutOfBoundsException if there's no path to given end vertex\n     * @return float\n     * @uses self::getEdgesTo()\n     */\n    public function getDistance(Vertex $endVertex)\n    {\n        return (float)\\count($this->getEdgesTo($endVertex));\n    }\n\n    /**\n     * get array of edges on the walk for each vertex (vertex ID => array of walk edges)\n     *\n     * @return array[]\n     */\n    public function getEdgesMap()\n    {\n        $vertexQueue = array();\n        $edges = array();\n\n        // $edges[$this->vertex->getId()] = array();\n\n        $vertexCurrent = $this->vertex;\n        $edgesCurrent = array();\n\n        do {\n            foreach ($vertexCurrent->getEdgesOut() as $edge) {\n                $vertexTarget = $edge->getVertexToFrom($vertexCurrent);\n                $vid = $vertexTarget->getId();\n                if (!isset($edges[$vid])) {\n                    $vertexQueue[] = $vertexTarget;\n                    $edges[$vid] = \\array_merge($edgesCurrent, array($edge));\n                }\n            }\n\n            // get next from queue\n            $vertexCurrent = \\array_shift($vertexQueue);\n            if ($vertexCurrent) {\n                $edgesCurrent = $edges[$vertexCurrent->getId()];\n            }\n        // untill queue is empty\n        } while ($vertexCurrent);\n\n        return $edges;\n    }\n\n    public function getEdgesTo(Vertex $endVertex)\n    {\n        if ($endVertex->getGraph() === $this->vertex->getGraph()) {\n            $map = $this->getEdgesMap();\n\n            if (isset($map[$endVertex->getId()])) {\n                return new Edges($map[$endVertex->getId()]);\n            }\n        }\n        throw new OutOfBoundsException('Given target vertex can not be reached from start vertex');\n    }\n\n    /**\n     * get map of vertex IDs to distance\n     *\n     * @return float[]\n     * @uses Vertex::hasLoop()\n     */\n    public function getDistanceMap()\n    {\n        $ret = array();\n        foreach ($this->getEdgesMap() as $vid => $edges) {\n            $ret[$vid] = (float)\\count($edges);\n        }\n\n        return $ret;\n    }\n\n    /**\n     * get array of all target vertices this vertex has a path to\n     *\n     * @return Vertices\n     * @uses self::getEdgesMap()\n     */\n    public function getVertices()\n    {\n        $ret = array();\n        $graph = $this->vertex->getGraph();\n        foreach (\\array_keys($this->getEdgesMap()) as $vid) {\n            $ret[$vid] = $graph->getVertex($vid);\n        }\n\n        return new Vertices($ret);\n    }\n\n    public function getEdges()\n    {\n        $ret = array();\n        foreach ($this->getEdgesMap() as $edges) {\n            foreach ($edges as $edge) {\n                if (!\\in_array($edge, $ret, true)) {\n                    $ret[] = $edge;\n                }\n            }\n        }\n\n        return new Edges($ret);\n    }\n}\n"
  },
  {
    "path": "src/ShortestPath/Dijkstra.php",
    "content": "<?php\n\nnamespace Graphp\\Algorithms\\ShortestPath;\n\nuse Graphp\\Graph\\Exception\\UnexpectedValueException;\nuse Graphp\\Graph\\Set\\Edges;\nuse SplPriorityQueue;\n\n/**\n * Commonly used Dijkstra's shortest path algorithm\n *\n * This is asymptotically the fastest known single-source shortest-path\n * algorithm for arbitrary graphs with non-negative weights. If your Graph\n * contains an Edge with negative weight, if will throw an\n * UnexpectedValueException. Consider using (the slower) MooreBellmanFord\n * algorithm instead.\n *\n * @link http://en.wikipedia.org/wiki/Dijkstra%27s_algorithm\n * @see MooreBellmanFord\n */\nclass Dijkstra extends Base\n{\n    /**\n     * get all edges on shortest path for this vertex\n     *\n     * @return Edges\n     * @throws UnexpectedValueException when encountering an Edge with negative weight\n     */\n    public function getEdges()\n    {\n        $totalCostOfCheapestPathTo  = Array();\n        // start node distance\n        $totalCostOfCheapestPathTo[$this->vertex->getId()] = INF;\n\n        // just to get the cheapest vertex in the correct order\n        $cheapestVertex = new SplPriorityQueue();\n        $cheapestVertex->insert($this->vertex, 0);\n\n        // predecessor\n        $predecesVertexOfCheapestPathTo  = Array();\n        $predecesVertexOfCheapestPathTo[$this->vertex->getId()] = $this->vertex;\n\n        // mark vertices when their cheapest path has been found\n        $usedVertices  = Array();\n\n        $isFirst = true;\n\n        // Repeat until all vertices have been marked\n        $totalCountOfVertices = \\count($this->vertex->getGraph()->getVertices());\n        for ($i = 0; $i < $totalCountOfVertices; ++$i) {\n            $currentVertex = NULL;\n            $currentVertexId = NULL;\n            $isEmpty = false;\n            do {\n                // if the priority queue is empty there are isolated vertices, but the algorithm visited all other vertices\n                if ($cheapestVertex->isEmpty()) {\n                    $isEmpty = true;\n                    break;\n                }\n                // Get cheapest unmarked vertex\n                $currentVertex = $cheapestVertex->extract();\n                $currentVertexId = $currentVertex->getId();\n            // Vertices can be in the priority queue multiple times, with different path costs (if vertex is already marked, this is an old unvalid entry)\n            } while (isset($usedVertices[$currentVertexId]));\n\n            // catch \"algorithm ends\" condition\n            if ($isEmpty) {\n                break;\n            }\n\n            if ($isFirst) {\n                $isFirst = false;\n            } else {\n                // mark this vertex\n                $usedVertices[$currentVertexId] = true;\n            }\n\n            // check for all edges of current vertex if there is a cheaper path (or IN OTHER WORDS: Add reachable nodes from currently added node and refresh the current possible distances)\n            foreach ($currentVertex->getEdgesOut() as $edge) {\n                $weight = $edge->getWeight();\n                if ($weight < 0) {\n                    throw new UnexpectedValueException('Djkstra not supported for negative weights - Consider using MooreBellmanFord');\n                }\n\n                $targetVertex = $edge->getVertexToFrom($currentVertex);\n                $targetVertexId = $targetVertex->getId();\n\n                // if the targetVertex is marked, the cheapest path for this vertex has already been found (no negative edges) {\n                if (!isset($usedVertices[$targetVertexId])) {\n                    // calculate new cost to vertex\n                    $newCostsToTargetVertex = $totalCostOfCheapestPathTo[$currentVertexId] + $weight;\n                    if (\\is_infinite($newCostsToTargetVertex)) {\n                        $newCostsToTargetVertex = $weight;\n                    }\n\n                    if ((!isset($predecesVertexOfCheapestPathTo[$targetVertexId]))\n                           // is the new path cheaper?\n                           || $totalCostOfCheapestPathTo[$targetVertexId] > $newCostsToTargetVertex){\n\n                        // Not an update, just an new insert with lower cost\n                        $cheapestVertex->insert($targetVertex, - $newCostsToTargetVertex);\n                                                                                                    // so the lowest cost will be extraced first\n                                                                                                    // and higher cost will be skipped during extraction\n\n                        // update/set costs found with the new connection\n                        $totalCostOfCheapestPathTo[$targetVertexId] = $newCostsToTargetVertex;\n                        // update/set predecessor vertex from the new connection\n                        $predecesVertexOfCheapestPathTo[$targetVertexId] = $currentVertex;\n                    }\n                }\n            }\n        }\n\n        if ($totalCostOfCheapestPathTo[$this->vertex->getId()] === INF) {\n            unset($predecesVertexOfCheapestPathTo[$this->vertex->getId()]);\n        }\n\n        // algorithm is done, return resulting edges\n        return $this->getEdgesCheapestPredecesor($predecesVertexOfCheapestPathTo);\n    }\n}\n"
  },
  {
    "path": "src/ShortestPath/MooreBellmanFord.php",
    "content": "<?php\n\nnamespace Graphp\\Algorithms\\ShortestPath;\n\nuse Graphp\\Graph\\Exception\\NegativeCycleException;\nuse Graphp\\Graph\\Exception\\UnderflowException;\nuse Graphp\\Graph\\Set\\Edges;\nuse Graphp\\Graph\\Vertex;\nuse Graphp\\Graph\\Walk;\n\n/**\n * Moore-Bellman-Ford's shortest path algorithm\n *\n * It is slower than Dijkstra's algorithm for the same problem, but more\n * versatile, as it is capable of handling Graphs with negative Edge weights.\n *\n * Also known as just \"Bellman–Ford algorithm\".\n *\n * @link http://en.wikipedia.org/wiki/Bellman%E2%80%93Ford_algorithm\n */\nclass MooreBellmanFord extends Base\n{\n    /**\n     * @param Edges    $edges\n     * @param int[]    $totalCostOfCheapestPathTo\n     * @param Vertex[] $predecessorVertexOfCheapestPathTo\n     * @return Vertex|NULL\n     */\n    private function bigStep(Edges $edges, array &$totalCostOfCheapestPathTo, array &$predecessorVertexOfCheapestPathTo)\n    {\n        $changed = NULL;\n        // check for all edges\n        foreach ($edges as $edge) {\n            // check for all \"ends\" of this edge (or for all targetes)\n            foreach ($edge->getVerticesTarget() as $toVertex) {\n                $fromVertex = $edge->getVertexFromTo($toVertex);\n\n                // If the fromVertex already has a path\n                if (isset($totalCostOfCheapestPathTo[$fromVertex->getId()])) {\n                    // New possible costs of this path\n                    $newCost = $totalCostOfCheapestPathTo[$fromVertex->getId()] + $edge->getWeight();\n                    if (\\is_infinite($newCost)) {\n                        $newCost = $edge->getWeight() + 0;\n                    }\n\n                    // No path has been found yet\n                    if (!isset($totalCostOfCheapestPathTo[$toVertex->getId()])\n                            // OR this path is cheaper than the old path\n                            || $totalCostOfCheapestPathTo[$toVertex->getId()] > $newCost){\n\n                        $changed = $toVertex;\n                        $totalCostOfCheapestPathTo[$toVertex->getId()] = $newCost;\n                        $predecessorVertexOfCheapestPathTo[$toVertex->getId()] = $fromVertex;\n                    }\n                }\n            }\n        }\n\n        return $changed;\n    }\n\n    /**\n     * Calculate the Moore-Bellman-Ford-Algorithm and get all edges on shortest path for this vertex\n     *\n     * @return Edges\n     * @throws NegativeCycleException if there is a negative cycle\n     */\n    public function getEdges()\n    {\n        // start node distance, add placeholder weight\n        $totalCostOfCheapestPathTo  = array($this->vertex->getId() => INF);\n\n        // predecessor\n        $predecessorVertexOfCheapestPathTo  = array($this->vertex->getId() => $this->vertex);\n\n        // the usal algorithm says we repeat (n-1) times.\n        // but because we also want to check for loop edges on the start vertex,\n        // we have to add an additional step:\n        $numSteps = \\count($this->vertex->getGraph()->getVertices());\n        $edges = $this->vertex->getGraph()->getEdges();\n        $changed = true;\n\n        for ($i = 0; $i < $numSteps && $changed; ++$i) {\n            $changed = $this->bigStep($edges, $totalCostOfCheapestPathTo, $predecessorVertexOfCheapestPathTo);\n        }\n\n        // no cheaper edge to start vertex found => remove placeholder weight\n        if ($totalCostOfCheapestPathTo[$this->vertex->getId()] === INF) {\n            unset($predecessorVertexOfCheapestPathTo[$this->vertex->getId()]);\n        }\n\n        // algorithm is done, build graph\n        $returnEdges = $this->getEdgesCheapestPredecesor($predecessorVertexOfCheapestPathTo);\n\n        // Check for negative cycles (only if last step didn't already finish anyway)\n        // something is still changing...\n        if ($changed && $changed = $this->bigStep($edges, $totalCostOfCheapestPathTo, $predecessorVertexOfCheapestPathTo)) {\n            $cycle = Walk::factoryCycleFromPredecessorMap($predecessorVertexOfCheapestPathTo, $changed, Edges::ORDER_WEIGHT);\n            throw new NegativeCycleException('Negative cycle found', 0, NULL, $cycle);\n        }\n\n        return $returnEdges;\n    }\n\n    /**\n     * get negative cycle\n     *\n     * @return Walk\n     * @throws UnderflowException if there's no negative cycle\n     */\n    public function getCycleNegative()\n    {\n        try {\n            $this->getEdges();\n        } catch (NegativeCycleException $e) {\n            return $e->getCycle();\n        }\n        throw new UnderflowException('No cycle found');\n    }\n}\n"
  },
  {
    "path": "src/Symmetric.php",
    "content": "<?php\n\nnamespace Graphp\\Algorithms;\n\nuse Graphp\\Graph\\EdgeDirected;\n\n/**\n * Basic algorithms for working with symmetric digraphs\n *\n * A directed graph is called symmetric if, for every arc that belongs to it,\n * the corresponding reversed arc (antiparallel directed edge) also belongs to it.\n *\n * @link http://en.wikipedia.org/wiki/Directed_graph#Classes_of_digraphs\n */\nclass Symmetric extends BaseGraph\n{\n    /**\n     * checks whether this graph is symmetric (for every edge a->b there's also an edge b->a)\n     *\n     * @return bool\n     * @uses Graph::getEdges()\n     * @uses EdgeDirected::getVertexStart()\n     * @uses EdgeDirected::getVertedEnd()\n     * @uses Vertex::hasEdgeTo()\n     */\n    public function isSymmetric()\n    {\n        // check all edges\n        foreach ($this->graph->getEdges() as $edge) {\n            // only check directed edges (undirected ones are symmetric by definition)\n            if ($edge instanceof EdgeDirected) {\n                // check if end also has an edge to start\n                if (!$edge->getVertexEnd()->hasEdgeTo($edge->getVertexStart())) {\n                    return false;\n                }\n            }\n        }\n\n        return true;\n    }\n}\n"
  },
  {
    "path": "src/TopologicalSort.php",
    "content": "<?php\n\nnamespace Graphp\\Algorithms;\n\nuse Graphp\\Graph\\Exception\\UnexpectedValueException;\nuse Graphp\\Graph\\Set\\Vertices;\nuse Graphp\\Graph\\Vertex;\n\n/**\n * topological sorting / order, also known as toposort / topsort, commonly used in resolving dependencies\n *\n * @author clue\n * @link http://en.wikipedia.org/wiki/Topological_sorting\n */\nclass TopologicalSort extends BaseGraph\n{\n    /**\n     * run algorithm and return an ordered/sorted set of Vertices\n     *\n     * the topological sorting may be non-unique depending on your edges\n     *\n     * @return Vertices\n     */\n    public function getVertices()\n    {\n        $stack = array(); // visited nodes with unvisited children\n        $visited = array();\n        $output = array();\n\n        // TODO: avoid having to reverse all vertices multiple times\n        // pick a node to examine next - assume there are isolated nodes\n        foreach (\\array_reverse($this->graph->getVertices()->getVector()) as $top) {\n            assert($top instanceof Vertex);\n            $tid = $top->getId();\n            if (!isset($visited[$tid])) { // don't examine if already found\n                \\array_push($stack, $top);\n            }\n\n            while ($stack) {\n                $node = \\end($stack);\n                assert($node instanceof Vertex);\n                $nid = $node->getId();\n\n                $visited[$nid] = false; // temporary mark\n                $found = false; // new children found during visit to this node\n\n                // find the next node to visit\n                foreach (\\array_reverse($node->getVerticesEdgeTo()->getVector()) as $child) {\n                    assert($child instanceof Vertex);\n                    $cid = $child->getId();\n                    if (!isset($visited[$cid])) {\n                        // found a new node - push it onto the stack\n                        \\array_push($stack, $child);\n                        $found = true; // move onto the new node\n                        break;\n                    } else if ($visited[$cid] === false) {\n                        // temporary mark => not a DAG\n                        throw new UnexpectedValueException('Not a DAG');\n                    }\n                }\n\n                if (!$found) {\n                    \\array_pop($stack); // no new children found - we're done with this node\n                    $visited[$nid] = true; // mark as visited\n                    \\array_push($output, $node); // add to results\n                }\n            }\n        }\n\n        return new Vertices(\\array_reverse($output, true));\n    }\n}\n"
  },
  {
    "path": "src/TransposeGraph.php",
    "content": "<?php\n\nnamespace Graphp\\Algorithms;\n\nuse Graphp\\Graph\\EdgeDirected;\nuse Graphp\\Graph\\Exception\\UnexpectedValueException;\nuse Graphp\\Graph\\Graph;\n\nclass TransposeGraph extends BaseGraph\n{\n    /**\n     * create transpose graph\n     *\n     * @throws UnexpectedValueException if input graph has undirected edges\n     * @return Graph\n     * @uses Graph::createGraphCloneEdgeless()\n     * @uses Graph::createEdgeClone()\n     * @uses Graph::createEdgeCloneInverted()\n     */\n    public function createGraph()\n    {\n        $newgraph = $this->graph->createGraphCloneEdgeless();\n\n        foreach ($this->graph->getEdges() as $edge) {\n            if (!($edge instanceof EdgeDirected)) {\n                throw new UnexpectedValueException('Edge is undirected');\n            }\n            $newgraph->createEdgeCloneInverted($edge);\n        }\n\n        return $newgraph;\n    }\n}\n"
  },
  {
    "path": "src/TravelingSalesmanProblem/Base.php",
    "content": "<?php\n\nnamespace Graphp\\Algorithms\\TravelingSalesmanProblem;\n\nuse Graphp\\Algorithms\\Base as AlgorithmBase;\nuse Graphp\\Graph\\Graph;\nuse Graphp\\Graph\\Set\\Edges;\nuse Graphp\\Graph\\Vertex;\nuse Graphp\\Graph\\Walk;\n\nabstract class Base extends AlgorithmBase\n{\n    /**\n     * get resulting graph with the (first) best circle of edges connecting all vertices\n     *\n     * @throws \\Exception on error\n     * @return Graph\n     * @uses self::getGraph()\n     * @uses self::getEdges()\n     * @uses Graph::createGraphCloneEdges()\n     */\n    public function createGraph()\n    {\n        return $this->getGraph()->createGraphCloneEdges($this->getEdges());\n    }\n\n    /**\n     * get graph this algorithm operates on\n     *\n     * @return Graph\n     */\n    abstract protected function getGraph();\n\n    /**\n     * get start vertex this algorithm starts on\n     *\n     * @return Vertex\n     */\n    abstract protected function getVertexStart();\n\n    /**\n     * get (first) best circle connecting all vertices\n     *\n     * @return Walk\n     * @uses self::getEdges()\n     * @uses self::getVertexStart()\n     * @uses Walk::factoryCycleFromEdges()\n     */\n    public function getCycle()\n    {\n        return Walk::factoryCycleFromEdges($this->getEdges(), $this->getVertexStart());\n    }\n\n    public function getWeight()\n    {\n        $weight = 0;\n        foreach ($this->getEdges() as $edge) {\n            $weight += $edge->getWeight();\n        }\n\n        return $weight;\n    }\n\n    /**\n     * get array of edges connecting all vertices in a circle\n     *\n     * @return Edges\n     */\n    abstract public function getEdges();\n}\n"
  },
  {
    "path": "src/TravelingSalesmanProblem/Bruteforce.php",
    "content": "<?php\n\nnamespace Graphp\\Algorithms\\TravelingSalesmanProblem;\n\nuse Graphp\\Algorithms\\TravelingSalesmanProblem\\MinimumSpanningTree as AlgorithmTspMst;\nuse Graphp\\Graph\\Edge;\nuse Graphp\\Graph\\Exception\\UnexpectedValueException;\nuse Graphp\\Graph\\Exception\\UnderflowException;\nuse Graphp\\Graph\\Graph;\nuse Graphp\\Graph\\Set\\Edges;\nuse Graphp\\Graph\\Vertex;\n\nclass Bruteforce extends Base\n{\n    /**\n     *\n     * @var Graph\n     */\n    private $graph;\n\n    /**\n     * best weight so for (used for branch-and-bound)\n     *\n     * @var number|NULL\n     */\n    private $bestWeight;\n\n    /**\n     * reference to start vertex\n     *\n     * @var Vertex\n     */\n    private $startVertex;\n\n    /**\n     * total number of edges needed\n     *\n     * @var int\n     */\n    private $numEdges;\n\n    /**\n     * upper limit to use for branch-and-bound (BNB)\n     *\n     * @var float|NULL\n     * @see self::setUpperLimit()\n     */\n    private $upperLimit = NULL;\n\n    /**\n     * whether to use branch-and-bound\n     *\n     * simply put, there's no valid reason why anybody would want to turn off this flag\n     *\n     * @var bool\n     */\n    private $branchAndBound = true;\n\n    /**\n     *\n     * @param Graph $graph\n     */\n    public function __construct(Graph $graph)\n    {\n        $this->graph = $graph;\n    }\n\n    /**\n     * explicitly set upper limit to use for branch-and-bound\n     *\n     * this method can be used to optimize the algorithm by providing an upper\n     * bound of when to stop branching any further.\n     *\n     * @param  float $limit\n     * @return self  $this (chainable)\n     */\n    public function setUpperLimit($limit)\n    {\n        $this->upperLimit = $limit;\n\n        return $this;\n    }\n\n    /**\n     * automatically sets upper limit to use for branch-and-bound from the MST heuristic\n     *\n     * @return self $this (chainable)\n     * @uses AlgorithmTspMst\n     */\n    public function setUpperLimitMst()\n    {\n        $alg = new AlgorithmTspMst($this->graph);\n        $this->upperLimit = $alg->getWeight();\n\n        return $this;\n    }\n\n    protected function getVertexStart()\n    {\n        // actual start doesn't really matter as we're only considering complete graphs here\n        return $this->graph->getVertices()->getVertexFirst();\n    }\n\n    protected function getGraph()\n    {\n        return $this->graph;\n    }\n\n    /**\n     * get resulting (first) best circle of edges connecting all vertices\n     *\n     * @throws \\Exception on error\n     * @return Edges\n     */\n    public function getEdges()\n    {\n        $this->numEdges = \\count($this->graph->getVertices());\n        if ($this->numEdges < 3) {\n            throw new UnderflowException('Needs at least 3 vertices');\n        }\n\n        // numEdges 3-12 should work\n\n        $this->bestWeight = $this->upperLimit;\n        $this->startVertex = $this->getVertexStart();\n\n        $result = $this->step($this->startVertex,\n                              0,\n                              array(),\n                              array()\n                  );\n\n        if ($result === NULL) {\n            throw new UnexpectedValueException('No resulting solution for TSP found');\n        }\n\n        return new Edges($result);\n    }\n\n    /**\n     *\n     * @param  Vertex    $vertex          current point-of-view\n     * @param  number    $totalWeight     total weight (so far)\n     * @param  bool[] $visitedVertices\n     * @param  Edge[]    $visitedEdges\n     * @return Edge[]|null\n     */\n    private function step(Vertex $vertex, $totalWeight, array $visitedVertices, array $visitedEdges)\n    {\n        // stop recursion if best result is exceeded (branch and bound)\n        if ($this->branchAndBound && $this->bestWeight !== NULL && $totalWeight >= $this->bestWeight) {\n            return NULL;\n        }\n        // kreis geschlossen am Ende\n        if ($vertex === $this->startVertex && \\count($visitedEdges) === $this->numEdges) {\n            // new best result\n            $this->bestWeight = $totalWeight;\n\n            return $visitedEdges;\n        }\n\n        // only visit each vertex once\n        if (isset($visitedVertices[$vertex->getId()])) {\n            return NULL;\n        }\n        $visitedVertices[$vertex->getId()] = true;\n\n        $bestResult = NULL;\n\n        // weiter verzweigen in alle vertices\n        foreach ($vertex->getEdgesOut() as $edge) {\n            // get target vertex of this edge\n            $target = $edge->getVertexToFrom($vertex);\n\n            $weight = $edge->getWeight();\n            if ($weight < 0) {\n                throw new UnexpectedValueException('Edge with negative weight \"' . $weight . '\" not supported');\n            }\n\n            $result = $this->step($target,\n                                  $totalWeight + $weight,\n                                  $visitedVertices,\n                                  \\array_merge($visitedEdges, array($edge))\n                      );\n\n            // new result found\n            if ($result !== NULL) {\n                // branch and bound enabled (default): returned result MUST be the new best result\n                if($this->branchAndBound ||\n                   // this is the first result, just use it anyway\n                   $bestResult === NULL ||\n                   // this is the new best result\n                   $this->sumEdges($result) < $this->sumEdges($bestResult)){\n                    $bestResult = $result;\n                }\n            }\n        }\n\n        return $bestResult;\n    }\n\n    /**\n     * get sum of weight of given edges\n     *\n     * no need to optimize this further, as it's only evaluated if branchAndBound is disabled and\n     * there's no valid reason why anybody would want to do so.\n     *\n     * @param  Edge[] $edges\n     * @return float\n     */\n    private function sumEdges(array $edges)\n    {\n        $sum = 0;\n        foreach ($edges as $edge) {\n            $sum += $edge->getWeight();\n        }\n\n        return $sum;\n    }\n}\n"
  },
  {
    "path": "src/TravelingSalesmanProblem/MinimumSpanningTree.php",
    "content": "<?php\n\nnamespace Graphp\\Algorithms\\TravelingSalesmanProblem;\n\nuse Graphp\\Algorithms\\MinimumSpanningTree\\Kruskal as MstKruskal;\nuse Graphp\\Algorithms\\Search\\BreadthFirst as SearchDepthFirst;\nuse Graphp\\Graph\\Graph;\nuse Graphp\\Graph\\Set\\Edges;\n\nclass MinimumSpanningTree extends Base\n{\n    /**\n     * @var Graph\n     */\n    private $graph;\n\n    public function __construct(Graph $inputGraph)\n    {\n        $this->graph = $inputGraph;\n    }\n\n    protected function getVertexStart()\n    {\n        return $this->graph->getVertices()->getVertexFirst();\n    }\n\n    protected function getGraph()\n    {\n        return $this->graph;\n    }\n\n    /**\n     * @return Edges\n     */\n    public function getEdges()\n    {\n        $returnEdges = array();\n\n        // Create minimum spanning tree\n        $minimumSpanningTreeAlgorithm = new MstKruskal($this->graph);\n        $minimumSpanningTree = $minimumSpanningTreeAlgorithm->createGraph();\n\n        $alg = new SearchDepthFirst($minimumSpanningTree->getVertices()->getVertexFirst());\n        // Depth first search in minmum spanning tree (for the eulerian path)\n\n        $startVertex = NULL;\n        $oldVertex = NULL;\n\n        // connect vertices in order of the depth first search\n        foreach ($alg->getVertices() as $vertex) {\n\n            // get vertex from the original graph (not from the depth first search)\n            $vertex = $this->graph->getVertex($vertex->getId());\n                                                                                // need to clone the edge from the original graph, therefore i need the original edge\n            if ($startVertex === NULL) {\n                $startVertex = $vertex;\n            } else {\n                // get edge(s) to clone, multiple edges are possible (returns an array if undirected edge)\n                assert($oldVertex !== null);\n                $returnEdges[] = $oldVertex->getEdgesTo($vertex)->getEdgeFirst();\n            }\n\n            $oldVertex = $vertex;\n        }\n\n        // connect last vertex with start vertex\n        // multiple edges are possible (returns an array if undirected edge)\n        assert($startVertex !== null && $oldVertex !== null);\n        $returnEdges[] = $oldVertex->getEdgesTo($startVertex)->getEdgeFirst();\n\n        return new Edges($returnEdges);\n    }\n}\n"
  },
  {
    "path": "src/TravelingSalesmanProblem/NearestNeighbor.php",
    "content": "<?php\n\nnamespace Graphp\\Algorithms\\TravelingSalesmanProblem;\n\nuse Graphp\\Graph\\Exception\\UnexpectedValueException;\nuse Graphp\\Graph\\Set\\Edges;\nuse Graphp\\Graph\\Vertex;\nuse SplPriorityQueue;\n\nclass NearestNeighbor extends Base\n{\n    /**\n     * @var Vertex\n     */\n    private $vertex;\n\n    public function __construct(Vertex $startVertex)\n    {\n         $this->vertex = $startVertex;\n    }\n\n    protected function getVertexStart()\n    {\n        return $this->vertex;\n    }\n\n    protected function getGraph()\n    {\n        return $this->vertex->getGraph();\n    }\n\n    /**\n     * @return Edges\n     */\n    public function getEdges()\n    {\n        $returnEdges = array();\n\n        $n = \\count($this->vertex->getGraph()->getVertices());\n\n        $vertex = $nextVertex = $this->vertex;\n        $visitedVertices = array($vertex->getId() => true);\n\n        for ($i = 0; $i < $n - 1; ++$i,\n                                    // n-1 steps (spanning tree)\n                                    $vertex = $nextVertex) {\n\n            // get all edges from the aktuel vertex\n            $edges = $vertex->getEdgesOut();\n\n            $sortedEdges = new SplPriorityQueue();\n\n            // sort the edges\n            foreach ($edges as $edge) {\n                $sortedEdges->insert($edge, - $edge->getWeight());\n            }\n\n            // Untill first is found: get cheepest edge\n            foreach ($sortedEdges as $edge) {\n\n                // Get EndVertex of this edge\n                $nextVertex = $edge->getVertexToFrom($vertex);\n\n                // is unvisited\n                if (!isset($visitedVertices[$nextVertex->getId()])) {\n                    break;\n                }\n            }\n\n            // check if there is a way i can use\n            if (isset($visitedVertices[$nextVertex->getId()])) {\n                throw new UnexpectedValueException('Graph is not complete - can\\'t find an edge to unconnected vertex');\n            }\n\n            $visitedVertices[$nextVertex->getId()] = TRUE;\n\n            // clone edge in new Graph\n            assert(isset($edge));\n            $returnEdges[] = $edge;\n\n        }\n\n        // check if there is a way from end edge to start edge\n        // get first connecting edge\n        // connect the last vertex with the start vertex\n        $returnEdges[] = $vertex->getEdgesTo($this->vertex)->getEdgeFirst();\n\n        return new Edges($returnEdges);\n    }\n}\n"
  },
  {
    "path": "src/Tree/Base.php",
    "content": "<?php\n\nnamespace Graphp\\Algorithms\\Tree;\n\nuse Graphp\\Algorithms\\BaseGraph;\nuse Graphp\\Algorithms\\Degree;\nuse Graphp\\Graph\\Graph;\nuse Graphp\\Graph\\Set\\Vertices;\nuse Graphp\\Graph\\Vertex;\n\n/**\n * Abstract base class for tree algorithms\n *\n * This abstract base class provides the base interface for working with\n * graphs that represent a tree.\n *\n * A tree is a connected Graph (single component) with no cycles. Every Tree is\n * a Graph, but not every Graph is a Tree. A null Graph (a Graph with no Vertices\n * and thus no Edges) is *NOT* considered a valid Tree, as it is not considered\n * connected (@see ConnectedComponents and @link)\n *\n *    A\n *   / \\\n *  B   C\n *     / \\\n *    D   E\n *\n * Special cases are undirected trees (like the one pictured above), handled via\n * Tree\\Undirected and directed, rooted trees (InTree and OutTree), handled via\n * Tree\\BaseDirected.\n *\n * @link http://en.wikipedia.org/wiki/Tree_%28graph_theory%29\n * @link http://en.wikipedia.org/wiki/Tree_%28data_structure%29\n * @link http://mathoverflow.net/questions/120536/is-the-empty-graph-a-tree\n * @see Undirected for an implementation of these algorithms on (undirected) trees\n * @see BaseDirected for an abstract implementation of these algorithms on directed, rooted trees\n */\nabstract class Base extends BaseGraph\n{\n    /**\n     * @var Degree\n     */\n    protected $degree;\n\n    public function __construct(Graph $graph)\n    {\n        parent::__construct($graph);\n\n        $this->degree = new Degree($graph);\n    }\n\n    /**\n     * checks whether the given graph is actually a tree\n     *\n     * @return bool\n     */\n    abstract public function isTree();\n\n    /**\n     * checks if the given $vertex is a leaf (outermost vertext)\n     *\n     * leaf vertex is also known as leaf node, external node or terminal node\n     *\n     * @param Vertex $vertex\n     * @return bool\n     */\n    abstract public function isVertexLeaf(Vertex $vertex);\n\n    /**\n     * checks if the given $vertex is an internal vertex (somewhere in the \"middle\" of the tree)\n     *\n     * internal vertex is also known as inner node (inode) or branch node\n     *\n     * @param Vertex $vertex\n     * @return bool\n     */\n    abstract public function isVertexInternal(Vertex $vertex);\n\n    /**\n     * get array of leaf vertices (outermost vertices with no children)\n     *\n     * @return Vertices\n     * @uses Graph::getVertices()\n     * @uses self::isVertexLeaf()\n     */\n    public function getVerticesLeaf()\n    {\n        return $this->graph->getVertices()->getVerticesMatch(array($this, 'isVertexLeaf'));\n    }\n\n    /**\n     * get array of internal vertices\n     *\n     * @return Vertices\n     * @uses Graph::getVertices()\n     * @uses self::isVertexInternal()\n     */\n    public function getVerticesInternal()\n    {\n        return $this->graph->getVertices()->getVerticesMatch(array($this, 'isVertexInternal'));\n    }\n}\n"
  },
  {
    "path": "src/Tree/BaseDirected.php",
    "content": "<?php\n\nnamespace Graphp\\Algorithms\\Tree;\n\nuse Graphp\\Algorithms\\Tree\\Base as Tree;\nuse Graphp\\Graph\\Exception\\UnderflowException;\nuse Graphp\\Graph\\Exception\\UnexpectedValueException;\nuse Graphp\\Graph\\Set\\Vertices;\nuse Graphp\\Graph\\Vertex;\n\n/**\n * Abstract algorithm base class for working with directed, rooted trees\n *\n * Directed trees have an designated root Vertex, which is the uppermost Vertex.\n * Every other Vertex is either a directed child of this root Vertex or an\n * indirect descendant (recursive child).\n *\n * There are two common implementations of directed trees:\n *\n * - Usual OutTree implementation where Edges \"point away\" from root Vertex\n *\n *          ROOT\n *          /  \\\n *    A <--/    \\--> B\n *                   \\\n *                    \\--> C\n *\n * - Alternative InTree implementation where Edges \"point towards\" root Vertex\n *\n *         ROOT\n *         ^  ^\n *        /    \\\n *       A      B\n *              ^\n *               \\\n *                C\n *\n * It's your choice on how to direct the edges, but make sure they all point in\n * the \"same direction\", or it will not be a valid tree anymore. However your\n * decision may be, in the above example, ROOT is always the root Vertex,\n * B is the parent of \"C\" and A, B are the children of ROOT.\n *\n * For performance reasons, except for `isTree()`, none of the below methods\n * check if the given Graph is actually a valid tree. So make sure to verify\n * `isTree()` returns `true` before relying on any of the methods.\n *\n * @link http://en.wikipedia.org/wiki/Arborescence_%28graph_theory%29\n * @link http://en.wikipedia.org/wiki/Spaghetti_stack\n * @see OutTree usual implementation where Edges \"point away\" from root vertex\n * @see InTree alternative implementation where Edges \"point towards\" root vertex\n */\nabstract class BaseDirected extends Tree\n{\n    /**\n     * get root vertex for this in-tree\n     *\n     * @return Vertex\n     * @throws UnderflowException if given graph is empty or no possible root candidate was found (check isTree()!)\n     * @uses Graph::getVertices() to iterate over each Vertex\n     * @uses self::isVertexPossibleRoot() to check if any Vertex is a possible root candidate\n     */\n    public function getVertexRoot()\n    {\n        foreach ($this->graph->getVertices() as $vertex) {\n            if ($this->isVertexPossibleRoot($vertex)) {\n                return $vertex;\n            }\n        }\n        throw new UnderflowException('No possible root found. Either empty graph or no Vertex with proper degree found.');\n    }\n\n    /**\n     * checks if this is a tree\n     *\n     * @return bool\n     * @uses self::getVertexRoot() to get root Vertex to start search from\n     * @uses self::getVerticesSubtree() to count number of vertices connected to root\n     */\n    public function isTree()\n    {\n        try {\n            $root = $this->getVertexRoot();\n        } catch (UnderflowException $e) {\n            return false;\n        } catch (UnexpectedValueException $e) {\n            return false;\n        }\n\n        try {\n            $num = \\count($this->getVerticesSubtree($root));\n        } catch (UnexpectedValueException $e) {\n            return false;\n        }\n\n        // check number of vertices reachable from root should match total number of vertices\n        return ($num === \\count($this->graph->getVertices()));\n    }\n\n    /**\n     * get parent vertex for given $vertex\n     *\n     * @param Vertex $vertex\n     * @throws UnderflowException if vertex has no parent (is a root vertex)\n     * @throws UnexpectedValueException if vertex has more than one possible parent (check isTree()!)\n     * @return Vertex\n     * @uses self::getVerticesParents() to get array of parent vertices\n     */\n    public function getVertexParent(Vertex $vertex)\n    {\n        $parents = $this->getVerticesParent($vertex);\n        if (\\count($parents) !== 1) {\n            if ($parents->isEmpty()) {\n                throw new UnderflowException('No parents for given vertex found');\n            } else {\n                throw new UnexpectedValueException('More than one parent');\n            }\n        }\n        return $parents->getVertexFirst();\n    }\n\n    /**\n     * get array of child vertices for given $vertex\n     *\n     * @param Vertex $vertex\n     * @return Vertices\n     * @throws UnexpectedValueException if the given $vertex contains invalid / parallel edges (check isTree()!)\n     */\n    abstract public function getVerticesChildren(Vertex $vertex);\n\n    /**\n     * internal helper to get all parents vertices\n     *\n     * a valid tree vertex only ever has a single parent, except for the root,\n     * which has none.\n     *\n     * @param Vertex $vertex\n     * @return Vertices\n     * @throws UnexpectedValueException if the given $vertex contains invalid / parallel edges (check isTree()!)\n     */\n    abstract protected function getVerticesParent(Vertex $vertex);\n\n    /**\n     * check if given vertex is a possible root (i.e. has no parent)\n     *\n     * @param Vertex $vertex\n     * @return bool\n     * @uses self::getVerticesParent()\n     */\n    protected function isVertexPossibleRoot(Vertex $vertex)\n    {\n        return (\\count($this->getVerticesParent($vertex)) === 0);\n    }\n\n    /**\n     * checks if the given $vertex is a leaf (outermost vertex with no children)\n     *\n     * @param Vertex $vertex\n     * @return bool\n     * @uses self::getVerticesChildren() to check given vertex has no children\n     */\n    public function isVertexLeaf(Vertex $vertex)\n    {\n        return (\\count($this->getVerticesChildren($vertex)) === 0);\n    }\n\n    /**\n     * checks if the given $vertex is an internal vertex (has children and is not root)\n     *\n     * @param Vertex $vertex\n     * @return bool\n     * @uses self::getVerticesParent() to check given vertex has a parent (is not root)\n     * @uses self::getVerticesChildren() to check given vertex has children (is not a leaf)\n     * @see \\Graphp\\Algorithms\\Tree\\Base::isVertexInternal() for more information\n     */\n    public function isVertexInternal(Vertex $vertex)\n    {\n        return (!$this->getVerticesParent($vertex)->isEmpty() && !$this->getVerticesChildren($vertex)->isEmpty());\n    }\n\n    /**\n     * get degree of tree (maximum number of children)\n     *\n     * @return int\n     * @throws UnderflowException for empty graphs\n     * @uses Graph::getVertices()\n     * @uses self::getVerticesChildren()\n     */\n    public function getDegree()\n    {\n        $max = null;\n        foreach ($this->graph->getVertices() as $vertex) {\n            $num = \\count($this->getVerticesChildren($vertex));\n            if ($max === null || $num > $max) {\n                $max = $num;\n            }\n        }\n        if ($max === null) {\n            throw new UnderflowException('No vertices found');\n        }\n        return $max;\n    }\n\n    /**\n     * get depth of given $vertex (number of edges between root vertex)\n     *\n     * root has depth zero\n     *\n     * @param Vertex $vertex\n     * @return int\n     * @throws UnderflowException for empty graphs\n     * @throws UnexpectedValueException if there's no path to root node (check isTree()!)\n     * @uses self::getVertexRoot()\n     * @uses self::getVertexParent() for each step\n     */\n    public function getDepthVertex(Vertex $vertex)\n    {\n        $root = $this->getVertexRoot();\n\n        $depth = 0;\n        while ($vertex !== $root) {\n            $vertex = $this->getVertexParent($vertex);\n            ++$depth;\n        }\n        return $depth;\n    }\n\n    /**\n     * get height of this tree (longest downward path to a leaf)\n     *\n     * a single vertex graph has height zero\n     *\n     * @return int\n     * @throws UnderflowException for empty graph\n     * @uses self::getVertexRoot()\n     * @uses self::getHeightVertex()\n     */\n    public function getHeight()\n    {\n        return $this->getHeightVertex($this->getVertexRoot());\n    }\n\n    /**\n     * get height of given vertex (longest downward path to a leaf)\n     *\n     * leafs has height zero\n     *\n     * @param Vertex $vertex\n     * @return int\n     * @uses self::getVerticesChildren() to get children of given vertex\n     * @uses self::getHeightVertex() to recurse into sub-children\n     */\n    public function getHeightVertex(Vertex $vertex)\n    {\n        $max = 0;\n        foreach ($this->getVerticesChildren($vertex) as $vertex) {\n            $height = $this->getHeightVertex($vertex) + 1;\n            if ($height > $max) {\n                $max = $height;\n            }\n        }\n        return $max;\n    }\n\n    /**\n     * get all vertices that are in the subtree of the given $vertex (which IS included)\n     *\n     * root vertex will return the whole tree, leaf vertices will only return themselves\n     *\n     * @param Vertex $vertex\n     * @throws UnexpectedValueException if there are invalid edges (check isTree()!)\n     * @return Vertices\n     * @uses self::getVerticesSubtreeRecursive()\n     * @uses self::getVerticesSubtree()\n     */\n    public function getVerticesSubtree(Vertex $vertex)\n    {\n        $vertices = array();\n        $this->getVerticesSubtreeRecursive($vertex, $vertices);\n\n        return new Vertices($vertices);\n    }\n\n    /**\n     * helper method to get recursively get subtree for given $vertex\n     *\n     * @param Vertex   $vertex\n     * @param Vertex[] $vertices\n     * @throws UnexpectedValueException if multiple links were found to the given edge (check isTree()!)\n     * @uses self::getVerticesChildren()\n     * @uses self::getVerticesSubtreeRecursive() to recurse into subtrees\n     */\n    private function getVerticesSubtreeRecursive(Vertex $vertex, array &$vertices)\n    {\n        $vid = $vertex->getId();\n        if (isset($vertices[$vid])) {\n            throw new UnexpectedValueException('Multiple links found');\n        }\n        $vertices[$vid] = $vertex;\n\n        foreach ($this->getVerticesChildren($vertex) as $vertexChild) {\n            $this->getVerticesSubtreeRecursive($vertexChild, $vertices);\n        }\n    }\n\n    /**\n     * get all vertices below the given $vertex (which is NOT included)\n     *\n     * think of this as the recursive version of getVerticesChildren()\n     *\n     * @param Vertex $vertex\n     * @return Vertices\n     * @throws UnexpectedValueException if there are invalid edges (check isTree()!)\n     * @uses self::getVerticesSubtree()\n     */\n    public function getVerticesDescendant(Vertex $vertex)\n    {\n        $vertices = $this->getVerticesSubtree($vertex)->getMap();\n        unset($vertices[$vertex->getId()]);\n\n        return new Vertices($vertices);\n    }\n}\n"
  },
  {
    "path": "src/Tree/InTree.php",
    "content": "<?php\n\nnamespace Graphp\\Algorithms\\Tree;\n\nuse Graphp\\Algorithms\\Tree\\BaseDirected as DirectedTree;\nuse Graphp\\Graph\\Exception\\UnexpectedValueException;\nuse Graphp\\Graph\\Vertex;\n\n/**\n * Alternative InTree implementation where Edges \"point towards\" root Vertex\n *\n *         ROOT\n *         ^  ^\n *        /    \\\n *       A      B\n *              ^\n *               \\\n *                C\n *\n * @link http://en.wikipedia.org/wiki/Spaghetti_stack\n * @see DirectedTree for more information on directed, rooted trees\n */\nclass InTree extends DirectedTree\n{\n    public function getVerticesChildren(Vertex $vertex)\n    {\n        $vertices = $vertex->getVerticesEdgeFrom();\n        if ($vertices->hasDuplicates()) {\n            throw new UnexpectedValueException();\n        }\n\n        return $vertices;\n    }\n\n    protected function getVerticesParent(Vertex $vertex)\n    {\n        $vertices = $vertex->getVerticesEdgeTo();\n        if ($vertices->hasDuplicates()) {\n            throw new UnexpectedValueException();\n        }\n\n        return $vertices;\n    }\n}\n"
  },
  {
    "path": "src/Tree/OutTree.php",
    "content": "<?php\n\nnamespace Graphp\\Algorithms\\Tree;\n\nuse Graphp\\Algorithms\\Tree\\BaseDirected as DirectedTree;\nuse Graphp\\Graph\\Exception\\UnexpectedValueException;\nuse Graphp\\Graph\\Vertex;\n\n/**\n * Usual OutTree implementation where Edges \"point away\" from root Vertex\n *\n *          ROOT\n *          /  \\\n *    A <--/    \\--> B\n *                   \\\n *                    \\--> C\n *\n * also known as arborescence\n *\n * @link http://en.wikipedia.org/wiki/Arborescence_%28graph_theory%29\n * @see DirectedTree for more information on directed, rooted trees\n */\nclass OutTree extends DirectedTree\n{\n    public function getVerticesChildren(Vertex $vertex)\n    {\n        $vertices = $vertex->getVerticesEdgeTo();\n        if ($vertices->hasDuplicates()) {\n            throw new UnexpectedValueException();\n        }\n\n        return $vertices;\n    }\n\n    protected function getVerticesParent(Vertex $vertex)\n    {\n        $vertices = $vertex->getVerticesEdgeFrom();\n        if ($vertices->hasDuplicates()) {\n            throw new UnexpectedValueException();\n        }\n\n        return $vertices;\n    }\n}\n"
  },
  {
    "path": "src/Tree/Undirected.php",
    "content": "<?php\n\nnamespace Graphp\\Algorithms\\Tree;\n\nuse Graphp\\Algorithms\\Tree\\Base as Tree;\nuse Graphp\\Graph\\EdgeUndirected;\nuse Graphp\\Graph\\Exception\\UnexpectedValueException;\nuse Graphp\\Graph\\Set\\Vertices;\nuse Graphp\\Graph\\Vertex;\n\n/**\n * Undirected tree implementation\n *\n * An undirected tree is a connected Graph (single component) with no cycles.\n * Every undirected Tree is an undirected Graph, but not every undirected Graph\n * is an undirected Tree.\n *\n *    A\n *   / \\\n *  B   C\n *     / \\\n *    D   E\n *\n * Undirected trees do not have special root Vertices (like the above picture\n * might suggest). The above tree Graph can also be equivalently be pictured\n * like this:\n *\n *      C\n *     /|\\\n *    / | \\\n *   A  D  E\n *  /\n * B\n *\n * If you're looking for a tree with a designated root Vertex, use directed,\n * rooted trees (BaseDirected).\n *\n * @link http://en.wikipedia.org/wiki/Tree_%28graph_theory%29\n * @see BaseDirected if you're looking for directed, rooted trees\n */\nclass Undirected extends Tree\n{\n    /**\n     * checks if this is a tree\n     *\n     * @return bool\n     * @uses Vertices::isEmpty() to skip null Graphs (a Graph with no Vertices is *NOT* a valid tree)\n     * @uses Vertices::getVertexFirst() to get get get random \"root\" Vertex to start search from\n     * @uses self::getVerticesSubtreeRecursive() to count number of vertices connected to root\n     */\n    public function isTree()\n    {\n        if ($this->graph->getVertices()->isEmpty()) {\n            return false;\n        }\n\n        // every vertex can represent a root vertex, so just pick one\n        $root = $this->graph->getVertices()->getVertexFirst();\n\n        $vertices = array();\n        try {\n            $this->getVerticesSubtreeRecursive($root, $vertices, null);\n        } catch (UnexpectedValueException $e) {\n            return false;\n        }\n\n        return (\\count($vertices) === \\count($this->graph->getVertices()));\n    }\n\n    /**\n     * checks if the given $vertex is a leaf (outermost vertex with exactly one edge)\n     *\n     * @param Vertex $vertex\n     * @return bool\n     * @uses Degree::getDegreeVertex()\n     */\n    public function isVertexLeaf(Vertex $vertex)\n    {\n        return ($this->degree->getDegreeVertex($vertex) === 1);\n    }\n\n    /**\n     * checks if the given $vertex is an internal vertex (inner vertex with at least 2 edges)\n     *\n     * @param Vertex $vertex\n     * @return bool\n     * @uses Degree::getDegreeVertex()\n     */\n    public function isVertexInternal(Vertex $vertex)\n    {\n        return ($this->degree->getDegreeVertex($vertex) >= 2);\n    }\n\n    /**\n     * get subtree for given Vertex and ignore path to \"parent\" ignoreVertex\n     *\n     * @param Vertex      $vertex\n     * @param Vertex[]    $vertices\n     * @param Vertex|null $ignore\n     * @throws UnexpectedValueException for cycles or directed edges (check isTree()!)\n     * @uses self::getVerticesNeighbor()\n     * @uses self::getVerticesSubtreeRecursive() to recurse into sub-subtrees\n     */\n    private function getVerticesSubtreeRecursive(Vertex $vertex, array &$vertices, Vertex $ignore = null)\n    {\n        if (isset($vertices[$vertex->getId()])) {\n            // vertex already visited => must be a cycle\n            throw new UnexpectedValueException('Vertex already visited');\n        }\n        $vertices[$vertex->getId()] = $vertex;\n\n        foreach ($this->getVerticesNeighbor($vertex) as $vertexNeighboor) {\n            if ($vertexNeighboor === $ignore) {\n                // ignore source vertex only once\n                $ignore = null;\n                continue;\n            }\n            $this->getVerticesSubtreeRecursive($vertexNeighboor, $vertices, $vertex);\n        }\n    }\n\n    /**\n     * get neighbor vertices for given start vertex\n     *\n     * @param Vertex $vertex\n     * @return Vertices (might include possible duplicates)\n     * @throws UnexpectedValueException for directed edges\n     * @uses Vertex::getEdges()\n     * @uses Edge::getVertexToFrom()\n     * @see Vertex::getVerticesEdge()\n     */\n    private function getVerticesNeighbor(Vertex $vertex)\n    {\n        $vertices = array();\n        foreach ($vertex->getEdges() as $edge) {\n            if (!$edge instanceof EdgeUndirected) {\n                throw new UnexpectedValueException('Directed edge encountered');\n            }\n            $vertices[] = $edge->getVertexToFrom($vertex);\n        }\n        return new Vertices($vertices);\n    }\n}\n"
  },
  {
    "path": "src/Weight.php",
    "content": "<?php\n\nnamespace Graphp\\Algorithms;\n\nuse Graphp\\Graph\\Graph;\n\n/**\n * Basic algorithms for working with the (total) weight of a Graph/Walk\n *\n * A weighted graph associates a label (weight) with every edge in the graph.\n * Sometimes the word cost is used instead of weight. The term network is a\n * synonym for a weighted graph.\n *\n * @link http://en.wikipedia.org/wiki/Glossary_of_graph_theory#Weighted_graphs_and_networks\n */\nclass Weight extends BaseDual\n{\n    /**\n     * checks whether this graph has any weighted edges\n     *\n     * edges usually have no weight attached. a weight explicitly set to (int) 0\n     * will be considered as 'weighted'.\n     *\n     * @return bool\n     * @uses Edge::getWeight()\n     */\n    public function isWeighted()\n    {\n        foreach ($this->set->getEdges() as $edge) {\n            if ($edge->getWeight() !== NULL) {\n                return true;\n            }\n        }\n\n        return false;\n    }\n\n    /**\n     * get total weight of graph (sum of weight of all edges)\n     *\n     * edges with no weight assigned will evaluate to weight (int) 0. thus an\n     * unweighted graph (see isWeighted()) will return total weight of (int) 0.\n     *\n     * returned weight can also be negative or (int) 0 if edges have been\n     * assigned a negative weight or a weight of (int) 0.\n     *\n     * @return float total weight\n     * @see self::isWeighted()\n     * @uses Edge::getWeight()\n     */\n    public function getWeight()\n    {\n        $weight = 0;\n        foreach ($this->set->getEdges() as $edge) {\n            $w = $edge->getWeight();\n            if ($w !== NULL) {\n                $weight += $w;\n            }\n        }\n\n        return $weight;\n    }\n\n    /**\n     * get minimum weight assigned to all edges\n     *\n     * minimum weight is often needed because some algorithms do not support\n     * negative weights or edges with zero weight.\n     *\n     * edges with NO (null) weight will NOT be considered for the minimum weight.\n     *\n     * @return float|NULL minimum edge weight or NULL if graph is not weighted or empty\n     * @uses Edge::getWeight()\n     */\n    public function getWeightMin()\n    {\n        $min = NULL;\n        foreach ($this->set->getEdges() as $edge) {\n            $weight = $edge->getWeight();\n            if ($weight !== null && ($min === NULL || $weight < $min)) {\n                $min = $weight;\n            }\n        }\n\n        return $min;\n    }\n\n    /**\n     * get total weight of current flow (sum of all edges flow(e) * weight(e))\n     *\n     * @return float\n     * @see Graph::getWeight() to just get the sum of all edges' weights\n     * @uses Edge::getFlow()\n     * @uses Edge::getWeight()\n     */\n    public function getWeightFlow()\n    {\n        $sum = 0;\n        foreach ($this->set->getEdges() as $edge) {\n            $sum += $edge->getFlow() * $edge->getWeight();\n        }\n\n        return $sum;\n    }\n}\n"
  },
  {
    "path": "tests/BipartitTest.php",
    "content": "<?php\n\nnamespace Graphp\\Tests\\Algorithms;\n\nuse Graphp\\Algorithms\\Bipartit as AlgorithmBipartit;\nuse Graphp\\Graph\\Graph;\n\nclass BipartitTest extends TestCase\n{\n    public function testGraphEmpty()\n    {\n        $graph = new Graph();\n\n        $alg = new AlgorithmBipartit($graph);\n\n        $this->assertTrue($alg->isBipartit());\n        $this->assertEquals(array(), $alg->getColors());\n        $this->assertEquals(array(0 => array(), 1 => array()), $alg->getColorVertices());\n    }\n\n    public function testGraphPairIsBipartit()\n    {\n        // 1 -> 2\n        $graph = new Graph();\n        $v1 = $graph->createVertex(1);\n        $v2 = $graph->createVertex(2);\n        $graph->createEdgeDirected($v1, $v2);\n\n        $alg = new AlgorithmBipartit($graph);\n\n        $this->assertTrue($alg->isBipartit());\n        $this->assertEquals(array(1 => 0, 2 => 1), $alg->getColors());\n        $this->assertEquals(array(0 => array(1 => $v1), 1 => array(2 => $v2)), $alg->getColorVertices());\n\n        return $alg;\n    }\n\n    /**\n     *\n     * @param AlgorithmBipartit $alg\n     * @depends testGraphPairIsBipartit\n     */\n    public function testGraphPairBipartitGroups(AlgorithmBipartit $alg)\n    {\n        // graph does not have any groups assigned, so its groups are not bipartit\n        $this->assertFalse($alg->isBipartitGroups());\n\n        // create a cloned graph with groups assigned according to bipartition\n        $graph = $alg->createGraphGroups();\n\n        $this->assertInstanceOf('Graphp\\Graph\\Graph', $graph);\n\n        $alg2 = new AlgorithmBipartit($graph);\n        $this->assertTrue($alg2->isBipartitGroups());\n    }\n\n    public function testGraphTriangleCycleIsNotBipartit()\n    {\n        // 1 -> 2 --> 3 --> 1\n        $graph = new Graph();\n        $v1 = $graph->createVertex(1);\n        $v2 = $graph->createVertex(2);\n        $v3 = $graph->createVertex(3);\n        $graph->createEdgeDirected($v1, $v2);\n        $graph->createEdgeDirected($v2, $v3);\n        $graph->createEdgeDirected($v3, $v1);\n\n        $alg = new AlgorithmBipartit($graph);\n\n        $this->assertFalse($alg->isBipartit());\n\n        return $alg;\n    }\n\n    /**\n     *\n     * @param AlgorithmBipartit $alg\n     * @depends testGraphTriangleCycleIsNotBipartit\n     */\n    public function testGraphTriangleCycleColorsInvalid(AlgorithmBipartit $alg)\n    {\n        $this->setExpectedException('UnexpectedValueException');\n        $alg->getColors();\n    }\n\n    /**\n     *\n     * @param AlgorithmBipartit $alg\n     * @depends testGraphTriangleCycleIsNotBipartit\n     */\n    public function testGraphTriangleCycleColorVerticesInvalid(AlgorithmBipartit $alg)\n    {\n        $this->setExpectedException('UnexpectedValueException');\n        $alg->getColorVertices();\n    }\n}\n"
  },
  {
    "path": "tests/CompleteTest.php",
    "content": "<?php\n\nnamespace Graphp\\Tests\\Algorithms;\n\nuse Graphp\\Algorithms\\Complete as AlgorithmComplete;\nuse Graphp\\Graph\\Graph;\n\nclass CompleteTest extends TestCase\n{\n    public function testGraphEmptyK0()\n    {\n        $graph = new Graph();\n\n        $alg = new AlgorithmComplete($graph);\n\n        $this->assertTrue($alg->isComplete());\n    }\n\n    public function testGraphSingleTrivialK1()\n    {\n        $graph = new Graph();\n        $graph->createVertex(1);\n\n        $alg = new AlgorithmComplete($graph);\n\n        $this->assertTrue($alg->isComplete());\n    }\n\n    public function testGraphSimplePairK2()\n    {\n        // 1 -- 2\n        $graph = new Graph();\n        $graph->createEdgeUndirected($graph->createVertex(1), $graph->createVertex(2));\n\n        $alg = new AlgorithmComplete($graph);\n\n        $this->assertTrue($alg->isComplete());\n    }\n\n    public function testGraphSingleDirectedIsNotComplete()\n    {\n        // 1 -> 2\n        $graph = new Graph();\n        $graph->createEdgeDirected($graph->createVertex(1), $graph->createVertex(2));\n\n        $alg = new AlgorithmComplete($graph);\n\n        $this->assertFalse($alg->isComplete());\n    }\n\n    public function testAdditionalEdgesToNotAffectCompleteness()\n    {\n        // 1 -> 2\n        // 1 -- 2\n        // 2 -> 1\n        // 1 -> 1\n        $graph = new Graph();\n        $graph->createEdgeDirected($graph->createVertex(1), $graph->createVertex(2));\n        $graph->createEdgeUndirected($graph->getVertex(1), $graph->getVertex(2));\n        $graph->createEdgeDirected($graph->getVertex(2), $graph->getVertex(1));\n        $graph->createEdgeDirected($graph->getVertex(1), $graph->getVertex(1));\n\n        $alg = new AlgorithmComplete($graph);\n\n        $this->assertTrue($alg->isComplete());\n    }\n}\n"
  },
  {
    "path": "tests/ConnectedComponentsTest.php",
    "content": "<?php\n\nnamespace Graphp\\Tests\\Algorithms;\n\nuse Graphp\\Algorithms\\ConnectedComponents as AlgorithmConnected;\nuse Graphp\\Graph\\Graph;\n\nclass ConnectedComponentsTest extends TestCase\n{\n    public function testNullGraph()\n    {\n        $graph = new Graph();\n\n        $alg = new AlgorithmConnected($graph);\n\n        $this->assertEquals(0, $alg->getNumberOfComponents());\n        $this->assertFalse($alg->isSingle());\n        $this->assertCount(0, $alg->createGraphsComponents());\n    }\n\n    public function testGraphSingleTrivial()\n    {\n        $graph = new Graph();\n        $graph->createVertex(1);\n\n        $alg = new AlgorithmConnected($graph);\n\n        $this->assertEquals(1, $alg->getNumberOfComponents());\n        $this->assertTrue($alg->isSingle());\n\n        $graphs = $alg->createGraphsComponents();\n\n        $this->assertCount(1, $graphs);\n        $this->assertGraphEquals($graph, \\reset($graphs));\n    }\n\n    public function testGraphEdgeDirections()\n    {\n        // 1 -- 2 -> 3 <- 4\n        $graph = new Graph();\n        $graph->createEdgeUndirected($graph->createVertex(1), $graph->createVertex(2));\n        $graph->createEdgeDirected($graph->getVertex(2), $graph->createVertex(3));\n        $graph->createEdgeDirected($graph->createVertex(4), $graph->getVertex(3));\n\n        $alg = new AlgorithmConnected($graph);\n\n        $this->assertEquals(1, $alg->getNumberOfComponents());\n        $this->assertTrue($alg->isSingle());\n\n        $graphs = $alg->createGraphsComponents();\n\n        $this->assertCount(1, $graphs);\n        $this->assertGraphEquals($graph, \\reset($graphs));\n        $this->assertGraphEquals($graph, $alg->createGraphComponentVertex($graph->getVertex(1)));\n    }\n\n    public function testComponents()\n    {\n        // 1 -- 2, 3 -> 4, 5\n        $graph = new Graph();\n        $v1 = $graph->createVertex(1);\n        $v2 = $graph->createVertex(2);\n        $v3 = $graph->createVertex(3);\n        $v4 = $graph->createVertex(4);\n        $v5 = $graph->createVertex(5);\n        $graph->createEdgeUndirected($v1, $v2);\n        $graph->createEdgeDirected($v3, $v4);\n\n        $alg = new AlgorithmConnected($graph);\n\n        $this->assertEquals(3, $alg->getNumberOfComponents());\n        $this->assertFalse($alg->isSingle());\n\n        $graphs = $alg->createGraphsComponents();\n        $this->assertCount(3, $graphs);\n\n        $ge = new Graph();\n        $ge->createEdgeUndirected($ge->createVertex(1), $ge->createVertex(2));\n        $this->assertGraphEquals($ge, $alg->createGraphComponentVertex($v2));\n\n        $ge = new Graph();\n        $ge->createVertex(5);\n        $this->assertEquals($ge, $alg->createGraphComponentVertex($v5));\n    }\n\n    public function testInvalidVertexPassedToAlgorithm()\n    {\n        $graph = new Graph();\n\n        $graph2 = new Graph();\n        $v2 = $graph2->createVertex(12);\n\n        $alg = new AlgorithmConnected($graph);\n\n        $this->setExpectedException('InvalidArgumentException');\n        $alg->createGraphComponentVertex($v2);\n    }\n}\n"
  },
  {
    "path": "tests/DegreeTest.php",
    "content": "<?php\n\nnamespace Graphp\\Tests\\Algorithms;\n\nuse Graphp\\Algorithms\\Degree as AlgorithmDegree;\nuse Graphp\\Graph\\Exception\\UnderflowException;\nuse Graphp\\Graph\\Exception\\UnexpectedValueException;\nuse Graphp\\Graph\\Graph;\n\nclass DegreeTest extends TestCase\n{\n    public function testGraphEmpty()\n    {\n        $graph = new Graph();\n\n        $alg = new AlgorithmDegree($graph);\n\n        try {\n            $alg->getDegree();\n            $this->fail();\n        } catch (UnderflowException $e) { }\n\n        try {\n            $alg->getDegreeMin();\n            $this->fail();\n        } catch (UnderflowException $e) { }\n\n        try {\n            $alg->getDegreeMax();\n            $this->fail();\n        } catch (UnderflowException $e) { }\n\n        $this->assertTrue($alg->isRegular());\n        $this->assertTrue($alg->isBalanced());\n    }\n\n    public function testGraphIsolated()\n    {\n        $graph = new Graph();\n        $graph->createVertex(1);\n        $graph->createVertex(2);\n\n        $alg = new AlgorithmDegree($graph);\n\n        $this->assertEquals(0, $alg->getDegree());\n        $this->assertEquals(0, $alg->getDegreeMin());\n        $this->assertEquals(0, $alg->getDegreeMax());\n        $this->assertTrue($alg->isRegular());\n        $this->assertTrue($alg->isBalanced());\n    }\n\n    public function testGraphIrregular()\n    {\n        // 1 -> 2 -> 3\n        $graph = new Graph();\n        $v1 = $graph->createVertex(1);\n        $v2 = $graph->createVertex(2);\n        $v3 = $graph->createVertex(3);\n        $graph->createEdgeDirected($v1, $v2);\n        $graph->createEdgeDirected($v2, $v3);\n\n        $alg = new AlgorithmDegree($graph);\n\n        try {\n            $this->assertEquals(0, $alg->getDegree());\n            $this->fail();\n        } catch (UnexpectedValueException $e) { }\n\n        $this->assertEquals(1, $alg->getDegreeMin());\n        $this->assertEquals(2, $alg->getDegreeMax());\n        $this->assertFalse($alg->isRegular());\n        $this->assertFalse($alg->isBalanced());\n\n\n        $this->assertEquals(0, $alg->getDegreeInVertex($v1));\n        $this->assertEquals(1, $alg->getDegreeOutVertex($v1));\n        $this->assertEquals(1, $alg->getDegreeVertex($v1));\n        $this->assertFalse($alg->isVertexIsolated($v1));\n        $this->assertFalse($alg->isVertexSink($v1));\n        $this->assertTrue($alg->isVertexSource($v1));\n\n        $this->assertEquals(1, $alg->getDegreeInVertex($v2));\n        $this->assertEquals(1, $alg->getDegreeOutVertex($v2));\n        $this->assertEquals(2, $alg->getDegreeVertex($v2));\n        $this->assertFalse($alg->isVertexIsolated($v2));\n        $this->assertFalse($alg->isVertexSink($v2));\n        $this->assertFalse($alg->isVertexSource($v2));\n\n        $this->assertEquals(1, $alg->getDegreeInVertex($v3));\n        $this->assertEquals(0, $alg->getDegreeOutVertex($v3));\n        $this->assertEquals(1, $alg->getDegreeVertex($v3));\n        $this->assertFalse($alg->isVertexIsolated($v3));\n        $this->assertTrue($alg->isVertexSink($v3));\n        $this->assertFalse($alg->isVertexSource($v3));\n    }\n}\n"
  },
  {
    "path": "tests/DetectNegativeCycleTest.php",
    "content": "<?php\n\nnamespace Graphp\\Tests\\Algorithms;\n\nuse Graphp\\Algorithms\\DetectNegativeCycle;\nuse Graphp\\Graph\\Graph;\n\nclass DetectNegativeCycleTest extends TestCase\n{\n    public function testNullGraph()\n    {\n        $graph = new Graph();\n\n        $alg = new DetectNegativeCycle($graph);\n\n        $this->assertFalse($alg->hasCycleNegative());\n\n        return $alg;\n    }\n\n    /**\n     *\n     * @param DetectNegativeCycle $alg\n     * @depends testNullGraph\n     */\n    public function testNullGraphHasNoCycle(DetectNegativeCycle $alg)\n    {\n        $this->setExpectedException('UnderflowException');\n        $alg->getCycleNegative();\n    }\n\n    /**\n     *\n     * @param DetectNegativeCycle $alg\n     * @depends testNullGraph\n     */\n    public function testNullGraphHasNoCycleGraph(DetectNegativeCycle $alg)\n    {\n        $this->setExpectedException('UnderflowException');\n        $alg->createGraph();\n    }\n\n    public function testNegativeLoop()\n    {\n        // 1 --[-1]--> 1\n        $graph = new Graph();\n        $v1 = $graph->createVertex(1);\n        $e1 = $graph->createEdgeDirected($v1, $v1)->setWeight(-1);\n\n        $alg = new DetectNegativeCycle($graph);\n\n        $this->assertTrue($alg->hasCycleNegative());\n\n        $cycle = $alg->getCycleNegative();\n\n        $this->assertCount(1, $cycle->getEdges());\n        $this->assertCount(2, $cycle->getVertices());\n        $this->assertEquals($e1, $cycle->getEdges()->getEdgeFirst());\n        $this->assertEquals($v1, $cycle->getVertices()->getVertexFirst());\n    }\n\n    public function testNegativeCycle()\n    {\n        // 1 --[-1]--> 2\n        // ^           |\n        // \\---[-2]----/\n        $graph = new Graph();\n        $v1 = $graph->createVertex(1);\n        $v2 = $graph->createVertex(2);\n        $graph->createEdgeDirected($v1, $v2)->setWeight(-1);\n        $graph->createEdgeDirected($v2, $v1)->setWeight(-2);\n\n        $alg = new DetectNegativeCycle($graph);\n\n        $this->assertTrue($alg->hasCycleNegative());\n\n        $cycle = $alg->getCycleNegative();\n\n        $this->assertCount(2, $cycle->getEdges());\n        $this->assertCount(3, $cycle->getVertices());\n    }\n\n    public function testNegativeUndirectedIsNegativeCycle()\n    {\n        // 1 --[-1]-- 2\n        $graph = new Graph();\n        $v1 = $graph->createVertex(1);\n        $v2 = $graph->createVertex(2);\n        $graph->createEdgeUndirected($v1, $v2)->setWeight(-1);\n\n        $alg = new DetectNegativeCycle($graph);\n\n        $this->assertTrue($alg->hasCycleNegative());\n\n        $cycle = $alg->getCycleNegative();\n\n        $this->assertCount(2, $cycle->getEdges());\n        $this->assertCount(3, $cycle->getVertices());\n    }\n\n    public function testNegativeCycleSubgraph()\n    {\n        // 1 --[1]--> 2 --[1]--> 3 --[1]--> 4\n        //                       ^          |\n        //                       \\---[-2]---/\n        $graph = new Graph();\n        $v1 = $graph->createVertex(1);\n        $v2 = $graph->createVertex(2);\n        $v3 = $graph->createVertex(3);\n        $v4 = $graph->createVertex(4);\n        $graph->createEdgeDirected($v1, $v2)->setWeight(1);\n        $graph->createEdgeDirected($v2, $v3)->setWeight(1);\n        $graph->createEdgeDirected($v3, $v4)->setWeight(1);\n        $graph->createEdgeDirected($v4, $v3)->setWeight(-2);\n\n        $alg = new DetectNegativeCycle($graph);\n\n        $this->assertTrue($alg->hasCycleNegative());\n\n        $cycle = $alg->getCycleNegative();\n\n        $this->assertCount(2, $cycle->getEdges());\n        $this->assertCount(3, $cycle->getVertices());\n        $this->assertTrue($cycle->getVertices()->hasVertexId(3));\n        $this->assertTrue($cycle->getVertices()->hasVertexId(4));\n    }\n\n    public function testNegativeComponents()\n    {\n        // 1 -- 2     3 --[-1]--> 4\n        //            ^           |\n        //            \\---[-2]----/\n        $graph = new Graph();\n        $v1 = $graph->createVertex(1);\n        $v2 = $graph->createVertex(2);\n        $v3 = $graph->createVertex(3);\n        $v4 = $graph->createVertex(4);\n        $graph->createEdgeUndirected($v1, $v2);\n        $graph->createEdgeDirected($v3, $v4)->setWeight(-1);\n        $graph->createEdgeDirected($v4, $v3)->setWeight(-2);\n\n        $alg = new DetectNegativeCycle($graph);\n\n        $this->assertTrue($alg->hasCycleNegative());\n\n        $cycle = $alg->getCycleNegative();\n\n        $this->assertCount(2, $cycle->getEdges());\n        $this->assertCount(3, $cycle->getVertices());\n        $this->assertTrue($cycle->getVertices()->hasVertexId(3));\n        $this->assertTrue($cycle->getVertices()->hasVertexId(4));\n    }\n}\n"
  },
  {
    "path": "tests/DirectedTest.php",
    "content": "<?php\n\nnamespace Graphp\\Tests\\Algorithms;\n\nuse Graphp\\Algorithms\\Directed as AlgorithmDirected;\nuse Graphp\\Graph\\Graph;\n\nclass DirectedTest extends TestCase\n{\n    public function testGraphEmpty()\n    {\n        $graph = new Graph();\n\n        $alg = new AlgorithmDirected($graph);\n\n        $this->assertFalse($alg->hasDirected());\n        $this->assertFalse($alg->hasUndirected());\n        $this->assertFalse($alg->isMixed());\n    }\n\n    public function testGraphUndirected()\n    {\n        // 1 -- 2\n        $graph = new Graph();\n        $graph->createEdgeUndirected($graph->createVertex(1), $graph->createVertex(2));\n\n        $alg = new AlgorithmDirected($graph);\n\n        $this->assertFalse($alg->hasDirected());\n        $this->assertTrue($alg->hasUndirected());\n        $this->assertFalse($alg->isMixed());\n    }\n\n    public function testGraphDirected()\n    {\n        // 1 -> 2\n        $graph = new Graph();\n        $graph->createEdgeDirected($graph->createVertex(1), $graph->createVertex(2));\n\n        $alg = new AlgorithmDirected($graph);\n\n        $this->assertTrue($alg->hasDirected());\n        $this->assertFalse($alg->hasUndirected());\n        $this->assertFalse($alg->isMixed());\n    }\n\n    public function testGraphMixed()\n    {\n        // 1 -- 2 -> 3\n        $graph = new Graph();\n        $graph->createEdgeUndirected($graph->createVertex(1), $graph->createVertex(2));\n        $graph->createEdgeDirected($graph->getVertex(2), $graph->createVertex(3));\n\n        $alg = new AlgorithmDirected($graph);\n\n        $this->assertTrue($alg->hasDirected());\n        $this->assertTrue($alg->hasUndirected());\n        $this->assertTrue($alg->isMixed());\n    }\n}\n"
  },
  {
    "path": "tests/EulerianTest.php",
    "content": "<?php\n\nnamespace Graphp\\Tests\\Algorithms;\n\nuse Graphp\\Algorithms\\Eulerian as AlgorithmEulerian;\nuse Graphp\\Graph\\Graph;\n\nclass EulerianTest extends TestCase\n{\n    public function testGraphEmpty()\n    {\n        $graph = new Graph();\n\n        $alg = new AlgorithmEulerian($graph);\n\n        $this->assertFalse($alg->hasCycle());\n    }\n\n    public function testGraphPairHasNoCycle()\n    {\n        // 1 -- 2\n        $graph = new Graph();\n        $v1 = $graph->createVertex(1);\n        $v2 = $graph->createVertex(2);\n        $graph->createEdgeUndirected($v1, $v2);\n\n        $alg = new AlgorithmEulerian($graph);\n\n        $this->assertFalse($alg->hasCycle());\n    }\n\n    public function testGraphTriangleCycleIsNotBipartit()\n    {\n        // 1 -- 2 -- 3 -- 1\n        $graph = new Graph();\n        $v1 = $graph->createVertex(1);\n        $v2 = $graph->createVertex(2);\n        $v3 = $graph->createVertex(3);\n        $graph->createEdgeUndirected($v1, $v2);\n        $graph->createEdgeUndirected($v2, $v3);\n        $graph->createEdgeUndirected($v3, $v1);\n\n        $alg = new AlgorithmEulerian($graph);\n\n        $this->assertTrue($alg->hasCycle());\n    }\n}\n"
  },
  {
    "path": "tests/FlowTest.php",
    "content": "<?php\n\nnamespace Graphp\\Tests\\Algorithms;\n\nuse Graphp\\Algorithms\\Flow as AlgorithmFlow;\nuse Graphp\\Graph\\Graph;\n\nclass FlowTest extends TestCase\n{\n    public function testGraphEmpty()\n    {\n        $graph = new Graph();\n\n        $alg = new AlgorithmFlow($graph);\n\n        $this->assertFalse($alg->hasFlow());\n        $this->assertEquals(0, $alg->getBalance());\n        $this->assertTrue($alg->isBalancedFlow());\n\n        return $graph;\n    }\n\n    public function testEdgeWithZeroFlowIsConsideredFlow()\n    {\n        // 1 -> 2\n        $graph = new Graph();\n        $graph->createEdgeDirected($graph->createVertex(1), $graph->createVertex(2))->setFlow(0);\n\n        $alg = new AlgorithmFlow($graph);\n\n        $this->assertTrue($alg->hasFlow());\n        $this->assertEquals(0, $alg->getFlowVertex($graph->getVertex(1)));\n        $this->assertEquals(0, $alg->getFlowVertex($graph->getVertex(2)));\n    }\n\n    /**\n     *\n     * @param Graph $graph\n     * @depends testGraphEmpty\n     */\n    public function testGraphSimple(Graph $graph)\n    {\n        // 1 -> 2\n        $graph->createEdgeDirected($graph->createVertex(1), $graph->createVertex(2));\n\n        $alg = new AlgorithmFlow($graph);\n\n        $this->assertFalse($alg->hasFlow());\n        $this->assertEquals(0, $alg->getFlowVertex($graph->getVertex(1)));\n        $this->assertEquals(0, $alg->getFlowVertex($graph->getVertex(2)));\n\n        return $graph;\n    }\n\n    /**\n     *\n     * @param Graph $graph\n     * @depends testGraphSimple\n     */\n    public function testGraphWithUnweightedEdges(Graph $graph)\n    {\n        // additional flow edge: 2 -> 3\n        $graph->createEdgeDirected($graph->getVertex(2), $graph->createVertex(3))->setFlow(10);\n\n        $alg = new AlgorithmFlow($graph);\n\n        $this->assertTrue($alg->hasFlow());\n        $this->assertEquals(10, $alg->getFlowVertex($graph->getVertex(2)));\n        $this->assertEquals(-10, $alg->getFlowVertex($graph->getVertex(3)));\n    }\n\n    public function testGraphBalance()\n    {\n        // source(+100) -> sink(-10)\n        $graph = new Graph();\n        $graph->createVertex('source')->setBalance(100);\n        $graph->createVertex('sink')->setBalance(-10);\n\n        $alg = new AlgorithmFlow($graph);\n\n        $this->assertEquals(90, $alg->getBalance());\n        $this->assertFalse($alg->isBalancedFlow());\n    }\n\n    public function testVertexWithUndirectedEdgeHasInvalidFlow()\n    {\n        // 1 -- 2\n        $graph = new Graph();\n        $graph->createEdgeUndirected($graph->createVertex(1), $graph->createVertex(2))->setFlow(10);\n\n        $alg = new AlgorithmFlow($graph);\n\n        $this->setExpectedException('UnexpectedValueException');\n        $alg->getFlowVertex($graph->getVertex(1));\n    }\n}\n"
  },
  {
    "path": "tests/GroupsTest.php",
    "content": "<?php\n\nnamespace Graphp\\Tests\\Algorithms;\n\nuse Graphp\\Algorithms\\Groups as AlgorithmGroups;\nuse Graphp\\Graph\\Graph;\n\nclass GroupsTest extends TestCase\n{\n    public function testGraphEmpty()\n    {\n        $graph = new Graph();\n\n        $alg = new AlgorithmGroups($graph);\n\n        $this->assertEquals(array(), $alg->getGroups());\n        $this->assertEquals(0, $alg->getNumberOfGroups());\n\n        $this->assertTrue($alg->getVerticesGroup(123)->isEmpty());\n\n        $this->assertFalse($alg->isBipartit());\n    }\n\n    public function testGraphPairIsBipartit()\n    {\n        // 1 -> 2\n        $graph = new Graph();\n        $v1 = $graph->createVertex(1)->setGroup(1);\n        $v2 = $graph->createVertex(2)->setGroup(2);\n        $graph->createEdgeDirected($v1, $v2);\n\n        $alg = new AlgorithmGroups($graph);\n\n        $this->assertEquals(array(1, 2), $alg->getGroups());\n        $this->assertEquals(2, $alg->getNumberOfGroups());\n\n        $this->assertTrue($alg->getVerticesGroup(123)->isEmpty());\n        $this->assertEquals(array(1 => $v1), $alg->getVerticesGroup(1)->getMap());\n\n        $this->assertTrue($alg->isBipartit());\n    }\n\n    public function testGraphTriangleCycleIsNotBipartit()\n    {\n        // 1 -> 2 -> 3 -> 1\n        $graph = new Graph();\n        $v1 = $graph->createVertex(1)->setGroup(1);\n        $v2 = $graph->createVertex(2)->setGroup(2);\n        $v3 = $graph->createVertex(3)->setGroup(1);\n        $graph->createEdgeDirected($v1, $v2);\n        $graph->createEdgeDirected($v2, $v3);\n        $graph->createEdgeDirected($v3, $v1);\n\n        $alg = new AlgorithmGroups($graph);\n\n        $this->assertEquals(array(1, 2), $alg->getGroups());\n        $this->assertEquals(2, $alg->getNumberOfGroups());\n\n        $this->assertTrue($alg->getVerticesGroup(123)->isEmpty());\n        $this->assertEquals(array(1 => $v1, 3 => $v3), $alg->getVerticesGroup(1)->getMap());\n\n        $this->assertFalse($alg->isBipartit());\n    }\n}\n"
  },
  {
    "path": "tests/LoopTest.php",
    "content": "<?php\n\nnamespace Graphp\\Tests\\Algorithms;\n\nuse Graphp\\Algorithms\\Loop as AlgorithmLoop;\nuse Graphp\\Graph\\Graph;\n\nclass LoopTest extends TestCase\n{\n    public function testGraphEmpty()\n    {\n        $graph = new Graph();\n\n        $alg = new AlgorithmLoop($graph);\n\n        $this->assertFalse($alg->hasLoop());\n    }\n\n    public function testGraphWithMixedCircuitIsNotConsideredLoop()\n    {\n        // 1 -> 2\n        // 2 -- 1\n        $graph = new Graph();\n        $v1 = $graph->createVertex(1);\n        $v2 = $graph->createVertex(2);\n        $graph->createEdgeDirected($v1, $v2);\n        $graph->createEdgeUndirected($v2, $v1);\n\n        $alg = new AlgorithmLoop($graph);\n\n        $this->assertFalse($alg->hasLoop());\n        $this->assertFalse($alg->hasLoopVertex($v1));\n        $this->assertFalse($alg->hasLoopVertex($v2));\n    }\n\n    public function testGraphUndirectedLoop()\n    {\n        // 1 -- 1\n        $graph = new Graph();\n        $graph->createEdgeUndirected($graph->createVertex(1), $v1 = $graph->getVertex(1));\n\n        $alg = new AlgorithmLoop($graph);\n\n        $this->assertTrue($alg->hasLoop());\n        $this->assertTrue($alg->hasLoopVertex($v1));\n    }\n\n    public function testGraphDirectedLoop()\n    {\n        // 1 -> 1\n        $graph = new Graph();\n        $graph->createEdgeDirected($graph->createVertex(1), $v1 = $graph->getVertex(1));\n\n        $alg = new AlgorithmLoop($graph);\n\n        $this->assertTrue($alg->hasLoop());\n        $this->assertTrue($alg->hasLoopVertex($v1));\n    }\n}\n"
  },
  {
    "path": "tests/MaxFlow/EdmondsKarpTest.php",
    "content": "<?php\n\nnamespace Graphp\\Tests\\Algorithms\\MaxFlow;\n\nuse Graphp\\Algorithms\\MaxFlow\\EdmondsKarp as AlgorithmMaxFlowEdmondsKarp;\nuse Graphp\\Graph\\Graph;\nuse Graphp\\Tests\\Algorithms\\TestCase;\n\nclass EdmondsKarpTest extends TestCase\n{\n    public function testEdgeDirected()\n    {\n        // 0 -[0/10]-> 1\n        $graph = new Graph();\n        $v0 = $graph->createVertex(0);\n        $v1 = $graph->createVertex(1);\n\n        $graph->createEdgeDirected($v0, $v1)->setCapacity(10);\n\n        // 0 -[10/10]-> 1\n        $alg = new AlgorithmMaxFlowEdmondsKarp($v0, $v1);\n\n        $this->assertEquals(10, $alg->getFlowMax());\n    }\n\n    public function testEdgesMultiplePaths()\n    {\n        // 0 -[0/5]---------> 1\n        // |                  ^\n        // |                  |\n        // \\-[0/7]-> 2 -[0/9]-/\n        $graph = new Graph();\n        $v0 = $graph->createVertex(0);\n        $v1 = $graph->createVertex(1);\n        $v2 = $graph->createVertex(2);\n\n        $graph->createEdgeDirected($v0, $v1)->setCapacity(5);\n        $graph->createEdgeDirected($v0, $v2)->setCapacity(7);\n        $graph->createEdgeDirected($v2, $v1)->setCapacity(9);\n\n        // 0 -[5/5]---------> 1\n        // |                  ^\n        // |                  |\n        // \\-[7/7]-> 2 -[7/9]-/\n        $alg = new AlgorithmMaxFlowEdmondsKarp($v0, $v1);\n\n        $this->assertEquals(12, $alg->getFlowMax());\n    }\n\n    public function testEdgesMultiplePathsTwo()\n    {\n        // 0 -[0/5]---------> 1-[0/10]-> 3\n        // |                  ^          |\n        // |                  |          |\n        // \\-[0/7]-> 2 -[0/9]-/          |\n        //           ^                   |\n        //           \\---[0/2]-----------/\n        $graph = new Graph();\n        $v0 = $graph->createVertex(0);\n        $v1 = $graph->createVertex(1);\n        $v2 = $graph->createVertex(2);\n        $v3 = $graph->createVertex(3);\n\n        $graph->createEdgeDirected($v0, $v1)->setCapacity(5);\n        $graph->createEdgeDirected($v0, $v2)->setCapacity(7);\n        $graph->createEdgeDirected($v2, $v1)->setCapacity(9);\n        $graph->createEdgeDirected($v1, $v3)->setCapacity(10);\n        $graph->createEdgeDirected($v3, $v2)->setCapacity(2);\n\n        $alg = new AlgorithmMaxFlowEdmondsKarp($v0, $v3);\n\n        $this->assertEquals(10, $alg->getFlowMax());\n\n        $alg = new AlgorithmMaxFlowEdmondsKarp($v0, $v2);\n\n        $this->assertEquals(9, $alg->getFlowMax());\n    }\n\n    public function testEdgesMultiplePathsTree()\n    {\n        $graph = new Graph();\n        $v0 = $graph->createVertex(0);\n        $v1 = $graph->createVertex(1);\n        $v2 = $graph->createVertex(2);\n        $v3 = $graph->createVertex(3);\n\n        $graph->createEdgeDirected($v0, $v1)->setCapacity(4);\n        $graph->createEdgeDirected($v0, $v2)->setCapacity(2);\n        $graph->createEdgeDirected($v1, $v2)->setCapacity(3);\n        $graph->createEdgeDirected($v1, $v3)->setCapacity(1);\n        $graph->createEdgeDirected($v2, $v3)->setCapacity(6);\n\n        $alg = new AlgorithmMaxFlowEdmondsKarp($v0, $v3);\n\n        $this->assertEquals(6, $alg->getFlowMax());\n    }\n\n//     public function testEdgesParallel(){\n//         $graph = new Graph();\n//         $v0 = $graph->createVertex(0);\n//         $v1 = $graph->createVertex(1);\n\n//         $graph->createEdgeDirected($v0, $v1)->setCapacity(3.4);\n//         $graph->createEdgeDirected($v0, $v1)->setCapacity(6.6);\n\n//         $alg = new AlgorithmMaxFlowEdmondsKarp($v0, $v1);\n\n//         $this->assertEquals(10, $alg->getFlowMax());\n//     }\n\n    public function testEdgesUndirected()\n    {\n        // 0 -[0/7]- 1\n        $graph = new Graph();\n        $v0 = $graph->createVertex(0);\n        $v1 = $graph->createVertex(1);\n\n        $graph->createEdgeUndirected($v1, $v0)->setCapacity(7);\n\n        // 0 -[7/7]- 1\n        $alg = new AlgorithmMaxFlowEdmondsKarp($v0, $v1);\n\n        $this->setExpectedException('UnexpectedValueException');\n        $this->assertEquals(7, $alg->getFlowMax());\n    }\n\n    /**\n     * run algorithm with bigger graph and check result against known result (will take several seconds)\n     */\n//     public function testKnownResultBig(){\n\n//         $graph = $this->readGraph('G_1_2.txt');\n\n//         $alg = new AlgorithmMaxFlowEdmondsKarp($graph->getVertex(0), $graph->getVertex(4));\n\n//         $this->assertEquals(0.735802, $alg->getFlowMax());\n//     }\n\n    public function testInvalidFlowToOtherGraph()\n    {\n        $graph1 = new Graph();\n        $vg1 = $graph1->createVertex(1);\n\n        $graph2 = new Graph();\n        $vg2 = $graph2->createVertex(2);\n\n        $this->setExpectedException('InvalidArgumentException');\n        new AlgorithmMaxFlowEdmondsKarp($vg1, $vg2);\n    }\n\n    public function testInvalidFlowToSelf()\n    {\n        $graph = new Graph();\n        $v1 = $graph->createVertex(1);\n\n        $this->setExpectedException('InvalidArgumentException');\n        new AlgorithmMaxFlowEdmondsKarp($v1, $v1);\n    }\n\n}\n"
  },
  {
    "path": "tests/MaximumMatching/FlowTest.php",
    "content": "<?php\n\nnamespace Graphp\\Tests\\Algorithms\\MaximumMatching;\n\nuse Graphp\\Algorithms\\MaximumMatching\\Flow;\nuse Graphp\\Graph\\Graph;\nuse Graphp\\Tests\\Algorithms\\TestCase;\n\nclass FlowTest extends TestCase\n{\n//     /**\n//      * run algorithm with small graph and check result against known result\n//      */\n//     public function testKnownResult()\n//     {\n//         $loader = new EdgeListBipartit(PATH_DATA . 'Matching_100_100.txt');\n//         $loader->setEnableDirectedEdges(false);\n//         $graph = $loader->createGraph();\n\n//         $alg = new Flow($graph);\n//         $this->assertEquals(100, $alg->getNumberOfMatches());\n//     }\n\n    public function testSingleEdge()\n    {\n        $graph = new Graph();\n        $edge = $graph->createEdgeUndirected($graph->createVertex(0)->setGroup(0), $graph->createVertex(1)->setGroup(1));\n\n        $alg = new Flow($graph);\n        // correct number of edges\n        $this->assertEquals(1, $alg->getNumberOfMatches());\n        // actual edge instance returned\n        $this->assertEquals(array($edge), $alg->getEdges()->getVector());\n\n        // check\n        $flowgraph = $alg->createGraph();\n        $this->assertInstanceOf('Graphp\\Graph\\Graph', $flowgraph);\n    }\n\n    /**\n     * expect exception for directed edges\n     */\n    public function testInvalidDirected()\n    {\n        $graph = new Graph();\n        $graph->createEdgeDirected($graph->createVertex(0)->setGroup(0), $graph->createVertex(1)->setGroup(1));\n\n        $alg = new Flow($graph);\n\n        $this->setExpectedException('UnexpectedValueException');\n        $alg->getNumberOfMatches();\n    }\n\n    /**\n     * expect exception for non-bipartit graphs\n     */\n    public function testInvalidBipartit()\n    {\n        $graph = new Graph();\n        $graph->createEdgeUndirected($graph->createVertex(0)->setGroup(1), $graph->createVertex(1)->setGroup(1));\n\n        $alg = new Flow($graph);\n\n        $this->setExpectedException('UnexpectedValueException');\n        $alg->getNumberOfMatches();\n    }\n}\n"
  },
  {
    "path": "tests/MinimumCostFlow/BaseMcfTest.php",
    "content": "<?php\n\nnamespace Graphp\\Tests\\Algorithms\\MinimumCostFlow;\n\nuse Graphp\\Algorithms\\MinimumCostFlow\\Base;\nuse Graphp\\Graph\\Graph;\nuse Graphp\\Tests\\Algorithms\\TestCase;\n\nabstract class BaseMcfTest extends TestCase\n{\n    /**\n     *\n     * @param Graph $graph\n     * @return Base\n     */\n    abstract protected function createAlgorithm(Graph $graph);\n\n    public function testNull()\n    {\n        $graph = new Graph();\n\n        $alg = $this->createAlgorithm($graph);\n        $this->assertEquals(0, $alg->getWeightFlow());\n    }\n\n    public function testSingleIntermediary()\n    {\n        $graph = new Graph();\n        $graph->createVertex(1);\n\n        $alg = $this->createAlgorithm($graph);\n        $this->assertEquals(0, $alg->getWeightFlow());\n    }\n\n    public function testSimpleEdge()\n    {\n        // 1(+2) -[0/2/2]-> 2(-2)\n        $graph = new Graph();\n        $v1 = $graph->createVertex(1)->setBalance(2);\n        $v2 = $graph->createVertex(2)->setBalance(-2);\n        $graph->createEdgeDirected($v1, $v2)->setWeight(2)->setCapacity(2);\n\n        $alg = $this->createAlgorithm($graph);\n        $this->assertEquals(4, $alg->getWeightFlow()); // 2x2\n    }\n\n    public function testMultipleSinks()\n    {\n        // 1(+2) -[0/2/2]-> 2(-1)\n        //       -[0/4/-5]-> 3(-1)\n        $graph = new Graph();\n        $v1 = $graph->createVertex(1)->setBalance(2);\n        $v2 = $graph->createVertex(2)->setBalance(-1);\n        $v3 = $graph->createVertex(3)->setBalance(-1);\n        $graph->createEdgeDirected($v1, $v2)->setWeight(2)->setCapacity(2);\n        $graph->createEdgeDirected($v1, $v3)->setWeight(-5)->setCapacity(4);\n\n        $alg = $this->createAlgorithm($graph);\n        $this->assertEquals(-3, $alg->getWeightFlow()); // 1*2 + 1*-5\n    }\n\n    public function testIntermediaryVertices()\n    {\n        // 1(+2) -[0/1/4]-> 2 -[0/6/-2]-> 4(-2)\n        //       -[0/4/5]-> 3 -[0/6/8]->\n        $graph = new Graph();\n        $v1 = $graph->createVertex(1)->setBalance(2);\n        $v2 = $graph->createVertex(2);\n        $v3 = $graph->createVertex(3);\n        $v4 = $graph->createVertex(4)->setBalance(-2);\n        $graph->createEdgeDirected($v1, $v2)->setWeight(4)->setCapacity(1);\n        $graph->createEdgeDirected($v2, $v4)->setWeight(-2)->setCapacity(6);\n        $graph->createEdgeDirected($v1, $v3)->setWeight(5)->setCapacity(4);\n        $graph->createEdgeDirected($v3, $v4)->setWeight(8)->setCapacity(6);\n\n        $alg = $this->createAlgorithm($graph);\n        $this->assertEquals(15, $alg->getWeightFlow()); // 1*4 + 1*-2 + 1*5 + 1*8\n    }\n\n    public function testEdgeCapacities()\n    {\n        // 1(+2) -[0/3/4]-> 2 -[0/4/5]-> 3 ->[0/6/-2]-> 4(-2)\n        $graph = new Graph();\n        $v1 = $graph->createVertex(1)->setBalance(2);\n        $v2 = $graph->createVertex(2);\n        $v3 = $graph->createVertex(3);\n        $v4 = $graph->createVertex(4)->setBalance(-2);\n        $graph->createEdgeDirected($v1, $v2)->setWeight(4)->setCapacity(3);\n        $graph->createEdgeDirected($v2, $v3)->setWeight(5)->setCapacity(4);\n        $graph->createEdgeDirected($v3, $v4)->setWeight(-2)->setCapacity(6);\n\n        $alg = $this->createAlgorithm($graph);\n        $this->assertEquals(14, $alg->getWeightFlow()); // 2*4 + 2*5 + 2*-2\n    }\n\n    public function testEdgeFlows()\n    {\n        // 1(+4) ---[3/4/2]---> 2 ---[3/3/3]---> 4(-4)\n        //  |                   |                  ^\n        //  |                [0/2/1]               |\n        //  |                   ↓                  |\n        //  \\-------[1/2/2]---> 3 ---[1/5/1]-------/\n        $graph = new Graph();\n        $v1 = $graph->createVertex(1)->setBalance(4);\n        $v2 = $graph->createVertex(2);\n        $v3 = $graph->createVertex(3);\n        $v4 = $graph->createVertex(4)->setBalance(-4);\n        $graph->createEdgeDirected($v1, $v2)->setFlow(3)->setCapacity(4)->setWeight(2);\n        $graph->createEdgeDirected($v2, $v4)->setFlow(3)->setCapacity(3)->setWeight(3);\n        $graph->createEdgeDirected($v1, $v3)->setFlow(1)->setCapacity(2)->setWeight(2);\n        $graph->createEdgeDirected($v3, $v4)->setFlow(1)->setCapacity(5)->setWeight(1);\n        $graph->createEdgeDirected($v2, $v3)->setFlow(0)->setCapacity(2)->setWeight(1);\n\n        $alg = $this->createAlgorithm($graph);\n        $this->assertEquals(14, $alg->getWeightFlow()); // 4*1 + 2*2 + 2*1 + 2*2\n    }\n\n    public function testEdgeCapacityInsufficientFails()\n    {\n        // 1(+2) -[0/1]-> 2(-2)\n        $graph = new Graph();\n        $v1 = $graph->createVertex(1)->setBalance(2);\n        $v2 = $graph->createVertex(2)->setBalance(-2);\n        $graph->createEdgeDirected($v1, $v2)->setCapacity(1);\n\n        $alg = $this->createAlgorithm($graph);\n\n        $this->setExpectedException('UnexpectedValueException');\n        $alg->getWeightFlow();\n    }\n\n    public function testEdgeCapacityUnsetFails()\n    {\n        // 1(+2) -> 2(-2)\n        $graph = new Graph();\n        $v1 = $graph->createVertex(1)->setBalance(2);\n        $v2 = $graph->createVertex(2)->setBalance(-2);\n        $graph->createEdgeDirected($v1, $v2);\n\n        $alg = $this->createAlgorithm($graph);\n\n        $this->setExpectedException('UnexpectedValueException');\n        $alg->getWeightFlow();\n    }\n\n    public function testIsolatedVerticesFail()\n    {\n        // 1(+2), 2(-2)\n        $graph = new Graph();\n        $graph->createVertex(1)->setBalance(2);\n        $graph->createVertex(2)->setBalance(-2);\n\n        $alg = $this->createAlgorithm($graph);\n\n        $this->setExpectedException('UnexpectedValueException');\n        $alg->getWeightFlow();\n    }\n\n    public function testUnbalancedFails()\n    {\n        // 1(+2) -> 2(-3)\n        $graph = new Graph();\n        $v1 = $graph->createVertex(1)->setBalance(2);\n        $v2 = $graph->createVertex(2)->setBalance(-3);\n        $graph->createEdgeDirected($v1, $v2)->setCapacity(3);\n\n        $alg = $this->createAlgorithm($graph);\n\n        $this->setExpectedException('UnexpectedValueException');\n        $alg->getWeightFlow();\n    }\n\n    public function testUndirectedFails()\n    {\n        // 1(+2) -- 2(-2)\n        $graph = new Graph();\n        $v1 = $graph->createVertex(1)->setBalance(2);\n        $v2 = $graph->createVertex(2)->setBalance(-2);\n        $graph->createEdgeUndirected($v1, $v2)->setCapacity(2);\n\n        $alg = $this->createAlgorithm($graph);\n\n        $this->setExpectedException('UnexpectedValueException');\n        $alg->getWeightFlow();\n    }\n\n    public function testUndirectedNegativeCycleFails()\n    {\n        // 1(+2) -[0/2/-1]- 2(-2)\n        $graph = new Graph();\n        $v1 = $graph->createVertex(1)->setBalance(2);\n        $v2 = $graph->createVertex(2)->setBalance(-2);\n        $graph->createEdgeUndirected($v1, $v2)->setCapacity(2)->setWeight(-1);\n\n        $alg = $this->createAlgorithm($graph);\n\n        $this->setExpectedException('UnexpectedValueException');\n        $alg->getWeightFlow();\n    }\n}\n"
  },
  {
    "path": "tests/MinimumCostFlow/CycleCancellingTest.php",
    "content": "<?php\n\nnamespace Graphp\\Tests\\Algorithms\\MinimumCostFlow;\n\nuse Graphp\\Algorithms\\MinimumCostFlow\\CycleCanceling;\nuse Graphp\\Graph\\Graph;\n\nclass CycleCancellingTest extends BaseMcfTest\n{\n    protected function createAlgorithm(Graph $graph)\n    {\n        return new CycleCanceling($graph);\n    }\n}\n"
  },
  {
    "path": "tests/MinimumCostFlow/SuccessiveShortestPathTest.php",
    "content": "<?php\n\nnamespace Graphp\\Tests\\Algorithms\\MinimumCostFlow;\n\nuse Graphp\\Algorithms\\MinimumCostFlow\\SuccessiveShortestPath;\nuse Graphp\\Graph\\Graph;\n\nclass SuccessiveShortestPathTest extends BaseMcfTest\n{\n    protected function createAlgorithm(Graph $graph)\n    {\n        return new SuccessiveShortestPath($graph);\n    }\n}\n"
  },
  {
    "path": "tests/MinimumSpanningTree/BaseMstTest.php",
    "content": "<?php\n\nnamespace Graphp\\Tests\\Algorithms\\MinimumSpanningTree;\n\nuse Graphp\\Algorithms\\MinimumSpanningTree\\Base as MstBase;\nuse Graphp\\Graph\\Graph;\nuse Graphp\\Graph\\Vertex;\nuse Graphp\\Tests\\Algorithms\\TestCase;\n\nabstract class BaseMstTest extends TestCase\n{\n    /**\n     * @param Vertex $vertex\n     * @return MstBase\n     */\n    abstract protected function createAlg(Vertex $vertex);\n\n    public function testIsolatedVertex()\n    {\n        $graph = new Graph();\n        $v1 = $graph->createVertex(1);\n\n        $alg = $this->createAlg($v1);\n\n        $this->assertCount(0, $alg->getEdges());\n        $this->assertEquals(0, $alg->getWeight());\n\n        $graphMst = $alg->createGraph();\n        $this->assertGraphEquals($graph, $graphMst);\n    }\n\n    public function testSingleEdge()\n    {\n        // 1 --[3]-- 2\n        $graph = new Graph();\n        $v1 = $graph->createVertex(1);\n        $v2 = $graph->createVertex(2);\n        $graph->createEdgeUndirected($v1, $v2)->setWeight(3);\n\n        $alg = $this->createAlg($v1);\n\n        $this->assertCount(1, $alg->getEdges());\n        $this->assertEquals(3, $alg->getWeight());\n        $this->assertGraphEquals($graph, $alg->createGraph());\n    }\n\n    public function testSimpleGraph()\n    {\n        // 1 --[6]-- 2 --[9]-- 3 --[7]-- 4 --[8]-- 5\n        $graph = new Graph();\n        $v1 = $graph->createVertex(1);\n        $v2 = $graph->createVertex(2);\n        $v3 = $graph->createVertex(3);\n        $v4 = $graph->createVertex(4);\n        $v5 = $graph->createVertex(5);\n        $graph->createEdgeUndirected($v1, $v2)->setWeight(6);\n        $graph->createEdgeUndirected($v2, $v3)->setWeight(9);\n        $graph->createEdgeUndirected($v3, $v4)->setWeight(7);\n        $graph->createEdgeUndirected($v4, $v5)->setWeight(8);\n\n        $alg = $this->createAlg($v1);\n\n        $graphMst = $alg->createGraph();\n        $this->assertGraphEquals($graph, $graphMst);\n    }\n\n    public function testFindingCheapestEdge()\n    {\n        //   /--[4]--\\\n        //  /         \\\n        // 1 ---[3]--- 2\n        //  \\         /\n        //   \\--[5]--/\n        $graph = new Graph();\n        $v1 = $graph->createVertex(1);\n        $v2 = $graph->createVertex(2);\n        $graph->createEdgeUndirected($v1, $v2)->setWeight(4);\n        $graph->createEdgeUndirected($v1, $v2)->setWeight(3);\n        $graph->createEdgeUndirected($v1, $v2)->setWeight(5);\n\n        $alg = $this->createAlg($v1);\n        $edges = $alg->getEdges();\n\n        $this->assertCount(1, $edges);\n        $this->assertEquals(3, $edges->getEdgeFirst()->getWeight());\n        $this->assertEquals(3, $alg->getWeight());\n    }\n\n    public function testFindingCheapestTree()\n    {\n        // 1 --[4]-- 2 --[5]-- 3\n        //  \\                 /\n        //   \\-------[6]-----/\n        $graph = new Graph();\n        $v1 = $graph->createVertex(1);\n        $v2 = $graph->createVertex(2);\n        $v3 = $graph->createVertex(3);\n        $graph->createEdgeUndirected($v1, $v2)->setWeight(4);\n        $graph->createEdgeUndirected($v2, $v3)->setWeight(5);\n        $graph->createEdgeUndirected($v3, $v1)->setWeight(6);\n\n        // 1 --[4]-- 2 -- [5] -- 3\n        $graphExpected = new Graph();\n        $ve1 = $graphExpected->createVertex(1);\n        $ve2 = $graphExpected->createVertex(2);\n        $ve3 = $graphExpected->createVertex(3);\n        $graphExpected->createEdgeUndirected($ve1, $ve2)->setWeight(4);\n        $graphExpected->createEdgeUndirected($ve2, $ve3)->setWeight(5);\n\n        $alg = $this->createAlg($v1);\n        $this->assertCount(2, $alg->getEdges());\n        $this->assertEquals(9, $alg->getWeight());\n        $this->assertGraphEquals($graphExpected, $alg->createGraph());\n    }\n\n    public function testMixedGraphDirectionIsIgnored()\n    {\n        // 1 --[6]-> 2 --[7]-- 3 --[8]-- 4 <-[9]-- 5\n        $graph = new Graph();\n        $v1 = $graph->createVertex(1);\n        $v2 = $graph->createVertex(2);\n        $v3 = $graph->createVertex(3);\n        $v4 = $graph->createVertex(4);\n        $v5 = $graph->createVertex(5);\n        $graph->createEdgeDirected($v1, $v2)->setWeight(6);\n        $graph->createEdgeUndirected($v2, $v3)->setWeight(7);\n        $graph->createEdgeUndirected($v4, $v3)->setWeight(8);\n        $graph->createEdgeDirected($v5, $v4)->setWeight(9);\n\n        $alg = $this->createAlg($v1);\n\n        $this->assertCount(4, $alg->getEdges());\n        $this->assertEquals(30, $alg->getWeight());\n        $this->assertGraphEquals($graph, $alg->createGraph());\n    }\n\n    public function testMultipleComponentsFail()\n    {\n        // 1 --[1]-- 2, 3 --[1]-- 4\n        $graph = new Graph();\n        $v1 = $graph->createVertex(1);\n        $v2 = $graph->createVertex(2);\n        $v3 = $graph->createVertex(3);\n        $v4 = $graph->createVertex(4);\n        $graph->createEdgeUndirected($v1, $v2)->setWeight(1);\n        $graph->createEdgeUndirected($v3, $v4)->setWeight(1);\n\n        $alg = $this->createAlg($v1);\n\n        $this->setExpectedException('UnexpectedValueException');\n        $alg->getEdges();\n    }\n\n    public function testMultipleIsolatedVerticesFormMultipleComponentsFail()\n    {\n        // 1, 2\n        $graph = new Graph();\n        $v1 = $graph->createVertex(1);\n        $graph->createVertex(2);\n\n        $alg = $this->createAlg($v1);\n\n        $this->setExpectedException('UnexpectedValueException');\n        $alg->getEdges();\n    }\n\n\n}"
  },
  {
    "path": "tests/MinimumSpanningTree/KruskalTest.php",
    "content": "<?php\n\nnamespace Graphp\\Tests\\Algorithms\\MinimumSpanningTree;\n\nuse Graphp\\Algorithms\\MinimumSpanningTree\\Kruskal;\nuse Graphp\\Graph\\Graph;\nuse Graphp\\Graph\\Vertex;\n\nclass KruskalTest extends BaseMstTest\n{\n    protected function createAlg(Vertex $vertex)\n    {\n        return new Kruskal($vertex->getGraph());\n    }\n\n    public function testNullGraphIsNotConsideredToBeConnected()\n    {\n        $graph = new Graph();\n\n        $alg = new Kruskal($graph);\n\n        $this->setExpectedException('UnexpectedValueException');\n        $alg->getEdges();\n    }\n}\n"
  },
  {
    "path": "tests/MinimumSpanningTree/PrimTest.php",
    "content": "<?php\n\nnamespace Graphp\\Tests\\Algorithms\\MinimumSpanningTree;\n\nuse Graphp\\Algorithms\\MinimumSpanningTree\\Prim;\nuse Graphp\\Graph\\Vertex;\n\nclass PrimTest extends BaseMstTest\n{\n    protected function createAlg(Vertex $vertex)\n    {\n        return new Prim($vertex);\n    }\n}\n"
  },
  {
    "path": "tests/ParallelTest.php",
    "content": "<?php\n\nnamespace Graphp\\Tests\\Algorithms;\n\nuse Graphp\\Algorithms\\Parallel as AlgorithmParallel;\nuse Graphp\\Graph\\Graph;\n\nclass ParallelTest extends TestCase\n{\n    public function testGraphEmpty()\n    {\n        $graph = new Graph();\n\n        $alg = new AlgorithmParallel($graph);\n\n        $this->assertFalse($alg->hasEdgeParallel());\n    }\n\n    public function testDirectedCycleIsNotConsideredParallel()\n    {\n        // 1 -> 2\n        // 2 -> 1\n        $graph = new Graph();\n        $v1 = $graph->createVertex(1);\n        $v2 = $graph->createVertex(2);\n        $e1 = $graph->createEdgeDirected($v1, $v2);\n        $e2 = $graph->createEdgeDirected($v2, $v1);\n\n        $alg = new AlgorithmParallel($graph);\n\n        $this->assertFalse($alg->hasEdgeParallel());\n        $this->assertEquals(array(), $alg->getEdgesParallelEdge($e1)->getVector());\n        $this->assertEquals(array(), $alg->getEdgesParallelEdge($e2)->getVector());\n    }\n\n    public function testDirectedParallelEdge()\n    {\n        // 1 -> 2\n        // 1 -> 2\n        $graph = new Graph();\n        $v1 = $graph->createVertex(1);\n        $v2 = $graph->createVertex(2);\n        $e1 = $graph->createEdgeDirected($v1, $v2);\n        $e2 = $graph->createEdgeDirected($v1, $v2);\n\n        $alg = new AlgorithmParallel($graph);\n\n        $this->assertTrue($alg->hasEdgeParallel());\n        $this->assertEquals(array($e2), $alg->getEdgesParallelEdge($e1)->getVector());\n        $this->assertEquals(array($e1), $alg->getEdgesParallelEdge($e2)->getVector());\n    }\n\n    public function testMixedParallelEdge()\n    {\n        // 1 -> 2\n        // 1 -- 2\n        $graph = new Graph();\n        $v1 = $graph->createVertex(1);\n        $v2 = $graph->createVertex(2);\n        $e1 = $graph->createEdgeDirected($v1, $v2);\n        $e2 = $graph->createEdgeUndirected($v1, $v2);\n\n        $alg = new AlgorithmParallel($graph);\n\n        $this->assertTrue($alg->hasEdgeParallel());\n        $this->assertEquals(array($e2), $alg->getEdgesParallelEdge($e1)->getVector());\n        $this->assertEquals(array($e1), $alg->getEdgesParallelEdge($e2)->getVector());\n    }\n\n    public function testMixedParallelEdgesMultiple()\n    {\n        // 1 -> 2\n        // 1 -> 2\n        // 1 -- 2\n        // 1 -- 2\n        // 2 -> 1\n        // 2 -> 1\n        $graph = new Graph();\n        $v1 = $graph->createVertex(1);\n        $v2 = $graph->createVertex(2);\n        $e1 = $graph->createEdgeDirected($v1, $v2);\n        $e2 = $graph->createEdgeDirected($v1, $v2);\n        $e3 = $graph->createEdgeUndirected($v1, $v2);\n        $e4 = $graph->createEdgeUndirected($v1, $v2);\n        $e5 = $graph->createEdgeDirected($v2, $v1);\n        $e6 = $graph->createEdgeDirected($v2, $v1);\n\n        $alg = new AlgorithmParallel($graph);\n\n        $this->assertTrue($alg->hasEdgeParallel());\n        $this->assertEquals(array($e2, $e3, $e4), $alg->getEdgesParallelEdge($e1)->getVector());\n        $this->assertEquals(array($e1, $e3, $e4), $alg->getEdgesParallelEdge($e2)->getVector());\n        $this->assertEquals(array($e1, $e2, $e4, $e5, $e6), $alg->getEdgesParallelEdge($e3)->getVector());\n        $this->assertEquals(array($e1, $e2, $e3, $e5, $e6), $alg->getEdgesParallelEdge($e4)->getVector());\n        $this->assertEquals(array($e3, $e4, $e6), $alg->getEdgesParallelEdge($e5)->getVector());\n        $this->assertEquals(array($e3, $e4, $e5), $alg->getEdgesParallelEdge($e6)->getVector());\n    }\n\n}\n"
  },
  {
    "path": "tests/Property/PropertyGraphTest.php",
    "content": "<?php\n\nnamespace Graphp\\Tests\\Algorithms\\Property;\n\nuse Graphp\\Algorithms\\Property\\GraphProperty;\nuse Graphp\\Graph\\Graph;\nuse Graphp\\Tests\\Algorithms\\TestCase;\n\nclass PropertyGraphTest extends TestCase\n{\n    public function testEmptyIsEdgeless()\n    {\n        $graph = new Graph();\n\n        $alg = new GraphProperty($graph);\n\n        $this->assertTrue($alg->isNull());\n        $this->assertTrue($alg->isEdgeless());\n        $this->assertFalse($alg->isTrivial());\n    }\n\n    public function testSingleVertexIsTrivial()\n    {\n        $graph = new Graph();\n        $graph->createVertex(1);\n\n        $alg = new GraphProperty($graph);\n\n        $this->assertFalse($alg->isNull());\n        $this->assertTrue($alg->isEdgeless());\n        $this->assertTrue($alg->isTrivial());\n    }\n}\n"
  },
  {
    "path": "tests/Property/WalkPropertyTest.php",
    "content": "<?php\n\nnamespace Graphp\\Tests\\Algorithms\\Property;\n\nuse Graphp\\Algorithms\\Property\\WalkProperty;\nuse Graphp\\Graph\\Graph;\nuse Graphp\\Graph\\Walk;\nuse Graphp\\Tests\\Algorithms\\TestCase;\n\nclass WalkPropertyTest extends TestCase\n{\n    public function testTrivialGraph()\n    {\n        $graph = new Graph();\n        $v1 = $graph->createVertex(1);\n\n        $walk = Walk::factoryFromEdges(array(), $v1);\n\n        $this->assertCount(1, $walk->getVertices());\n        $this->assertCount(0, $walk->getEdges());\n\n        $alg = new WalkProperty($walk);\n\n        $this->assertFalse($alg->isLoop());\n        $this->assertFalse($alg->hasLoop());\n\n        $this->assertFalse($alg->isCycle());\n        $this->assertFalse($alg->hasCycle());\n\n        $this->assertTrue($alg->isPath());\n        $this->assertTrue($alg->isSimple());\n\n        $this->assertTrue($alg->isEulerian());\n        $this->assertTrue($alg->isHamiltonian());\n    }\n\n    public function testLoop()\n    {\n        // 1 -- 1\n        $graph = new Graph();\n        $v1 = $graph->createVertex(1);\n        $e1 = $graph->createEdgeUndirected($v1, $v1);\n\n        $walk = Walk::factoryFromEdges(array($e1), $v1);\n\n        $alg = new WalkProperty($walk);\n\n        $this->assertTrue($alg->isLoop());\n        $this->assertTrue($alg->hasLoop());\n\n        $this->assertTrue($alg->isCycle());\n        $this->assertTrue($alg->hasCycle());\n\n        $this->assertTrue($alg->isPath());\n        $this->assertTrue($alg->isSimple());\n\n        $this->assertTrue($alg->isEulerian());\n        $this->assertTrue($alg->isHamiltonian());\n    }\n\n    public function testCycle()\n    {\n        // 1 -- 2 -- 1\n        $graph = new Graph();\n        $v1 = $graph->createVertex(1);\n        $v2 = $graph->createVertex(2);\n        $e1 = $graph->createEdgeUndirected($v1, $v2);\n        $e2 = $graph->createEdgeUndirected($v2, $v1);\n\n        $walk = Walk::factoryFromEdges(array($e1, $e2), $v1);\n\n        $this->assertCount(3, $walk->getVertices());\n        $this->assertCount(2, $walk->getEdges());\n\n        $alg = new WalkProperty($walk);\n\n        $this->assertTrue($alg->isCycle());\n        $this->assertTrue($alg->hasCycle());\n        $this->assertTrue($alg->isPath());\n        $this->assertTrue($alg->isSimple());\n\n        $this->assertTrue($alg->isEulerian());\n        $this->assertTrue($alg->isHamiltonian());\n    }\n\n    public function testCircuit()\n    {\n        // 1 -> 2 -> 1, 2 -> 2\n        $graph = new Graph();\n        $v1 = $graph->createVertex(1);\n        $v2 = $graph->createVertex(2);\n        $e1 = $graph->createEdgeDirected($v1, $v2);\n        $e2 = $graph->createEdgeDirected($v2, $v1);\n        $e3 = $graph->createEdgeDirected($v2, $v2);\n\n        // 1 -> 2 -> 2 -> 1\n        $walk = Walk::factoryFromEdges(array($e1, $e3, $e2), $v1);\n\n        $this->assertEquals(array(1, 2, 2, 1), $walk->getVertices()->getIds());\n\n        $alg = new WalkProperty($walk);\n\n        $this->assertTrue($alg->isCycle());\n        $this->assertTrue($alg->isCircuit());\n    }\n\n    public function testNonCircuit()\n    {\n        // 1 -> 2 -> 1, 2 -> 2\n        $graph = new Graph();\n        $v1 = $graph->createVertex(1);\n        $v2 = $graph->createVertex(2);\n        $e1 = $graph->createEdgeDirected($v1, $v2);\n        $e2 = $graph->createEdgeDirected($v2, $v1);\n        $e3 = $graph->createEdgeDirected($v2, $v2);\n\n        // non-circuit: taking loop twice\n        // 1 -> 2 -> 2 -> 2 -> 1\n        $walk = Walk::factoryFromEdges(array($e1, $e3, $e3, $e2), $v1);\n\n        $this->assertEquals(array(1, 2, 2, 2, 1), $walk->getVertices()->getIds());\n\n        $alg = new WalkProperty($walk);\n\n        $this->assertTrue($alg->isCycle());\n        $this->assertFalse($alg->isCircuit());\n    }\n\n    public function testDigon()\n    {\n        // 1 -> 2 -> 1\n        $graph = new Graph();\n        $v1 = $graph->createVertex(1);\n        $v2 = $graph->createVertex(2);\n        $e1 = $graph->createEdgeDirected($v1, $v2);\n        $e2 = $graph->createEdgeDirected($v2, $v1);\n\n        $walk = Walk::factoryFromEdges(array($e1, $e2), $v1);\n\n        $alg = new WalkProperty($walk);\n\n        $this->assertTrue($alg->isDigon());\n    }\n\n    public function testTriangle()\n    {\n        // 1 -> 2 -> 3 -> 1\n        $graph = new Graph();\n        $v1 = $graph->createVertex(1);\n        $v2 = $graph->createVertex(2);\n        $v3 = $graph->createVertex(3);\n        $e1 = $graph->createEdgeDirected($v1, $v2);\n        $e2 = $graph->createEdgeDirected($v2, $v3);\n        $e3 = $graph->createEdgeDirected($v3, $v1);\n\n        $walk = Walk::factoryFromEdges(array($e1, $e2, $e3), $v1);\n\n        $alg = new WalkProperty($walk);\n\n        $this->assertTrue($alg->isTriangle());\n    }\n\n    public function testSimplePathWithinGraph()\n    {\n        // 1 -- 2 -- 2\n        $graph = new Graph();\n        $v1 = $graph->createVertex(1);\n        $v2 = $graph->createVertex(2);\n        $graph->createEdgeUndirected($v1, $v2);\n        $e2 = $graph->createEdgeUndirected($v2, $v2);\n\n        // only use \"2 -- 2\" part\n        $walk = Walk::factoryFromEdges(array($e2), $v2);\n\n        $this->assertCount(2, $walk->getVertices());\n        $this->assertCount(1, $walk->getEdges());\n\n        $alg = new WalkProperty($walk);\n\n        $this->assertTrue($alg->isCycle());\n        $this->assertTrue($alg->hasCycle());\n        $this->assertTrue($alg->isPath());\n        $this->assertTrue($alg->isSimple());\n\n        $this->assertFalse($alg->isEulerian());\n        $this->assertFalse($alg->isHamiltonian());\n    }\n}\n"
  },
  {
    "path": "tests/ResidualGraphTest.php",
    "content": "<?php\n\nnamespace Graphp\\Tests\\Algorithms;\n\nuse Graphp\\Algorithms\\ResidualGraph;\nuse Graphp\\Graph\\Graph;\n\nclass ResidualGraphTest extends TestCase\n{\n    public function testGraphEmpty()\n    {\n        $graph = new Graph();\n\n        $alg = new ResidualGraph($graph);\n        $residual = $alg->createGraph();\n\n        $this->assertGraphEquals($graph, $residual);\n    }\n\n    /**\n     * test an edge with capacity unused\n     */\n    public function testEdgeUnused()\n    {\n        $graph = new Graph();\n\n        $graph->createEdgeDirected($graph->createVertex(0), $graph->createVertex(1))->setFlow(0)\n                                                                      ->setCapacity(2)\n                                                                      ->setWeight(3);\n\n        $alg = new ResidualGraph($graph);\n        $residual = $alg->createGraph();\n\n        $this->assertGraphEquals($graph, $residual);\n    }\n\n    /**\n     * test an edge with capacity completely used\n     */\n    public function testEdgeUsed()\n    {\n        $graph = new Graph();\n\n        $graph->createEdgeDirected($graph->createVertex(0), $graph->createVertex(1))->setFlow(2)\n                                                                      ->setCapacity(2)\n                                                                      ->setWeight(3);\n\n        $alg = new ResidualGraph($graph);\n        $residual = $alg->createGraph();\n\n        $expected = new Graph();\n        $expected->createEdgeDirected($expected->createVertex(1), $expected->createVertex(0))->setFlow(0)\n                                                                            ->setCapacity(2)\n                                                                            ->setWeight(-3);\n\n        $this->assertGraphEquals($expected, $residual);\n    }\n\n    /**\n     * test an edge with capacity remaining\n     */\n    public function testEdgePartial()\n    {\n        $graph = new Graph();\n\n        $graph->createEdgeDirected($graph->createVertex(0), $graph->createVertex(1))->setFlow(1)\n                                                                    ->setCapacity(2)\n                                                                    ->setWeight(3);\n\n        $alg = new ResidualGraph($graph);\n        $residual = $alg->createGraph();\n\n        $expected = new Graph();\n        $expected->createVertex(0);\n        $expected->createVertex(1);\n\n        // remaining edge\n        $expected->createEdgeDirected($expected->getVertex(0), $expected->getVertex(1))->setFlow(0)\n                                                                      ->setCapacity(1)\n                                                                      ->setWeight(3);\n\n        // back edge\n        $expected->createEdgeDirected($expected->getVertex(1), $expected->getVertex(0))->setFlow(0)\n                                                                      ->setCapacity(1)\n                                                                      ->setWeight(-3);\n\n        $this->assertGraphEquals($expected, $residual);\n    }\n\n    public function testResidualGraphCanOptionallyKeepNullCapacityForEdgeWithZeroFlow()\n    {\n        // 1 -[0/2]-> 2\n        $graph = new Graph();\n        $v1 = $graph->createVertex(1);\n        $v2 = $graph->createVertex(2);\n        $graph->createEdgeDirected($v1, $v2)->setFlow(0)->setCapacity(2);\n\n        // 1 -[0/2]-> 2\n        // ^          |\n        // \\--[0/0]---/\n        $expected = new Graph();\n        $v1 = $expected->createVertex(1);\n        $v2 = $expected->createVertex(2);\n        $expected->createEdgeDirected($v1, $v2)->setFlow(0)->setCapacity(2);\n        $expected->createEdgeDirected($v2, $v1)->setFlow(0)->setCapacity(0);\n\n        $alg = new ResidualGraph($graph);\n        $alg->setKeepNullCapacity(true);\n        $residual = $alg->createGraph();\n\n        $this->assertGraphEquals($expected, $residual);\n    }\n\n    public function testResidualGraphCanOptionallyKeepNullCapacityForEdgeWithZeroCapacityRemaining()\n    {\n        // 1 -[2/2]-> 2\n        $graph = new Graph();\n        $v1 = $graph->createVertex(1);\n        $v2 = $graph->createVertex(2);\n        $graph->createEdgeDirected($v1, $v2)->setFlow(2)->setCapacity(2);\n\n        // 1 -[0/0]-> 2\n        // ^          |\n        // \\--[0/2]---/\n        $expected = new Graph();\n        $v1 = $expected->createVertex(1);\n        $v2 = $expected->createVertex(2);\n        $expected->createEdgeDirected($v1, $v2)->setFlow(0)->setCapacity(0);\n        $expected->createEdgeDirected($v2, $v1)->setFlow(0)->setCapacity(2);\n\n        $alg = new ResidualGraph($graph);\n        $alg->setKeepNullCapacity(true);\n        $residual = $alg->createGraph();\n\n        $this->assertGraphEquals($expected, $residual);\n    }\n\n    public function testParallelEdgesCanBeMerged()\n    {\n        // 1 -[1/2]-> 2\n        // |          ^\n        // \\--[2/3]---/\n        $graph = new Graph();\n        $v1 = $graph->createVertex(1);\n        $v2 = $graph->createVertex(2);\n        $graph->createEdgeDirected($v1, $v2)->setFlow(1)->setCapacity(2);\n        $graph->createEdgeDirected($v1, $v2)->setFlow(2)->setCapacity(3);\n\n        // 1 -[0/2]-> 2\n        // ^          |\n        // \\--[0/3]---/\n        $expected = new Graph();\n        $v1 = $expected->createVertex(1);\n        $v2 = $expected->createVertex(2);\n        $expected->createEdgeDirected($v1, $v2)->setFlow(0)->setCapacity(2);\n        $expected->createEdgeDirected($v2, $v1)->setFlow(0)->setCapacity(3);\n\n        $alg = new ResidualGraph($graph);\n        $alg->setMergeParallelEdges(true);\n        $residual = $alg->createGraph();\n\n        $this->assertGraphEquals($expected, $residual);\n    }\n\n    /**\n     * expect exception for undirected edges\n     */\n    public function testInvalidUndirected()\n    {\n        $graph = new Graph();\n\n        $graph->createEdgeUndirected($graph->createVertex(), $graph->createVertex())->setFlow(1)\n                                                                  ->setCapacity(2);\n\n        $alg = new ResidualGraph($graph);\n\n        $this->setExpectedException('UnexpectedValueException');\n        $alg->createGraph();\n    }\n\n    /**\n     * expect exception for edges with no flow\n     */\n    public function testInvalidNoFlow()\n    {\n        $graph = new Graph();\n\n        $graph->createEdgeDirected($graph->createVertex(), $graph->createVertex())->setCapacity(1);\n\n        $alg = new ResidualGraph($graph);\n\n        $this->setExpectedException('UnexpectedValueException');\n        $alg->createGraph();\n    }\n\n    /**\n     * expect exception for edges with no capacity\n     */\n    public function testInvalidNoCapacity()\n    {\n        $graph = new Graph();\n\n        $graph->createEdgeDirected($graph->createVertex(), $graph->createVertex())->setFlow(1);\n\n        $alg = new ResidualGraph($graph);\n\n        $this->setExpectedException('UnexpectedValueException');\n        $alg->createGraph();\n    }\n\n}\n"
  },
  {
    "path": "tests/Search/BreadthFirstTest.php",
    "content": "<?php\n\nnamespace Graphp\\Tests\\Algorithms\\Search;\n\nuse Graphp\\Algorithms\\Search\\BreadthFirst;\nuse Graphp\\Graph\\Graph;\nuse Graphp\\Tests\\Algorithms\\TestCase;\n\nclass BreadthFirstTest extends TestCase\n{\n    public function providerMaxDepth()\n    {\n        return array(\n            \"simple path (no limit)\" => array(\n                \"edges\" => array(\n                    array(1, 2), array(2, 3), array(3, 4), array(4, 5),\n                ),\n                \"subject\" => 1,\n                \"maxDepth\" => null,\n                \"expected\" => array(1, 2, 3, 4, 5),\n            ),\n            \"simple path (limit = 0)\" => array(\n                \"edges\" => array(\n                    array(1, 2), array(2, 3), array(3, 4), array(4, 5),\n                ),\n                \"subject\" => 1,\n                \"maxDepth\" => 0,\n                \"expected\" => array(1),\n            ),\n            \"simple path (limit = 1)\" => array(\n                \"edges\" => array(\n                    array(1, 2), array(2, 3), array(3, 4), array(4, 5),\n                ),\n                \"subject\" => 1,\n                \"maxDepth\" => 1,\n                \"expected\" => array(1, 2),\n            ),\n        );\n    }\n\n    /**\n     * @dataProvider providerMaxDepth\n     */\n    public function testMaxDepth(array $edges, $subject, $maxDepth, array $expected)\n    {\n        $g = new Graph();\n        foreach ($edges as $e) {\n            $g->createEdgeDirected($g->createVertex($e[0], true), $g->createVertex($e[1], true));\n        }\n        $a = new BreadthFirst($g->getVertex($subject));\n        if ($maxDepth !== null) {\n            $v = $a->getVertices($maxDepth);\n        } else {\n            $v = $a->getVertices(); // Simulate default\n        }\n        $this->assertSame($expected, $v->getIds());\n    }\n}\n"
  },
  {
    "path": "tests/ShortestPath/BaseShortestPathTest.php",
    "content": "<?php\n\nnamespace Graphp\\Tests\\Algorithms\\ShortestPath;\n\nuse Graphp\\Algorithms\\ShortestPath\\Base as ShortestPathAlg;\nuse Graphp\\Graph\\Graph;\nuse Graphp\\Graph\\Vertex;\nuse Graphp\\Tests\\Algorithms\\TestCase;\n\nabstract class BaseShortestPathTest extends TestCase\n{\n    /**\n     *\n     * @param Vertex $vertex\n     * @return ShortestPathAlg\n     */\n    abstract protected function createAlg(Vertex $vertex);\n\n    abstract public function testGraphParallelNegative();\n\n    public function testGraphTrivial()\n    {\n        // 1\n        $graph = new Graph();\n        $v1 = $graph->createVertex(1);\n\n        $alg = $this->createAlg($v1);\n\n        $this->assertFalse($alg->hasVertex($v1));\n        //$this->assertEquals(0, $alg->getDistance($v1));\n        $this->assertEquals(array(), $alg->getDistanceMap());\n        $this->assertEquals(array(), $alg->getEdges()->getVector());\n        //$this->assertEquals(array(), $alg->getEdgesTo($v1));\n        $this->assertEquals(array(), $alg->getVertices()->getVector());\n        $this->assertEquals(array(), $alg->getVertices()->getIds());\n\n        $clone = $alg->createGraph();\n        $this->assertGraphEquals($graph,$clone);\n    }\n\n    public function testGraphSingleLoop()\n    {\n        // 1 -[4]> 1\n        $graph = new Graph();\n        $v1 = $graph->createVertex(1);\n        $e1 = $graph->createEdgeDirected($v1, $v1)->setWeight(4);\n\n        $alg = $this->createAlg($v1);\n\n        $this->assertEquals(array($e1), $alg->getEdges()->getVector());\n\n        $expectedWeight = $this->getExpectedWeight(array($e1));\n        $this->assertTrue($alg->hasVertex($v1));\n        $this->assertEquals($expectedWeight, $alg->getDistance($v1));\n        $this->assertEquals(array(1 => $expectedWeight), $alg->getDistanceMap());\n        $this->assertEquals(array($e1), $alg->getEdgesTo($v1)->getVector());\n        $this->assertEquals(array(1 => $v1), $alg->getVertices()->getMap());\n        $this->assertEquals(array(1), $alg->getVertices()->getIds());\n    }\n\n    public function testGraphCycle()\n    {\n        // 1 -[4]-> 2 -[2]-> 1\n        $graph = new Graph();\n        $v1 = $graph->createVertex(1);\n        $v2 = $graph->createVertex(2);\n        $e1 = $graph->createEdgeDirected($v1, $v2)->setWeight(4);\n        $e2 = $graph->createEdgeDirected($v2, $v1)->setWeight(2);\n\n        $alg = $this->createAlg($v1);\n\n        //$this->assertEquals(array($e2, $e1), $alg->getEdges());\n\n        $expectedWeight = $this->getExpectedWeight(array($e1));\n        $this->assertTrue($alg->hasVertex($v2));\n        $this->assertEquals(array($e1), $alg->getEdgesTo($v2)->getVector());\n        $this->assertEquals($expectedWeight, $alg->getDistance($v2));\n\n        $expectedWeight = $this->getExpectedWeight(array($e1, $e2));\n        $this->assertTrue($alg->hasVertex($v1));\n        $this->assertEquals(array($e1, $e2), $alg->getEdgesTo($v1)->getVector());\n        $this->assertEquals($expectedWeight, $alg->getDistance($v1));\n\n        $walk = $alg->getWalkTo($v1);\n        $this->assertCount(2, $walk->getEdges());\n    }\n\n    public function testIsolatedVertexIsNotReachable()\n    {\n        // 1, 2\n        $graph = new Graph();\n        $v1 = $graph->createVertex(1);\n        $v2 = $graph->createVertex(2);\n\n        $alg = $this->createAlg($v1);\n\n        $this->assertFalse($alg->hasVertex($v2));\n\n        $this->setExpectedException('OutOfBoundsException');\n        $alg->getEdgesTo($v2);\n    }\n\n    public function testSeparateGraphsAreNotReachable()\n    {\n        // 1\n        $graph1 = new Graph();\n        $vg1 = $graph1->createVertex(1);\n\n        $graph2 = new Graph();\n        $vg2 = $graph2->createVertex(1);\n\n        $alg = $this->createAlg($vg1);\n\n        $this->setExpectedException('OutOfBoundsException');\n        $alg->getEdgesTo($vg2);\n    }\n\n    public function testGraphUnweighted()\n    {\n        // 1 -> 2\n        $graph = new Graph();\n        $v1 = $graph->createVertex(1);\n        $v2 = $graph->createVertex(2);\n        $e1 = $graph->createEdgeDirected($v1, $v2);\n\n        $alg = $this->createAlg($v1);\n\n        $expectedWeight = $this->getExpectedWeight(array($e1));\n        $this->assertEquals($expectedWeight, $alg->getDistance($v2));\n        $this->assertEquals(array(2 => $expectedWeight), $alg->getDistanceMap());\n        $this->assertEquals(array($e1), $alg->getEdges()->getVector());\n        $this->assertEquals(array($e1), $alg->getEdgesTo($v2)->getVector());\n        $this->assertEquals(array(2), $alg->getVertices()->getIds());\n    }\n\n    public function testGraphTwoComponents()\n    {\n        // 1 -[10]-> 2\n        // 3 -[20]-> 4\n        $graph = new Graph();\n        $v1 = $graph->createVertex(1);\n        $v2 = $graph->createVertex(2);\n        $v3 = $graph->createVertex(3);\n        $v4 = $graph->createVertex(4);\n        $e1 = $graph->createEdgeDirected($v1, $v2)->setWeight(10);\n        $graph->createEdgeDirected($v3, $v4)->setWeight(20);\n\n        $alg = $this->createAlg($v1);\n\n        $expectedWeight = $this->getExpectedWeight(array($e1));\n        $this->assertEquals($expectedWeight, $alg->getDistance($v2));\n        $this->assertEquals(array(2 => $expectedWeight), $alg->getDistanceMap());\n        $this->assertEquals(array($e1), $alg->getEdges()->getVector());\n        // $this->assertEquals(array(), $alg->getEdgesTo($v1));\n        $this->assertEquals(array($e1), $alg->getEdgesTo($v2)->getVector());\n        $this->assertEquals(array(2 => $v2), $alg->getVertices()->getMap());\n        $this->assertEquals(array(2), $alg->getVertices()->getIds());\n    }\n\n    protected function getExpectedWeight($edges)\n    {\n        $sum = 0;\n        foreach ($edges as $edge) {\n            $sum += $edge->getWeight();\n        }\n        return $sum;\n    }\n}\n"
  },
  {
    "path": "tests/ShortestPath/BreadthFirstTest.php",
    "content": "<?php\n\nnamespace Graphp\\Tests\\Algorithms\\ShortestPath;\n\nuse Graphp\\Algorithms\\ShortestPath\\BreadthFirst;\nuse Graphp\\Graph\\Graph;\nuse Graphp\\Graph\\Vertex;\n\nclass BreadthFirstTest extends BaseShortestPathTest\n{\n    protected function createAlg(Vertex $vertex)\n    {\n        return new BreadthFirst($vertex);\n    }\n\n    public function testGraphParallelNegative()\n    {\n        // 1 -[10]-> 2\n        // |         ^\n        // \\--[-1]---/\n        $graph = new Graph();\n        $v1 = $graph->createVertex(1);\n        $v2 = $graph->createVertex(2);\n        $e1 = $graph->createEdgeDirected($v1, $v2)->setWeight(10);\n        $graph->createEdgeDirected($v1, $v2)->setWeight(-1);\n\n        $alg = $this->createAlg($v1);\n\n        $this->assertEquals(1, $alg->getDistance($v2));\n        $this->assertEquals(array(2 => 1), $alg->getDistanceMap());\n        $this->assertEquals(array($e1), $alg->getEdges()->getVector());\n        $this->assertEquals(array($e1), $alg->getEdgesTo($v2)->getVector());\n        $this->assertEquals(array(2 => $v2), $alg->getVertices()->getMap());\n        $this->assertEquals(array(2), $alg->getVertices()->getIds());\n    }\n\n    protected function getExpectedWeight($edges)\n    {\n        return \\count($edges);\n    }\n}\n"
  },
  {
    "path": "tests/ShortestPath/DijkstraTest.php",
    "content": "<?php\n\nnamespace Graphp\\Tests\\Algorithms\\ShortestPath;\n\nuse Graphp\\Algorithms\\ShortestPath\\Dijkstra;\nuse Graphp\\Graph\\Graph;\nuse Graphp\\Graph\\Vertex;\n\nclass DijkstraTest extends BaseShortestPathTest\n{\n    protected function createAlg(Vertex $vertex)\n    {\n        return new Dijkstra($vertex);\n    }\n\n    public function testGraphParallelNegative()\n    {\n        // 1 -[10]-> 2\n        // |         ^\n        // \\--[-1]---/\n        $graph = new Graph();\n        $v1 = $graph->createVertex(1);\n        $v2 = $graph->createVertex(2);\n        $graph->createEdgeDirected($v1, $v2)->setWeight(10);\n        $graph->createEdgeDirected($v1, $v2)->setWeight(-1);\n\n        $alg = $this->createAlg($v1);\n\n        $this->setExpectedException('UnexpectedValueException');\n        $alg->getEdges();\n    }\n}\n"
  },
  {
    "path": "tests/ShortestPath/MooreBellmanFordTest.php",
    "content": "<?php\n\nnamespace Graphp\\Tests\\Algorithms\\ShortestPath;\n\nuse Graphp\\Algorithms\\ShortestPath\\MooreBellmanFord;\nuse Graphp\\Graph\\Graph;\nuse Graphp\\Graph\\Vertex;\n\nclass MooreBellmanFordTest extends BaseShortestPathTest\n{\n    protected function createAlg(Vertex $vertex)\n    {\n        return new MooreBellmanFord($vertex);\n    }\n\n    public function testGraphParallelNegative()\n    {\n        // 1 -[10]-> 2\n        // |         ^\n        // \\--[-1]---/\n        $graph = new Graph();\n        $v1 = $graph->createVertex(1);\n        $v2 = $graph->createVertex(2);\n        $graph->createEdgeDirected($v1, $v2)->setWeight(10);\n        $e2 = $graph->createEdgeDirected($v1, $v2)->setWeight(-1);\n\n        $alg = $this->createAlg($v1);\n\n        // $this->assertEquals(0, $alg->getDistance($v1));\n        $this->assertEquals(-1, $alg->getDistance($v2));\n        $this->assertEquals(array(2 => -1), $alg->getDistanceMap());\n        $this->assertEquals(array($e2), $alg->getEdges()->getVector());\n        //$this->assertEquals(array(), $alg->getEdgesTo($v1));\n        $this->assertEquals(array($e2), $alg->getEdgesTo($v2)->getVector());\n        $this->assertEquals(array(2 => $v2), $alg->getVertices()->getMap());\n        $this->assertEquals(array(2), $alg->getVertices()->getIds());\n\n        return $alg;\n    }\n\n    /**\n     * @param MooreBellmanFord $alg\n     * @depends testGraphParallelNegative\n     */\n    public function testNoNegativeCycle(MooreBellmanFord $alg)\n    {\n        $this->setExpectedException('UnderflowException');\n        $alg->getCycleNegative();\n    }\n\n    public function testUndirectedNegativeWeightIsCycle()\n    {\n        // 1 -[-10]- 2\n        $graph = new Graph();\n        $v1 = $graph->createVertex(1);\n        $v2 = $graph->createVertex(2);\n        $graph->createEdgeUndirected($v1, $v2)->setWeight(-10);\n\n        $alg = $this->createAlg($v1);\n\n        $cycle = $alg->getCycleNegative();\n\n        $this->assertInstanceOf('Graphp\\Graph\\Walk', $cycle);\n    }\n\n    public function testLoopNegativeWeightIsCycle()\n    {\n        // 1 -[-10]-> 1\n        $graph = new Graph();\n        $v1 = $graph->createVertex(1);\n        $graph->createEdgeUndirected($v1, $v1)->setWeight(-10);\n\n        $alg = $this->createAlg($v1);\n\n        $cycle = $alg->getCycleNegative();\n\n        $this->assertInstanceOf('Graphp\\Graph\\Walk', $cycle);\n    }\n\n    public function testNegativeComponentHasCycle()\n    {\n        // 1 -[1]-> 2     3 --[-1]--> 4\n        //                ^           |\n        //                \\---[-2]----/\n        $graph = new Graph();\n        $v1 = $graph->createVertex(1);\n        $v2 = $graph->createVertex(2);\n        $v3 = $graph->createVertex(3);\n        $v4 = $graph->createVertex(4);\n        $graph->createEdgeDirected($v1, $v2)->setWeight(1);\n        $graph->createEdgeDirected($v3, $v4)->setWeight(-1);\n        $graph->createEdgeDirected($v4, $v3)->setWeight(-2);\n\n        // second component has a cycle\n        $alg = $this->createAlg($v3);\n        $cycle = $alg->getCycleNegative();\n        assert(isset($cycle));\n\n        // first component does not have a cycle\n        $alg = $this->createAlg($v1);\n\n        $this->setExpectedException('UnderflowException');\n        $alg->getCycleNegative();\n    }\n}\n"
  },
  {
    "path": "tests/SymmetricTest.php",
    "content": "<?php\n\nnamespace Graphp\\Tests\\Algorithms;\n\nuse Graphp\\Algorithms\\Symmetric as AlgorithmSymmetric;\nuse Graphp\\Graph\\Graph;\n\nclass SymmetricTest extends TestCase\n{\n    public function testGraphEmpty()\n    {\n        $graph = new Graph();\n\n        $alg = new AlgorithmSymmetric($graph);\n\n        $this->assertTrue($alg->isSymmetric());\n    }\n\n    public function testGraphIsolated()\n    {\n        $graph = new Graph();\n        $graph->createVertex(1);\n        $graph->createVertex(2);\n\n        $alg = new AlgorithmSymmetric($graph);\n\n        $this->assertTrue($alg->isSymmetric());\n    }\n\n    public function testGraphSingleArcIsNotSymmetricr()\n    {\n        // 1 -> 2\n        $graph = new Graph();\n        $graph->createEdgeDirected($graph->createVertex(1), $graph->createVertex(2));\n\n        $alg = new AlgorithmSymmetric($graph);\n\n        $this->assertFalse($alg->isSymmetric());\n    }\n\n    public function testGraphAntiparallelIsSymmetricr()\n    {\n        // 1 -> 2 -> 1\n        $graph = new Graph();\n        $graph->createEdgeDirected($graph->createVertex(1), $graph->createVertex(2));\n        $graph->createEdgeDirected($graph->getVertex(2), $graph->getVertex(1));\n\n        $alg = new AlgorithmSymmetric($graph);\n\n        $this->assertTrue($alg->isSymmetric());\n    }\n\n    public function testGraphSingleUndirectedIsSymmetricr()\n    {\n        // 1 -- 2\n        $graph = new Graph();\n        $graph->createEdgeUndirected($graph->createVertex(1), $graph->createVertex(2));\n\n        $alg = new AlgorithmSymmetric($graph);\n\n        $this->assertTrue($alg->isSymmetric());\n    }\n}\n"
  },
  {
    "path": "tests/TestCase.php",
    "content": "<?php\n\nnamespace Graphp\\Tests\\Algorithms;\n\nuse Graphp\\Graph\\Edge;\nuse Graphp\\Graph\\EdgeDirected;\nuse Graphp\\Graph\\Graph;\nuse Graphp\\Graph\\Vertex;\nuse PHPUnit\\Framework\\TestCase as BaseTestCase;\n\nclass TestCase extends BaseTestCase\n{\n    protected function assertGraphEquals(Graph $expected, Graph $actual)\n    {\n        $f = function(Graph $graph){\n            $ret = \\get_class($graph);\n            $ret .= PHP_EOL . 'vertices: ' . \\count($graph->getVertices());\n            $ret .= PHP_EOL . 'edges: ' . \\count($graph->getEdges());\n\n            return $ret;\n        };\n\n        // assert graph base parameters are equal\n        $this->assertEquals($f($expected), $f($actual));\n\n        // next, assert that all vertices in both graphs are the same\n        // each vertex has a unique ID, therefor it's easy to search a matching partner\n        // do not use assertVertexEquals() in order to not increase assertion counter\n\n        foreach ($expected->getVertices()->getMap() as $vid => $vertex) {\n            $other = $actual->getVertex($vid);\n            assert(isset($other));\n\n            if ($this->getVertexDump($vertex) !== $this->getVertexDump($vertex)) {\n                $this->fail();\n            }\n        }\n\n        // next, assert that all edges in both graphs are the same\n        // assertEdgeEquals() does not work, as the order of the edges is unknown\n        // therefor, build an array of edge dump and make sure each entry has a match\n\n        $edgesExpected = array();\n        foreach ($expected->getEdges() as $edge) {\n            $edgesExpected[] = $this->getEdgeDump($edge);\n        }\n\n        foreach ($actual->getEdges() as $edge) {\n            $dump = $this->getEdgeDump($edge);\n\n            $pos = \\array_search($dump, $edgesExpected, true);\n            if ($pos === false) {\n                $this->fail('given edge ' . $dump . ' not found');\n            } else {\n                unset($edgesExpected[$pos]);\n            }\n        }\n    }\n\n    protected function assertVertexEquals(Vertex $expected, Vertex $actual)\n    {\n        $this->assertEquals($this->getVertexDump($expected), $this->getVertexDump($actual));\n    }\n\n    protected function assertEdgeEquals(Edge $expected, Edge $actual)\n    {\n        $this->assertEquals($this->getEdgeDump($expected), $this->getEdgeDump($actual));\n    }\n\n    private function getVertexDump(Vertex $vertex)\n    {\n        $ret = \\get_class($vertex);\n\n        $ret .= PHP_EOL . 'id: ' . $vertex->getId();\n        $ret .= PHP_EOL . 'attributes: ' . \\json_encode($vertex->getAttributeBag()->getAttributes());\n        $ret .= PHP_EOL . 'balance: ' . $vertex->getBalance();\n        $ret .= PHP_EOL . 'group: ' . $vertex->getGroup();\n\n        return $ret;\n    }\n\n    private function getEdgeDump(Edge $edge)\n    {\n        $ret = \\get_class($edge) . ' ';\n        if ($edge instanceof EdgeDirected) {\n            $ret .= $edge->getVertexStart()->getId() . ' -> ' . $edge->getVertexEnd()->getId();\n        } else {\n            $vertices = $edge->getVertices()->getIds();\n            $ret .= $vertices[0] . ' -- ' . $vertices[1];\n        }\n        $ret .= PHP_EOL . 'flow: ' . $edge->getFlow();\n        $ret .= PHP_EOL . 'capacity: ' . $edge->getCapacity();\n        $ret .= PHP_EOL . 'weight: ' . $edge->getWeight();\n        $ret .= PHP_EOL . 'attributes: ' . \\json_encode($edge->getAttributeBag()->getAttributes());\n\n        return $ret;\n    }\n\n    public function setExpectedException($exception, $exceptionMessage = '', $exceptionCode = null)\n    {\n        if (method_exists($this, 'expectException')) {\n            // PHPUnit 6+\n            $this->expectException($exception);\n            if ($exceptionMessage !== '') {\n                $this->expectExceptionMessage($exceptionMessage);\n            }\n            if ($exceptionCode !== null) {\n                $this->expectExceptionCode($exceptionCode);\n            }\n        } else {\n            // legacy PHPUnit 4 - PHPUnit 5\n            parent::setExpectedException($exception, $exceptionMessage, $exceptionCode);\n        }\n    }\n}\n"
  },
  {
    "path": "tests/TopologicalSortTest.php",
    "content": "<?php\n\nnamespace Graphp\\Tests\\Algorithms;\n\nuse Graphp\\Algorithms\\TopologicalSort;\nuse Graphp\\Graph\\Graph;\n\nclass TopologicalSortTest extends TestCase\n{\n    public function testGraphEmpty()\n    {\n        $graph = new Graph();\n\n        $alg = new TopologicalSort($graph);\n\n        $this->assertInstanceOf('Graphp\\Graph\\Set\\Vertices', $alg->getVertices());\n        $this->assertTrue($alg->getVertices()->isEmpty());\n    }\n\n    public function testGraphIsolated()\n    {\n        $graph = new Graph();\n        $graph->createVertex(1);\n        $graph->createVertex(2);\n\n        $alg = new TopologicalSort($graph);\n\n        $this->assertSame(array($graph->getVertex(1), $graph->getVertex(2)), $alg->getVertices()->getVector());\n    }\n\n    public function testGraphSimple()\n    {\n        $graph = new Graph();\n        $graph->createEdgeDirected($graph->createVertex(1), $graph->createVertex(2));\n\n        $alg = new TopologicalSort($graph);\n\n        $this->assertSame(array($graph->getVertex(1), $graph->getVertex(2)), $alg->getVertices()->getVector());\n    }\n\n    public function testFailUndirected()\n    {\n        $graph = new Graph();\n        $graph->createEdgeUndirected($graph->createVertex(1), $graph->createVertex(2));\n\n        $alg = new TopologicalSort($graph);\n\n        $this->setExpectedException('UnexpectedValueException');\n        $alg->getVertices();\n    }\n\n    public function testFailLoop()\n    {\n        $graph = new Graph();\n        $graph->createEdgeDirected($graph->createVertex(1), $graph->getVertex(1));\n\n        $alg = new TopologicalSort($graph);\n\n        $this->setExpectedException('UnexpectedValueException');\n        $alg->getVertices();\n    }\n\n    public function testFailCycle()\n    {\n        $graph = new Graph();\n        $graph->createEdgeDirected($graph->createVertex(1), $graph->createVertex(2));\n        $graph->createEdgeDirected($graph->getVertex(2), $graph->getVertex(1));\n\n        $alg = new TopologicalSort($graph);\n\n        $this->setExpectedException('UnexpectedValueException');\n        $alg->getVertices();\n    }\n}\n"
  },
  {
    "path": "tests/TravelingSalesmanProblem/BruteforceTest.php",
    "content": "<?php\n\nnamespace Graphp\\Tests\\Algorithms\\TravelingSalesmanProblem;\n\nuse Graphp\\Algorithms\\TravelingSalesmanProblem\\Bruteforce;\nuse Graphp\\Graph\\Graph;\nuse Graphp\\Tests\\Algorithms\\TestCase;\n\nclass BruteforceTest extends TestCase\n{\n    public function testGetWeightReturnsExpectedWeightForSimpleCycle()\n    {\n        $graph = new Graph();\n        $a = $graph->createVertex();\n        $b = $graph->createVertex();\n        $c = $graph->createVertex();\n        $graph->createEdgeDirected($a, $b)->setWeight(1);\n        $graph->createEdgeDirected($b, $c)->setWeight(2);\n        $graph->createEdgeDirected($c, $a)->setWeight(3);\n\n        $alg = new Bruteforce($graph);\n\n        $this->assertEquals(6, $alg->getWeight());\n    }\n\n    public function testSetUpperLimitMstSetsExactLimitForSimpleCycle()\n    {\n        $graph = new Graph();\n        $a = $graph->createVertex();\n        $b = $graph->createVertex();\n        $c = $graph->createVertex();\n        $graph->createEdgeDirected($a, $b)->setWeight(1);\n        $graph->createEdgeDirected($b, $c)->setWeight(2);\n        $graph->createEdgeDirected($c, $a)->setWeight(3);\n\n        $alg = new Bruteforce($graph);\n        $alg->setUpperLimitMst();\n\n        $ref = new \\ReflectionProperty($alg, 'upperLimit');\n        $ref->setAccessible(true);\n\n        $this->assertEquals(6, $ref->getValue($alg));\n    }\n}\n"
  },
  {
    "path": "tests/Tree/BaseDirectedTest.php",
    "content": "<?php\n\nnamespace Graphp\\Tests\\Algorithms\\Tree;\n\nuse Graphp\\Algorithms\\Tree\\BaseDirected;\nuse Graphp\\Graph\\Graph;\nuse Graphp\\Graph\\Set\\Vertices;\nuse Graphp\\Tests\\Algorithms\\TestCase;\n\nabstract class BaseDirectedTest extends TestCase\n{\n    /**\n     *\n     * @param Graph $graph\n     * @return BaseDirected\n     */\n    abstract protected function createTreeAlg(Graph $graph);\n\n    /**\n     * @return Graph\n     */\n    abstract protected function createGraphNonTree();\n\n    /**\n     * @return Graph\n     */\n    abstract protected function createGraphTree();\n\n    /**\n     * @return Graph\n     */\n    abstract protected function createGraphParallelEdge();\n\n    public function testNullGraph()\n    {\n        $graph = new Graph();\n\n        $tree = $this->createTreeAlg($graph);\n        $this->assertFalse($tree->isTree());\n        $this->assertTrue($tree->getVerticesLeaf()->isEmpty());\n        $this->assertTrue($tree->getVerticesInternal()->isEmpty());\n\n        return $tree;\n    }\n\n    /**\n     * @param BaseDirected $tree\n     * @depends testNullGraph\n     */\n    public function testEmptyGraphDoesNotHaveRootVertex(BaseDirected $tree)\n    {\n        $this->setExpectedException('UnderflowException');\n        $tree->getVertexRoot();\n    }\n\n    /**\n     * @param BaseDirected $tree\n     * @depends testNullGraph\n     */\n    public function testEmptyGraphDoesNotHaveDegree(BaseDirected $tree)\n    {\n        $this->setExpectedException('UnderflowException');\n        $tree->getDegree();\n    }\n\n    /**\n     * @param BaseDirected $tree\n     * @depends testNullGraph\n     */\n    public function testEmptyGraphDoesNotHaveHeight(BaseDirected $tree)\n    {\n        $this->setExpectedException('UnderflowException');\n        $tree->getHeight();\n    }\n\n    public function testGraphTree()\n    {\n        $graph = $this->createGraphTree();\n        $root = $graph->getVertices()->getVertexFirst();\n\n        $nonRoot = $graph->getVertices()->getMap();\n        unset($nonRoot[$root->getId()]);\n        $nonRoot = new Vertices($nonRoot);\n\n        $c1 = $nonRoot->getVertexFirst();\n\n        $tree = $this->createTreeAlg($graph);\n\n        $this->assertTrue($tree->isTree());\n        $this->assertSame($root, $tree->getVertexRoot());\n        $this->assertSame($graph->getVertices()->getVector(), $tree->getVerticesSubtree($root)->getVector());\n        $this->assertSame($nonRoot->getVector(), $tree->getVerticesChildren($root)->getVector());\n        $this->assertSame($nonRoot->getVector(), $tree->getVerticesDescendant($root)->getVector());\n        $this->assertSame($nonRoot->getVector(), $tree->getVerticesLeaf()->getVector());\n        $this->assertSame(array(), $tree->getVerticesInternal()->getVector());\n        $this->assertSame($root, $tree->getVertexParent($c1));\n        $this->assertSame(array(), $tree->getVerticesChildren($c1)->getVector());\n        $this->assertSame(array(), $tree->getVerticesDescendant($c1)->getVector());\n        $this->assertSame(array($c1), $tree->getVerticesSubtree($c1)->getVector());\n        $this->assertEquals(2, $tree->getDegree());\n        $this->assertEquals(0, $tree->getDepthVertex($root));\n        $this->assertEquals(1, $tree->getDepthVertex($c1));\n        $this->assertEquals(1, $tree->getHeight());\n        $this->assertEquals(1, $tree->getHeightVertex($root));\n        $this->assertEquals(0, $tree->getHeightvertex($c1));\n\n        return $tree;\n    }\n\n    /**\n     *\n     * @param BaseDirected $tree\n     * @depends testGraphTree\n     */\n    public function testGraphTreeRootDoesNotHaveParent(BaseDirected $tree)\n    {\n        $root = $tree->getVertexRoot();\n\n        $this->setExpectedException('UnderflowException');\n        $tree->getVertexParent($root);\n    }\n\n    public function testNonTree()\n    {\n        $graph = $this->createGraphNonTree();\n\n        $tree = $this->createTreeAlg($graph);\n\n        $this->assertFalse($tree->isTree());\n    }\n\n    public function testNonTreeVertexHasMoreThanOneParent()\n    {\n        $graph = $this->createGraphNonTree();\n\n        $tree = $this->createTreeAlg($graph);\n\n        $this->setExpectedException('UnexpectedValueException');\n        $tree->getVertexParent($graph->getVertex('v3'));\n    }\n\n    public function testGraphWithParallelEdgeIsNotTree()\n    {\n        $graph = $this->createGraphParallelEdge();\n\n        $tree = $this->createTreeAlg($graph);\n\n        $this->assertFalse($tree->isTree());\n    }\n\n    public function testGraphWithLoopIsNotTree()\n    {\n        // v1 -> v1\n        $graph = new Graph();\n        $graph->createEdgeDirected($graph->createVertex('v1'), $graph->getVertex('v1'));\n\n        $tree = $this->createTreeAlg($graph);\n\n        $this->assertFalse($tree->isTree());\n    }\n\n    public function testGraphWithLoopCanNotGetSubgraph()\n    {\n        // v1 -> v1\n        $graph = new Graph();\n        $graph->createEdgeDirected($graph->createVertex('v1'), $graph->getVertex('v1'));\n\n        $tree = $this->createTreeAlg($graph);\n\n        $this->setExpectedException('UnexpectedValueException');\n        $tree->getVerticesSubtree($graph->getVertex('v1'));\n    }\n\n    public function testGraphWithUndirectedEdgeIsNotTree()\n    {\n        // v1 -- v2\n        $graph = new Graph();\n        $graph->createEdgeUndirected($graph->createVertex('v1'), $graph->createVertex('v2'));\n\n        $tree = $this->createTreeAlg($graph);\n\n        $this->assertFalse($tree->isTree());\n    }\n\n    public function testGraphWithMixedEdgesIsNotTree()\n    {\n        // v1 -> v2 -- v3 -> v4\n        $graph = new Graph();\n        $graph->createEdgeDirected($graph->createVertex('v1'), $graph->createVertex('v2'));\n        $graph->createEdgeUndirected($graph->getVertex('v2'), $graph->createVertex('v3'));\n        $graph->createEdgeDirected($graph->getVertex('v3'), $graph->createVertex('v4'));\n\n        $tree = $this->createTreeAlg($graph);\n\n        $this->assertFalse($tree->isTree());\n    }\n}\n"
  },
  {
    "path": "tests/Tree/InTreeTest.php",
    "content": "<?php\n\nnamespace Graphp\\Tests\\Algorithms\\Tree;\n\nuse Graphp\\Algorithms\\Tree\\InTree;\nuse Graphp\\Graph\\Graph;\n\nclass InTreeTest extends BaseDirectedTest\n{\n    protected function createGraphTree()\n    {\n        // c1 -> root <- c2\n        $graph = new Graph();\n        $root = $graph->createVertex();\n\n        $c1 = $graph->createVertex();\n        $graph->createEdgeDirected($c1, $root);\n\n        $c2 = $graph->createVertex();\n        $graph->createEdgeDirected($c2, $root);\n\n        return $graph;\n    }\n\n    protected function createTreeAlg(Graph $graph)\n    {\n        return new InTree($graph);\n    }\n\n    protected function createGraphNonTree()\n    {\n        // v1 -> v2 <- v3 -> v4\n        $graph = new Graph();\n        $graph->createEdgeDirected($graph->createVertex('v1'), $graph->createVertex('v2'));\n        $graph->createEdgeDirected($graph->createVertex('v3'), $graph->getVertex('v2'));\n        $graph->createEdgeDirected($graph->getVertex('v3'), $graph->createVertex('v4'));\n\n        return $graph;\n    }\n\n    protected function createGraphParallelEdge()\n    {\n        // v1 <- v2, v1 <- v2\n        $graph = new Graph();\n        $graph->createEdgeDirected($graph->createVertex('v2'), $graph->createVertex('v1'));\n        $graph->createEdgeDirected($graph->getVertex('v2'), $graph->getVertex('v1'));\n\n        return $graph;\n    }\n}\n"
  },
  {
    "path": "tests/Tree/OutTreeTest.php",
    "content": "<?php\n\nnamespace Graphp\\Tests\\Algorithms\\Tree;\n\nuse Graphp\\Algorithms\\Tree\\OutTree;\nuse Graphp\\Graph\\Graph;\n\nclass OutTreeTest extends BaseDirectedTest\n{\n    protected function createGraphTree()\n    {\n        // c1 <- root -> c2\n        $graph = new Graph();\n        $root = $graph->createVertex();\n\n        $c1 = $graph->createVertex();\n        $graph->createEdgeDirected($root, $c1);\n\n        $c2 = $graph->createVertex();\n        $graph->createEdgeDirected($root, $c2);\n\n        return $graph;\n    }\n\n    protected function createTreeAlg(Graph $graph)\n    {\n        return new OutTree($graph);\n    }\n\n    protected function createGraphNonTree()\n    {\n        // v1 -> v3 <- v2 -> v4\n        $graph = new Graph();\n        $graph->createEdgeDirected($graph->createVertex('v1'), $graph->createVertex('v3'));\n        $graph->createEdgeDirected($graph->createVertex('v2'), $graph->getVertex('v3'));\n        $graph->createEdgeDirected($graph->getVertex('v2'), $graph->createVertex('v4'));\n\n        return $graph;\n    }\n\n    protected function createGraphParallelEdge()\n    {\n        // v1 -> v2, v1 -> v2\n        $graph = new Graph();\n        $graph->createEdgeDirected($graph->createVertex('v1'), $graph->createVertex('v2'));\n        $graph->createEdgeDirected($graph->getVertex('v1'), $graph->getVertex('v2'));\n\n        return $graph;\n    }\n}\n"
  },
  {
    "path": "tests/Tree/UndirectedTest.php",
    "content": "<?php\n\nnamespace Graphp\\Tests\\Algorithms\\Tree;\n\nuse Graphp\\Algorithms\\Tree\\Undirected;\nuse Graphp\\Graph\\Graph;\nuse Graphp\\Tests\\Algorithms\\TestCase;\n\nclass UndirectedTest extends TestCase\n{\n    protected function createTree(Graph $graph)\n    {\n        return new Undirected($graph);\n    }\n\n    public function testNullGraph()\n    {\n        $graph = new Graph();\n\n        $tree = $this->createTree($graph);\n\n        $this->assertFalse($tree->isTree());\n        $this->assertTrue($tree->getVerticesInternal()->isEmpty());\n        $this->assertTrue($tree->getVerticesLeaf()->isEmpty());\n    }\n\n    public function testGraphTrivial()\n    {\n        $graph = new Graph();\n        $graph->createVertex('v1');\n\n        $tree = $this->createTree($graph);\n        $this->assertTrue($tree->isTree());\n        $this->assertSame(array(), $tree->getVerticesInternal()->getVector());\n        $this->assertSame(array(), $tree->getVerticesLeaf()->getVector());\n    }\n\n    public function testGraphSimplePair()\n    {\n        // v1 -- v2\n        $graph = new Graph();\n        $graph->createEdgeUndirected($graph->createVertex('v1'), $graph->createVertex('v2'));\n\n        $tree = $this->createTree($graph);\n        $this->assertTrue($tree->isTree());\n        $this->assertSame(array(), $tree->getVerticesInternal()->getVector());\n        $this->assertSame($graph->getVertices()->getVector(), $tree->getVerticesLeaf()->getVector());\n    }\n\n    public function testGraphSimpleLine()\n    {\n        // v1 -- v2 -- v3\n        $graph = new Graph();\n        $graph->createEdgeUndirected($graph->createVertex('v1'), $graph->createVertex('v2'));\n        $graph->createEdgeUndirected($graph->getVertex('v2'), $graph->createVertex('v3'));\n\n        $tree = $this->createTree($graph);\n        $this->assertTrue($tree->isTree());\n        $this->assertSame(array($graph->getVertex('v2')), $tree->getVerticesInternal()->getVector());\n        $this->assertSame(array($graph->getVertex('v1'), $graph->getVertex('v3')), $tree->getVerticesLeaf()->getVector());\n    }\n\n    public function testGraphPairParallelIsNotTree()\n    {\n        // v1 -- v2 -- v1\n        $graph = new Graph();\n        $graph->createEdgeUndirected($graph->createVertex('v1'), $graph->createVertex('v2'));\n        $graph->createEdgeUndirected($graph->getVertex('v1'), $graph->getVertex('v2'));\n\n        $tree = $this->createTree($graph);\n        $this->assertFalse($tree->isTree());\n    }\n\n    public function testGraphLoopIsNotTree()\n    {\n        // v1 -- v1\n        $graph = new Graph();\n        $graph->createEdgeUndirected($graph->createVertex('v1'), $graph->getVertex('v1'));\n\n        $tree = $this->createTree($graph);\n        $this->assertFalse($tree->isTree());\n    }\n\n    public function testGraphCycleIsNotTree()\n    {\n        // v1 -- v2 -- v3 -- v1\n        $graph = new Graph();\n        $graph->createEdgeUndirected($graph->createVertex('v1'), $graph->createVertex('v2'));\n        $graph->createEdgeUndirected($graph->getVertex('v2'), $graph->createVertex('v3'));\n        $graph->createEdgeUndirected($graph->getVertex('v3'), $graph->getVertex('v1'));\n\n        $tree = $this->createTree($graph);\n        $this->assertFalse($tree->isTree());\n    }\n\n    public function testGraphDirectedIsNotTree()\n    {\n        // v1 -> v2\n        $graph = new Graph();\n        $graph->createEdgeDirected($graph->createVertex('v1'), $graph->createVertex('v2'));\n\n        $tree = $this->createTree($graph);\n        $this->assertFalse($tree->isTree());\n    }\n\n    public function testGraphMixedIsNotTree()\n    {\n        // v1 -- v2 -> v3\n        $graph = new Graph();\n        $graph->createEdgeUndirected($graph->createVertex('v1'), $graph->createVertex('v2'));\n        $graph->createEdgeDirected($graph->getVertex('v2'), $graph->createVertex('v3'));\n\n        $tree = $this->createTree($graph);\n        $this->assertFalse($tree->isTree());\n    }\n}\n"
  },
  {
    "path": "tests/WeightTest.php",
    "content": "<?php\n\nnamespace Graphp\\Tests\\Algorithms;\n\nuse Graphp\\Algorithms\\Weight as AlgorithmWeight;\nuse Graphp\\Graph\\Graph;\n\nclass WeightTest extends TestCase\n{\n    public function testGraphEmpty()\n    {\n        $graph = new Graph();\n\n        $alg = new AlgorithmWeight($graph);\n\n        $this->assertEquals(null, $alg->getWeight());\n        $this->assertEquals(0, $alg->getWeightFlow());\n        $this->assertEquals(null, $alg->getWeightMin());\n        $this->assertFalse($alg->isWeighted());\n\n        return $graph;\n    }\n\n    /**\n     *\n     * @param Graph $graph\n     * @depends testGraphEmpty\n     */\n    public function testGraphSimple(Graph $graph)\n    {\n        // 1 -> 2\n        $graph->createEdgeDirected($graph->createVertex(1), $graph->createVertex(2))->setWeight(3)->setFlow(4);\n\n        $alg = new AlgorithmWeight($graph);\n\n        $this->assertEquals(3, $alg->getWeight());\n        $this->assertEquals(12, $alg->getWeightFlow());\n        $this->assertEquals(3, $alg->getWeightMin());\n        $this->assertTrue($alg->isWeighted());\n\n        return $graph;\n    }\n\n    /**\n     *\n     * @param Graph $graph\n     * @depends testGraphSimple\n     */\n    public function testGraphWithUnweightedEdges(Graph $graph)\n    {\n        $graph->createEdgeDirected($graph->createVertex(5), $graph->createVertex(6))->setFlow(7);\n\n        $alg = new AlgorithmWeight($graph);\n\n        $this->assertEquals(3, $alg->getWeight());\n        $this->assertEquals(12, $alg->getWeightFlow());\n        $this->assertEquals(3, $alg->getWeightMin());\n        $this->assertTrue($alg->isWeighted());\n    }\n}\n"
  }
]