Skip to content
Snippets Groups Projects
Commit e64a4c79 authored by Angie Byron's avatar Angie Byron
Browse files

Issue #2498599 by Cottser, naveenvalecha, webchick, karolus, cilefen: Remove...

Issue #2498599 by Cottser, naveenvalecha, webchick, karolus, cilefen: Remove sdboyer/gliph since it is unused by core
parent a8f8b33e
No related branches found
No related tags found
2 merge requests!7452Issue #1797438. HTML5 validation is preventing form submit and not fully...,!789Issue #3210310: Adjust Database API to remove deprecated Drupal 9 code in Drupal 10
Showing
with 1 addition and 1744 deletions
......@@ -5,7 +5,6 @@
"license": "GPL-2.0+",
"require": {
"php": ">=5.5.9",
"sdboyer/gliph": "0.1.*",
"symfony/class-loader": "2.7.*",
"symfony/console": "2.7.*",
"symfony/css-selector": "2.7.*",
......
......@@ -4,7 +4,7 @@
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file",
"This file is @generated automatically"
],
"hash": "34a206d03b9060c6f1b2895c0517792c",
"hash": "3708d8fdb54957e5ce661cda1df88353",
"packages": [
{
"name": "behat/mink",
......@@ -1637,54 +1637,6 @@
],
"time": "2012-12-21 11:40:51"
},
{
"name": "sdboyer/gliph",
"version": "0.1.8",
"source": {
"type": "git",
"url": "https://github.com/sdboyer/gliph.git",
"reference": "db9e4b77622f91e2d338cc45f83c2cd0e3cf0e1e"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/sdboyer/gliph/zipball/db9e4b77622f91e2d338cc45f83c2cd0e3cf0e1e",
"reference": "db9e4b77622f91e2d338cc45f83c2cd0e3cf0e1e",
"shasum": ""
},
"require": {
"php": ">=5.3"
},
"require-dev": {
"phpunit/phpunit": "3.7.*",
"satooshi/php-coveralls": "0.6.*"
},
"type": "library",
"autoload": {
"psr-0": {
"Gliph": "src/"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Sam Boyer",
"email": "tech@samboyer.org"
}
],
"description": "A graph library for PHP.",
"homepage": "http://github.com/sdboyer/gliph",
"keywords": [
"gliph",
"graph",
"library",
"php",
"spl"
],
"time": "2014-08-03 14:34:47"
},
{
"name": "sebastian/comparator",
"version": "1.1.1",
......
......@@ -12,7 +12,6 @@
'Stack' => array($vendorDir . '/stack/builder/src'),
'Psr\\Log\\' => array($vendorDir . '/psr/log'),
'Prophecy\\' => array($vendorDir . '/phpspec/prophecy/src'),
'Gliph' => array($vendorDir . '/sdboyer/gliph/src'),
'Egulias\\' => array($vendorDir . '/egulias/email-validator/src'),
'EasyRdf_' => array($vendorDir . '/easyrdf/easyrdf/lib'),
'Doctrine\\Instantiator\\' => array($vendorDir . '/doctrine/instantiator/src'),
......
......@@ -423,56 +423,6 @@
"timer"
]
},
{
"name": "sdboyer/gliph",
"version": "0.1.8",
"version_normalized": "0.1.8.0",
"source": {
"type": "git",
"url": "https://github.com/sdboyer/gliph.git",
"reference": "db9e4b77622f91e2d338cc45f83c2cd0e3cf0e1e"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/sdboyer/gliph/zipball/db9e4b77622f91e2d338cc45f83c2cd0e3cf0e1e",
"reference": "db9e4b77622f91e2d338cc45f83c2cd0e3cf0e1e",
"shasum": ""
},
"require": {
"php": ">=5.3"
},
"require-dev": {
"phpunit/phpunit": "3.7.*",
"satooshi/php-coveralls": "0.6.*"
},
"time": "2014-08-03 14:34:47",
"type": "library",
"installation-source": "dist",
"autoload": {
"psr-0": {
"Gliph": "src/"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Sam Boyer",
"email": "tech@samboyer.org"
}
],
"description": "A graph library for PHP.",
"homepage": "http://github.com/sdboyer/gliph",
"keywords": [
"gliph",
"graph",
"library",
"php",
"spl"
]
},
{
"name": "psr/log",
"version": "1.0.0",
......
Copyright (c) Sam Boyer
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is furnished
to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
# Gliph
[![Build Status](https://travis-ci.org/sdboyer/gliph.png?branch=php53)](https://travis-ci.org/sdboyer/gliph)
[![Latest Stable Version](https://poser.pugx.org/sdboyer/gliph/v/stable.png)](https://packagist.org/packages/sdboyer/gliph)
[![Coverage Status](https://coveralls.io/repos/sdboyer/gliph/badge.png?branch=php53)](https://coveralls.io/r/sdboyer/gliph?branch=php53)
Gliph is a **g**raph **li**brary for **PH**P. It provides graph building blocks and datastructures for use by other PHP applications. It is (currently) designed for use with in-memory graphs, not for interaction with a graph database like [Neo4J](http://neo4j.org/).
Gliph aims for both sane interfaces and performant implementation - at least, as performant as can be hoped for a PHP graph library. This does require knowing enough about graphs to know what type is appropriate for your use case, but we are aiming to provide helpers that simplify those choices.
## Core Concepts
Gliph has several components that work together: graph classes, algorithms, and visitors. Generally speaking, Gliph is patterned after the [C++ Boost Graph Library](http://www.boost.org/libs/graph/doc); reading their documentation can yield a lot of insight into how Gliph is intended to work.
Note that Gliph is currently written for compatibility with PHP 5.3, but it is intended to port the library to PHP 5.5. The availability of traits, non-scalar keys in iterators, and generators will considerably change and improve both the internal and public-facing implementations.
### Graphs
There are a number of different strategies for representing graphs; these strategies are more or less efficient depending on certain properties the graph, and what needs to be done to the graph. The approach taken in Gliph is to offer a roughly consistent 'Graph' interface that is common to all these different strategies. The strategies will have varying levels of efficiency at meeting this common interface, so it is the responsibility of the user to select a graph implementation that is appropriate for their use case. This approach draws heavily from the [taxonomy of graphs](http://www.boost.org/doc/libs/1_54_0/libs/graph/doc/graph_concepts.html) established by the BGL.
Gliph currently implements only an adjacency list graph strategy, in both directed and undirected flavors. Adjacency lists offer efficient access to out-edges, but inefficient access to in-edges (in a directed graph - in an undirected graph, in-edges and out-edges are the same). Adjacency lists and are generally more space-efficient for sparse graphs.
### Algorithms
Gliph provides various algorithms that can be run on graph objects. These algorithms interact with the graph by making calls to methods defined in the assorted Graph interfaces. If a graph implements the interface type-hinted by a particular algorithm, then the algorithm can run on that graph. But the efficiency of the algorithm will be largely determined by how efficiently that graph implementation can meet the requirements of the interface. Adjacency lists, for example, are not terribly efficient at providing a list of all edges in a graph, but are very good at single-vertex-centric operations.
Gliph's algorithms are typically implemented quite sparsely (especially traversers) - they seek to implement the simplest, most generic version of an algorithm. They also may not return any output, as that work is left to Visitors.
### Visitors
Most algorithms require a visitor object to be provided. The visitor conforms to an interface specified by the algorithm, and the algorithm will call the visitor at certain choice points during its execution. This allows the algorithms to stay highly generic, while visitors can be tailored to a more specific purpose.
For example, a ```DepthFirst``` visitor might be used to calculate vertex reach, or generate a topologically sorted list. Each of these are things that a depth-first graph traversal can do. But the work of doing so is left to the visitor so that only one traversal algorithm is needed, and that algorithm is as cheap (memory and cycles) as possible.
## TODOs
Lots. But, to start with:
- Port to, or provide a parallel implementation in, PHP 5.5. Generators and non-scalar keys from iterators make this all SO much better. In doing that, also shift as much over to traits as possible.
- Implement a generic breadth-first algorithm and its corresponding visitors.
- Implement a generic iterative deepening depth-first algorithm, and its corresponding visitors.
- Implement other popular connected components algorithms, as well as some shortest path algorithms (starting with Dijkstra)
- Write up some examples showing how to actually use the library.
- Extend the ```DepthFirst::traverse()``` algorithm and ```DepthFirstVisitorInterface``` to allow the visitor to stop the traversal. useful if, e.g., a search is being performed and the desired vertex has been found.
## Acknowledgements
This library draws heavy inspiration from the [C++ Boost Graph Library](http://www.boost.org/libs/graph/doc).
## License
MIT
{
"name": "sdboyer/gliph",
"description": "A graph library for PHP.",
"license": "MIT",
"keywords": ["gliph", "library", "php", "spl", "graph"],
"homepage": "http://github.com/sdboyer/gliph",
"type": "library",
"authors": [
{
"name": "Sam Boyer",
"email": "tech@samboyer.org"
}
],
"require": {
"php": ">=5.3"
},
"require-dev": {
"satooshi/php-coveralls": "0.6.*",
"phpunit/phpunit": "3.7.*"
},
"autoload": {
"psr-0": { "Gliph": "src/" }
}
}
This diff is collapsed.
<?php
namespace Gliph\Algorithm;
use Gliph\Graph\DirectedGraph;
use Gliph\Visitor\TarjanSCCVisitor;
/**
* Contains algorithms for discovering connected components.
*/
class ConnectedComponent {
/**
* Finds connected components in the provided directed graph.
*
* @param DirectedGraph $graph
* The DirectedGraph to search for connected components.
* @param TarjanSCCVisitor $visitor
* The visitor that will collect and store the connected components. One
* will be created if not provided.
*
* @return TarjanSCCVisitor
* The finalized visitor.
*/
public static function tarjan_scc(DirectedGraph $graph, TarjanSCCVisitor $visitor = NULL) {
$visitor = $visitor ?: new TarjanSCCVisitor();
$counter = 0;
$stack = array();
$indices = new \SplObjectStorage();
$lowlimits = new \SplObjectStorage();
$visit = function($vertex) use (&$visit, &$counter, $graph, &$stack, $indices, $lowlimits, $visitor) {
$indices->attach($vertex, $counter);
$lowlimits->attach($vertex, $counter);
$stack[] = $vertex;
$counter++;
$graph->eachAdjacent($vertex, function ($to) use (&$visit, $vertex, $indices, $lowlimits, &$stack) {
if (!$indices->contains($to)) {
$visit($to);
$lowlimits[$vertex] = min($lowlimits[$vertex], $lowlimits[$to]);
}
else if (in_array($to, $stack, TRUE)) {
$lowlimits[$vertex] = min($lowlimits[$vertex], $indices[$to]);
}
});
if ($lowlimits[$vertex] === $indices[$vertex]) {
$visitor->newComponent();
do {
$other = array_pop($stack);
$visitor->addToCurrentComponent($other);
} while ($other != $vertex);
}
};
$graph->eachVertex(function($vertex) use (&$visit, $indices) {
if (!$indices->contains($vertex)) {
$visit($vertex);
}
});
return $visitor;
}
}
\ No newline at end of file
<?php
/**
* @file
* Contains \Gliph\Exception\InvalidVertexTypeException.
*/
namespace Gliph\Exception;
/**
* Error thrown when attempting to add a vertex of an invalid type.
*/
class InvalidVertexTypeException extends \Exception {}
\ No newline at end of file
<?php
/**
* @file
* Contains \Gliph\Exception\NonexistentVertexException.
*/
namespace Gliph\Exception;
/**
* Exception thrown when a vertex not present in a Graph is provided as a
* parameter to a method that requires the vertex to be present (e.g., removing
* the vertex, checking the edges of that vertex).
*/
class NonexistentVertexException extends \OutOfBoundsException {}
\ No newline at end of file
<?php
namespace Gliph\Exception;
/**
* OutOfRangeException for Gliph.
*/
class OutOfRangeException extends \OutOfRangeException {}
\ No newline at end of file
<?php
namespace Gliph\Exception;
/**
* RuntimeException for Gliph.
*/
class RuntimeException extends \RuntimeException {}
<?php
namespace Gliph\Exception;
/**
* An exception thrown when a method is called on a visitor that it does not
* expect in its current state.
*
* For example, this exception should be thrown by a visitor if it has a method
* that returns data produced by a full traversal algorithm, but the algorithm
* has not yet informed the visitor that it is done running.
*/
class WrongVisitorStateException extends \LogicException {}
\ No newline at end of file
<?php
namespace Gliph\Graph;
use Gliph\Exception\InvalidVertexTypeException;
use Gliph\Exception\NonexistentVertexException;
/**
* A graph, represented as an adjacency list.
*
* Adjacency lists store vertices directly, and edges relative to the vertices
* they connect. That means there is no overall list of edges in the graph; only
* a list of the graph's vertices. In this implementation, that list is keyed by
* vertex, with the value being a list of all the vertices to which that vertex
* is adjacent - hence, "adjacency list."
*
* Consequently, this structure offers highly efficient access to vertices, but
* less efficient access to edges.
*
* In an undirected graph, the edges are stored in both vertices' adjacency
* lists. In a directed graph, only the out-edges are stored in each vertex's
* adjacency list. This makes accessing in-edge information in a directed graph
* highly inefficient.
*/
abstract class AdjacencyList implements MutableGraph {
/**
* Contains the adjacency list of vertices.
*
* @var \SplObjectStorage
*/
protected $vertices;
/**
* Bookkeeper for nested iteration.
*
* @var \SplObjectStorage
*/
protected $walking;
/**
* Count of the number of edges in the graph.
*
* We keep track because calculating it on demand is expensive.
*
* @var int
*/
protected $size = 0;
public function __construct() {
$this->vertices = new \SplObjectStorage();
$this->walking = new \SplObjectStorage();
}
/**
* {@inheritdoc}
*/
public function addVertex($vertex) {
if (!is_object($vertex)) {
throw new InvalidVertexTypeException('Vertices must be objects; non-object provided.');
}
if (!$this->hasVertex($vertex)) {
$this->vertices[$vertex] = new \SplObjectStorage();
}
return $this;
}
/**
* {@inheritdoc}
*/
public function eachAdjacent($vertex, $callback) {
if (!$this->hasVertex($vertex)) {
throw new NonexistentVertexException('Vertex is not in graph; cannot iterate over its adjacent vertices.');
}
$set = $this->_getTraversableSplos($this->vertices[$vertex]);
foreach ($set as $adjacent_vertex) {
call_user_func($callback, $adjacent_vertex);
}
$this->walking->detach($set);
return $this;
}
/**
* {@inheritdoc}
*/
public function eachVertex($callback) {
$this->fev(function ($v, $adjacent) use ($callback) {
call_user_func($callback, $v, $adjacent);
});
return $this;
}
/**
* {@inheritdoc}
*/
public function hasVertex($vertex) {
return $this->vertices->contains($vertex);
}
/**
* {@inheritdoc}
*/
public function order() {
return $this->vertices->count();
}
/**
* {@inheritdoc}
*/
public function size() {
return $this->size;
}
protected function fev($callback) {
$set = $this->_getTraversableSplos($this->vertices);
foreach ($set as $vertex) {
$outgoing = $set->getInfo();
$callback($vertex, $outgoing);
}
$this->walking->detach($set);
return $this;
}
/**
* Helper function to ensure SPLOS traversal pointer is not overridden.
*
* This would otherwise occur if nested calls are made that traverse the
* same SPLOS. This keeps track of which SPLOSes are currently being
* traversed, and if it's in use, it returns a clone.
*
* It is incumbent on the calling code to release the semaphore directly
* by calling $this->_cleanupSplosTraversal() when the traversal in
* question is complete. (This is very important!)
*
* Only public because it needs to be called from within closures.
*
* @param \SplObjectStorage $splos
* The SPLOS to traverse.
*
* @return \SplObjectStorage
* A SPLOS that is safe for traversal; may or may not be a clone of the
* original.
*/
public function _getTraversableSplos(\SplObjectStorage $splos) {
if ($this->walking->contains($splos)) {
return clone $splos;
}
else {
$this->walking->attach($splos);
return $splos;
}
}
/**
* Helper function to clean up SPLOSes after finishing traversal.
*
* @param \SplObjectStorage $splos
* The SPLOS to mark as safe for traversal again.
*/
public function _cleanupSplosTraversal(\SplObjectStorage $splos) {
$this->walking->detach($splos);
}
}
\ No newline at end of file
<?php
namespace Gliph\Graph;
use Gliph\Algorithm\ConnectedComponent;
use Gliph\Exception\NonexistentVertexException;
use Gliph\Exception\RuntimeException;
use Gliph\Traversal\DepthFirst;
use Gliph\Visitor\DepthFirstToposortVisitor;
class DirectedAdjacencyList extends AdjacencyList implements MutableDirectedGraph {
/**
* {@inheritdoc}
*/
public function addDirectedEdge($tail, $head) {
$this->addVertex($tail)->addVertex($head);
if (!$this->vertices[$tail]->contains($head)) {
$this->size++;
}
$this->vertices[$tail]->attach($head);
}
/**
* {@inheritdoc}
*/
public function removeVertex($vertex) {
if (!$this->hasVertex($vertex)) {
throw new NonexistentVertexException('Vertex is not in the graph, it cannot be removed.', E_WARNING);
}
$this->eachVertex(function($v, $outgoing) use ($vertex) {
if ($outgoing->contains($vertex)) {
$outgoing->detach($vertex);
}
});
unset($this->vertices[$vertex]);
}
/**
* {@inheritdoc}
*/
public function removeEdge($tail, $head) {
$this->vertices[$tail]->detach($head);
}
/**
* {@inheritdoc}
*/
public function eachEdge($callback) {
$edges = array();
$that = $this;
$this->fev(function ($from, $outgoing) use (&$edges, $that) {
$set = $that->_getTraversableSplos($outgoing);
foreach ($set as $to) {
$edges[] = array($from, $to);
}
$that->_cleanupSplosTraversal($set);
});
foreach ($edges as $edge) {
call_user_func($callback, $edge);
}
}
/**
* {@inheritdoc}
*/
public function transpose() {
$graph = new self();
$this->eachEdge(function($edge) use (&$graph) {
$graph->addDirectedEdge($edge[1], $edge[0]);
});
return $graph;
}
/**
* {@inheritdoc}
*/
public function isAcyclic() {
// The DepthFirstToposortVisitor throws an exception on cycles.
try {
DepthFirst::traverse($this, new DepthFirstToposortVisitor());
return TRUE;
}
catch (RuntimeException $e) {
return FALSE;
}
}
/**
* {@inheritdoc}
*/
public function getCycles() {
$scc = ConnectedComponent::tarjan_scc($this);
return $scc->getConnectedComponents();
}
/**
* {@inheritdoc}
*/
public function inDegree($vertex) {
if (!$this->hasVertex($vertex)) {
throw new NonexistentVertexException('Vertex is not in the graph, in-degree information cannot be provided', E_WARNING);
}
$count = 0;
$this->fev(function ($from, $outgoing) use (&$count, $vertex) {
if ($outgoing->contains($vertex)) {
$count++;
}
});
return $count;
}
/**
* {@inheritdoc}
*/
public function outDegree($vertex) {
if (!$this->hasVertex($vertex)) {
throw new NonexistentVertexException('Vertex is not in the graph, out-degree information cannot be provided', E_WARNING);
}
return $this->vertices[$vertex]->count();
}
}
<?php
namespace Gliph\Graph;
/**
* Interface for directed graph datastructures.
*/
interface DirectedGraph extends Graph {
/**
* Returns the transpose of this graph.
*
* A transpose is identical to the current graph, except that its edges
* have had their directionality reversed.
*
* Transposed graphs are sometimes called the 'reverse' or 'converse'.
*
* @return DirectedGraph
*/
public function transpose();
/**
* Indicates whether or not this graph is acyclic.
*
* @return bool
*/
public function isAcyclic();
/**
* Returns the cycles in this graph, if any.
*
* @return array
* An array of arrays, each subarray representing a full cycle in the
* graph. If the array is empty, the graph is acyclic.
*/
public function getCycles();
}
\ No newline at end of file
<?php
namespace Gliph\Graph;
use Gliph\Exception\InvalidVertexTypeException;
use Gliph\Exception\NonexistentVertexException;
/**
* The most basic interface for graph datastructures.
*/
interface Graph {
/**
* Calls the callback with each vertex adjacent to the provided vertex.
*
* The meaning of "adjacency" depends on the type of graph. In a directed
* graph, it refers to all the out-edges of the provided vertex. In an
* undirected graph, in-edges and out-edges are the same, so this method
* will iterate over both.
*
* @param object $vertex
* The vertex whose out-edges should be visited.
* @param callback $callback
* The callback to fire. For each vertex found along an out-edge, this
* callback will be called with that vertex as the sole parameter.
*
* @return Graph
* The current graph instance.
*
* @throws NonexistentVertexException
* Thrown if the vertex provided in the first parameter is not present in
* the graph.
*/
public function eachAdjacent($vertex, $callback);
/**
* Calls the provided callback for each vertex in the graph.
*
* @param $callback
* The callback is called once for each vertex in the graph. Two
* parameters are provided:
* - The vertex being inspected.
* - An SplObjectStorage containing a list of all the vertices adjacent
* to the vertex being inspected.
*
* @return Graph
* The current graph instance.
*/
public function eachVertex($callback);
/**
* Calls the provided callback for each edge in the graph.
*
* @param $callback
* The callback is called once for each unique edge in the graph. A single
* parameter is provided: a 2-tuple (indexed array with two elements),
* where the first element is the first vertex (in a directed graph, the
* tail) and the second element is the second vertex (in a directed graph,
* the head).
*
* @return Graph
* The current graph instance.
*/
public function eachEdge($callback);
/**
* Indicates whether or not the provided vertex is present in the graph.
*
* @param object $vertex
* The vertex object to check for membership in the graph.
*
* @return bool
* TRUE if the vertex is present, FALSE otherwise.
*/
public function hasVertex($vertex);
/**
* Returns the in-degree (number of incoming edges) for the provided vertex.
*
* In undirected graphs, in-degree and out-degree are the same.
*
* @param object $vertex
* The vertex for which to retrieve in-degree information.
*
* @return int
*
* @throws NonexistentVertexException
* Thrown if the vertex provided in the first parameter is not present in
* the graph.
*
*/
public function inDegree($vertex);
/**
* Returns the out-degree (count of outgoing edges) for the provided vertex.
*
* In undirected graphs, in-degree and out-degree are the same.
*
* @param object $vertex
* The vertex for which to retrieve out-degree information.
*
* @return int
*
* @throws NonexistentVertexException
* Thrown if the vertex provided in the first parameter is not present in
* the graph.
*
*/
public function outDegree($vertex);
/**
* Returns the number of edges in the graph.
*
* @return int
*/
public function size();
/**
* Returns the number of vertices in the graph.
*
* @return int
*/
public function order();
}
<?php
namespace Gliph\Graph;
/**
* Describes a directed graph that can be modified after initial creation.
*/
interface MutableDirectedGraph extends MutableGraph, DirectedGraph {
/**
* Adds a directed edge to this graph.
*
* Directed edges are also often referred to as 'arcs'.
*
* @param object $tail
* An object vertex from which the edge originates. The vertex will be
* added to the graph if it is not already present.
* @param object $head
* An object vertex to which the edge points. The vertex will be added to
* the graph if it is not already present.
*
* @return DirectedGraph
* The current graph instance.
*/
public function addDirectedEdge($tail, $head);
}
\ No newline at end of file
<?php
namespace Gliph\Graph;
/**
* Describes a graph that can be modified after initial creation.
*/
interface MutableGraph extends Graph {
/**
* Adds a vertex to the graph.
*
* Gliph requires that its graph vertices be objects; beyond that, it does
* not care about vertex type.
*
* @param object $vertex
* An object to use as a vertex in the graph.
*
* @return Graph
* The current graph instance.
*
* @throws InvalidVertexTypeException
* Thrown if an invalid type of data is provided as a vertex.
*/
public function addVertex($vertex);
/**
* Remove a vertex from the graph.
*
* This will also remove any edges that include the vertex.
*
* @param object $vertex
* A vertex object to remove from the graph.
*
* @return Graph
* The current graph instance.
*
* @throws NonexistentVertexException
* Thrown if the provided vertex is not present in the graph.
*/
public function removeVertex($vertex);
/**
* Removes an edge from the graph.
*
* @param $a
* The first vertex in the edge pair to remove. In a directed graph, this
* is the tail vertex.
* @param $b
* The second vertex in the edge pair to remove. In a directed graph, this
* is the head vertex.
*
* @return Graph
* The current graph instance.
*/
public function removeEdge($a, $b);
}
\ No newline at end of file
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment