我想为小学制作学校时间表。我正在使用Optaplanner来实现同样的目标。我希望每个类都有这样的计划。 [Sub1/T1] means subject1 taught by teacher1
。
Day | Period1 | Period2 | Period2 | Period4 | Period 5 |
------------------------------------------------------------
Mon | Sub1/T1 | Sub2/T2 | Sub3/T3 | Sub4/T2 | Sub4/T8 |
Tue | Sub3/T4 | Sub4/T8 | Sub2/T3 | Sub5/T1 | Sub4/T5 |
Wed | Sub6/T1 | Sub6/T2 | Sub6/T3 | Sub1/T2 | Sub4/T6 |
Thu | Sub3/T1 | Sub8/T2 | Sub2/T3 | Sub5/T2 | Sub4/T3 |
Fri | Sub5/T1 | Sub2/T2 | Sub4/T3 | Sub1/T2 | Sub4/T5 |
Sat | Sub2/T1 | Sub1/T2 | Sub1/T3 | Sub2/T2 | Sub4/T1 |
硬约束是:
软约束是:
我为as:
设计了域模型public class Period {
private Day day;
private Timeslot timeslot;
//getters and setters
}
public class Teacher{
private Integer id;
private String name;
private Set<Subject> subjects = new HashSet<>(); //Subjects which a teacher can teach
private Set<Standard> standards = new HashSet<>(); //Classes[Standards] in which teacher can teach
//Getters and setters
}
@PlanningEntity
public class Schedule implements Serializable{
private Long id;
private Subject subject;
private Standard std;
//Planning variables
private Period period;
private Teacher teacher;
public Schedule() {
}
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public Subject getSubject() {
return subject;
}
public void setSubject(Subject subject) {
this.subject = subject;
}
public Standard getStd() {
return std;
}
public void setStd(Standard std) {
this.std = std;
}
@PlanningVariable(valueRangeProviderRefs = {"periods"})
public Period getPeriod() {
return period;
}
public void setPeriod(Period period) {
this.period = period;
}
@PlanningVariable(valueRangeProviderRefs = {"teachers"})
public Teacher getTeacher() {
return teacher;
}
public void setTeacher(Teacher teacher) {
this.teacher = teacher;
}
@Override
public int hashCode() {
int hash = 7;
hash = 47 * hash + Objects.hashCode(this.id);
return hash;
}
@Override
public boolean equals(Object obj) {
if (this == obj) {
return true;
}
if (obj == null) {
return false;
}
if (getClass() != obj.getClass()) {
return false;
}
final Schedule other = (Schedule) obj;
return Objects.equals(this.id, other.id);
}
}
@PlanningSolution
public class TimeTable implements Solution<HardSoftScore> {
private List<Period> periodList;
private List<Teacher> teacherList;
private List<Standard> stdList;
private List<Day> dayList;
private List<Timeslot> timeslotList;
private List<Subject> subjectList;
private List<Schedule> scheduleList;
private HardSoftScore score;
public TimeTable() {
}
@ValueRangeProvider(id = "periods")
public List<Period> getPeriodList() {
return periodList;
}
public void setPeriodList(List<Period> periodList) {
this.periodList = periodList;
}
@ValueRangeProvider(id = "teachers")
public List<Teacher> getTeacherList() {
return teacherList;
}
public void setTeacherList(List<Teacher> teacherList) {
this.teacherList = teacherList;
}
public List<Standard> getStdList() {
return stdList;
}
public void setStdList(List<Standard> stdList) {
this.stdList = stdList;
}
public List<Day> getDayList() {
return dayList;
}
public void setDayList(List<Day> dayList) {
this.dayList = dayList;
}
public List<Timeslot> getTimeslotList() {
return timeslotList;
}
public void setTimeslotList(List<Timeslot> timeslotList) {
this.timeslotList = timeslotList;
}
public List<Subject> getSubjectList() {
return subjectList;
}
public void setSubjectList(List<Subject> subjectList) {
this.subjectList = subjectList;
}
@PlanningEntityCollectionProperty
public List<Schedule> getScheduleList() {
return scheduleList;
}
public void setScheduleList(List<Schedule> scheduleList) {
this.scheduleList = scheduleList;
}
@Override
public HardSoftScore getScore() {
return score;
}
@Override
public void setScore(HardSoftScore score) {
this.score = score;
}
@Override
public Collection<? extends Object> getProblemFacts() {
List<Object> facts = new ArrayList<>();
facts.addAll(periodList);
facts.addAll(teacherList);
facts.addAll(stdList);
facts.addAll(dayList);
facts.addAll(timeslotList);
facts.addAll(subjectList);
return facts;
}
}
我的规划实体为Schedule
,规划变量为Period
和Teacher
,规划解决方案为TimeTable
。我未解决的解决方案有&#39; Schedule&#39;对于每个标准和每个时期,但教师和时期最初未分配,我希望Optaplanner为我分配考虑所有约束。
我的DRL文件是:
package com.example.school.solver
dialect "java"
import com.example.school.entity.Period;
import com.example.school.entity.Schedule;
import com.example.school.entity.Standard;
import com.example.school.entity.Subject;
import com.example.school.entity.Teacher;
import com.example.school.entity.TimeTable;
import com.example.school.entity.Day;
import com.example.school.entity.Timeslot;
import java.util.ArrayList;
import org.optaplanner.core.api.score.buildin.hardsoft.HardSoftScoreHolder;
global HardSoftScoreHolder scoreHolder;
//Rule 1: Each Schedule should be in distinct period for any class
rule "scheduleInDistinctPeriodForAnyClass"
when
Schedule($id : id, $std : std, period != null, $period : period )
Schedule(id > $id, std == $std, period == $period)
then
scoreHolder.addHardConstraintMatch(kcontext, -1);
end
//Rule 2: A Teacher can not be in multiple classes in a day at particular period
rule "TeacherInOneClassOnlyInAnyPeriod"
when
Schedule($id : id, period != null, $period : period, teacher != null, $teacher : teacher )
Schedule(id > $id, period == $period, teacher == $teacher)
then
scoreHolder.addHardConstraintMatch(kcontext, -1);
end
//Rule 3: A Teacher can teach only particular subjects
rule "TeacherCanTeachOnlySomeSubjects"
when
Schedule($id : id, teacher != null, teacher.subjects not contains subject )
then
scoreHolder.addHardConstraintMatch(kcontext, -1);
end
//Rule 4: A Teacher can teach only in particular Classes
rule "TeacherCanTeachOnlySomeClasses"
when
Schedule($id : id, teacher != null, teacher.standards not contains std )
then
scoreHolder.addHardConstraintMatch(kcontext, -1);
end
//Rule 5: A particular subject should be taught once a day in a class
rule "SubjectTaughtOnceADayInAnyClass"
when
Schedule($id : id, $subject : subject, $std : std, period != null, $day : day)
Schedule(id > $id, subject == $subject, std == $std, day == $day )
then
scoreHolder.addHardConstraintMatch(kcontext, -1);
end
内置的硬约束是:在一个班级中,只能教授某些科目,每个科目每周可以进行多次讲座。计划初始化时有这种约束,一周的讲座总数等于总周期数一周以内。 除了规则5之外,所有规则都运行良好并提供可行的解决方案。在规则5中,我指定对于任何标准,特定日期应该只有一个特定主题的讲座[期间]。
如果我仅使用规则1运行我的代码[仅为了简单起见显示输出一条规则,因为规则5没有提供可行的解决方案而不管规则2,3,4],我得到了这个输出:< / p>
在此课程的输出中,课程被分配多次。我的目标是每天为课程分配一个科目。我试过规则5这样做。但它没有提供可行的解决方案,但解决方案存在。
我错过了什么?提前谢谢。
更新:SolverConfig文件:
<?xml version="1.0" encoding="UTF-8"?>
<solver>
<!-- Domain model configuration -->
<scanAnnotatedClasses/>
<!-- Score configuration -->
<scoreDirectorFactory>
<scoreDefinitionType>HARD_SOFT</scoreDefinitionType>
<!--<easyScoreCalculatorClass>com.example.school.solver.score.ScheduleEasyScoreCalculator</easyScoreCalculatorClass>-->
<scoreDrl>com/example/school/solver/TimeTableScoreRule.drl</scoreDrl>
</scoreDirectorFactory>
<!-- Optimization algorithms configuration -->
<termination>
<!--<unimprovedSecondsSpentLimit>10</unimprovedSecondsSpentLimit>-->
<secondsSpentLimit>30</secondsSpentLimit>
</termination>
</solver>