/machinelearning/5.0.x/drools-solver/drools-solver-examples/src/main/java/org/drools/solver/examples/itc2007/curriculumcourse/solver/solution/initializer/CurriculumCourseStartingSolutionInitializer.java

https://github.com/etirelli/droolsjbpm-contributed-experiments · Java · 193 lines · 158 code · 28 blank · 7 comment · 23 complexity · 1ee46c7b180b1556ca1b1d50086d73bd MD5 · raw file

  1. package org.drools.solver.examples.itc2007.curriculumcourse.solver.solution.initializer;
  2. import java.util.ArrayList;
  3. import java.util.Collections;
  4. import java.util.List;
  5. import org.apache.commons.lang.builder.CompareToBuilder;
  6. import org.drools.WorkingMemory;
  7. import org.drools.runtime.rule.FactHandle;
  8. import org.drools.solver.core.localsearch.LocalSearchSolverScope;
  9. import org.drools.solver.core.solution.initializer.AbstractStartingSolutionInitializer;
  10. import org.drools.solver.examples.common.domain.PersistableIdComparator;
  11. import org.drools.solver.examples.itc2007.curriculumcourse.domain.Course;
  12. import org.drools.solver.examples.itc2007.curriculumcourse.domain.CurriculumCourseSchedule;
  13. import org.drools.solver.examples.itc2007.curriculumcourse.domain.Lecture;
  14. import org.drools.solver.examples.itc2007.curriculumcourse.domain.Period;
  15. import org.drools.solver.examples.itc2007.curriculumcourse.domain.Room;
  16. import org.drools.solver.examples.itc2007.curriculumcourse.domain.UnavailablePeriodConstraint;
  17. /**
  18. * @author Geoffrey De Smet
  19. */
  20. public class CurriculumCourseStartingSolutionInitializer extends AbstractStartingSolutionInitializer {
  21. @Override
  22. public boolean isSolutionInitialized(LocalSearchSolverScope localSearchSolverScope) {
  23. CurriculumCourseSchedule schedule = (CurriculumCourseSchedule) localSearchSolverScope.getWorkingSolution();
  24. return schedule.isInitialized();
  25. }
  26. public void initializeSolution(LocalSearchSolverScope localSearchSolverScope) {
  27. CurriculumCourseSchedule schedule = (CurriculumCourseSchedule) localSearchSolverScope.getWorkingSolution();
  28. initializeLectureList(localSearchSolverScope, schedule);
  29. }
  30. private void initializeLectureList(LocalSearchSolverScope localSearchSolverScope,
  31. CurriculumCourseSchedule schedule) {
  32. List<Period> periodList = schedule.getPeriodList();
  33. List<Room> roomList = schedule.getRoomList();
  34. WorkingMemory workingMemory = localSearchSolverScope.getWorkingMemory();
  35. List<Lecture> lectureList = createLectureList(schedule);
  36. for (Lecture lecture : lectureList) {
  37. double unscheduledScore = localSearchSolverScope.calculateScoreFromWorkingMemory();
  38. FactHandle lectureHandle = null;
  39. List<PeriodScoring> periodScoringList = new ArrayList<PeriodScoring>(periodList.size());
  40. for (Period period : periodList) {
  41. if (lectureHandle == null) {
  42. lecture.setPeriod(period);
  43. lectureHandle = workingMemory.insert(lecture);
  44. } else {
  45. lecture.setPeriod(period);
  46. workingMemory.update(lectureHandle, lecture);
  47. }
  48. double score = localSearchSolverScope.calculateScoreFromWorkingMemory();
  49. periodScoringList.add(new PeriodScoring(period, score));
  50. }
  51. Collections.sort(periodScoringList);
  52. boolean almostPerfectMatch = false;
  53. double bestScore = Double.NEGATIVE_INFINITY;
  54. Period bestPeriod = null;
  55. Room bestRoom = null;
  56. for (PeriodScoring periodScoring : periodScoringList) {
  57. if (bestScore >= periodScoring.getScore()) {
  58. // No need to check the rest
  59. break;
  60. }
  61. lecture.setPeriod(periodScoring.getPeriod());
  62. workingMemory.update(lectureHandle, lecture);
  63. for (Room room : roomList) {
  64. lecture.setRoom(room);
  65. workingMemory.update(lectureHandle, lecture);
  66. double score = localSearchSolverScope.calculateScoreFromWorkingMemory();
  67. if (score < unscheduledScore) {
  68. if (score > bestScore) {
  69. bestScore = score;
  70. bestPeriod = periodScoring.getPeriod();
  71. bestRoom = room;
  72. }
  73. } else if (score >= unscheduledScore) {
  74. // TODO due to the score rules, the score can unscheduledScore can be higher than the score
  75. // In theory every possibility should be looked into
  76. almostPerfectMatch = true;
  77. break;
  78. }
  79. }
  80. if (almostPerfectMatch) {
  81. break;
  82. }
  83. }
  84. if (!almostPerfectMatch) {
  85. if (bestPeriod == null || bestRoom == null) {
  86. throw new IllegalStateException("The bestPeriod (" + bestPeriod + ") or the bestRoom ("
  87. + bestRoom + ") cannot be null.");
  88. }
  89. lecture.setPeriod(bestPeriod);
  90. lecture.setRoom(bestRoom);
  91. workingMemory.update(lectureHandle, lecture);
  92. }
  93. logger.debug(" Lecture ({}) initialized for starting solution.", lecture);
  94. }
  95. Collections.sort(lectureList, new PersistableIdComparator());
  96. schedule.setLectureList(lectureList);
  97. }
  98. public List<Lecture> createLectureList(CurriculumCourseSchedule schedule) {
  99. List<Course> courseList = schedule.getCourseList();
  100. List<CourseInitializationWeight> courseInitializationWeightList
  101. = new ArrayList<CourseInitializationWeight>(courseList.size());
  102. for (Course course : courseList) {
  103. courseInitializationWeightList.add(new CourseInitializationWeight(schedule, course));
  104. }
  105. Collections.sort(courseInitializationWeightList);
  106. List<Lecture> lectureList = new ArrayList<Lecture>(courseList.size() * 5);
  107. int lectureId = 0;
  108. for (CourseInitializationWeight courseInitializationWeight : courseInitializationWeightList) {
  109. Course course = courseInitializationWeight.getCourse();
  110. for (int i = 0; i < course.getLectureSize(); i++) {
  111. Lecture lecture = new Lecture();
  112. lecture.setId((long) lectureId);
  113. lecture.setCourse(course);
  114. lecture.setLectureIndexInCourse(i);
  115. lectureList.add(lecture);
  116. lectureId++;
  117. }
  118. }
  119. return lectureList;
  120. }
  121. private class CourseInitializationWeight implements Comparable<CourseInitializationWeight> {
  122. private Course course;
  123. private int unavailablePeriodConstraintCount;
  124. private CourseInitializationWeight(CurriculumCourseSchedule schedule, Course course) {
  125. this.course = course;
  126. unavailablePeriodConstraintCount = 0;
  127. // TODO this could be improved by iteration the unavailablePeriodConstraintList and using a hashmap
  128. for (UnavailablePeriodConstraint constraint : schedule.getUnavailablePeriodConstraintList()) {
  129. if (constraint.getCourse().equals(course)) {
  130. unavailablePeriodConstraintCount++;
  131. }
  132. }
  133. }
  134. public Course getCourse() {
  135. return course;
  136. }
  137. public int compareTo(CourseInitializationWeight other) {
  138. return new CompareToBuilder()
  139. .append(other.course.getCurriculumList().size(), course.getCurriculumList().size()) // Descending
  140. .append(other.unavailablePeriodConstraintCount, unavailablePeriodConstraintCount) // Descending
  141. .append(other.course.getLectureSize(), course.getLectureSize()) // Descending
  142. .append(other.course.getStudentSize(), course.getStudentSize()) // Descending
  143. .append(other.course.getMinWorkingDaySize(), course.getMinWorkingDaySize()) // Descending
  144. .append(course.getId(), other.course.getId()) // Ascending
  145. .toComparison();
  146. }
  147. }
  148. private class PeriodScoring implements Comparable<PeriodScoring> {
  149. private Period period;
  150. private double score;
  151. private PeriodScoring(Period period, double score) {
  152. this.period = period;
  153. this.score = score;
  154. }
  155. public Period getPeriod() {
  156. return period;
  157. }
  158. public double getScore() {
  159. return score;
  160. }
  161. public int compareTo(PeriodScoring other) {
  162. return -new CompareToBuilder().append(score, other.score).toComparison();
  163. }
  164. }
  165. }