Files
Chamilo/vendor/graphp/algorithms/src/MinimumCostFlow/CycleCanceling.php
T
Xes 73154ae174
Behat tests 1.11.x 🐞 / PHP 7.4 Test on ubuntu-latest (push) Canceled after 0s
PHP-CS-Fixer / composer_install (7.4) (push) Canceled after 0s
Chamilo 1.11.40 (ZIP oficial v1.11.40)
Fuente: https://github.com/chamilo/chamilo-lms/releases/download/v1.11.40/chamilo-1.11.40.zip
sha256: 1cf4bf2cc7bae1ef1a1eff643235db1d552f78ddf4b6dd1e2d2dac9868679439
Snapshot independiente (rama huerfana); diffable vs 1.11.38. vendor incluido.
2026-08-06 17:59:45 +02:00

80 lines
2.7 KiB
PHP

<?php
namespace Graphp\Algorithms\MinimumCostFlow;
use Fhaculty\Graph\Exception\UnderflowException;
use Fhaculty\Graph\Exception\UnexpectedValueException;
use Fhaculty\Graph\Set\Edges;
use Graphp\Algorithms\DetectNegativeCycle;
use Graphp\Algorithms\MaxFlow\EdmondsKarp as MaxFlowEdmondsKarp;
use Graphp\Algorithms\ResidualGraph;
class CycleCanceling extends Base
{
public function createGraph()
{
$this->checkBalance();
// create resulting graph with supersource and supersink
$resultGraph = $this->graph->createGraphClone();
$superSource = $resultGraph->createVertex();
$superSink = $resultGraph->createVertex();
$sumBalance = 0;
// connect supersource s* and supersink t* with all "normal" sources and sinks
foreach ($resultGraph->getVertices() as $vertex) {
$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);
}
}
// calculate (s*, t*)-flow
$algMaxFlow = new MaxFlowEdmondsKarp($superSource, $superSink);
$flowMax = $algMaxFlow->getFlowMax();
if ($flowMax !== $sumBalance) {
throw new UnexpectedValueException('Network does not support required flow of ' . $sumBalance . ' (maximum possible flow limited to ' . $flowMax . ')');
}
$resultGraph = $algMaxFlow->createGraph();
while (true) {
// create residual graph
$algRG = new ResidualGraph($resultGraph);
$residualGraph = $algRG->createGraph();
// get negative cycle
$alg = new DetectNegativeCycle($residualGraph);
try {
$clonedEdges = $alg->getCycleNegative()->getEdges();
} catch (UnderflowException $ignore) {
// no negative cycle found => end algorithm
break;
}
// calculate maximal possible flow = minimum capacity remaining for all edges
$newFlow = $clonedEdges->getEdgeOrder(Edges::ORDER_CAPACITY_REMAINING)->getCapacityRemaining();
// set flow on original graph
assert($newFlow !== null);
$this->addFlow($resultGraph, $clonedEdges, $newFlow);
}
// destroy temporary supersource and supersink again
$resultGraph->getVertex($superSink->getId())->destroy();
$resultGraph->getVertex($superSource->getId())->destroy();
return $resultGraph;
}
}