Actualización

This commit is contained in:
Xes
2025-04-10 12:24:57 +02:00
parent 8969cc929d
commit 45420b6f0d
39760 changed files with 4303286 additions and 0 deletions

View File

@@ -0,0 +1,94 @@
<?php
use Fhaculty\Graph\Graph;
use Graphp\Algorithms\Bipartit as AlgorithmBipartit;
class BipartitTest extends TestCase
{
public function testGraphEmpty()
{
$graph = new Graph();
$alg = new AlgorithmBipartit($graph);
$this->assertTrue($alg->isBipartit());
$this->assertEquals(array(), $alg->getColors());
$this->assertEquals(array(0 => array(), 1 => array()), $alg->getColorVertices());
}
public function testGraphPairIsBipartit()
{
// 1 -> 2
$graph = new Graph();
$v1 = $graph->createVertex(1);
$v2 = $graph->createVertex(2);
$v1->createEdgeTo($v2);
$alg = new AlgorithmBipartit($graph);
$this->assertTrue($alg->isBipartit());
$this->assertEquals(array(1 => 0, 2 => 1), $alg->getColors());
$this->assertEquals(array(0 => array(1 => $v1), 1 => array(2 => $v2)), $alg->getColorVertices());
return $alg;
}
/**
*
* @param AlgorithmBipartit $alg
* @depends testGraphPairIsBipartit
*/
public function testGraphPairBipartitGroups(AlgorithmBipartit $alg)
{
// graph does not have any groups assigned, so its groups are not bipartit
$this->assertFalse($alg->isBipartitGroups());
// create a cloned graph with groups assigned according to bipartition
$graph = $alg->createGraphGroups();
$this->assertInstanceOf('Fhaculty\Graph\Graph', $graph);
$alg2 = new AlgorithmBipartit($graph);
$this->assertTrue($alg2->isBipartitGroups());
}
public function testGraphTriangleCycleIsNotBipartit()
{
// 1 -> 2 --> 3 --> 1
$graph = new Graph();
$v1 = $graph->createVertex(1);
$v2 = $graph->createVertex(2);
$v3 = $graph->createVertex(3);
$v1->createEdgeTo($v2);
$v2->createEdgeTo($v3);
$v3->createEdgeTo($v1);
$alg = new AlgorithmBipartit($graph);
$this->assertFalse($alg->isBipartit());
return $alg;
}
/**
*
* @param AlgorithmBipartit $alg
* @expectedException UnexpectedValueException
* @depends testGraphTriangleCycleIsNotBipartit
*/
public function testGraphTriangleCycleColorsInvalid(AlgorithmBipartit $alg)
{
$alg->getColors();
}
/**
*
* @param AlgorithmBipartit $alg
* @expectedException UnexpectedValueException
* @depends testGraphTriangleCycleIsNotBipartit
*/
public function testGraphTriangleCycleColorVerticesInvalid(AlgorithmBipartit $alg)
{
$alg->getColorVertices();
}
}

View File

@@ -0,0 +1,65 @@
<?php
use Fhaculty\Graph\Graph;
use Graphp\Algorithms\Complete as AlgorithmComplete;
class CompleteTest extends TestCase
{
public function testGraphEmptyK0()
{
$graph = new Graph();
$alg = new AlgorithmComplete($graph);
$this->assertTrue($alg->isComplete());
}
public function testGraphSingleTrivialK1()
{
$graph = new Graph();
$graph->createVertex(1);
$alg = new AlgorithmComplete($graph);
$this->assertTrue($alg->isComplete());
}
public function testGraphSimplePairK2()
{
// 1 -- 2
$graph = new Graph();
$graph->createVertex(1)->createEdge($graph->createVertex(2));
$alg = new AlgorithmComplete($graph);
$this->assertTrue($alg->isComplete());
}
public function testGraphSingleDirectedIsNotComplete()
{
// 1 -> 2
$graph = new Graph();
$graph->createVertex(1)->createEdgeTo($graph->createVertex(2));
$alg = new AlgorithmComplete($graph);
$this->assertFalse($alg->isComplete());
}
public function testAdditionalEdgesToNotAffectCompleteness()
{
// 1 -> 2
// 1 -- 2
// 2 -> 1
// 1 -> 1
$graph = new Graph();
$graph->createVertex(1)->createEdgeTo($graph->createVertex(2));
$graph->getVertex(1)->createEdge($graph->getVertex(2));
$graph->getVertex(2)->createEdgeTo($graph->getVertex(1));
$graph->getVertex(1)->createEdgeTo($graph->getVertex(1));
$alg = new AlgorithmComplete($graph);
$this->assertTrue($alg->isComplete());
}
}

View File

@@ -0,0 +1,97 @@
<?php
use Fhaculty\Graph\Graph;
use Graphp\Algorithms\ConnectedComponents as AlgorithmConnected;
class ConnectedComponentsTest extends TestCase
{
public function testNullGraph()
{
$graph = new Graph();
$alg = new AlgorithmConnected($graph);
$this->assertEquals(0, $alg->getNumberOfComponents());
$this->assertFalse($alg->isSingle());
$this->assertCount(0, $alg->createGraphsComponents());
}
public function testGraphSingleTrivial()
{
$graph = new Graph();
$graph->createVertex(1);
$alg = new AlgorithmConnected($graph);
$this->assertEquals(1, $alg->getNumberOfComponents());
$this->assertTrue($alg->isSingle());
$graphs = $alg->createGraphsComponents();
$this->assertCount(1, $graphs);
$this->assertGraphEquals($graph, \reset($graphs));
}
public function testGraphEdgeDirections()
{
// 1 -- 2 -> 3 <- 4
$graph = new Graph();
$graph->createVertex(1)->createEdge($graph->createVertex(2));
$graph->getVertex(2)->createEdgeTo($graph->createVertex(3));
$graph->createVertex(4)->createEdgeTo($graph->getVertex(3));
$alg = new AlgorithmConnected($graph);
$this->assertEquals(1, $alg->getNumberOfComponents());
$this->assertTrue($alg->isSingle());
$graphs = $alg->createGraphsComponents();
$this->assertCount(1, $graphs);
$this->assertGraphEquals($graph, \reset($graphs));
$this->assertGraphEquals($graph, $alg->createGraphComponentVertex($graph->getVertex(1)));
}
public function testComponents()
{
// 1 -- 2, 3 -> 4, 5
$graph = new Graph();
$v1 = $graph->createVertex(1);
$v2 = $graph->createVertex(2);
$v3 = $graph->createVertex(3);
$v4 = $graph->createVertex(4);
$v5 = $graph->createVertex(5);
$v1->createEdge($v2);
$v3->createEdgeTo($v4);
$alg = new AlgorithmConnected($graph);
$this->assertEquals(3, $alg->getNumberOfComponents());
$this->assertFalse($alg->isSingle());
$graphs = $alg->createGraphsComponents();
$this->assertCount(3, $graphs);
$ge = new Graph();
$ge->createVertex(1)->createEdge($ge->createVertex(2));
$this->assertGraphEquals($ge, $alg->createGraphComponentVertex($v2));
$ge = new Graph();
$ge->createVertex(5);
$this->assertEquals($ge, $alg->createGraphComponentVertex($v5));
}
/**
* @expectedException InvalidArgumentException
*/
public function testInvalidVertexPassedToAlgorithm()
{
$graph = new Graph();
$graph2 = new Graph();
$v2 = $graph2->createVertex(12);
$alg = new AlgorithmConnected($graph);
$alg->createGraphComponentVertex($v2);
}
}

View File

@@ -0,0 +1,94 @@
<?php
use Fhaculty\Graph\Exception\UnderflowException;
use Fhaculty\Graph\Exception\UnexpectedValueException;
use Fhaculty\Graph\Graph;
use Graphp\Algorithms\Degree as AlgorithmDegree;
class DegreeTest extends TestCase
{
public function testGraphEmpty()
{
$graph = new Graph();
$alg = new AlgorithmDegree($graph);
try {
$alg->getDegree();
$this->fail();
} catch (UnderflowException $e) { }
try {
$alg->getDegreeMin();
$this->fail();
} catch (UnderflowException $e) { }
try {
$alg->getDegreeMax();
$this->fail();
} catch (UnderflowException $e) { }
$this->assertTrue($alg->isRegular());
$this->assertTrue($alg->isBalanced());
}
public function testGraphIsolated()
{
$graph = new Graph();
$graph->createVertex(1);
$graph->createVertex(2);
$alg = new AlgorithmDegree($graph);
$this->assertEquals(0, $alg->getDegree());
$this->assertEquals(0, $alg->getDegreeMin());
$this->assertEquals(0, $alg->getDegreeMax());
$this->assertTrue($alg->isRegular());
$this->assertTrue($alg->isBalanced());
}
public function testGraphIrregular()
{
// 1 -> 2 -> 3
$graph = new Graph();
$v1 = $graph->createVertex(1);
$v2 = $graph->createVertex(2);
$v3 = $graph->createVertex(3);
$v1->createEdgeTo($v2);
$v2->createEdgeTo($v3);
$alg = new AlgorithmDegree($graph);
try {
$this->assertEquals(0, $alg->getDegree());
$this->fail();
} catch (UnexpectedValueException $e) { }
$this->assertEquals(1, $alg->getDegreeMin());
$this->assertEquals(2, $alg->getDegreeMax());
$this->assertFalse($alg->isRegular());
$this->assertFalse($alg->isBalanced());
$this->assertEquals(0, $alg->getDegreeInVertex($v1));
$this->assertEquals(1, $alg->getDegreeOutVertex($v1));
$this->assertEquals(1, $alg->getDegreeVertex($v1));
$this->assertFalse($alg->isVertexIsolated($v1));
$this->assertFalse($alg->isVertexSink($v1));
$this->assertTrue($alg->isVertexSource($v1));
$this->assertEquals(1, $alg->getDegreeInVertex($v2));
$this->assertEquals(1, $alg->getDegreeOutVertex($v2));
$this->assertEquals(2, $alg->getDegreeVertex($v2));
$this->assertFalse($alg->isVertexIsolated($v2));
$this->assertFalse($alg->isVertexSink($v2));
$this->assertFalse($alg->isVertexSource($v2));
$this->assertEquals(1, $alg->getDegreeInVertex($v3));
$this->assertEquals(0, $alg->getDegreeOutVertex($v3));
$this->assertEquals(1, $alg->getDegreeVertex($v3));
$this->assertFalse($alg->isVertexIsolated($v3));
$this->assertTrue($alg->isVertexSink($v3));
$this->assertFalse($alg->isVertexSource($v3));
}
}

View File

@@ -0,0 +1,151 @@
<?php
use Fhaculty\Graph\Graph;
use Graphp\Algorithms\DetectNegativeCycle;
class DetectNegativeCycleTest extends TestCase
{
public function testNullGraph()
{
$graph = new Graph();
$alg = new DetectNegativeCycle($graph);
$this->assertFalse($alg->hasCycleNegative());
return $alg;
}
/**
*
* @param DetectNegativeCycle $alg
* @depends testNullGraph
* @expectedException UnderflowException
*/
public function testNullGraphHasNoCycle(DetectNegativeCycle $alg)
{
$alg->getCycleNegative();
}
/**
*
* @param DetectNegativeCycle $alg
* @depends testNullGraph
* @expectedException UnderflowException
*/
public function testNullGraphHasNoCycleGraph(DetectNegativeCycle $alg)
{
$alg->createGraph();
}
public function testNegativeLoop()
{
// 1 --[-1]--> 1
$graph = new Graph();
$v1 = $graph->createVertex(1);
$e1 = $v1->createEdgeTo($v1)->setWeight(-1);
$alg = new DetectNegativeCycle($graph);
$this->assertTrue($alg->hasCycleNegative());
$cycle = $alg->getCycleNegative();
$this->assertCount(1, $cycle->getEdges());
$this->assertCount(2, $cycle->getVertices());
$this->assertEquals($e1, $cycle->getEdges()->getEdgeFirst());
$this->assertEquals($v1, $cycle->getVertices()->getVertexFirst());
}
public function testNegativeCycle()
{
// 1 --[-1]--> 2
// ^ |
// \---[-2]----/
$graph = new Graph();
$v1 = $graph->createVertex(1);
$v2 = $graph->createVertex(2);
$v1->createEdgeTo($v2)->setWeight(-1);
$v2->createEdgeTo($v1)->setWeight(-2);
$alg = new DetectNegativeCycle($graph);
$this->assertTrue($alg->hasCycleNegative());
$cycle = $alg->getCycleNegative();
$this->assertCount(2, $cycle->getEdges());
$this->assertCount(3, $cycle->getVertices());
}
public function testNegativeUndirectedIsNegativeCycle()
{
// 1 --[-1]-- 2
$graph = new Graph();
$v1 = $graph->createVertex(1);
$v2 = $graph->createVertex(2);
$v1->createEdge($v2)->setWeight(-1);
$alg = new DetectNegativeCycle($graph);
$this->assertTrue($alg->hasCycleNegative());
$cycle = $alg->getCycleNegative();
$this->assertCount(2, $cycle->getEdges());
$this->assertCount(3, $cycle->getVertices());
}
public function testNegativeCycleSubgraph()
{
// 1 --[1]--> 2 --[1]--> 3 --[1]--> 4
// ^ |
// \---[-2]---/
$graph = new Graph();
$v1 = $graph->createVertex(1);
$v2 = $graph->createVertex(2);
$v3 = $graph->createVertex(3);
$v4 = $graph->createVertex(4);
$v1->createEdgeTo($v2)->setWeight(1);
$v2->createEdgeTo($v3)->setWeight(1);
$v3->createEdgeTo($v4)->setWeight(1);
$v4->createEdgeTo($v3)->setWeight(-2);
$alg = new DetectNegativeCycle($graph);
$this->assertTrue($alg->hasCycleNegative());
$cycle = $alg->getCycleNegative();
$this->assertCount(2, $cycle->getEdges());
$this->assertCount(3, $cycle->getVertices());
$this->assertTrue($cycle->getVertices()->hasVertexId(3));
$this->assertTrue($cycle->getVertices()->hasVertexId(4));
}
public function testNegativeComponents()
{
// 1 -- 2 3 --[-1]--> 4
// ^ |
// \---[-2]----/
$graph = new Graph();
$v1 = $graph->createVertex(1);
$v2 = $graph->createVertex(2);
$v3 = $graph->createVertex(3);
$v4 = $graph->createVertex(4);
$v1->createEdge($v2);
$v3->createEdgeTo($v4)->setWeight(-1);
$v4->createEdgeTo($v3)->setWeight(-2);
$alg = new DetectNegativeCycle($graph);
$this->assertTrue($alg->hasCycleNegative());
$cycle = $alg->getCycleNegative();
$this->assertCount(2, $cycle->getEdges());
$this->assertCount(3, $cycle->getVertices());
$this->assertTrue($cycle->getVertices()->hasVertexId(3));
$this->assertTrue($cycle->getVertices()->hasVertexId(4));
}
}

View File

@@ -0,0 +1,58 @@
<?php
use Fhaculty\Graph\Graph;
use Graphp\Algorithms\Directed as AlgorithmDirected;
class DirectedTest extends TestCase
{
public function testGraphEmpty()
{
$graph = new Graph();
$alg = new AlgorithmDirected($graph);
$this->assertFalse($alg->hasDirected());
$this->assertFalse($alg->hasUndirected());
$this->assertFalse($alg->isMixed());
}
public function testGraphUndirected()
{
// 1 -- 2
$graph = new Graph();
$graph->createVertex(1)->createEdge($graph->createVertex(2));
$alg = new AlgorithmDirected($graph);
$this->assertFalse($alg->hasDirected());
$this->assertTrue($alg->hasUndirected());
$this->assertFalse($alg->isMixed());
}
public function testGraphDirected()
{
// 1 -> 2
$graph = new Graph();
$graph->createVertex(1)->createEdgeTo($graph->createVertex(2));
$alg = new AlgorithmDirected($graph);
$this->assertTrue($alg->hasDirected());
$this->assertFalse($alg->hasUndirected());
$this->assertFalse($alg->isMixed());
}
public function testGraphMixed()
{
// 1 -- 2 -> 3
$graph = new Graph();
$graph->createVertex(1)->createEdge($graph->createVertex(2));
$graph->getVertex(2)->createEdgeTo($graph->createVertex(3));
$alg = new AlgorithmDirected($graph);
$this->assertTrue($alg->hasDirected());
$this->assertTrue($alg->hasUndirected());
$this->assertTrue($alg->isMixed());
}
}

View File

@@ -0,0 +1,45 @@
<?php
use Fhaculty\Graph\Graph;
use Graphp\Algorithms\Eulerian as AlgorithmEulerian;
class EulerianTest extends TestCase
{
public function testGraphEmpty()
{
$graph = new Graph();
$alg = new AlgorithmEulerian($graph);
$this->assertFalse($alg->hasCycle());
}
public function testGraphPairHasNoCycle()
{
// 1 -- 2
$graph = new Graph();
$v1 = $graph->createVertex(1);
$v2 = $graph->createVertex(2);
$v1->createEdge($v2);
$alg = new AlgorithmEulerian($graph);
$this->assertFalse($alg->hasCycle());
}
public function testGraphTriangleCycleIsNotBipartit()
{
// 1 -- 2 -- 3 -- 1
$graph = new Graph();
$v1 = $graph->createVertex(1);
$v2 = $graph->createVertex(2);
$v3 = $graph->createVertex(3);
$v1->createEdge($v2);
$v2->createEdge($v3);
$v3->createEdge($v1);
$alg = new AlgorithmEulerian($graph);
$this->assertTrue($alg->hasCycle());
}
}

View File

@@ -0,0 +1,98 @@
<?php
use Fhaculty\Graph\Graph;
use Graphp\Algorithms\Flow as AlgorithmFlow;
class FlowaTest extends TestCase
{
public function testGraphEmpty()
{
$graph = new Graph();
$alg = new AlgorithmFlow($graph);
$this->assertFalse($alg->hasFlow());
$this->assertEquals(0, $alg->getBalance());
$this->assertTrue($alg->isBalancedFlow());
return $graph;
}
public function testEdgeWithZeroFlowIsConsideredFlow()
{
// 1 -> 2
$graph = new Graph();
$graph->createVertex(1)->createEdgeTo($graph->createVertex(2))->setFlow(0);
$alg = new AlgorithmFlow($graph);
$this->assertTrue($alg->hasFlow());
$this->assertEquals(0, $alg->getFlowVertex($graph->getVertex(1)));
$this->assertEquals(0, $alg->getFlowVertex($graph->getVertex(2)));
}
/**
*
* @param Graph $graph
* @depends testGraphEmpty
*/
public function testGraphSimple(Graph $graph)
{
// 1 -> 2
$graph->createVertex(1)->createEdgeTo($graph->createVertex(2));
$alg = new AlgorithmFlow($graph);
$this->assertFalse($alg->hasFlow());
$this->assertEquals(0, $alg->getFlowVertex($graph->getVertex(1)));
$this->assertEquals(0, $alg->getFlowVertex($graph->getVertex(2)));
return $graph;
}
/**
*
* @param Graph $graph
* @depends testGraphSimple
*/
public function testGraphWithUnweightedEdges(Graph $graph)
{
// additional flow edge: 2 -> 3
$graph->getVertex(2)->createEdgeTo($graph->createVertex(3))->setFlow(10);
$alg = new AlgorithmFlow($graph);
$this->assertTrue($alg->hasFlow());
$this->assertEquals(10, $alg->getFlowVertex($graph->getVertex(2)));
$this->assertEquals(-10, $alg->getFlowVertex($graph->getVertex(3)));
}
public function testGraphBalance()
{
// source(+100) -> sink(-10)
$graph = new Graph();
$graph->createVertex('source')->setBalance(100);
$graph->createVertex('sink')->setBalance(-10);
$alg = new AlgorithmFlow($graph);
$this->assertEquals(90, $alg->getBalance());
$this->assertFalse($alg->isBalancedFlow());
}
/**
* @expectedException UnexpectedValueException
*/
public function testVertexWithUndirectedEdgeHasInvalidFlow()
{
// 1 -- 2
$graph = new Graph();
$graph->createVertex(1)->createEdge($graph->createVertex(2))->setFlow(10);
$alg = new AlgorithmFlow($graph);
$alg->getFlowVertex($graph->getVertex(1));
}
}

View File

@@ -0,0 +1,62 @@
<?php
use Fhaculty\Graph\Graph;
use Graphp\Algorithms\Groups as AlgorithmGroups;
class GroupsTest extends TestCase
{
public function testGraphEmpty()
{
$graph = new Graph();
$alg = new AlgorithmGroups($graph);
$this->assertEquals(array(), $alg->getGroups());
$this->assertEquals(0, $alg->getNumberOfGroups());
$this->assertTrue($alg->getVerticesGroup(123)->isEmpty());
$this->assertFalse($alg->isBipartit());
}
public function testGraphPairIsBipartit()
{
// 1 -> 2
$graph = new Graph();
$v1 = $graph->createVertex(1)->setGroup(1);
$v2 = $graph->createVertex(2)->setGroup(2);
$v1->createEdgeTo($v2);
$alg = new AlgorithmGroups($graph);
$this->assertEquals(array(1, 2), $alg->getGroups());
$this->assertEquals(2, $alg->getNumberOfGroups());
$this->assertTrue($alg->getVerticesGroup(123)->isEmpty());
$this->assertEquals(array(1 => $v1), $alg->getVerticesGroup(1)->getMap());
$this->assertTrue($alg->isBipartit());
}
public function testGraphTriangleCycleIsNotBipartit()
{
// 1 -> 2 -> 3 -> 1
$graph = new Graph();
$v1 = $graph->createVertex(1)->setGroup(1);
$v2 = $graph->createVertex(2)->setGroup(2);
$v3 = $graph->createVertex(3)->setGroup(1);
$v1->createEdgeTo($v2);
$v2->createEdgeTo($v3);
$v3->createEdgeTo($v1);
$alg = new AlgorithmGroups($graph);
$this->assertEquals(array(1, 2), $alg->getGroups());
$this->assertEquals(2, $alg->getNumberOfGroups());
$this->assertTrue($alg->getVerticesGroup(123)->isEmpty());
$this->assertEquals(array(1 => $v1, 3 => $v3), $alg->getVerticesGroup(1)->getMap());
$this->assertFalse($alg->isBipartit());
}
}

View File

@@ -0,0 +1,57 @@
<?php
use Fhaculty\Graph\Graph;
use Graphp\Algorithms\Loop as AlgorithmLoop;
class LoopTest extends TestCase
{
public function testGraphEmpty()
{
$graph = new Graph();
$alg = new AlgorithmLoop($graph);
$this->assertFalse($alg->hasLoop());
}
public function testGraphWithMixedCircuitIsNotConsideredLoop()
{
// 1 -> 2
// 2 -- 1
$graph = new Graph();
$v1 = $graph->createVertex(1);
$v2 = $graph->createVertex(2);
$v1->createEdgeTo($v2);
$v2->createEdge($v1);
$alg = new AlgorithmLoop($graph);
$this->assertFalse($alg->hasLoop());
$this->assertFalse($alg->hasLoopVertex($v1));
$this->assertFalse($alg->hasLoopVertex($v2));
}
public function testGraphUndirectedLoop()
{
// 1 -- 1
$graph = new Graph();
$graph->createVertex(1)->createEdge($v1 = $graph->getVertex(1));
$alg = new AlgorithmLoop($graph);
$this->assertTrue($alg->hasLoop());
$this->assertTrue($alg->hasLoopVertex($v1));
}
public function testGraphDirectedLoop()
{
// 1 -> 1
$graph = new Graph();
$graph->createVertex(1)->createEdgeTo($v1 = $graph->getVertex(1));
$alg = new AlgorithmLoop($graph);
$this->assertTrue($alg->hasLoop());
$this->assertTrue($alg->hasLoopVertex($v1));
}
}

View File

@@ -0,0 +1,165 @@
<?php
use Fhaculty\Graph\Graph;
use Graphp\Algorithms\MaxFlow\EdmondsKarp as AlgorithmMaxFlowEdmondsKarp;
use PHPUnit\Framework\TestCase;
class EdmondsKarpTest extends TestCase
{
public function testEdgeDirected()
{
// 0 -[0/10]-> 1
$graph = new Graph();
$v0 = $graph->createVertex(0);
$v1 = $graph->createVertex(1);
$v0->createEdgeTo($v1)->setCapacity(10);
// 0 -[10/10]-> 1
$alg = new AlgorithmMaxFlowEdmondsKarp($v0, $v1);
$this->assertEquals(10, $alg->getFlowMax());
}
public function testEdgesMultiplePaths()
{
// 0 -[0/5]---------> 1
// | ^
// | |
// \-[0/7]-> 2 -[0/9]-/
$graph = new Graph();
$v0 = $graph->createVertex(0);
$v1 = $graph->createVertex(1);
$v2 = $graph->createVertex(2);
$v0->createEdgeTo($v1)->setCapacity(5);
$v0->createEdgeTo($v2)->setCapacity(7);
$v2->createEdgeTo($v1)->setCapacity(9);
// 0 -[5/5]---------> 1
// | ^
// | |
// \-[7/7]-> 2 -[7/9]-/
$alg = new AlgorithmMaxFlowEdmondsKarp($v0, $v1);
$this->assertEquals(12, $alg->getFlowMax());
}
public function testEdgesMultiplePathsTwo()
{
// 0 -[0/5]---------> 1-[0/10]-> 3
// | ^ |
// | | |
// \-[0/7]-> 2 -[0/9]-/ |
// ^ |
// \---[0/2]-----------/
$graph = new Graph();
$v0 = $graph->createVertex(0);
$v1 = $graph->createVertex(1);
$v2 = $graph->createVertex(2);
$v3 = $graph->createVertex(3);
$v0->createEdgeTo($v1)->setCapacity(5);
$v0->createEdgeTo($v2)->setCapacity(7);
$v2->createEdgeTo($v1)->setCapacity(9);
$v1->createEdgeTo($v3)->setCapacity(10);
$v3->createEdgeTo($v2)->setCapacity(2);
$alg = new AlgorithmMaxFlowEdmondsKarp($v0, $v3);
$this->assertEquals(10, $alg->getFlowMax());
$alg = new AlgorithmMaxFlowEdmondsKarp($v0, $v2);
$this->assertEquals(9, $alg->getFlowMax());
}
public function testEdgesMultiplePathsTree()
{
$graph = new Graph();
$v0 = $graph->createVertex(0);
$v1 = $graph->createVertex(1);
$v2 = $graph->createVertex(2);
$v3 = $graph->createVertex(3);
$v0->createEdgeTo($v1)->setCapacity(4);
$v0->createEdgeTo($v2)->setCapacity(2);
$v1->createEdgeTo($v2)->setCapacity(3);
$v1->createEdgeTo($v3)->setCapacity(1);
$v2->createEdgeTo($v3)->setCapacity(6);
$alg = new AlgorithmMaxFlowEdmondsKarp($v0, $v3);
$this->assertEquals(6, $alg->getFlowMax());
}
// public function testEdgesParallel(){
// $graph = new Graph();
// $v0 = $graph->createVertex(0);
// $v1 = $graph->createVertex(1);
// $v0->createEdgeTo($v1)->setCapacity(3.4);
// $v0->createEdgeTo($v1)->setCapacity(6.6);
// $alg = new AlgorithmMaxFlowEdmondsKarp($v0, $v1);
// $this->assertEquals(10, $alg->getFlowMax());
// }
/**
* @expectedException UnexpectedValueException
*/
public function testEdgesUndirected()
{
// 0 -[0/7]- 1
$graph = new Graph();
$v0 = $graph->createVertex(0);
$v1 = $graph->createVertex(1);
$v1->createEdge($v0)->setCapacity(7);
// 0 -[7/7]- 1
$alg = new AlgorithmMaxFlowEdmondsKarp($v0, $v1);
$this->assertEquals(7, $alg->getFlowMax());
}
/**
* run algorithm with bigger graph and check result against known result (will take several seconds)
*/
// public function testKnownResultBig(){
// $graph = $this->readGraph('G_1_2.txt');
// $alg = new AlgorithmMaxFlowEdmondsKarp($graph->getVertex(0), $graph->getVertex(4));
// $this->assertEquals(0.735802, $alg->getFlowMax());
// }
/**
* @expectedException InvalidArgumentException
*/
public function testInvalidFlowToOtherGraph()
{
$graph1 = new Graph();
$vg1 = $graph1->createVertex(1);
$graph2 = new Graph();
$vg2 = $graph2->createVertex(2);
new AlgorithmMaxFlowEdmondsKarp($vg1, $vg2);
}
/**
* @expectedException InvalidArgumentException
*/
public function testInvalidFlowToSelf()
{
$graph = new Graph();
$v1 = $graph->createVertex(1);
new AlgorithmMaxFlowEdmondsKarp($v1, $v1);
}
}

View File

@@ -0,0 +1,63 @@
<?php
use Fhaculty\Graph\Graph;
use Graphp\Algorithms\MaximumMatching\Flow;
use PHPUnit\Framework\TestCase;
class FlowTest extends TestCase
{
// /**
// * run algorithm with small graph and check result against known result
// */
// public function testKnownResult()
// {
// $loader = new EdgeListBipartit(PATH_DATA . 'Matching_100_100.txt');
// $loader->setEnableDirectedEdges(false);
// $graph = $loader->createGraph();
// $alg = new Flow($graph);
// $this->assertEquals(100, $alg->getNumberOfMatches());
// }
public function testSingleEdge()
{
$graph = new Graph();
$edge = $graph->createVertex(0)->setGroup(0)->createEdge($graph->createVertex(1)->setGroup(1));
$alg = new Flow($graph);
// correct number of edges
$this->assertEquals(1, $alg->getNumberOfMatches());
// actual edge instance returned
$this->assertEquals(array($edge), $alg->getEdges()->getVector());
// check
$flowgraph = $alg->createGraph();
$this->assertInstanceOf('Fhaculty\Graph\Graph', $flowgraph);
}
/**
* expect exception for directed edges
* @expectedException UnexpectedValueException
*/
public function testInvalidDirected()
{
$graph = new Graph();
$graph->createVertex(0)->setGroup(0)->createEdgeTo($graph->createVertex(1)->setGroup(1));
$alg = new Flow($graph);
$alg->getNumberOfMatches();
}
/**
* expect exception for non-bipartit graphs
* @expectedException UnexpectedValueException
*/
public function testInvalidBipartit()
{
$graph = new Graph();
$graph->createVertex(0)->setGroup(1)->createEdge($graph->createVertex(1)->setGroup(1));
$alg = new Flow($graph);
$alg->getNumberOfMatches();
}
}

View File

@@ -0,0 +1,203 @@
<?php
use Fhaculty\Graph\Graph;
use Graphp\Algorithms\MinimumCostFlow\Base;
abstract class BaseMcfTest extends TestCase
{
/**
*
* @param Graph $graph
* @return Base
*/
abstract protected function createAlgorithm(Graph $graph);
public function testNull()
{
$graph = new Graph();
$alg = $this->createAlgorithm($graph);
$this->assertEquals(0, $alg->getWeightFlow());
}
public function testSingleIntermediary()
{
$graph = new Graph();
$graph->createVertex(1);
$alg = $this->createAlgorithm($graph);
$this->assertEquals(0, $alg->getWeightFlow());
}
public function testSimpleEdge()
{
// 1(+2) -[0/2/2]-> 2(-2)
$graph = new Graph();
$v1 = $graph->createVertex(1)->setBalance(2);
$v2 = $graph->createVertex(2)->setBalance(-2);
$v1->createEdgeTo($v2)->setWeight(2)->setCapacity(2);
$alg = $this->createAlgorithm($graph);
$this->assertEquals(4, $alg->getWeightFlow()); // 2x2
}
public function testMultipleSinks()
{
// 1(+2) -[0/2/2]-> 2(-1)
// -[0/4/-5]-> 3(-1)
$graph = new Graph();
$v1 = $graph->createVertex(1)->setBalance(2);
$v2 = $graph->createVertex(2)->setBalance(-1);
$v3 = $graph->createVertex(3)->setBalance(-1);
$v1->createEdgeTo($v2)->setWeight(2)->setCapacity(2);
$v1->createEdgeTo($v3)->setWeight(-5)->setCapacity(4);
$alg = $this->createAlgorithm($graph);
$this->assertEquals(-3, $alg->getWeightFlow()); // 1*2 + 1*-5
}
public function testIntermediaryVertices()
{
// 1(+2) -[0/1/4]-> 2 -[0/6/-2]-> 4(-2)
// -[0/4/5]-> 3 -[0/6/8]->
$graph = new Graph();
$v1 = $graph->createVertex(1)->setBalance(2);
$v2 = $graph->createVertex(2);
$v3 = $graph->createVertex(3);
$v4 = $graph->createVertex(4)->setBalance(-2);
$v1->createEdgeTo($v2)->setWeight(4)->setCapacity(1);
$v2->createEdgeTo($v4)->setWeight(-2)->setCapacity(6);
$v1->createEdgeTo($v3)->setWeight(5)->setCapacity(4);
$v3->createEdgeTo($v4)->setWeight(8)->setCapacity(6);
$alg = $this->createAlgorithm($graph);
$this->assertEquals(15, $alg->getWeightFlow()); // 1*4 + 1*-2 + 1*5 + 1*8
}
public function testEdgeCapacities()
{
// 1(+2) -[0/3/4]-> 2 -[0/4/5]-> 3 ->[0/6/-2]-> 4(-2)
$graph = new Graph();
$v1 = $graph->createVertex(1)->setBalance(2);
$v2 = $graph->createVertex(2);
$v3 = $graph->createVertex(3);
$v4 = $graph->createVertex(4)->setBalance(-2);
$v1->createEdgeTo($v2)->setWeight(4)->setCapacity(3);
$v2->createEdgeTo($v3)->setWeight(5)->setCapacity(4);
$v3->createEdgeTo($v4)->setWeight(-2)->setCapacity(6);
$alg = $this->createAlgorithm($graph);
$this->assertEquals(14, $alg->getWeightFlow()); // 2*4 + 2*5 + 2*-2
}
public function testEdgeFlows()
{
// 1(+4) ---[3/4/2]---> 2 ---[3/3/3]---> 4(-4)
// | | ^
// | [0/2/1] |
// | ↓ |
// \-------[1/2/2]---> 3 ---[1/5/1]-------/
$graph = new Graph();
$v1 = $graph->createVertex(1)->setBalance(4);
$v2 = $graph->createVertex(2);
$v3 = $graph->createVertex(3);
$v4 = $graph->createVertex(4)->setBalance(-4);
$v1->createEdgeTo($v2)->setFlow(3)->setCapacity(4)->setWeight(2);
$v2->createEdgeTo($v4)->setFlow(3)->setCapacity(3)->setWeight(3);
$v1->createEdgeTo($v3)->setFlow(1)->setCapacity(2)->setWeight(2);
$v3->createEdgeTo($v4)->setFlow(1)->setCapacity(5)->setWeight(1);
$v2->createEdgeTo($v3)->setFlow(0)->setCapacity(2)->setWeight(1);
$alg = $this->createAlgorithm($graph);
$this->assertEquals(14, $alg->getWeightFlow()); // 4*1 + 2*2 + 2*1 + 2*2
}
/**
* @expectedException UnexpectedValueException
*/
public function testEdgeCapacityInsufficientFails()
{
// 1(+2) -[0/1]-> 2(-2)
$graph = new Graph();
$v1 = $graph->createVertex(1)->setBalance(2);
$v2 = $graph->createVertex(2)->setBalance(-2);
$v1->createEdgeTo($v2)->setCapacity(1);
$alg = $this->createAlgorithm($graph);
$alg->getWeightFlow();
}
/**
* @expectedException UnexpectedValueException
*/
public function testEdgeCapacityUnsetFails()
{
// 1(+2) -> 2(-2)
$graph = new Graph();
$v1 = $graph->createVertex(1)->setBalance(2);
$v2 = $graph->createVertex(2)->setBalance(-2);
$v1->createEdgeTo($v2);
$alg = $this->createAlgorithm($graph);
$alg->getWeightFlow();
}
/**
* @expectedException UnexpectedValueException
*/
public function testIsolatedVerticesFail()
{
// 1(+2), 2(-2)
$graph = new Graph();
$graph->createVertex(1)->setBalance(2);
$graph->createVertex(2)->setBalance(-2);
$alg = $this->createAlgorithm($graph);
$alg->getWeightFlow();
}
/**
* @expectedException UnexpectedValueException
*/
public function testUnbalancedFails()
{
// 1(+2) -> 2(-3)
$graph = new Graph();
$v1 = $graph->createVertex(1)->setBalance(2);
$v2 = $graph->createVertex(2)->setBalance(-3);
$v1->createEdgeTo($v2)->setCapacity(3);
$alg = $this->createAlgorithm($graph);
$alg->getWeightFlow();
}
/**
* @expectedException UnexpectedValueException
*/
public function testUndirectedFails()
{
// 1(+2) -- 2(-2)
$graph = new Graph();
$v1 = $graph->createVertex(1)->setBalance(2);
$v2 = $graph->createVertex(2)->setBalance(-2);
$v1->createEdge($v2)->setCapacity(2);
$alg = $this->createAlgorithm($graph);
$alg->getWeightFlow();
}
/**
* @expectedException UnexpectedValueException
*/
public function testUndirectedNegativeCycleFails()
{
// 1(+2) -[0/2/-1]- 2(-2)
$graph = new Graph();
$v1 = $graph->createVertex(1)->setBalance(2);
$v2 = $graph->createVertex(2)->setBalance(-2);
$v1->createEdge($v2)->setCapacity(2)->setWeight(-1);
$alg = $this->createAlgorithm($graph);
$alg->getWeightFlow();
}
}

View File

@@ -0,0 +1,12 @@
<?php
use Fhaculty\Graph\Graph;
use Graphp\Algorithms\MinimumCostFlow\CycleCanceling;
class CycleCancellingTest extends BaseMcfTest
{
protected function createAlgorithm(Graph $graph)
{
return new CycleCanceling($graph);
}
}

View File

@@ -0,0 +1,12 @@
<?php
use Fhaculty\Graph\Graph;
use Graphp\Algorithms\MinimumCostFlow\SuccessiveShortestPath;
class SuccessiveShortestPathTest extends BaseMcfTest
{
protected function createAlgorithm(Graph $graph)
{
return new SuccessiveShortestPath($graph);
}
}

View File

@@ -0,0 +1,167 @@
<?php
use Fhaculty\Graph\Graph;
use Fhaculty\Graph\Vertex;
use Graphp\Algorithms\MinimumSpanningTree\Base as MstBase;
abstract class BaseMstTest extends TestCase
{
/**
* @param Vertex $vertex
* @return MstBase
*/
abstract protected function createAlg(Vertex $vertex);
public function testIsolatedVertex()
{
$graph = new Graph();
$v1 = $graph->createVertex(1);
$alg = $this->createAlg($v1);
$this->assertCount(0, $alg->getEdges());
$this->assertEquals(0, $alg->getWeight());
$graphMst = $alg->createGraph();
$this->assertGraphEquals($graph, $graphMst);
}
public function testSingleEdge()
{
// 1 --[3]-- 2
$graph = new Graph();
$v1 = $graph->createVertex(1);
$v2 = $graph->createVertex(2);
$v1->createEdge($v2)->setWeight(3);
$alg = $this->createAlg($v1);
$this->assertCount(1, $alg->getEdges());
$this->assertEquals(3, $alg->getWeight());
$this->assertGraphEquals($graph, $alg->createGraph());
}
public function testSimpleGraph()
{
// 1 --[6]-- 2 --[9]-- 3 --[7]-- 4 --[8]-- 5
$graph = new Graph();
$v1 = $graph->createVertex(1);
$v2 = $graph->createVertex(2);
$v3 = $graph->createVertex(3);
$v4 = $graph->createVertex(4);
$v5 = $graph->createVertex(5);
$v1->createEdge($v2)->setWeight(6);
$v2->createEdge($v3)->setWeight(9);
$v3->createEdge($v4)->setWeight(7);
$v4->createEdge($v5)->setWeight(8);
$alg = $this->createAlg($v1);
$graphMst = $alg->createGraph();
$this->assertGraphEquals($graph, $graphMst);
}
public function testFindingCheapestEdge()
{
// /--[4]--\
// / \
// 1 ---[3]--- 2
// \ /
// \--[5]--/
$graph = new Graph();
$v1 = $graph->createVertex(1);
$v2 = $graph->createVertex(2);
$v1->createEdge($v2)->setWeight(4);
$v1->createEdge($v2)->setWeight(3);
$v1->createEdge($v2)->setWeight(5);
$alg = $this->createAlg($v1);
$edges = $alg->getEdges();
$this->assertCount(1, $edges);
$this->assertEquals(3, $edges->getEdgeFirst()->getWeight());
$this->assertEquals(3, $alg->getWeight());
}
public function testFindingCheapestTree()
{
// 1 --[4]-- 2 --[5]-- 3
// \ /
// \-------[6]-----/
$graph = new Graph();
$v1 = $graph->createVertex(1);
$v2 = $graph->createVertex(2);
$v3 = $graph->createVertex(3);
$v1->createEdge($v2)->setWeight(4);
$v2->createEdge($v3)->setWeight(5);
$v3->createEdge($v1)->setWeight(6);
// 1 --[4]-- 2 -- [5] -- 3
$graphExpected = new Graph();
$ve1 = $graphExpected->createVertex(1);
$ve2 = $graphExpected->createVertex(2);
$ve3 = $graphExpected->createVertex(3);
$ve1->createEdge($ve2)->setWeight(4);
$ve2->createEdge($ve3)->setWeight(5);
$alg = $this->createAlg($v1);
$this->assertCount(2, $alg->getEdges());
$this->assertEquals(9, $alg->getWeight());
$this->assertGraphEquals($graphExpected, $alg->createGraph());
}
public function testMixedGraphDirectionIsIgnored()
{
// 1 --[6]-> 2 --[7]-- 3 --[8]-- 4 <-[9]-- 5
$graph = new Graph();
$v1 = $graph->createVertex(1);
$v2 = $graph->createVertex(2);
$v3 = $graph->createVertex(3);
$v4 = $graph->createVertex(4);
$v5 = $graph->createVertex(5);
$v1->createEdgeTo($v2)->setWeight(6);
$v2->createEdge($v3)->setWeight(7);
$v4->createEdge($v3)->setWeight(8);
$v5->createEdgeTo($v4)->setWeight(9);
$alg = $this->createAlg($v1);
$this->assertCount(4, $alg->getEdges());
$this->assertEquals(30, $alg->getWeight());
$this->assertGraphEquals($graph, $alg->createGraph());
}
/**
* @expectedException UnexpectedValueException
*/
public function testMultipleComponentsFail()
{
// 1 --[1]-- 2, 3 --[1]-- 4
$graph = new Graph();
$v1 = $graph->createVertex(1);
$v2 = $graph->createVertex(2);
$v3 = $graph->createVertex(3);
$v4 = $graph->createVertex(4);
$v1->createEdge($v2)->setWeight(1);
$v3->createEdge($v4)->setWeight(1);
$alg = $this->createAlg($v1);
$alg->getEdges();
}
/**
* @expectedException UnexpectedValueException
*/
public function testMultipleIsolatedVerticesFormMultipleComponentsFail()
{
// 1, 2
$graph = new Graph();
$v1 = $graph->createVertex(1);
$graph->createVertex(2);
$alg = $this->createAlg($v1);
$alg->getEdges();
}
}

View File

@@ -0,0 +1,24 @@
<?php
use Fhaculty\Graph\Graph;
use Fhaculty\Graph\Vertex;
use Graphp\Algorithms\MinimumSpanningTree\Kruskal;
class KruskalTest extends BaseMstTest
{
protected function createAlg(Vertex $vertex)
{
return new Kruskal($vertex->getGraph());
}
/**
* @expectedException UnexpectedValueException
*/
public function testNullGraphIsNotConsideredToBeConnected()
{
$graph = new Graph();
$alg = new Kruskal($graph);
$alg->getEdges();
}
}

View File

@@ -0,0 +1,12 @@
<?php
use Fhaculty\Graph\Vertex;
use Graphp\Algorithms\MinimumSpanningTree\Prim;
class PrimTest extends BaseMstTest
{
protected function createAlg(Vertex $vertex)
{
return new Prim($vertex);
}
}

View File

@@ -0,0 +1,97 @@
<?php
use Fhaculty\Graph\Graph;
use Graphp\Algorithms\Parallel as AlgorithmParallel;
class ParallelTest extends TestCase
{
public function testGraphEmpty()
{
$graph = new Graph();
$alg = new AlgorithmParallel($graph);
$this->assertFalse($alg->hasEdgeParallel());
}
public function testDirectedCycleIsNotConsideredParallel()
{
// 1 -> 2
// 2 -> 1
$graph = new Graph();
$v1 = $graph->createVertex(1);
$v2 = $graph->createVertex(2);
$e1 = $v1->createEdgeTo($v2);
$e2 = $v2->createEdgeTo($v1);
$alg = new AlgorithmParallel($graph);
$this->assertFalse($alg->hasEdgeParallel());
$this->assertEquals(array(), $alg->getEdgesParallelEdge($e1)->getVector());
$this->assertEquals(array(), $alg->getEdgesParallelEdge($e2)->getVector());
}
public function testDirectedParallelEdge()
{
// 1 -> 2
// 1 -> 2
$graph = new Graph();
$v1 = $graph->createVertex(1);
$v2 = $graph->createVertex(2);
$e1 = $v1->createEdgeTo($v2);
$e2 = $v1->createEdgeTo($v2);
$alg = new AlgorithmParallel($graph);
$this->assertTrue($alg->hasEdgeParallel());
$this->assertEquals(array($e2), $alg->getEdgesParallelEdge($e1)->getVector());
$this->assertEquals(array($e1), $alg->getEdgesParallelEdge($e2)->getVector());
}
public function testMixedParallelEdge()
{
// 1 -> 2
// 1 -- 2
$graph = new Graph();
$v1 = $graph->createVertex(1);
$v2 = $graph->createVertex(2);
$e1 = $v1->createEdgeTo($v2);
$e2 = $v1->createEdge($v2);
$alg = new AlgorithmParallel($graph);
$this->assertTrue($alg->hasEdgeParallel());
$this->assertEquals(array($e2), $alg->getEdgesParallelEdge($e1)->getVector());
$this->assertEquals(array($e1), $alg->getEdgesParallelEdge($e2)->getVector());
}
public function testMixedParallelEdgesMultiple()
{
// 1 -> 2
// 1 -> 2
// 1 -- 2
// 1 -- 2
// 2 -> 1
// 2 -> 1
$graph = new Graph();
$v1 = $graph->createVertex(1);
$v2 = $graph->createVertex(2);
$e1 = $v1->createEdgeTo($v2);
$e2 = $v1->createEdgeTo($v2);
$e3 = $v1->createEdge($v2);
$e4 = $v1->createEdge($v2);
$e5 = $v2->createEdgeTo($v1);
$e6 = $v2->createEdgeTo($v1);
$alg = new AlgorithmParallel($graph);
$this->assertTrue($alg->hasEdgeParallel());
$this->assertEquals(array($e2, $e3, $e4), $alg->getEdgesParallelEdge($e1)->getVector());
$this->assertEquals(array($e1, $e3, $e4), $alg->getEdgesParallelEdge($e2)->getVector());
$this->assertEquals(array($e1, $e2, $e4, $e5, $e6), $alg->getEdgesParallelEdge($e3)->getVector());
$this->assertEquals(array($e1, $e2, $e3, $e5, $e6), $alg->getEdgesParallelEdge($e4)->getVector());
$this->assertEquals(array($e3, $e4, $e6), $alg->getEdgesParallelEdge($e5)->getVector());
$this->assertEquals(array($e3, $e4, $e5), $alg->getEdgesParallelEdge($e6)->getVector());
}
}

View File

@@ -0,0 +1,30 @@
<?php
use Fhaculty\Graph\Graph;
use Graphp\Algorithms\Property\GraphProperty;
class PropertyGraphTest extends TestCase
{
public function testEmptyIsEdgeless()
{
$graph = new Graph();
$alg = new GraphProperty($graph);
$this->assertTrue($alg->isNull());
$this->assertTrue($alg->isEdgeless());
$this->assertFalse($alg->isTrivial());
}
public function testSingleVertexIsTrivial()
{
$graph = new Graph();
$graph->createVertex(1);
$alg = new GraphProperty($graph);
$this->assertFalse($alg->isNull());
$this->assertTrue($alg->isEdgeless());
$this->assertTrue($alg->isTrivial());
}
}

View File

@@ -0,0 +1,185 @@
<?php
use Fhaculty\Graph\Graph;
use Fhaculty\Graph\Walk;
use Graphp\Algorithms\Property\WalkProperty;
class WalkPropertyTest extends TestCase
{
public function testTrivialGraph()
{
$graph = new Graph();
$v1 = $graph->createVertex(1);
$walk = Walk::factoryFromEdges(array(), $v1);
$this->assertEquals(1, \count($walk->getVertices()));
$this->assertEquals(0, \count($walk->getEdges()));
$alg = new WalkProperty($walk);
$this->assertFalse($alg->isLoop());
$this->assertFalse($alg->hasLoop());
$this->assertFalse($alg->isCycle());
$this->assertFalse($alg->hasCycle());
$this->assertTrue($alg->isPath());
$this->assertTrue($alg->isSimple());
$this->assertTrue($alg->isEulerian());
$this->assertTrue($alg->isHamiltonian());
}
public function testLoop()
{
// 1 -- 1
$graph = new Graph();
$v1 = $graph->createVertex(1);
$e1 = $v1->createEdge($v1);
$walk = Walk::factoryFromEdges(array($e1), $v1);
$alg = new WalkProperty($walk);
$this->assertTrue($alg->isLoop());
$this->assertTrue($alg->hasLoop());
$this->assertTrue($alg->isCycle());
$this->assertTrue($alg->hasCycle());
$this->assertTrue($alg->isPath());
$this->assertTrue($alg->isSimple());
$this->assertTrue($alg->isEulerian());
$this->assertTrue($alg->isHamiltonian());
}
public function testCycle()
{
// 1 -- 2 -- 1
$graph = new Graph();
$v1 = $graph->createVertex(1);
$v2 = $graph->createVertex(2);
$e1 = $v1->createEdge($v2);
$e2 = $v2->createEdge($v1);
$walk = Walk::factoryFromEdges(array($e1, $e2), $v1);
$this->assertEquals(3, \count($walk->getVertices()));
$this->assertEquals(2, \count($walk->getEdges()));
$alg = new WalkProperty($walk);
$this->assertTrue($alg->isCycle());
$this->assertTrue($alg->hasCycle());
$this->assertTrue($alg->isPath());
$this->assertTrue($alg->isSimple());
$this->assertTrue($alg->isEulerian());
$this->assertTrue($alg->isHamiltonian());
}
public function testCircuit()
{
// 1 -> 2 -> 1, 2 -> 2
$graph = new Graph();
$v1 = $graph->createVertex(1);
$v2 = $graph->createVertex(2);
$e1 = $v1->createEdgeTo($v2);
$e2 = $v2->createEdgeTo($v1);
$e3 = $v2->createEdgeTo($v2);
// 1 -> 2 -> 2 -> 1
$walk = Walk::factoryFromEdges(array($e1, $e3, $e2), $v1);
$this->assertEquals(array(1, 2, 2, 1), $walk->getVertices()->getIds());
$alg = new WalkProperty($walk);
$this->assertTrue($alg->isCycle());
$this->assertTrue($alg->isCircuit());
}
public function testNonCircuit()
{
// 1 -> 2 -> 1, 2 -> 2
$graph = new Graph();
$v1 = $graph->createVertex(1);
$v2 = $graph->createVertex(2);
$e1 = $v1->createEdgeTo($v2);
$e2 = $v2->createEdgeTo($v1);
$e3 = $v2->createEdgeTo($v2);
// non-circuit: taking loop twice
// 1 -> 2 -> 2 -> 2 -> 1
$walk = Walk::factoryFromEdges(array($e1, $e3, $e3, $e2), $v1);
$this->assertEquals(array(1, 2, 2, 2, 1), $walk->getVertices()->getIds());
$alg = new WalkProperty($walk);
$this->assertTrue($alg->isCycle());
$this->assertFalse($alg->isCircuit());
}
public function testDigon()
{
// 1 -> 2 -> 1
$graph = new Graph();
$v1 = $graph->createVertex(1);
$v2 = $graph->createVertex(2);
$e1 = $v1->createEdgeTo($v2);
$e2 = $v2->createEdgeTo($v1);
$walk = Walk::factoryFromEdges(array($e1, $e2), $v1);
$alg = new WalkProperty($walk);
$this->assertTrue($alg->isDigon());
}
public function testTriangle()
{
// 1 -> 2 -> 3 -> 1
$graph = new Graph();
$v1 = $graph->createVertex(1);
$v2 = $graph->createVertex(2);
$v3 = $graph->createVertex(3);
$e1 = $v1->createEdgeTo($v2);
$e2 = $v2->createEdgeTo($v3);
$e3 = $v3->createEdgeTo($v1);
$walk = Walk::factoryFromEdges(array($e1, $e2, $e3), $v1);
$alg = new WalkProperty($walk);
$this->assertTrue($alg->isTriangle());
}
public function testSimplePathWithinGraph()
{
// 1 -- 2 -- 2
$graph = new Graph();
$v1 = $graph->createVertex(1);
$v2 = $graph->createVertex(2);
$v1->createEdge($v2);
$e2 = $v2->createEdge($v2);
// only use "2 -- 2" part
$walk = Walk::factoryFromEdges(array($e2), $v2);
$this->assertEquals(2, \count($walk->getVertices()));
$this->assertEquals(1, \count($walk->getEdges()));
$alg = new WalkProperty($walk);
$this->assertTrue($alg->isCycle());
$this->assertTrue($alg->hasCycle());
$this->assertTrue($alg->isPath());
$this->assertTrue($alg->isSimple());
$this->assertFalse($alg->isEulerian());
$this->assertFalse($alg->isHamiltonian());
}
}

View File

@@ -0,0 +1,206 @@
<?php
use Fhaculty\Graph\Graph;
use Graphp\Algorithms\ResidualGraph;
class ResidualGraphTest extends TestCase
{
public function testGraphEmpty()
{
$graph = new Graph();
$alg = new ResidualGraph($graph);
$residual = $alg->createGraph();
$this->assertGraphEquals($graph, $residual);
}
/**
* test an edge with capacity unused
*/
public function testEdgeUnused()
{
$graph = new Graph();
$graph->createVertex(0)->createEdgeTo($graph->createVertex(1))->setFlow(0)
->setCapacity(2)
->setWeight(3);
$alg = new ResidualGraph($graph);
$residual = $alg->createGraph();
$this->assertGraphEquals($graph, $residual);
}
/**
* test an edge with capacity completely used
*/
public function testEdgeUsed()
{
$graph = new Graph();
$graph->createVertex(0)->createEdgeTo($graph->createVertex(1))->setFlow(2)
->setCapacity(2)
->setWeight(3);
$alg = new ResidualGraph($graph);
$residual = $alg->createGraph();
$expected = new Graph();
$expected->createVertex(1)->createEdgeTo($expected->createVertex(0))->setFlow(0)
->setCapacity(2)
->setWeight(-3);
$this->assertGraphEquals($expected, $residual);
}
/**
* test an edge with capacity remaining
*/
public function testEdgePartial()
{
$graph = new Graph();
$graph->createVertex(0)->createEdgeTo($graph->createVertex(1))->setFlow(1)
->setCapacity(2)
->setWeight(3);
$alg = new ResidualGraph($graph);
$residual = $alg->createGraph();
$expected = new Graph();
$expected->createVertex(0);
$expected->createVertex(1);
// remaining edge
$expected->getVertex(0)->createEdgeTo($expected->getVertex(1))->setFlow(0)
->setCapacity(1)
->setWeight(3);
// back edge
$expected->getVertex(1)->createEdgeTo($expected->getVertex(0))->setFlow(0)
->setCapacity(1)
->setWeight(-3);
$this->assertGraphEquals($expected, $residual);
}
public function testResidualGraphCanOptionallyKeepNullCapacityForEdgeWithZeroFlow()
{
// 1 -[0/2]-> 2
$graph = new Graph();
$v1 = $graph->createVertex(1);
$v2 = $graph->createVertex(2);
$v1->createEdgeTo($v2)->setFlow(0)->setCapacity(2);
// 1 -[0/2]-> 2
// ^ |
// \--[0/0]---/
$expected = new Graph();
$v1 = $expected->createVertex(1);
$v2 = $expected->createVertex(2);
$v1->createEdgeTo($v2)->setFlow(0)->setCapacity(2);
$v2->createEdgeTo($v1)->setFlow(0)->setCapacity(0);
$alg = new ResidualGraph($graph);
$alg->setKeepNullCapacity(true);
$residual = $alg->createGraph();
$this->assertGraphEquals($expected, $residual);
}
public function testResidualGraphCanOptionallyKeepNullCapacityForEdgeWithZeroCapacityRemaining()
{
// 1 -[2/2]-> 2
$graph = new Graph();
$v1 = $graph->createVertex(1);
$v2 = $graph->createVertex(2);
$v1->createEdgeTo($v2)->setFlow(2)->setCapacity(2);
// 1 -[0/0]-> 2
// ^ |
// \--[0/2]---/
$expected = new Graph();
$v1 = $expected->createVertex(1);
$v2 = $expected->createVertex(2);
$v1->createEdgeTo($v2)->setFlow(0)->setCapacity(0);
$v2->createEdgeTo($v1)->setFlow(0)->setCapacity(2);
$alg = new ResidualGraph($graph);
$alg->setKeepNullCapacity(true);
$residual = $alg->createGraph();
$this->assertGraphEquals($expected, $residual);
}
public function testParallelEdgesCanBeMerged()
{
// 1 -[1/2]-> 2
// | ^
// \--[2/3]---/
$graph = new Graph();
$v1 = $graph->createVertex(1);
$v2 = $graph->createVertex(2);
$v1->createEdgeTo($v2)->setFlow(1)->setCapacity(2);
$v1->createEdgeTo($v2)->setFlow(2)->setCapacity(3);
// 1 -[0/2]-> 2
// ^ |
// \--[0/3]---/
$expected = new Graph();
$v1 = $expected->createVertex(1);
$v2 = $expected->createVertex(2);
$v1->createEdgeTo($v2)->setFlow(0)->setCapacity(2);
$v2->createEdgeTo($v1)->setFlow(0)->setCapacity(3);
$alg = new ResidualGraph($graph);
$alg->setMergeParallelEdges(true);
$residual = $alg->createGraph();
$this->assertGraphEquals($expected, $residual);
}
/**
* expect exception for undirected edges
* @expectedException UnexpectedValueException
*/
public function testInvalidUndirected()
{
$graph = new Graph();
$graph->createVertex()->createEdge($graph->createVertex())->setFlow(1)
->setCapacity(2);
$alg = new ResidualGraph($graph);
$alg->createGraph();
}
/**
* expect exception for edges with no flow
* @expectedException UnexpectedValueException
*/
public function testInvalidNoFlow()
{
$graph = new Graph();
$graph->createVertex()->createEdgeTo($graph->createVertex())->setCapacity(1);
$alg = new ResidualGraph($graph);
$alg->createGraph();
}
/**
* expect exception for edges with no capacity
* @expectedException UnexpectedValueException
*/
public function testInvalidNoCapacity()
{
$graph = new Graph();
$graph->createVertex()->createEdgeTo($graph->createVertex())->setFlow(1);
$alg = new ResidualGraph($graph);
$alg->createGraph();
}
}

View File

@@ -0,0 +1,55 @@
<?php
use Fhaculty\Graph\Graph;
use Graphp\Algorithms\Search\BreadthFirst;
class BreadthFirstSearchTest extends TestCase
{
public function providerMaxDepth()
{
return array(
"simple path (no limit)" => array(
"edges" => array(
array(1, 2), array(2, 3), array(3, 4), array(4, 5),
),
"subject" => 1,
"maxDepth" => null,
"expected" => array(1, 2, 3, 4, 5),
),
"simple path (limit = 0)" => array(
"edges" => array(
array(1, 2), array(2, 3), array(3, 4), array(4, 5),
),
"subject" => 1,
"maxDepth" => 0,
"expected" => array(1),
),
"simple path (limit = 1)" => array(
"edges" => array(
array(1, 2), array(2, 3), array(3, 4), array(4, 5),
),
"subject" => 1,
"maxDepth" => 1,
"expected" => array(1, 2),
),
);
}
/**
* @dataProvider providerMaxDepth
*/
public function testMaxDepth(array $edges, $subject, $maxDepth, array $expected)
{
$g = new Graph();
foreach ($edges as $e) {
$g->createVertex($e[0], true)->createEdgeTo($g->createVertex($e[1], true));
}
$a = new BreadthFirst($g->getVertex($subject));
if ($maxDepth !== null) {
$v = $a->getVertices($maxDepth);
} else {
$v = $a->getVertices(); // Simulate default
}
$this->assertSame($expected, $v->getIds());
}
}

View File

@@ -0,0 +1,169 @@
<?php
use Fhaculty\Graph\Graph;
use Fhaculty\Graph\Vertex;
use Graphp\Algorithms\ShortestPath\Base as ShortestPathAlg;
abstract class BaseShortestPathTest extends TestCase
{
/**
*
* @param Vertex $vertex
* @return ShortestPathAlg
*/
abstract protected function createAlg(Vertex $vertex);
abstract public function testGraphParallelNegative();
public function testGraphTrivial()
{
// 1
$graph = new Graph();
$v1 = $graph->createVertex(1);
$alg = $this->createAlg($v1);
$this->assertFalse($alg->hasVertex($v1));
//$this->assertEquals(0, $alg->getDistance($v1));
$this->assertEquals(array(), $alg->getDistanceMap());
$this->assertEquals(array(), $alg->getEdges()->getVector());
//$this->assertEquals(array(), $alg->getEdgesTo($v1));
$this->assertEquals(array(), $alg->getVertices()->getVector());
$this->assertEquals(array(), $alg->getVertices()->getIds());
$clone = $alg->createGraph();
$this->assertGraphEquals($graph,$clone);
}
public function testGraphSingleLoop()
{
// 1 -[4]> 1
$graph = new Graph();
$v1 = $graph->createVertex(1);
$e1 = $v1->createEdgeTo($v1)->setWeight(4);
$alg = $this->createAlg($v1);
$this->assertEquals(array($e1), $alg->getEdges()->getVector());
$expectedWeight = $this->getExpectedWeight(array($e1));
$this->assertTrue($alg->hasVertex($v1));
$this->assertEquals($expectedWeight, $alg->getDistance($v1));
$this->assertEquals(array(1 => $expectedWeight), $alg->getDistanceMap());
$this->assertEquals(array($e1), $alg->getEdgesTo($v1)->getVector());
$this->assertEquals(array(1 => $v1), $alg->getVertices()->getMap());
$this->assertEquals(array(1), $alg->getVertices()->getIds());
}
public function testGraphCycle()
{
// 1 -[4]-> 2 -[2]-> 1
$graph = new Graph();
$v1 = $graph->createVertex(1);
$v2 = $graph->createVertex(2);
$e1 = $v1->createEdgeTo($v2)->setWeight(4);
$e2 = $v2->createEdgeTo($v1)->setWeight(2);
$alg = $this->createAlg($v1);
//$this->assertEquals(array($e2, $e1), $alg->getEdges());
$expectedWeight = $this->getExpectedWeight(array($e1));
$this->assertTrue($alg->hasVertex($v2));
$this->assertEquals(array($e1), $alg->getEdgesTo($v2)->getVector());
$this->assertEquals($expectedWeight, $alg->getDistance($v2));
$expectedWeight = $this->getExpectedWeight(array($e1, $e2));
$this->assertTrue($alg->hasVertex($v1));
$this->assertEquals(array($e1, $e2), $alg->getEdgesTo($v1)->getVector());
$this->assertEquals($expectedWeight, $alg->getDistance($v1));
$walk = $alg->getWalkTo($v1);
$this->assertEquals(2, \count($walk->getEdges()));
}
/**
* @expectedException OutOfBoundsException
*/
public function testIsolatedVertexIsNotReachable()
{
// 1, 2
$graph = new Graph();
$v1 = $graph->createVertex(1);
$v2 = $graph->createVertex(2);
$alg = $this->createAlg($v1);
$this->assertFalse($alg->hasVertex($v2));
$alg->getEdgesTo($v2);
}
/**
* @expectedException OutOfBoundsException
*/
public function testSeparateGraphsAreNotReachable()
{
// 1
$graph1 = new Graph();
$vg1 = $graph1->createVertex(1);
$graph2 = new Graph();
$vg2 = $graph2->createVertex(1);
$alg = $this->createAlg($vg1);
$alg->getEdgesTo($vg2);
}
public function testGraphUnweighted()
{
// 1 -> 2
$graph = new Graph();
$v1 = $graph->createVertex(1);
$v2 = $graph->createVertex(2);
$e1 = $v1->createEdgeTo($v2);
$alg = $this->createAlg($v1);
$expectedWeight = $this->getExpectedWeight(array($e1));
$this->assertEquals($expectedWeight, $alg->getDistance($v2));
$this->assertEquals(array(2 => $expectedWeight), $alg->getDistanceMap());
$this->assertEquals(array($e1), $alg->getEdges()->getVector());
$this->assertEquals(array($e1), $alg->getEdgesTo($v2)->getVector());
$this->assertEquals(array(2), $alg->getVertices()->getIds());
}
public function testGraphTwoComponents()
{
// 1 -[10]-> 2
// 3 -[20]-> 4
$graph = new Graph();
$v1 = $graph->createVertex(1);
$v2 = $graph->createVertex(2);
$v3 = $graph->createVertex(3);
$v4 = $graph->createVertex(4);
$e1 = $v1->createEdgeTo($v2)->setWeight(10);
$v3->createEdgeTo($v4)->setWeight(20);
$alg = $this->createAlg($v1);
$expectedWeight = $this->getExpectedWeight(array($e1));
$this->assertEquals($expectedWeight, $alg->getDistance($v2));
$this->assertEquals(array(2 => $expectedWeight), $alg->getDistanceMap());
$this->assertEquals(array($e1), $alg->getEdges()->getVector());
// $this->assertEquals(array(), $alg->getEdgesTo($v1));
$this->assertEquals(array($e1), $alg->getEdgesTo($v2)->getVector());
$this->assertEquals(array(2 => $v2), $alg->getVertices()->getMap());
$this->assertEquals(array(2), $alg->getVertices()->getIds());
}
protected function getExpectedWeight($edges)
{
$sum = 0;
foreach ($edges as $edge) {
$sum += $edge->getWeight();
}
return $sum;
}
}

View File

@@ -0,0 +1,39 @@
<?php
use Fhaculty\Graph\Graph;
use Fhaculty\Graph\Vertex;
use Graphp\Algorithms\ShortestPath\BreadthFirst;
class BreadthFirstTest extends BaseShortestPathTest
{
protected function createAlg(Vertex $vertex)
{
return new BreadthFirst($vertex);
}
public function testGraphParallelNegative()
{
// 1 -[10]-> 2
// | ^
// \--[-1]---/
$graph = new Graph();
$v1 = $graph->createVertex(1);
$v2 = $graph->createVertex(2);
$e1 = $v1->createEdgeTo($v2)->setWeight(10);
$v1->createEdgeTo($v2)->setWeight(-1);
$alg = $this->createAlg($v1);
$this->assertEquals(1, $alg->getDistance($v2));
$this->assertEquals(array(2 => 1), $alg->getDistanceMap());
$this->assertEquals(array($e1), $alg->getEdges()->getVector());
$this->assertEquals(array($e1), $alg->getEdgesTo($v2)->getVector());
$this->assertEquals(array(2 => $v2), $alg->getVertices()->getMap());
$this->assertEquals(array(2), $alg->getVertices()->getIds());
}
protected function getExpectedWeight($edges)
{
return \count($edges);
}
}

View File

@@ -0,0 +1,32 @@
<?php
use Fhaculty\Graph\Graph;
use Fhaculty\Graph\Vertex;
use Graphp\Algorithms\ShortestPath\Dijkstra;
class DijkstraTest extends BaseShortestPathTest
{
protected function createAlg(Vertex $vertex)
{
return new Dijkstra($vertex);
}
/**
* @expectedException UnexpectedValueException
*/
public function testGraphParallelNegative()
{
// 1 -[10]-> 2
// | ^
// \--[-1]---/
$graph = new Graph();
$v1 = $graph->createVertex(1);
$v2 = $graph->createVertex(2);
$v1->createEdgeTo($v2)->setWeight(10);
$v1->createEdgeTo($v2)->setWeight(-1);
$alg = $this->createAlg($v1);
$alg->getEdges();
}
}

View File

@@ -0,0 +1,111 @@
<?php
use Fhaculty\Graph\Graph;
use Fhaculty\Graph\Vertex;
use Graphp\Algorithms\ShortestPath\MooreBellmanFord;
class MooreBellmanFordTest extends BaseShortestPathTest
{
protected function createAlg(Vertex $vertex)
{
return new MooreBellmanFord($vertex);
}
public function testGraphParallelNegative()
{
// 1 -[10]-> 2
// | ^
// \--[-1]---/
$graph = new Graph();
$v1 = $graph->createVertex(1);
$v2 = $graph->createVertex(2);
$v1->createEdgeTo($v2)->setWeight(10);
$e2 = $v1->createEdgeTo($v2)->setWeight(-1);
$alg = $this->createAlg($v1);
// $this->assertEquals(0, $alg->getDistance($v1));
$this->assertEquals(-1, $alg->getDistance($v2));
$this->assertEquals(array(2 => -1), $alg->getDistanceMap());
$this->assertEquals(array($e2), $alg->getEdges()->getVector());
//$this->assertEquals(array(), $alg->getEdgesTo($v1));
$this->assertEquals(array($e2), $alg->getEdgesTo($v2)->getVector());
$this->assertEquals(array(2 => $v2), $alg->getVertices()->getMap());
$this->assertEquals(array(2), $alg->getVertices()->getIds());
return $alg;
}
/**
* @param MooreBellmanFord $alg
* @depends testGraphParallelNegative
* @expectedException UnderflowException
*/
public function testNoNegativeCycle(MooreBellmanFord $alg)
{
$alg->getCycleNegative();
}
public function testUndirectedNegativeWeightIsCycle()
{
// 1 -[-10]- 2
$graph = new Graph();
$v1 = $graph->createVertex(1);
$v2 = $graph->createVertex(2);
$v1->createEdge($v2)->setWeight(-10);
$alg = $this->createAlg($v1);
$cycle = $alg->getCycleNegative();
$this->assertInstanceOf('Fhaculty\Graph\Walk', $cycle);
}
public function testLoopNegativeWeightIsCycle()
{
// 1 -[-10]-> 1
$graph = new Graph();
$v1 = $graph->createVertex(1);
$v1->createEdge($v1)->setWeight(-10);
$alg = $this->createAlg($v1);
$cycle = $alg->getCycleNegative();
$this->assertInstanceOf('Fhaculty\Graph\Walk', $cycle);
}
public function testNegativeComponentHasCycle()
{
// 1 -[1]-> 2 3 --[-1]--> 4
// ^ |
// \---[-2]----/
$graph = new Graph();
$v1 = $graph->createVertex(1);
$v2 = $graph->createVertex(2);
$v3 = $graph->createVertex(3);
$v4 = $graph->createVertex(4);
$v1->createEdgeTo($v2)->setWeight(1);
$v3->createEdgeTo($v4)->setWeight(-1);
$v4->createEdgeTo($v3)->setWeight(-2);
// second component has a cycle
$alg = $this->createAlg($v3);
$cycle = $alg->getCycleNegative();
assert(isset($cycle));
// first component does not have a cycle
$alg = $this->createAlg($v1);
$this->expectException('UnderflowException');
$alg->getCycleNegative();
}
public function expectException($class)
{
if (\method_exists($this, 'setExpectedException')) {
$this->setExpectedException($class);
} else {
parent::expectException($class);
}
}
}

View File

@@ -0,0 +1,61 @@
<?php
use Fhaculty\Graph\Graph;
use Graphp\Algorithms\Symmetric as AlgorithmSymmetric;
class SymmetricTest extends TestCase
{
public function testGraphEmpty()
{
$graph = new Graph();
$alg = new AlgorithmSymmetric($graph);
$this->assertTrue($alg->isSymmetric());
}
public function testGraphIsolated()
{
$graph = new Graph();
$graph->createVertex(1);
$graph->createVertex(2);
$alg = new AlgorithmSymmetric($graph);
$this->assertTrue($alg->isSymmetric());
}
public function testGraphSingleArcIsNotSymmetricr()
{
// 1 -> 2
$graph = new Graph();
$graph->createVertex(1)->createEdgeTo($graph->createVertex(2));
$alg = new AlgorithmSymmetric($graph);
$this->assertFalse($alg->isSymmetric());
}
public function testGraphAntiparallelIsSymmetricr()
{
// 1 -> 2 -> 1
$graph = new Graph();
$graph->createVertex(1)->createEdgeTo($graph->createVertex(2));
$graph->getVertex(2)->createEdgeTo($graph->getVertex(1));
$alg = new AlgorithmSymmetric($graph);
$this->assertTrue($alg->isSymmetric());
}
public function testGraphSingleUndirectedIsSymmetricr()
{
// 1 -- 2
$graph = new Graph();
$graph->createVertex(1)->createEdge($graph->createVertex(2));
$alg = new AlgorithmSymmetric($graph);
$this->assertTrue($alg->isSymmetric());
}
}

View File

@@ -0,0 +1,75 @@
<?php
use Fhaculty\Graph\Graph;
use Graphp\Algorithms\TopologicalSort;
class TopologicalSortTest extends TestCase
{
public function testGraphEmpty()
{
$graph = new Graph();
$alg = new TopologicalSort($graph);
$this->assertInstanceOf('Fhaculty\Graph\Set\Vertices', $alg->getVertices());
$this->assertTrue($alg->getVertices()->isEmpty());
}
public function testGraphIsolated()
{
$graph = new Graph();
$graph->createVertex(1);
$graph->createVertex(2);
$alg = new TopologicalSort($graph);
$this->assertSame(array($graph->getVertex(1), $graph->getVertex(2)), $alg->getVertices()->getVector());
}
public function testGraphSimple()
{
$graph = new Graph();
$graph->createVertex(1)->createEdgeTo($graph->createVertex(2));
$alg = new TopologicalSort($graph);
$this->assertSame(array($graph->getVertex(1), $graph->getVertex(2)), $alg->getVertices()->getVector());
}
/**
* @expectedException UnexpectedValueException
*/
public function testFailUndirected()
{
$graph = new Graph();
$graph->createVertex(1)->createEdge($graph->createVertex(2));
$alg = new TopologicalSort($graph);
$alg->getVertices();
}
/**
* @expectedException UnexpectedValueException
*/
public function testFailLoop()
{
$graph = new Graph();
$graph->createVertex(1)->createEdgeTo($graph->getVertex(1));
$alg = new TopologicalSort($graph);
$alg->getVertices();
}
/**
* @expectedException UnexpectedValueException
*/
public function testFailCycle()
{
$graph = new Graph();
$graph->createVertex(1)->createEdgeTo($graph->createVertex(2));
$graph->getVertex(2)->createEdgeTo($graph->getVertex(1));
$alg = new TopologicalSort($graph);
$alg->getVertices();
}
}

View File

@@ -0,0 +1,41 @@
<?php
use Fhaculty\Graph\Graph;
use Graphp\Algorithms\TravelingSalesmanProblem\Bruteforce;
class BruteforceTest extends TestCase
{
public function testGetWeightReturnsExpectedWeightForSimpleCycle()
{
$graph = new Graph();
$a = $graph->createVertex();
$b = $graph->createVertex();
$c = $graph->createVertex();
$a->createEdgeTo($b)->setWeight(1);
$b->createEdgeTo($c)->setWeight(2);
$c->createEdgeTo($a)->setWeight(3);
$alg = new Bruteforce($graph);
$this->assertEquals(6, $alg->getWeight());
}
public function testSetUpperLimitMstSetsExactLimitForSimpleCycle()
{
$graph = new Graph();
$a = $graph->createVertex();
$b = $graph->createVertex();
$c = $graph->createVertex();
$a->createEdgeTo($b)->setWeight(1);
$b->createEdgeTo($c)->setWeight(2);
$c->createEdgeTo($a)->setWeight(3);
$alg = new Bruteforce($graph);
$alg->setUpperLimitMst();
$ref = new ReflectionProperty($alg, 'upperLimit');
$ref->setAccessible(true);
$this->assertEquals(6, $ref->getValue($alg));
}
}

View File

@@ -0,0 +1,197 @@
<?php
use Fhaculty\Graph\Graph;
use Fhaculty\Graph\Set\Vertices;
use Graphp\Algorithms\Tree\BaseDirected;
abstract class BaseDirectedTest extends TestCase
{
/**
*
* @param Graph $graph
* @return BaseDirected
*/
abstract protected function createTreeAlg(Graph $graph);
/**
* @return Graph
*/
abstract protected function createGraphNonTree();
/**
* @return Graph
*/
abstract protected function createGraphTree();
/**
* @return Graph
*/
abstract protected function createGraphParallelEdge();
public function testNullGraph()
{
$graph = new Graph();
$tree = $this->createTreeAlg($graph);
$this->assertFalse($tree->isTree());
$this->assertTrue($tree->getVerticesLeaf()->isEmpty());
$this->assertTrue($tree->getVerticesInternal()->isEmpty());
return $tree;
}
/**
* @param BaseDirected $tree
* @depends testNullGraph
* @expectedException UnderflowException
*/
public function testEmptyGraphDoesNotHaveRootVertex(BaseDirected $tree)
{
$tree->getVertexRoot();
}
/**
* @param BaseDirected $tree
* @depends testNullGraph
* @expectedException UnderflowException
*/
public function testEmptyGraphDoesNotHaveDegree(BaseDirected $tree)
{
$tree->getDegree();
}
/**
* @param BaseDirected $tree
* @depends testNullGraph
* @expectedException UnderflowException
*/
public function testEmptyGraphDoesNotHaveHeight(BaseDirected $tree)
{
$tree->getHeight();
}
public function testGraphTree()
{
$graph = $this->createGraphTree();
$root = $graph->getVertices()->getVertexFirst();
$nonRoot = $graph->getVertices()->getMap();
unset($nonRoot[$root->getId()]);
$nonRoot = new Vertices($nonRoot);
$c1 = $nonRoot->getVertexFirst();
$tree = $this->createTreeAlg($graph);
$this->assertTrue($tree->isTree());
$this->assertSame($root, $tree->getVertexRoot());
$this->assertSame($graph->getVertices()->getVector(), $tree->getVerticesSubtree($root)->getVector());
$this->assertSame($nonRoot->getVector(), $tree->getVerticesChildren($root)->getVector());
$this->assertSame($nonRoot->getVector(), $tree->getVerticesDescendant($root)->getVector());
$this->assertSame($nonRoot->getVector(), $tree->getVerticesLeaf()->getVector());
$this->assertSame(array(), $tree->getVerticesInternal()->getVector());
$this->assertSame($root, $tree->getVertexParent($c1));
$this->assertSame(array(), $tree->getVerticesChildren($c1)->getVector());
$this->assertSame(array(), $tree->getVerticesDescendant($c1)->getVector());
$this->assertSame(array($c1), $tree->getVerticesSubtree($c1)->getVector());
$this->assertEquals(2, $tree->getDegree());
$this->assertEquals(0, $tree->getDepthVertex($root));
$this->assertEquals(1, $tree->getDepthVertex($c1));
$this->assertEquals(1, $tree->getHeight());
$this->assertEquals(1, $tree->getHeightVertex($root));
$this->assertEquals(0, $tree->getHeightvertex($c1));
return $tree;
}
/**
*
* @param BaseDirected $tree
* @depends testGraphTree
* @expectedException UnderflowException
*/
public function testGraphTreeRootDoesNotHaveParent(BaseDirected $tree)
{
$root = $tree->getVertexRoot();
$tree->getVertexParent($root);
}
public function testNonTree()
{
$graph = $this->createGraphNonTree();
$tree = $this->createTreeAlg($graph);
$this->assertFalse($tree->isTree());
}
/**
* @expectedException UnexpectedValueException
*/
public function testNonTreeVertexHasMoreThanOneParent()
{
$graph = $this->createGraphNonTree();
$tree = $this->createTreeAlg($graph);
$tree->getVertexParent($graph->getVertex('v3'));
}
public function testGraphWithParallelEdgeIsNotTree()
{
$graph = $this->createGraphParallelEdge();
$tree = $this->createTreeAlg($graph);
$this->assertFalse($tree->isTree());
}
public function testGraphWithLoopIsNotTree()
{
// v1 -> v1
$graph = new Graph();
$graph->createVertex('v1')->createEdgeTo($graph->getVertex('v1'));
$tree = $this->createTreeAlg($graph);
$this->assertFalse($tree->isTree());
}
/**
* @expectedException UnexpectedValueException
*/
public function testGraphWithLoopCanNotGetSubgraph()
{
// v1 -> v1
$graph = new Graph();
$graph->createVertex('v1')->createEdgeTo($graph->getVertex('v1'));
$tree = $this->createTreeAlg($graph);
$tree->getVerticesSubtree($graph->getVertex('v1'));
}
public function testGraphWithUndirectedEdgeIsNotTree()
{
// v1 -- v2
$graph = new Graph();
$graph->createVertex('v1')->createEdge($graph->createVertex('v2'));
$tree = $this->createTreeAlg($graph);
$this->assertFalse($tree->isTree());
}
public function testGraphWithMixedEdgesIsNotTree()
{
// v1 -> v2 -- v3 -> v4
$graph = new Graph();
$graph->createVertex('v1')->createEdgeTo($graph->createVertex('v2'));
$graph->getVertex('v2')->createEdge($graph->createVertex('v3'));
$graph->getVertex('v3')->createEdgeTo($graph->createVertex('v4'));
$tree = $this->createTreeAlg($graph);
$this->assertFalse($tree->isTree());
}
}

View File

@@ -0,0 +1,48 @@
<?php
use Fhaculty\Graph\Graph;
use Graphp\Algorithms\Tree\InTree;
class InTreeTest extends BaseDirectedTest
{
protected function createGraphTree()
{
// c1 -> root <- c2
$graph = new Graph();
$root = $graph->createVertex();
$c1 = $graph->createVertex();
$c1->createEdgeTo($root);
$c2 = $graph->createVertex();
$c2->createEdgeTo($root);
return $graph;
}
protected function createTreeAlg(Graph $graph)
{
return new InTree($graph);
}
protected function createGraphNonTree()
{
// v1 -> v2 <- v3 -> v4
$graph = new Graph();
$graph->createVertex('v1')->createEdgeTo($graph->createVertex('v2'));
$graph->createVertex('v3')->createEdgeTo($graph->getVertex('v2'));
$graph->getVertex('v3')->createEdgeTo($graph->createVertex('v4'));
return $graph;
}
protected function createGraphParallelEdge()
{
// v1 <- v2, v1 <- v2
$graph = new Graph();
$graph->createVertex('v2')->createEdgeTo($graph->createVertex('v1'));
$graph->getVertex('v2')->createEdgeTo($graph->getVertex('v1'));
return $graph;
}
}

View File

@@ -0,0 +1,48 @@
<?php
use Fhaculty\Graph\Graph;
use Graphp\Algorithms\Tree\OutTree;
class OutTreeTest extends BaseDirectedTest
{
protected function createGraphTree()
{
// c1 <- root -> c2
$graph = new Graph();
$root = $graph->createVertex();
$c1 = $graph->createVertex();
$root->createEdgeTo($c1);
$c2 = $graph->createVertex();
$root->createEdgeTo($c2);
return $graph;
}
protected function createTreeAlg(Graph $graph)
{
return new OutTree($graph);
}
protected function createGraphNonTree()
{
// v1 -> v3 <- v2 -> v4
$graph = new Graph();
$graph->createVertex('v1')->createEdgeTo($graph->createVertex('v3'));
$graph->createVertex('v2')->createEdgeTo($graph->getVertex('v3'));
$graph->getVertex('v2')->createEdgeTo($graph->createVertex('v4'));
return $graph;
}
protected function createGraphParallelEdge()
{
// v1 -> v2, v1 -> v2
$graph = new Graph();
$graph->createVertex('v1')->createEdgeTo($graph->createVertex('v2'));
$graph->getVertex('v1')->createEdgeTo($graph->getVertex('v2'));
return $graph;
}
}

View File

@@ -0,0 +1,113 @@
<?php
use Fhaculty\Graph\Graph;
use Graphp\Algorithms\Tree\Undirected;
class UndirectedTest extends TestCase
{
protected function createTree(Graph $graph)
{
return new Undirected($graph);
}
public function testNullGraph()
{
$graph = new Graph();
$tree = $this->createTree($graph);
$this->assertFalse($tree->isTree());
$this->assertTrue($tree->getVerticesInternal()->isEmpty());
$this->assertTrue($tree->getVerticesLeaf()->isEmpty());
}
public function testGraphTrivial()
{
$graph = new Graph();
$graph->createVertex('v1');
$tree = $this->createTree($graph);
$this->assertTrue($tree->isTree());
$this->assertSame(array(), $tree->getVerticesInternal()->getVector());
$this->assertSame(array(), $tree->getVerticesLeaf()->getVector());
}
public function testGraphSimplePair()
{
// v1 -- v2
$graph = new Graph();
$graph->createVertex('v1')->createEdge($graph->createVertex('v2'));
$tree = $this->createTree($graph);
$this->assertTrue($tree->isTree());
$this->assertSame(array(), $tree->getVerticesInternal()->getVector());
$this->assertSame($graph->getVertices()->getVector(), $tree->getVerticesLeaf()->getVector());
}
public function testGraphSimpleLine()
{
// v1 -- v2 -- v3
$graph = new Graph();
$graph->createVertex('v1')->createEdge($graph->createVertex('v2'));
$graph->getVertex('v2')->createEdge($graph->createVertex('v3'));
$tree = $this->createTree($graph);
$this->assertTrue($tree->isTree());
$this->assertSame(array($graph->getVertex('v2')), $tree->getVerticesInternal()->getVector());
$this->assertSame(array($graph->getVertex('v1'), $graph->getVertex('v3')), $tree->getVerticesLeaf()->getVector());
}
public function testGraphPairParallelIsNotTree()
{
// v1 -- v2 -- v1
$graph = new Graph();
$graph->createVertex('v1')->createEdge($graph->createVertex('v2'));
$graph->getVertex('v1')->createEdge($graph->getVertex('v2'));
$tree = $this->createTree($graph);
$this->assertFalse($tree->isTree());
}
public function testGraphLoopIsNotTree()
{
// v1 -- v1
$graph = new Graph();
$graph->createVertex('v1')->createEdge($graph->getVertex('v1'));
$tree = $this->createTree($graph);
$this->assertFalse($tree->isTree());
}
public function testGraphCycleIsNotTree()
{
// v1 -- v2 -- v3 -- v1
$graph = new Graph();
$graph->createVertex('v1')->createEdge($graph->createVertex('v2'));
$graph->getVertex('v2')->createEdge($graph->createVertex('v3'));
$graph->getVertex('v3')->createEdge($graph->getVertex('v1'));
$tree = $this->createTree($graph);
$this->assertFalse($tree->isTree());
}
public function testGraphDirectedIsNotTree()
{
// v1 -> v2
$graph = new Graph();
$graph->createVertex('v1')->createEdgeTo($graph->createVertex('v2'));
$tree = $this->createTree($graph);
$this->assertFalse($tree->isTree());
}
public function testGraphMixedIsNotTree()
{
// v1 -- v2 -> v3
$graph = new Graph();
$graph->createVertex('v1')->createEdge($graph->createVertex('v2'));
$graph->getVertex('v2')->createEdgeTo($graph->createVertex('v3'));
$tree = $this->createTree($graph);
$this->assertFalse($tree->isTree());
}
}

View File

@@ -0,0 +1,58 @@
<?php
use Fhaculty\Graph\Graph;
use Graphp\Algorithms\Weight as AlgorithmWeight;
class WeightTest extends TestCase
{
public function testGraphEmpty()
{
$graph = new Graph();
$alg = new AlgorithmWeight($graph);
$this->assertEquals(null, $alg->getWeight());
$this->assertEquals(0, $alg->getWeightFlow());
$this->assertEquals(null, $alg->getWeightMin());
$this->assertFalse($alg->isWeighted());
return $graph;
}
/**
*
* @param Graph $graph
* @depends testGraphEmpty
*/
public function testGraphSimple(Graph $graph)
{
// 1 -> 2
$graph->createVertex(1)->createEdgeTo($graph->createVertex(2))->setWeight(3)->setFlow(4);
$alg = new AlgorithmWeight($graph);
$this->assertEquals(3, $alg->getWeight());
$this->assertEquals(12, $alg->getWeightFlow());
$this->assertEquals(3, $alg->getWeightMin());
$this->assertTrue($alg->isWeighted());
return $graph;
}
/**
*
* @param Graph $graph
* @depends testGraphSimple
*/
public function testGraphWithUnweightedEdges(Graph $graph)
{
$graph->createVertex(5)->createEdgeTo($graph->createVertex(6))->setFlow(7);
$alg = new AlgorithmWeight($graph);
$this->assertEquals(3, $alg->getWeight());
$this->assertEquals(12, $alg->getWeightFlow());
$this->assertEquals(3, $alg->getWeightMin());
$this->assertTrue($alg->isWeighted());
}
}

View File

@@ -0,0 +1,98 @@
<?php
use Fhaculty\Graph\Edge\Directed;
use Fhaculty\Graph\Edge\Base as Edge;
use Fhaculty\Graph\Graph;
use Fhaculty\Graph\Vertex;
use PHPUnit\Framework\TestCase as BaseTestCase;
(include_once __DIR__ . '/../vendor/autoload.php') OR die(PHP_EOL . 'ERROR: composer autoloader not found, run "composer install" or see README for instructions' . PHP_EOL);
class TestCase extends BaseTestCase
{
protected function assertGraphEquals(Graph $expected, Graph $actual)
{
$f = function(Graph $graph){
$ret = \get_class($graph);
$ret .= PHP_EOL . 'vertices: ' . \count($graph->getVertices());
$ret .= PHP_EOL . 'edges: ' . \count($graph->getEdges());
return $ret;
};
// assert graph base parameters are equal
$this->assertEquals($f($expected), $f($actual));
// next, assert that all vertices in both graphs are the same
// each vertex has a unique ID, therefor it's easy to search a matching partner
// do not use assertVertexEquals() in order to not increase assertion counter
foreach ($expected->getVertices()->getMap() as $vid => $vertex) {
$other = $actual->getVertex($vid);
assert(isset($other));
if ($this->getVertexDump($vertex) !== $this->getVertexDump($vertex)) {
$this->fail();
}
}
// next, assert that all edges in both graphs are the same
// assertEdgeEquals() does not work, as the order of the edges is unknown
// therefor, build an array of edge dump and make sure each entry has a match
$edgesExpected = array();
foreach ($expected->getEdges() as $edge) {
$edgesExpected[] = $this->getEdgeDump($edge);
}
foreach ($actual->getEdges() as $edge) {
$dump = $this->getEdgeDump($edge);
$pos = \array_search($dump, $edgesExpected, true);
if ($pos === false) {
$this->fail('given edge ' . $dump . ' not found');
} else {
unset($edgesExpected[$pos]);
}
}
}
protected function assertVertexEquals(Vertex $expected, Vertex $actual)
{
$this->assertEquals($this->getVertexDump($expected), $this->getVertexDump($actual));
}
protected function assertEdgeEquals(Edge $expected, Edge $actual)
{
$this->assertEquals($this->getEdgeDump($expected), $this->getEdgeDump($actual));
}
private function getVertexDump(Vertex $vertex)
{
$ret = \get_class($vertex);
$ret .= PHP_EOL . 'id: ' . $vertex->getId();
$ret .= PHP_EOL . 'attributes: ' . \json_encode($vertex->getAttributeBag()->getAttributes());
$ret .= PHP_EOL . 'balance: ' . $vertex->getBalance();
$ret .= PHP_EOL . 'group: ' . $vertex->getGroup();
return $ret;
}
private function getEdgeDump(Edge $edge)
{
$ret = \get_class($edge) . ' ';
if ($edge instanceof Directed) {
$ret .= $edge->getVertexStart()->getId() . ' -> ' . $edge->getVertexEnd()->getId();
} else {
$vertices = $edge->getVertices()->getIds();
$ret .= $vertices[0] . ' -- ' . $vertices[1];
}
$ret .= PHP_EOL . 'flow: ' . $edge->getFlow();
$ret .= PHP_EOL . 'capacity: ' . $edge->getCapacity();
$ret .= PHP_EOL . 'weight: ' . $edge->getWeight();
$ret .= PHP_EOL . 'attributes: ' . \json_encode($edge->getAttributeBag()->getAttributes());
return $ret;
}
}