使用 Optapy 的学校时间表 - 允许从列表中选择老师上课
School timetabling with Optapy - allow to choose teacher from a list for a lesson
我正在尝试以学校时间表示例为基础使用 Optapy。
对于任何给定的科目,我都有一份可能教授该科目的教师名单,每位教师可能会教授 1 到 3 门科目。我想优化课程的教师分配,这样,每个学生组在任何给定科目上只能有一名老师,并且每个学生组在任何科目上都应该很少上课(即给定学生组 A 的 4 次数学课由老师 B)
为此,我尝试添加这个问题事实:
@problem_fact
class Teacher:
def __init__(self, id, name, subject, subject2, subject3):
self.id = id
self.name = name
self.subject = subject
self.subject2 = subject2
self.subject3 = subject3
@planning_id
def get_id(self):
return self.id
def __str__(self):
return (
f"Teacher("
f"id={self.id}, "
f"name={self.name}, "
f"subject={self.subject}, "
f"subject2={self.subject2}, "
f"subject3={self.subject3})"
)
并且我向规划实体添加了规划变量:
@planning_variable(Teacher, ["teacherRange"])
def get_teacher(self):
return self.teacher
def set_teacher(self, new_teacher):
self.teacher = new_teacher
但我不知道如何继续制作从列表中选择一位老师的算法,以及如何为任何科目的一个学生组添加一位老师的约束。有帮助吗?
为了使算法从列表中选择老师,必须从 @planning_solution
class 上的方法返回列表,并用适当的 @value_range_provider
注释:
@planning_solution
class TimeTable:
def __init__(self, teacher_list, ..., score=None):
self.teacher_list = teacher_list
# ...
self.score = score
@problem_fact_collection_property(Teacher)
@value_range_provider("teacherRange")
def get_teacher_list(self):
return self.teacher_list
# rest of the class
对于“任何科目的一个学生组的一位老师”的约束,我将其改写为“学生组的科目一致的老师”(即,如果一节课有相同的学生组和科目,它也必须有同一个老师)。应该这样写:
def consistent_teacher_for_subject_and_student_group(constraint_factory: ConstraintFactory):
return constraint_factory \
.forEach(LessonClass) \
.join(LessonClass,
[
# ... the same student group ...
Joiners.equal(lambda lesson: lesson.student_group),
# ... the same subject ...
Joiners.equal(lambda lesson: lesson.subject),
# form unique pairs
Joiners.lessThan(lambda lesson: lesson.id)
]) \
.filter(lambda lesson1, lesson2: lesson1.teacher != lesson2.teacher) \
.penalize("Different teacher for the same student group and subject", HardSoftScore.ONE_HARD)
对于“teacher must be able to teach subject”这一约束条件,您可以使用过滤器:
def teacher_must_be_able_to_teach_subject(constraint_factory: ConstraintFactory):
return constraint_factory \
.forEach(LessonClass) \
.filter(lambda lesson: lesson.subject not in {lesson.teacher.subject, lesson.teacher.subject2, lesson.teacher.subject3}) \
.penalize("Teacher cannot teach subject", HardSoftScore.ONE_HARD)
我正在尝试以学校时间表示例为基础使用 Optapy。 对于任何给定的科目,我都有一份可能教授该科目的教师名单,每位教师可能会教授 1 到 3 门科目。我想优化课程的教师分配,这样,每个学生组在任何给定科目上只能有一名老师,并且每个学生组在任何科目上都应该很少上课(即给定学生组 A 的 4 次数学课由老师 B)
为此,我尝试添加这个问题事实:
@problem_fact
class Teacher:
def __init__(self, id, name, subject, subject2, subject3):
self.id = id
self.name = name
self.subject = subject
self.subject2 = subject2
self.subject3 = subject3
@planning_id
def get_id(self):
return self.id
def __str__(self):
return (
f"Teacher("
f"id={self.id}, "
f"name={self.name}, "
f"subject={self.subject}, "
f"subject2={self.subject2}, "
f"subject3={self.subject3})"
)
并且我向规划实体添加了规划变量:
@planning_variable(Teacher, ["teacherRange"])
def get_teacher(self):
return self.teacher
def set_teacher(self, new_teacher):
self.teacher = new_teacher
但我不知道如何继续制作从列表中选择一位老师的算法,以及如何为任何科目的一个学生组添加一位老师的约束。有帮助吗?
为了使算法从列表中选择老师,必须从 @planning_solution
class 上的方法返回列表,并用适当的 @value_range_provider
注释:
@planning_solution
class TimeTable:
def __init__(self, teacher_list, ..., score=None):
self.teacher_list = teacher_list
# ...
self.score = score
@problem_fact_collection_property(Teacher)
@value_range_provider("teacherRange")
def get_teacher_list(self):
return self.teacher_list
# rest of the class
对于“任何科目的一个学生组的一位老师”的约束,我将其改写为“学生组的科目一致的老师”(即,如果一节课有相同的学生组和科目,它也必须有同一个老师)。应该这样写:
def consistent_teacher_for_subject_and_student_group(constraint_factory: ConstraintFactory):
return constraint_factory \
.forEach(LessonClass) \
.join(LessonClass,
[
# ... the same student group ...
Joiners.equal(lambda lesson: lesson.student_group),
# ... the same subject ...
Joiners.equal(lambda lesson: lesson.subject),
# form unique pairs
Joiners.lessThan(lambda lesson: lesson.id)
]) \
.filter(lambda lesson1, lesson2: lesson1.teacher != lesson2.teacher) \
.penalize("Different teacher for the same student group and subject", HardSoftScore.ONE_HARD)
对于“teacher must be able to teach subject”这一约束条件,您可以使用过滤器:
def teacher_must_be_able_to_teach_subject(constraint_factory: ConstraintFactory):
return constraint_factory \
.forEach(LessonClass) \
.filter(lambda lesson: lesson.subject not in {lesson.teacher.subject, lesson.teacher.subject2, lesson.teacher.subject3}) \
.penalize("Teacher cannot teach subject", HardSoftScore.ONE_HARD)