From a504f6bd0e170e1b4586834c28fde71936c3d5c0 Mon Sep 17 00:00:00 2001 From: Dennis Eichhorn Date: Thu, 17 Oct 2019 10:49:52 +0200 Subject: [PATCH] Implement weighted job scheduling --- Algorithm/JobScheduling/Job.php | 123 ++++++++++++++++++++++++ Algorithm/JobScheduling/Weighted.php | 135 +++++++++++++++++++++++++++ 2 files changed, 258 insertions(+) diff --git a/Algorithm/JobScheduling/Job.php b/Algorithm/JobScheduling/Job.php index e69de29bb..73fda98de 100644 --- a/Algorithm/JobScheduling/Job.php +++ b/Algorithm/JobScheduling/Job.php @@ -0,0 +1,123 @@ +value = $value; + $this->start = $start; + $this->end = $end; + $this->name = $name; + } + + /** + * Get value of the job + * + * @return float + * + * @since 1.0.0 + */ + public function getValue() : float + { + return $this->value; + } + + /** + * Get start time of the job + * + * @return \DateTime + * + * @since 1.0.0 + */ + public function getStart() : \DateTime + { + return $this->start; + } + + /** + * Get end time of the job + * + * @return \DateTime + * + * @since 1.0.0 + */ + public function getEnd() : ?\DateTime + { + return $this->end; + } + + /** + * Get the name of the job + * + * @return string + * + * @since 1.0.0 + */ + public function getName() : string + { + return $this->name; + } +} diff --git a/Algorithm/JobScheduling/Weighted.php b/Algorithm/JobScheduling/Weighted.php index e69de29bb..423363492 100644 --- a/Algorithm/JobScheduling/Weighted.php +++ b/Algorithm/JobScheduling/Weighted.php @@ -0,0 +1,135 @@ +getEnd() === null && $j2->getEnd() !== null) { + return 1; + } + + if ($j1->getEnd() === null && $j2->getEnd() === null) { + return 0; + } + + if ($j1->getEnd() !== null && $j2->getEnd() === null) { + return -1; + } + + return $j1->getEnd()->getTimestamp() <=> $j2->getEnd()->getTimestamp(); + } + + /** + * Search for a none-conflicting job that comes befor a defined job + * + * @param Job[] $jobs List of jobs + * @param int $pivot Job to find the previous job to + * + * @return int + * + * @since 1.0.0 + */ + private static function binarySearch(array $jobs, int $pivot) : int + { + $lo = 0; + $hi = $pivot - 1; + + while ($lo <= $hi) { + $mid = (int) (($lo + $hi) / 2); + + if ($jobs[$mid]->getEnd() !== null + && $jobs[$mid]->getEnd()->getTimestamp() <= $jobs[$pivot]->getStart()->getTimestamp() + ) { + if ($jobs[$mid + 1]->getEnd() !== null + && $jobs[$mid + 1]->getEnd()->getTimestamp() <= $jobs[$pivot]->getStart()->getTimestamp() + ) { + $lo = $mid + 1; + } else { + return $mid; + } + } else { + $hi = $mid - 1; + } + } + + return -1; + } + + /** + * Maximize the value of the job execution without overlapping jobs + * + * @param Job[] $jobs Jobs to filter + * + * @return Job[] + * + * @since 1.0.0 + */ + public static function solve(array $jobs) : array + { + $n = \count($jobs); + + if ($n < 2) { + return $jobs; + } + + \usort($jobs, [self::class, 'sortByEnd']); + + $valueTable = [$jobs[0]->getValue()]; + + $resultTable = []; + $resultTable[0] = [$jobs[0]]; + + for ($i = 1; $i < $n; ++$i) { + $value = $jobs[$i]->getValue(); + $jList = [$jobs[$i]]; + $l = self::binarySearch($jobs, $i); + + if ($l != -1) { + $value += $valueTable[$l]; + $jList = \array_merge($resultTable[$l], $jList); + } + + if ($value > $valueTable[$i - 1]) { + $valueTable[$i] = $value; + $resultTable[$i] = $jList; + } else { + $valueTable[$i] = $valueTable[$i - 1]; + $resultTable[$i] = $resultTable[$i - 1]; + } + } + + return $resultTable[$n - 1]; + } +}