Assigning consecutive classes for a teacher #3474
-
Problem:
Code: from ortools.sat.python import cp_model
class TeacherPeriodsSolutionPrinter(cp_model.CpSolverSolutionCallback):
"""Print intermediate solutions."""
def __init__(self, periods, num_teachers, num_days, num_periods, sols):
cp_model.CpSolverSolutionCallback.__init__(self)
self._periods = periods
self._num_teachers = num_teachers
self._num_days = num_days
self._num_periods = num_periods
self._solutions = set(sols)
self._solution_count = 0
def on_solution_callback(self):
if self._solution_count in self._solutions:
print('Solution %i' % self._solution_count)
for t in range(self._num_teachers):
for d in range(self._num_days):
for p in range(self._num_periods):
if self.Value(self._periods[(t, d, p)]):
print("Teacher %i teaches on day %i and period %i." % (t, d, p))
print()
self._solution_count += 1
def solution_count(self):
return self._solution_count
def main():
# Data.
num_teachers = 2
num_days = 5
num_periods = 3 # Maximum number of periods in a day.
all_teachers = range(num_teachers)
all_days = range(num_days)
all_periods = range(num_periods)
# Creates the model.
model = cp_model.CpModel()
# Create variables.
periods = {}
for d in all_days:
for p in all_periods:
for t in all_teachers:
periods[(t, d, p)] = model.NewBoolVar('t%i_d%i_p%i' % (t, d, p))
# Constraints.
# Each Teacher should teach 4 classes in a week.
for t in all_teachers:
model.Add(sum(periods[(t, d, p)] for d in all_days for p in all_periods) == 4)
# Only one teacher can teach in a period.
for d in all_days:
for p in all_periods:
model.Add(sum(periods[(t, d, p)] for t in all_teachers) < 2)
# Contraint for Sam?
# Creates the solver and solve.
solver = cp_model.CpSolver()
solver.parameters.linearization_level = 0
a_few_solutions = range(2)
solution_printer = TeacherPeriodsSolutionPrinter(periods, num_teachers, num_days,
num_periods, a_few_solutions)
solver.Solve(model)
for t in range(num_teachers):
for d in range(num_days):
for p in range(num_periods):
if solver.Value(periods[(t, d, p)]):
print("Teacher %i teaches on day %i and period %i." % (t, d, p))
print()
# Statistics.
print()
print('Statistics')
print(' - wall time : %f s' % solver.WallTime())
print(' - Number of period requests met : %i' % solver.ObjectiveValue()),
if __name__ == '__main__':
main() How do I solve the consecutive class constraint? The solution should be generic enough to work for |
Beta Was this translation helpful? Give feedback.
Replies: 4 comments 9 replies
-
What do you mean by consecutive?
You do not have a notion of time in your solver.
Does consecutive `===`
```
if (from_period + 1 == to_period)
then consecutive[from_period,to_period]=True
else consecutive[from_period,to_period]=False
```
James
|
Beta Was this translation helpful? Give feedback.
-
off topic you also miss
aka # at most three classes in a day
for d in all_days:
model.Add(sum(periods[(t, d, p)] for t in all_teachers for p in all_periods) <= 3) |
Beta Was this translation helpful? Give feedback.
-
Okay, so what I said.
So use that rule to define booleans, for consecutive classes, then set your constraint using that.
Check out the help docs for Boolean logic, esp the part about how to multiply two Booleans
ConsecutiveboolAB * teacherAclassA * teacherAclassB = BoolTeacherDoesConsecutiveClass
Etc.
James
… On Sep 26, 2022, at 11:00, sarthakgaur ***@***.***> wrote:
Yes.
—
Reply to this email directly, view it on GitHub, or unsubscribe.
You are receiving this because you commented.
|
Beta Was this translation helpful? Give feedback.
-
Here is the solution to the problem: def negated_bounded_span(works, start, length):
sequence = []
# Left border (start of works, or works[start - 1])
if start > 0:
sequence.append(works[start - 1])
for i in range(length):
sequence.append(works[start + i].Not())
# Right border (end of works or works[start + length])
if start + length < len(works):
sequence.append(works[start + length])
return sequence
def add_hard_sequence_constraint(model, works, hard_min, hard_max):
# Forbid sequences that are too short.
for length in range(1, hard_min):
for start in range(len(works) - length + 1):
model.AddBoolOr(negated_bounded_span(works, start, length))
# Just forbid any sequence of true variables with length hard_max + 1
for start in range(len(works) - hard_max):
model.AddBoolOr([works[i].Not() for i in range(start, start + hard_max + 1)])
# Contraint for Sam
sam = 1
for d in all_days:
works = [periods[(sam, d, p)] for p in all_periods]
add_hard_sequence_constraint(model, works, 2, 2) References: |
Beta Was this translation helpful? Give feedback.
Here is the solution to the problem: