You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

221 lines
5.8 KiB
PHP

<?php
namespace Graphp\Algorithms;
use Graphp\Algorithms\BaseGraph;
use Fhaculty\Graph\Graph;
use Fhaculty\Graph\Vertex;
use Fhaculty\Graph\Exception\UnexpectedValueException;
use Fhaculty\Graph\Set\Vertices;
/**
* Basic algorithms for working with the degrees of Graphs.
*
* The degree (or valency) of a Vertex of a Graph is the number of Edges
* incident to the Vertex, with Loops counted twice.
*
* @link http://en.wikipedia.org/wiki/Degree_%28graph_theory%29
* @link http://en.wikipedia.org/wiki/Regular_graph
*/
class Degree extends BaseGraph
{
/**
* get degree for k-regular-graph (only if each vertex has the same degree)
*
* @return int
* @throws UnderflowException if graph is empty
* @throws UnexpectedValueException if graph is not regular (i.e. vertex degrees are not equal)
* @uses self::getDegreeVertex()
* @see self::isRegular()
*/
public function getDegree()
{
// get initial degree of any start vertex to compare others to
$degree = $this->getDegreeVertex($this->graph->getVertices()->getVertexFirst());
foreach ($this->graph->getVertices() as $vertex) {
/** @var $vertex Vertex */
$i = $this->getDegreeVertex($vertex);
if ($i !== $degree) {
throw new UnexpectedValueException('Graph is not k-regular (vertex degrees differ)');
}
}
return $degree;
}
/**
* get minimum degree of vertices
*
* @return int
* @throws Exception if graph is empty or directed
* @uses Vertices::getVertexOrder()
* @uses self::getDegreeVertex()
*/
public function getDegreeMin()
{
return $this->getDegreeVertex($this->graph->getVertices()->getVertexOrder(array($this, 'getDegreeVertex')));
}
/**
* get maximum degree of vertices
*
* @return int
* @throws Exception if graph is empty or directed
* @uses Vertices::getVertexOrder()
* @uses self::getDegreeVertex()
*/
public function getDegreeMax()
{
return $this->getDegreeVertex($this->graph->getVertices()->getVertexOrder(array($this, 'getDegreeVertex'), true));
}
/**
* checks whether this graph is regular, i.e. each vertex has the same indegree/outdegree
*
* @return boolean
* @uses self::getDegree()
*/
public function isRegular()
{
// an empty graph is considered regular
if ($this->graph->getVertices()->isEmpty()) {
return true;
}
try {
$this->getDegree();
return true;
} catch (UnexpectedValueException $ignore) { }
return false;
}
/**
* checks whether the indegree of every vertex equals its outdegree
*
* @return boolean
* @uses self::getDegreeInVertex()
* @uses self::getDegreeOutVertex()
*/
public function isBalanced()
{
foreach ($this->graph->getVertices() as $vertex) {
if ($this->getDegreeInVertex($vertex) !== $this->getDegreeOutVertex($vertex)) {
return false;
}
}
return true;
}
/**
* checks whether this vertex is a source, i.e. its indegree is zero
*
* @param Vertex $vertex
* @return boolean
* @uses Edge::hasVertexTarget()
* @see self::getDegreeInVertex()
*/
public function isVertexSource(Vertex $vertex)
{
foreach ($vertex->getEdges() as $edge) {
if ($edge->hasVertexTarget($vertex)) {
return false;
}
}
// reach this point: no edge to this vertex
return true;
}
/**
* checks whether this vertex is a sink, i.e. its outdegree is zero
*
* @param Vertex $vertex
* @return boolean
* @uses Edge::hasVertexStart()
* @see self::getDegreeOutVertex()
*/
public function isVertexSink(Vertex $vertex)
{
foreach ($vertex->getEdges() as $edge) {
if ($edge->hasVertexStart($vertex)) {
return false;
}
}
// reach this point: no edge away from this vertex
return true;
}
/**
* get degree of this vertex (total number of edges)
*
* vertex degree counts the total number of edges attached to this vertex
* regardless of whether they're directed or not. loop edges are counted
* twice as both start and end form a 'line' to the same vertex.
*
* @param Vertex $vertex
* @return int
* @see self::getDegreeInVertex()
* @see self::getDegreeOutVertex()
*/
public function getDegreeVertex(Vertex $vertex)
{
return count($vertex->getEdges());
}
/**
* check whether this vertex is isolated (i.e. has no edges attached)
*
* @param Vertex $vertex
* @return boolean
*/
public function isVertexIsolated(Vertex $vertex)
{
return $vertex->getEdges()->isEmpty();
}
/**
* get indegree of this vertex (number of edges TO this vertex)
*
* @param Vertex $vertex
* @return int
* @uses Edge::hasVertexTarget()
* @see self::getDegreeVertex()
*/
public function getDegreeInVertex($vertex)
{
$n = 0;
foreach ($vertex->getEdges() as $edge) {
if ($edge->hasVertexTarget($vertex)) {
++$n;
}
}
return $n;
}
/**
* get outdegree of this vertex (number of edges FROM this vertex TO other vertices)
*
* @param Vertex $vertex
* @return int
* @uses Edge::hasVertexStart()
* @see self::getDegreeVertex()
*/
public function getDegreeOutVertex(Vertex $vertex)
{
$n = 0;
foreach ($vertex->getEdges() as $edge) {
if ($edge->hasVertexStart($vertex)) {
++$n;
}
}
return $n;
}
}