optaplanner 调度 AI 是否适合优化大学日程?
Is optaplanner scheduling AI suitable for optimising a college schedule?
Optaplanner school timetabling 示例显示的问题与我需要解决的问题不同。
问题:
让我们上三门课:数学、英语、历史
所有这些课程都提供多个时间段(并行),学生可以为每个时间段选择一个。
假设:
Math: Monday: 9:00 - 10:00, Tuesday: 10:00 - 11:00
English: Monday: 9:00 - 10:00, Tuesday: 11:00 - 12:00, 14:00 - 15:00,
Friday: 16:00 - 17:00
History: Tuesday: 10:00 - 11:00, Friday: 10:00 - 11:00
我想为这些课程中的每一个找到最佳可能的时间段。 最好 我的意思是间隔最少的那个,更重要的是,让你有最多空闲时间的那个。
示例问题的最佳解决方案可能类似于
Tuesday: Math: 9:00 - 10:00, History: 10:00 - 11:00, English: 11:00 -
12:00
不留空档,同时提供 4 天免费。
这对 OptaPlanner 可行吗?还是我应该使用不同的求解器?我注意到Lesson
对象只有一个TimeSlot
而不是一个列表,这让我觉得不支持这种时间表优化。
从描述来看,您的问题似乎是“学生计划自己的时间表”(而学校时间表是“教师为所有学生制定学校时间表”)。
我会这样建模:
@PlanningEntity
public class CourseSection {
private List<TimeSlot> availableTimeslots;
@PlanningId // needed for forEachUniquePair
private String courseSectionIdentifier;
@PlanningVariable(valueRangeProviderRefs = {"timeslotRange"})
private TimeSlot selectedTimeslot;
@ValueRangeProvider(id="timeslotRange")
public List<TimeSlot> getTimeslotRangeForCourse() {
return availableTimeslots;
}
// getters and setters ...
}
这利用了 value range provider on a planning entity,这意味着每个规划实体都有自己的值范围(并且不会尝试课程的 non-existing TimeSlot)。
我使用了 CourseSection,因为课程可以分为多个部分(1 个讲座 + 2 个教程、2 个讲座等),并且每个部分都有一个 CourseSection。 (如果课程只有一个lecture section,那么就只有一个CourseSection,如果课程一个lecture+tutorial,就有两个CourseSection,等等)。
对于最小化间隙约束,我会使用实验性连续区间约束收集器。要使用它,您需要添加 OptaPlanner Examples as a maven dependency or copy it from the source code of examples;一旦我们确定 API (可能会发生变化,因为它仍处于实验阶段),它最终将被移入 ConstraintCollectors。使用连续间隔约束收集器,它将如下所示:
Constraint minimizeGaps(ConstraintFactory constraintFactory) {
return constraintFactory.forEach(CourseSection.class)
.groupBy(section -> section.getSelectedTimeslot().getDayOfWeek(),
ExperimentalConstraintCollectors.consecutiveTemporalIntervals(
section -> section.getSelectedTimeslot().getStartTime(),
section -> section.getSelectedTimeslot().getEndTime()))
.flattenLast(ConsecutiveIntervalInfo::getBreaks)
.penalize("Minimize Gaps", HardMediumSoft.ONE_SOFT);
}
对于最大空闲天数限制,我会把它写成“最小化工作天数”,如下所示:
Constraint minimizeWorkingDays(ConstraintFactory constraintFactory) {
return constraintFactory.forEach(CourseSection.class)
.groupBy(section -> section.getSelectedTimeslot().getDayOfWeek())
.penalize("Minimize Working Days", HardMediumSoft.ONE_MEDIUM);
}
最后,我们需要确保没有两个课程部分重叠:
Constraint noOverlappingCourseSections(ConstraintFactory constraintFactory) {
return constraintFactory.forEachUniquePair(CourseSection.class,
Joiners.equal(section -> section.getSelectedTimeslot().getDayOfWeek()),
Joiners.overlapping(
section -> section.getSelectedTimeslot().getStartTime(),
section -> section.getSelectedTimeslot().getEndTime()))
.penalize("Overlapping sections", HardMediumSoftScore.ONE_HARD);
}
请注意,在我提供的限制条件下,工作日较少的解决方案总是优于工作日较多的解决方案,即使工作日较少的解决方案有 8 小时的差距。您可能想要对允许的最大间隙添加额外的约束(您可以使用检查 IntervalBreak.getLength()
的过滤器来实现)。
Optaplanner school timetabling 示例显示的问题与我需要解决的问题不同。
问题:
让我们上三门课:数学、英语、历史
所有这些课程都提供多个时间段(并行),学生可以为每个时间段选择一个。
假设:
Math: Monday: 9:00 - 10:00, Tuesday: 10:00 - 11:00
English: Monday: 9:00 - 10:00, Tuesday: 11:00 - 12:00, 14:00 - 15:00, Friday: 16:00 - 17:00
History: Tuesday: 10:00 - 11:00, Friday: 10:00 - 11:00
我想为这些课程中的每一个找到最佳可能的时间段。 最好 我的意思是间隔最少的那个,更重要的是,让你有最多空闲时间的那个。
示例问题的最佳解决方案可能类似于
Tuesday: Math: 9:00 - 10:00, History: 10:00 - 11:00, English: 11:00 - 12:00
不留空档,同时提供 4 天免费。
这对 OptaPlanner 可行吗?还是我应该使用不同的求解器?我注意到Lesson
对象只有一个TimeSlot
而不是一个列表,这让我觉得不支持这种时间表优化。
从描述来看,您的问题似乎是“学生计划自己的时间表”(而学校时间表是“教师为所有学生制定学校时间表”)。
我会这样建模:
@PlanningEntity
public class CourseSection {
private List<TimeSlot> availableTimeslots;
@PlanningId // needed for forEachUniquePair
private String courseSectionIdentifier;
@PlanningVariable(valueRangeProviderRefs = {"timeslotRange"})
private TimeSlot selectedTimeslot;
@ValueRangeProvider(id="timeslotRange")
public List<TimeSlot> getTimeslotRangeForCourse() {
return availableTimeslots;
}
// getters and setters ...
}
这利用了 value range provider on a planning entity,这意味着每个规划实体都有自己的值范围(并且不会尝试课程的 non-existing TimeSlot)。
我使用了 CourseSection,因为课程可以分为多个部分(1 个讲座 + 2 个教程、2 个讲座等),并且每个部分都有一个 CourseSection。 (如果课程只有一个lecture section,那么就只有一个CourseSection,如果课程一个lecture+tutorial,就有两个CourseSection,等等)。
对于最小化间隙约束,我会使用实验性连续区间约束收集器。要使用它,您需要添加 OptaPlanner Examples as a maven dependency or copy it from the source code of examples;一旦我们确定 API (可能会发生变化,因为它仍处于实验阶段),它最终将被移入 ConstraintCollectors。使用连续间隔约束收集器,它将如下所示:
Constraint minimizeGaps(ConstraintFactory constraintFactory) {
return constraintFactory.forEach(CourseSection.class)
.groupBy(section -> section.getSelectedTimeslot().getDayOfWeek(),
ExperimentalConstraintCollectors.consecutiveTemporalIntervals(
section -> section.getSelectedTimeslot().getStartTime(),
section -> section.getSelectedTimeslot().getEndTime()))
.flattenLast(ConsecutiveIntervalInfo::getBreaks)
.penalize("Minimize Gaps", HardMediumSoft.ONE_SOFT);
}
对于最大空闲天数限制,我会把它写成“最小化工作天数”,如下所示:
Constraint minimizeWorkingDays(ConstraintFactory constraintFactory) {
return constraintFactory.forEach(CourseSection.class)
.groupBy(section -> section.getSelectedTimeslot().getDayOfWeek())
.penalize("Minimize Working Days", HardMediumSoft.ONE_MEDIUM);
}
最后,我们需要确保没有两个课程部分重叠:
Constraint noOverlappingCourseSections(ConstraintFactory constraintFactory) {
return constraintFactory.forEachUniquePair(CourseSection.class,
Joiners.equal(section -> section.getSelectedTimeslot().getDayOfWeek()),
Joiners.overlapping(
section -> section.getSelectedTimeslot().getStartTime(),
section -> section.getSelectedTimeslot().getEndTime()))
.penalize("Overlapping sections", HardMediumSoftScore.ONE_HARD);
}
请注意,在我提供的限制条件下,工作日较少的解决方案总是优于工作日较多的解决方案,即使工作日较少的解决方案有 8 小时的差距。您可能想要对允许的最大间隙添加额外的约束(您可以使用检查 IntervalBreak.getLength()
的过滤器来实现)。