spread heavy workload days

This commit is contained in:
Yisroel Baum 2026-08-20 08:21:15 +03:00
parent 85e2c33c31
commit 6dc2ccbb55
Signed by: yisroelbaum
GPG key ID: 0FA60884F75520A9
2 changed files with 65 additions and 53 deletions

View file

@ -18,15 +18,7 @@ class EvenDistributionScheduler
$differenceInDays = $startDate->diff($targetDate)->days; $differenceInDays = $startDate->diff($targetDate)->days;
$dayCount = $differenceInDays + 1; $dayCount = $differenceInDays + 1;
if ($workloadPlacement === WorkloadPlacement::Spread) { return $this->distributedDates(
return $this->sparseDates(
assignmentCount: $assignmentCount,
dayCount: $dayCount,
startDate: $startDate,
);
}
return $this->groupedDates(
assignmentCount: $assignmentCount, assignmentCount: $assignmentCount,
dayCount: $dayCount, dayCount: $dayCount,
startDate: $startDate, startDate: $startDate,
@ -37,33 +29,7 @@ class EvenDistributionScheduler
/** /**
* @return list<DateTimeImmutable> * @return list<DateTimeImmutable>
*/ */
private function sparseDates( private function distributedDates(
int $assignmentCount,
int $dayCount,
DateTimeImmutable $startDate,
): array {
if ($assignmentCount === 1) {
return [$startDate];
}
$dates = [];
for ($assignmentIndex = 0;
$assignmentIndex < $assignmentCount;
$assignmentIndex++
) {
$scaledIndex = $assignmentIndex * ($dayCount - 1)
/ ($assignmentCount - 1);
$dayIndex = (int) floor($scaledIndex + 0.5);
$dates[] = $startDate->modify("+{$dayIndex} days");
}
return $dates;
}
/**
* @return list<DateTimeImmutable>
*/
private function groupedDates(
int $assignmentCount, int $assignmentCount,
int $dayCount, int $dayCount,
DateTimeImmutable $startDate, DateTimeImmutable $startDate,
@ -71,19 +37,18 @@ class EvenDistributionScheduler
): array { ): array {
$assignmentsPerDay = intdiv($assignmentCount, $dayCount); $assignmentsPerDay = intdiv($assignmentCount, $dayCount);
$remainderDayCount = $assignmentCount % $dayCount; $remainderDayCount = $assignmentCount % $dayCount;
$remainderBlockStart = $this->remainderBlockStart( $remainderDayIndexes = $this->remainderDayIndexes(
assignmentsPerDay: $assignmentsPerDay,
dayCount: $dayCount, dayCount: $dayCount,
remainderDayCount: $remainderDayCount, remainderDayCount: $remainderDayCount,
workloadPlacement: $workloadPlacement, workloadPlacement: $workloadPlacement,
); );
$remainderDays = array_fill_keys($remainderDayIndexes, true);
$dates = []; $dates = [];
for ($dayIndex = 0; $dayIndex < $dayCount; $dayIndex++) { for ($dayIndex = 0; $dayIndex < $dayCount; $dayIndex++) {
$assignmentCountForDay = $assignmentsPerDay; $assignmentCountForDay = $assignmentsPerDay;
if ( if (isset($remainderDays[$dayIndex])) {
$dayIndex >= $remainderBlockStart
&& $dayIndex < $remainderBlockStart + $remainderDayCount
) {
$assignmentCountForDay++; $assignmentCountForDay++;
} }
@ -96,6 +61,65 @@ class EvenDistributionScheduler
return $dates; return $dates;
} }
/**
* @return list<int>
*/
private function remainderDayIndexes(
int $assignmentsPerDay,
int $dayCount,
int $remainderDayCount,
WorkloadPlacement $workloadPlacement,
): array {
if ($remainderDayCount === 0) {
return [];
}
if ($workloadPlacement === WorkloadPlacement::Spread) {
return $this->spreadRemainderDayIndexes(
assignmentsPerDay: $assignmentsPerDay,
dayCount: $dayCount,
remainderDayCount: $remainderDayCount,
);
}
$blockStart = $this->remainderBlockStart(
dayCount: $dayCount,
remainderDayCount: $remainderDayCount,
workloadPlacement: $workloadPlacement,
);
return range($blockStart, $blockStart + $remainderDayCount - 1);
}
/**
* @return list<int>
*/
private function spreadRemainderDayIndexes(
int $assignmentsPerDay,
int $dayCount,
int $remainderDayCount,
): array {
if ($remainderDayCount === 1) {
if ($assignmentsPerDay === 0) {
return [0];
}
return [intdiv($dayCount - 1, 2)];
}
$dayIndexes = [];
for ($remainderIndex = 0;
$remainderIndex < $remainderDayCount;
$remainderIndex++
) {
$scaledIndex = $remainderIndex * ($dayCount - 1)
/ ($remainderDayCount - 1);
$dayIndexes[] = (int) floor($scaledIndex + 0.5);
}
return $dayIndexes;
}
private function remainderBlockStart( private function remainderBlockStart(
int $dayCount, int $dayCount,
int $remainderDayCount, int $remainderDayCount,

View file

@ -248,9 +248,6 @@ class CreateSchedule
return $workloadPlacement; return $workloadPlacement;
} }
/**
* @throws BadRequestException
*/
private function resolvedWorkloadPlacement( private function resolvedWorkloadPlacement(
?WorkloadPlacement $requestedWorkloadPlacement, ?WorkloadPlacement $requestedWorkloadPlacement,
int $assignmentCount, int $assignmentCount,
@ -267,15 +264,6 @@ class CreateSchedule
: WorkloadPlacement::Middle; : WorkloadPlacement::Middle;
} }
if (
$requestedWorkloadPlacement === WorkloadPlacement::Spread
&& ! $isSparse
) {
throw new BadRequestException(
'spread placement requires fewer assignments than days',
);
}
return $requestedWorkloadPlacement; return $requestedWorkloadPlacement;
} }
} }