OptaPlanner:无法找到可行的解决方案

时间:2016-08-30 08:31:11

标签: drools optaplanner

我想为小学制作学校时间表。我正在使用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  |

硬约束是:

  1. 老师不能同时上两节课。
  2. 教师只能教某些科目。
  3. 老师只能教授某些课程。
  4. 每周固定课程中任何科目的总课数。
  5. 软约束是:

    1. 老师可以要求休息一天。他们可能会偏爱那一天。
    2. 老师可能希望连续上课。
    3. 我为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,规划变量为PeriodTeacher,规划解决方案为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>

      enter image description here

      在此课程的输出中,课程被分配多次。我的目标是每天为课程分配一个科目。我试过规则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>
      

0 个答案:

没有答案