Skip to content

Commit

Permalink
Merge pull request #74 from clue/fix-algo-minimumcostflow
Browse files Browse the repository at this point in the history
Fix Algorithm\MinimumCostFlow
  • Loading branch information
clue committed Dec 31, 2013
2 parents 23985a2 + 2b7b8b8 commit 3ce5097
Show file tree
Hide file tree
Showing 7 changed files with 269 additions and 65 deletions.
7 changes: 6 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,12 @@ you spot any mistakes.
* Fix: Throwing an `UnexpectedValueException` if writing GraphViz Dot script
to a temporary file fails and remove its debugging output
([#77](https://github.com/clue/graph/issues/77) and [#78](https://github.com/clue/graph/issues/78) @Metabor)


* Fix: The `Algorithm\MinimumCostFlow` algorithms now work again. The reference
to a non-existant class has been updated. Also fixed several issues with
regards to special cases such as disconnected or undirected graphs.
([#74](https://github.com/clue/graph/issues/74)

* BC break: Remove unneeded alias definitions of `getVertexFirst()`,
`getVertexSource()` and `getVertexTarget()`
[#76]https://github.com/clue/graph/issues/76)):
Expand Down
5 changes: 4 additions & 1 deletion lib/Fhaculty/Graph/Algorithm/MinimumCostFlow/Base.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

use Fhaculty\Graph\Algorithm\BaseGraph;
use Fhaculty\Graph\Algorithm\Weight as AlgorithmWeight;
use Fhaculty\Graph\Algorithm\Flow as AlgorithmFlow;
use Fhaculty\Graph\Exception\UnderflowException;
use Fhaculty\Graph\Edge\Base as Edge;
use Fhaculty\Graph\Set\Edges;
Expand All @@ -20,7 +21,9 @@ abstract class Base extends BaseGraph
*/
protected function checkBalance()
{
$balance = $this->graph->getBalance();
$alg = new AlgorithmFlow($this->graph);
$balance = $alg->getBalance();

$tolerance = 0.000001;
if ($balance >= $tolerance || $balance <= -$tolerance) {
throw new UnexpectedValueException('The given graph is not balanced value is: ' . $balance);
Expand Down
26 changes: 11 additions & 15 deletions lib/Fhaculty/Graph/Algorithm/MinimumCostFlow/CycleCanceling.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,8 @@

namespace Fhaculty\Graph\Algorithm\MinimumCostFlow;


use Fhaculty\Graph\Exception\UnexpectedValueException;

use Fhaculty\Graph\Exception\UnderflowException;

use Fhaculty\Graph\Edge\Base as Edge;
use Fhaculty\Graph\Set\Edges;
use Fhaculty\Graph\Algorithm\MaxFlow\EdmondsKarp as MaxFlowEdmondsKarp;
Expand All @@ -29,17 +26,16 @@ public function createGraph()

// connect supersource s* and supersink t* with all "normal" sources and sinks
foreach ($resultGraph->getVertices() as $vertex) {
// $vertex->getFlow();
$flow = $vertex->getBalance();
$b = abs($vertex->getBalance());
// source
if ($flow > 0) {
$superSource->createEdgeTo($vertex)->setCapacity($b);

$sumBalance += $flow;
// sink
} elseif ($flow < 0) {
$vertex->createEdgeTo($superSink)->setCapacity($b);
$balance = $vertex->getBalance();

if ($balance > 0) {
// positive balance => source capacity
$superSource->createEdgeTo($vertex)->setCapacity($balance);

$sumBalance += $balance;
} elseif ($balance < 0) {
// negative balance => sink capacity (positive)
$vertex->createEdgeTo($superSink)->setCapacity(-$balance);
}
}

Expand All @@ -62,8 +58,8 @@ public function createGraph()
$alg = new DetectNegativeCycle($residualGraph);
try {
$clonedEdges = $alg->getCycleNegative()->getEdges();
// no negative cycle found => end algorithm
} catch (UnderflowException $ignore) {
// no negative cycle found => end algorithm
break;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,8 @@
namespace Fhaculty\Graph\Algorithm\MinimumCostFlow;

use Fhaculty\Graph\Exception\DomainException;

use Fhaculty\Graph\Exception\UnderflowException;

use Fhaculty\Graph\Exception\UnexpectedValueException;

use Fhaculty\Graph\Graph;
use Fhaculty\Graph\Vertex;
use Fhaculty\Graph\Edge\Base as Edge;
Expand All @@ -21,10 +18,9 @@ class SuccessiveShortestPath extends Base
{
/**
* @uses Graph::createGraphClone()
* @uses AlgorithmResidualGraph::createGraph()
* @uses AlgorithmSpMooreBellmanFord::getEdgesTo(Vertex $targetVertex)
*
* @see AlgorithmMCF::createGraph()
* @uses ResidualGraph::createGraph()
* @uses SpMooreBellmanFord::getEdgesTo(Vertex $targetVertex)
* @see Base::createGraph()
*/
public function createGraph()
{
Expand All @@ -40,29 +36,29 @@ public function createGraph()
// initial flow of edges
$edges = $resultGraph->getEdges();
foreach ($edges as $edge) {
// 0 if weight of edge is positiv
if (!($edge instanceof EdgeDirected)) {
throw new UnexpectedValueException('Undirected edges are not supported for SuccessiveShortestPath');
}

// 0 if weight of edge is positive
$flow = 0;

// maximal flow if weight of edge is negative
if ($edge->getWeight() < 0) {
$flow = $edge->getCapacity();

if ($edge instanceof EdgeDirected) {
$startVertex = $edge->getVertexStart();
$endVertex = $edge->getVertexEnd();
$startVertex = $edge->getVertexStart();
$endVertex = $edge->getVertexEnd();

// add balance to start- and end-vertex
$this->addBalance($startVertex, $flow);
$this->addBalance($endVertex, - $flow);
} else {
throw new UnexpectedValueException('Undirected Edges not suported');
}
// add balance to start- and end-vertex
$this->addBalance($startVertex, $flow);
$this->addBalance($endVertex, - $flow);
}

$edge->setFlow($flow);
}

// return or Exception insite this while
// return or Exception inside this while
while (true) {
// create residual graph
$algRG = new ResidualGraph($resultGraph);
Expand All @@ -71,25 +67,25 @@ public function createGraph()
// search for a source
try {
$sourceVertex = $this->getVertexSource($residualGraph);
// if no source is found the minimum-cost flow is found
} catch (UnderflowException $ignore) {
// no source is found => minimum-cost flow is found
break;
}

// search for reachble sink from this source
// search for reachable target sink from this source
try {
$targetVertex = $this->getVertexSink($sourceVertex);
// if no target is found the network has not enough capacity
} catch (UnderflowException $ignore) {
throw new UnexpectedValueException('The graph has not enough capacity for the minimum-cost flow');
} catch (UnderflowException $e) {
// no target found => network does not have enough capacity
throw new UnexpectedValueException('The graph has not enough capacity for the minimum-cost flow', 0, $e);
}

// calculate shortest path between source- and target-vertex
$algSP = new SpMooreBellmanFord($sourceVertex);
$edgesOnFlow = $algSP->getEdgesTo($targetVertex);

// calculate the maximal possible flow
// new flow is the maximal possible flow for this path
// new flow is the maximal possible flow for this path
$newflow = $this->graph->getVertex($sourceVertex->getId())->getBalance() - $sourceVertex->getBalance();
$targetFlow = - ($this->graph->getVertex($targetVertex->getId())->getBalance() - $targetVertex->getBalance());

Expand All @@ -107,7 +103,7 @@ public function createGraph()
// add the new flow to the path
$this->addFlow($resultGraph, $edgesOnFlow, $newflow);

// add balance to source and remove for the sink
// add balance to source and remove for the target sink
$oriSourceVertex = $resultGraph->getVertex($sourceVertex->getId());
$oriTargetVertex = $resultGraph->getVertex($targetVertex->getId());

Expand All @@ -118,29 +114,6 @@ public function createGraph()
return $resultGraph;
}

/**
* check if balance on each vertex of the given graph matches the original graph's
*
* @param Graph $graph
* @return boolean
* @throws Exception if given graph is not a clone of the original graph (each vertex has to be present in both graphs)
* @uses Graph::getBalanace()
* @uses Graph::getVertex()
*/
private function isBalanceReached(Graph $graph)
{
if (count($graph->getVertices()) !== count($this->graph->getVertices())) {
throw new DomainException('Given graph does not appear to be a clone of input graph');
}
foreach ($this->graph->getVertices()->getMap() as $vid => $vertex) {
if ($vertex->getBalance() !== $graph->getVertex($vid)->getBalance()) {
return false;
}
}

return true;
}

/**
*
*
Expand Down
Loading

0 comments on commit 3ce5097

Please sign in to comment.