phpOMS/Algorithm/JobScheduling/Weighted.php
2024-03-20 07:21:26 +00:00

148 lines
3.5 KiB
PHP
Executable File

<?php
/**
* Jingga
*
* PHP Version 8.2
*
* @package phpOMS\Algorithm\JobScheduling
* @copyright Dennis Eichhorn
* @license OMS License 2.0
* @version 1.0.0
* @link https://jingga.app
*/
declare(strict_types=1);
namespace phpOMS\Algorithm\JobScheduling;
/**
* Job scheduling algorithm with no overlapping jobs
*
* @package phpOMS\Algorithm\JobScheduling
* @license OMS License 2.0
* @link https://jingga.app
* @since 1.0.0
*/
final class Weighted
{
/**
* Constructor
*
* @since 1.0.0
* @codeCoverageIgnore
*/
private function __construct()
{
}
/**
* Sort jobs by end date.
*
* @param JobInterface $j1 Job 1
* @param JobInterface $j2 Job 2
*
* @return int
*
* @since 1.0.0
*/
private static function sortByEnd(JobInterface $j1, JobInterface $j2) : int
{
if ($j1->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 before a defined job
*
* @param JobInterface[] $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 JobInterface[] $jobs Jobs to filter
*
* @return JobInterface[]
*
* @since 1.0.0
*/
public static function solve(array $jobs) : array
{
$n = \count($jobs);
if ($n < 2) {
return $jobs;
}
\usort($jobs, function (\phpOMS\Algorithm\JobScheduling\JobInterface $j1, \phpOMS\Algorithm\JobScheduling\JobInterface $j2) : int {
return self::sortByEnd($j1, $j2);
});
$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];
}
}