Spaces:
Sleeping
Sleeping
Update constraint_engine.py
Browse files- constraint_engine.py +32 -0
constraint_engine.py
CHANGED
|
@@ -315,3 +315,35 @@ class ConstraintEngine:
|
|
| 315 |
for lit in at_slot: self.model.AddImplication(is_active.Not(), lit.Not())
|
| 316 |
literals.append(is_active)
|
| 317 |
self.model.Add(sum(literals) <= self.max_continuous_stretch)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 315 |
for lit in at_slot: self.model.AddImplication(is_active.Not(), lit.Not())
|
| 316 |
literals.append(is_active)
|
| 317 |
self.model.Add(sum(literals) <= self.max_continuous_stretch)
|
| 318 |
+
|
| 319 |
+
def _apply_no_first_hour_free(self):
|
| 320 |
+
"""
|
| 321 |
+
HARD CONSTRAINT:
|
| 322 |
+
Ensures that the first hour (slot 0) of every day is never free for any section.
|
| 323 |
+
Every section must have at least one class starting at slot 0 every day.
|
| 324 |
+
"""
|
| 325 |
+
from collections import defaultdict
|
| 326 |
+
import constants as const
|
| 327 |
+
|
| 328 |
+
tasks_by_sec = defaultdict(list)
|
| 329 |
+
for task in self.tasks:
|
| 330 |
+
tasks_by_sec[task.section.section_id].append(task)
|
| 331 |
+
|
| 332 |
+
for sec_id, sec_tasks in tasks_by_sec.items():
|
| 333 |
+
if not sec_tasks: continue
|
| 334 |
+
|
| 335 |
+
for day in range(const.NUM_WORKING_DAYS):
|
| 336 |
+
first_slot = day * const.NUM_TEACHING_SLOTS_PER_DAY
|
| 337 |
+
|
| 338 |
+
starts_at_first = []
|
| 339 |
+
for task in sec_tasks:
|
| 340 |
+
start_var = self.task_vars[task.task_id][0]
|
| 341 |
+
# We create a boolean variable that is True if start_var == first_slot
|
| 342 |
+
at_first = self.model.NewBoolVar(f"hard_at1st_{task.task_id}_d{day}")
|
| 343 |
+
self.model.Add(start_var == first_slot).OnlyEnforceIf(at_first)
|
| 344 |
+
self.model.Add(start_var != first_slot).OnlyEnforceIf(at_first.Not())
|
| 345 |
+
starts_at_first.append(at_first)
|
| 346 |
+
|
| 347 |
+
if starts_at_first:
|
| 348 |
+
# At least one task MUST start at the first slot
|
| 349 |
+
self.model.AddBoolOr(starts_at_first)
|