perf(planning): reuse immutable non-working date counts
This commit is contained in:
1 parent
c7e7abcd24
commit
433a8b0ade
3 files changed
+95
-3
No files matched your search
@@ -75,6 +75,29 @@ describe('composable planning objectives', () => {
|
||||
).toEqual([3, 7, 4, 6, 5, 2]);
|
||||
});
|
||||
|
||||
it.each(['sum', 'count', 'maximum'] as const)(
|
||||
'keeps %s distinct-date scores current with frozen and mutable period dates',
|
||||
(aggregation) => {
|
||||
const mutableDates = ['2024-05-08'];
|
||||
const observations: OptimizationObservations = {
|
||||
...empty,
|
||||
timeOffPeriods: Object.freeze([
|
||||
Object.freeze({
|
||||
nonWorkingDates: Object.freeze(['2024-01-06', '2024-01-07', '2024-01-07']),
|
||||
}),
|
||||
Object.freeze({ nonWorkingDates: mutableDates }),
|
||||
]),
|
||||
};
|
||||
const configuration = { ...OPTIMIZATION_PRESETS.nonWorkingDayGain, aggregation };
|
||||
const initial = { sum: 3, count: 2, maximum: 2 };
|
||||
expect(evaluateOptimization(configuration, observations)).toBe(initial[aggregation]);
|
||||
expect(evaluateOptimization(configuration, observations)).toBe(initial[aggregation]);
|
||||
mutableDates.push('2024-05-09', '2024-05-09', '2024-05-11');
|
||||
const updated = { sum: 5, count: 2, maximum: 3 };
|
||||
expect(evaluateOptimization(configuration, observations)).toBe(updated[aggregation]);
|
||||
},
|
||||
);
|
||||
|
||||
it.each(['sum', 'count', 'maximum'] as const)(
|
||||
'defines empty %s as zero for every measure',
|
||||
(aggregation) => {
|
||||
|
||||
@@ -203,6 +203,9 @@ export interface OptimizationObservations {
|
||||
leavePlacements: readonly { supporting: boolean }[];
|
||||
}
|
||||
|
||||
// Calendar geometry reuses frozen date arrays across candidate plans.
|
||||
const nonWorkingDateCounts = new WeakMap<readonly string[], number>();
|
||||
|
||||
export function evaluateOptimization(
|
||||
configuration: OptimizationConfiguration,
|
||||
observations: OptimizationObservations,
|
||||
@@ -224,9 +227,14 @@ export function evaluateOptimization(
|
||||
.map((week) => week.value);
|
||||
break;
|
||||
case 'time-off-periods':
|
||||
values = observations.timeOffPeriods.map(
|
||||
(period) => new Set(period.nonWorkingDates).size,
|
||||
);
|
||||
values = observations.timeOffPeriods.map(({ nonWorkingDates }) => {
|
||||
const cached = nonWorkingDateCounts.get(nonWorkingDates);
|
||||
if (cached !== undefined) return cached;
|
||||
const count = new Set(nonWorkingDates).size;
|
||||
if (Object.isFrozen(nonWorkingDates))
|
||||
nonWorkingDateCounts.set(nonWorkingDates, count);
|
||||
return count;
|
||||
});
|
||||
break;
|
||||
case 'work-sequences':
|
||||
values = observations.workSequences
|
||||
|
||||
Reference in new issue
Block a user