Skip to content

Commit e95f125

Browse files
committed
Optimize time masks and schedule generation
Replace per-slot looping with a BigInt range-mask in meetingTimesToBinaryMask for faster mask construction and remove the now-unused helper. Introduce generateCombinations.ts: an optimized, iterative combination generator with prefix/skip logic and a MAX_RESULTS cap to avoid runaway generation. Update generateSchedules to use the new generator, precompute optional section masks, and rewrite addOptionalCourses to thread a combined bigint mask and respect MAX_RESULTS for early exit. Add extensive unit/benchmark tests to validate performance and correctness across many scenarios.
1 parent 3c72c58 commit e95f125

6 files changed

Lines changed: 1657 additions & 165 deletions

File tree

apps/searchneu/lib/scheduler/binaryMeetingTime.ts

Lines changed: 9 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -18,29 +18,22 @@ function timeToSlotIndex(time: number): number {
1818
return Math.floor(totalMinutes / MINUTES_PER_SLOT);
1919
}
2020

21-
/**
22-
* Get global slot index (0-2015) for a given day and slot within that day.
23-
*/
24-
function getGlobalSlotIndex(day: number, slot: number): number {
25-
return day * SLOTS_PER_DAY + slot;
26-
}
27-
2821
/**
2922
* Convert a section's meeting times to a binary mask.
30-
* Each occupied 5-minute slot gets one bit set.
23+
* Uses a range-mask formula to set a contiguous block of bits per meeting
24+
* in a single BigInt expression instead of looping over individual slots.
3125
*/
3226
export function meetingTimesToBinaryMask(section: SectionWithCourse): bigint {
33-
let mask = BigInt(0); // Use BigInt constructor to avoid ES2020 literal
27+
let mask = BigInt(0);
3428
for (const meetingTime of section.meetingTimes) {
3529
const startSlot = timeToSlotIndex(meetingTime.startTime);
36-
const endSlotExclusive = timeToSlotIndex(meetingTime.endTime);
37-
38-
// Set bits for each occupied slot
30+
const numSlots = timeToSlotIndex(meetingTime.endTime) - startSlot;
31+
if (numSlots <= 0) continue;
32+
// Create a block of `numSlots` consecutive 1-bits: (1 << numSlots) - 1
33+
const slotBlock = (BigInt(1) << BigInt(numSlots)) - BigInt(1);
3934
for (const day of meetingTime.days) {
40-
for (let slot = startSlot; slot < endSlotExclusive; slot++) {
41-
const globalSlot = getGlobalSlotIndex(day, slot);
42-
mask |= BigInt(1) << BigInt(globalSlot);
43-
}
35+
const globalStart = day * SLOTS_PER_DAY + startSlot;
36+
mask |= slotBlock << BigInt(globalStart);
4437
}
4538
}
4639
return mask;

0 commit comments

Comments
 (0)