Skip to content

Commit 0a22699

Browse files
updated room prescheduling, and update a random log
1 parent 0f04ac6 commit 0a22699

4 files changed

Lines changed: 114 additions & 38 deletions

File tree

java/hello-world/src/main/java/org/acme/schooltimetabling/helperClasses/Generators/TeacherGenerator.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -161,7 +161,7 @@ public static HashMap<String, Teacher> generateTeachers(List<HashMap<String, Str
161161
/*Check if the instructor wanted to bleed forward*/
162162
if(teacherBleed.containsKey(instructorName)){
163163

164-
LOGGER.info(String.format("Trying to use %s's old survey", instructorName));
164+
LOGGER.info(String.format("Trying to use %s's old survey so they can bleed forward", instructorName));
165165
/*If the instructor choose to bleed forward in the previous survey
166166
* we will be forced to skip them :( */
167167
if(BLEED_FORWARD_STRING.equals(surveyEntry.get(BLEED_FORWARD_KEY))){

java/hello-world/src/main/java/org/acme/schooltimetabling/solver/TimetableConstraintProvider.java

Lines changed: 24 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -91,7 +91,7 @@ else if(AGGRESSIVE_CHOICE.equals("NONE")){
9191
}
9292

9393
//add in the room prescheduling conflict constraint only if we prescheduled rooms detected
94-
if(Room.hasPrescheduled){
94+
if(Room.hasPrescheduled || ScheduleConfig.isTesting()){
9595
LOGGER.info("At least on room has been found to be prescheduled. Including the room prescheduling constraint.");
9696
solver_constraints.add(roomPreschedule(constraintFactory));
9797
}
@@ -354,6 +354,29 @@ Constraint studioLabAfterLec(ConstraintFactory constraintFactory){
354354
.asConstraint("Studio lab right after lecture");
355355
}
356356

357+
/**
358+
* constraint that will be added in when a prescheduled room is detected. The constraint will ensure that
359+
* no lesson is scheduled in a room during its preschedule time
360+
*/
361+
Constraint roomPreschedule(ConstraintFactory constraintFactory){
362+
return constraintFactory.forEach(Lesson.class)
363+
.filter(lesson -> {
364+
//skip lessons that are in the lecture only room
365+
//take into account only lessons that have a room that has prescheduling times
366+
if(Constants.LEC_ONLY.equals(lesson.getRoom().getName()) ||
367+
lesson.getRoom().getPrescheduled().isEmpty()) return false;
368+
369+
//penalize lessons that are scheduled in a rooms prescheduled time
370+
BitSet prescheduled = lesson.getRoom().getPrescheduled();
371+
372+
//studio course both// non studio only lab
373+
return prescheduled.intersects(lesson.getTimeslot().getLabActBitSet()) ||
374+
(lesson.isStudio() && prescheduled.intersects(lesson.getTimeslot().getLectureBitSet()));
375+
})
376+
.penalize(HardMediumSoftScore.ONE_HARD)
377+
.asConstraint("Penalize a lesson ");
378+
}
379+
357380
//-------------------------------------- Medium Constraints --------------------------------------
358381

359382
Constraint prefTime(ConstraintFactory constraintFactory){
@@ -604,24 +627,4 @@ Constraint outBestTime(ConstraintFactory constraintFactory){
604627
.penalize(HardMediumSoftScore.ONE_SOFT)
605628
.asConstraint("Penalize time out of preferred time interval");
606629
}
607-
608-
//--------------------- NEW COSNTRAINT FOR THE ROOM PRESCHEDULING ---------------//
609-
Constraint roomPreschedule(ConstraintFactory constraintFactory){
610-
return constraintFactory.forEach(Lesson.class)
611-
.filter(lesson -> {
612-
//skip lessons that are in the lecture only room
613-
//take into account only lessons that have a room that has prescheduling times
614-
if(Objects.equals(lesson.getRoom().getName(), Constants.LEC_ONLY)
615-
|| !lesson.getRoom().getPrescheduled().isEmpty() ) return false;
616-
617-
//penalize lessons that are scheduled in a rooms prescheduled time
618-
BitSet prescheduled = lesson.getRoom().getPrescheduled();
619-
620-
return prescheduled.intersects(lesson.getTimeslot().getLectureBitSet()) ||
621-
prescheduled.intersects(lesson.getTimeslot().getLabActBitSet());
622-
})
623-
.penalize(HardMediumSoftScore.ONE_SOFT)
624-
.asConstraint("Penalize a lesson ");
625-
}
626-
627630
}

java/hello-world/src/test/java/org/acme/schooltimetabling/solver/ConstraintTestHelper.java

Lines changed: 37 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,10 @@
55
import org.acme.schooltimetabling.domain.Room;
66
import org.acme.schooltimetabling.domain.Timeslot;
77
import org.acme.schooltimetabling.domain.teacher.Teacher;
8+
import org.acme.schooltimetabling.helperClasses.BitSetHelper;
89
import org.glassfish.jaxb.runtime.v2.runtime.reflect.opt.Const;
910

11+
import java.time.LocalTime;
1012
import java.util.BitSet;
1113
import java.util.EnumSet;
1214
import java.util.Set;
@@ -22,12 +24,16 @@ public class ConstraintTestHelper {
2224
/**
2325
* Test: room name; will be used by a specific course {@link #TEST_L_W_LAB_SPECIFIC}
2426
*/
25-
public final static String TEST_LAB_ROOM_SPECIFIC = "LabRoom";
27+
public final static String TEST_NAME_LAB_ROOM_SPECIFIC = "LabRoom";
2628
/**
2729
* Test: name of lab room not assigned to an course specifically
2830
*/
29-
public final static String TEST_RANDOM_LAB_ROOM = "Random lab room";
30-
public final static Set<String> TEST_SET_LAB_ROOMS = Set.of(TEST_LAB_ROOM_SPECIFIC);
31+
public final static String TEST_NAME_RANDOM_LAB_ROOM = "Random lab room";
32+
/**
33+
* Test: name of prescheduled ROOM
34+
*/
35+
public final static String TEST_NAME_PRESCHEDULED_ROOM = "Room Prescheduled";
36+
public final static Set<String> TEST_SET_LAB_ROOMS = Set.of(TEST_NAME_LAB_ROOM_SPECIFIC);
3137
/**
3238
* Test: name of a course that has a specific lab*/
3339
public final static String TEST_L_W_LAB_SPECIFIC = "Lab/Act course";
@@ -39,28 +45,48 @@ public class ConstraintTestHelper {
3945
* Room that is used for a course specifically and can also be used by an lab
4046
*/
4147
public static Room TEST_ROOM_SPECIFIC;
48+
/**
49+
* Room prescheduled
50+
*/
51+
public static Room TEST_ROOM_PRESCHEDULED;
4252
public static String NON_STUDIO_SPECIFIC = "non studio course with a specific room";
4353

4454
static{
45-
Constants.POSSIBLE_ROOMS.add(TEST_LAB_ROOM_SPECIFIC);
46-
Constants.ROOM_TO_ID_BIMAP.put(TEST_LAB_ROOM_SPECIFIC, 1000);
55+
//add rooms to those that are possible
56+
Constants.POSSIBLE_ROOMS.add(TEST_NAME_LAB_ROOM_SPECIFIC);
57+
Constants.ROOM_TO_ID_BIMAP.put(TEST_NAME_LAB_ROOM_SPECIFIC, 1000);
4758

48-
Constants.POSSIBLE_ROOMS.add(TEST_RANDOM_LAB_ROOM);
49-
Constants.ROOM_TO_ID_BIMAP.put(TEST_RANDOM_LAB_ROOM, 1001);
59+
Constants.POSSIBLE_ROOMS.add(TEST_NAME_RANDOM_LAB_ROOM);
60+
Constants.ROOM_TO_ID_BIMAP.put(TEST_NAME_RANDOM_LAB_ROOM, 1001);
5061

62+
Constants.POSSIBLE_ROOMS.add(TEST_NAME_PRESCHEDULED_ROOM);
63+
Constants.ROOM_TO_ID_BIMAP.put(TEST_NAME_PRESCHEDULED_ROOM, 1002);
64+
65+
//add course names to their ID
5166
Constants.COURSE_ID_BIMAP.put(DUMMY_STUDIO, 2000);
5267
Constants.COURSE_ID_BIMAP.put(NON_STUDIO_SPECIFIC, 2001);
5368

69+
//add which lessons are studios
5470
Constants.STUDIO_STYLE_COURSES.add(DUMMY_STUDIO);
5571
Constants.STUDIO_STYLE_COURSES.add(TEST_L_W_LAB_SPECIFIC);
5672

73+
//add mapping for which courses can be in certain rooms
5774
Constants.COURSE_TO_ROOMS.put(TEST_L_W_LAB_SPECIFIC, TEST_SET_LAB_ROOMS);
5875
Constants.COURSE_TO_ROOMS.put(NON_STUDIO_SPECIFIC, TEST_SET_LAB_ROOMS);
5976

60-
TEST_ROOM_RANDO_LAB = new Room(Integer.toString(Constants.ROOM_TO_ID_BIMAP.get(TEST_RANDOM_LAB_ROOM)),
61-
TEST_RANDOM_LAB_ROOM, Constants.ROOM_TO_ID_BIMAP.get(TEST_RANDOM_LAB_ROOM));
62-
TEST_ROOM_SPECIFIC = new Room(Integer.toString(Constants.ROOM_TO_ID_BIMAP.get(TEST_LAB_ROOM_SPECIFIC)),
63-
TEST_LAB_ROOM_SPECIFIC, Constants.ROOM_TO_ID_BIMAP.get(TEST_LAB_ROOM_SPECIFIC));
77+
//create the room objects
78+
TEST_ROOM_RANDO_LAB = new Room(Integer.toString(Constants.ROOM_TO_ID_BIMAP.get(TEST_NAME_RANDOM_LAB_ROOM)),
79+
TEST_NAME_RANDOM_LAB_ROOM, Constants.ROOM_TO_ID_BIMAP.get(TEST_NAME_RANDOM_LAB_ROOM));
80+
TEST_ROOM_SPECIFIC = new Room(Integer.toString(Constants.ROOM_TO_ID_BIMAP.get(TEST_NAME_LAB_ROOM_SPECIFIC)),
81+
TEST_NAME_LAB_ROOM_SPECIFIC, Constants.ROOM_TO_ID_BIMAP.get(TEST_NAME_LAB_ROOM_SPECIFIC));
82+
TEST_ROOM_PRESCHEDULED = new Room(Integer.toString(Constants.ROOM_TO_ID_BIMAP.get(TEST_NAME_LAB_ROOM_SPECIFIC)),
83+
TEST_NAME_LAB_ROOM_SPECIFIC, Constants.ROOM_TO_ID_BIMAP.get(TEST_NAME_LAB_ROOM_SPECIFIC));
84+
85+
//let's preschedule a room
86+
EnumSet<Days> MWF = EnumSet.of(Days.MONDAY, Days.WEDNESDAY, Days.FRIDAY);
87+
BitSet roomBlocked = BitSetHelper.timeSlotBitSet(LocalTime.parse("9:00AM", Constants.TIME_FORMATTER), 2, MWF);
88+
TEST_ROOM_PRESCHEDULED.prescheduleUpdate(roomBlocked);
89+
6490

6591
Constants.TESTING = true;
6692
}

java/hello-world/src/test/java/org/acme/schooltimetabling/solver/TestConstraints.java

Lines changed: 52 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -12,14 +12,11 @@
1212
import org.acme.schooltimetabling.helperClasses.BitSetHelper;
1313
import org.acme.schooltimetabling.helperClasses.Generators.LessonGenerator;
1414
import org.acme.schooltimetabling.helperClasses.ScheduleConfig;
15-
import org.glassfish.jaxb.runtime.v2.runtime.reflect.opt.Const;
1615
import org.junit.jupiter.api.BeforeAll;
17-
import org.junit.jupiter.api.Disabled;
1816
import org.junit.jupiter.api.DisplayName;
1917
import org.junit.jupiter.api.Test;
2018
import ai.timefold.solver.test.api.score.stream.ConstraintVerifier;
2119

22-
import java.sql.Time;
2320
import java.time.LocalTime;
2421
import java.time.format.DateTimeFormatter;
2522
import java.util.BitSet;
@@ -342,7 +339,7 @@ void noPenLessonRoomCheck(){
342339
Lesson lesson2 = Lesson.test_buildLesson("1", 1, "some only lec course", "",
343340
"", "1-0-0", 1111, ConstraintTestHelper.DUMMY_TEACHER,
344341
ConstraintTestHelper.DUMMY_TS, LEC_ONLY_ROOM);
345-
Lesson lsLabOnly = Lesson.test_buildLesson("2", 1, ConstraintTestHelper.TEST_RANDOM_LAB_ROOM,
342+
Lesson lsLabOnly = Lesson.test_buildLesson("2", 1, ConstraintTestHelper.TEST_NAME_RANDOM_LAB_ROOM,
346343
"noName", "", "0-0-1", 1, ConstraintTestHelper.DUMMY_TEACHER,
347344
ConstraintTestHelper.DUMMY_TS, ConstraintTestHelper.DUMMY_ROOM);
348345

@@ -710,6 +707,56 @@ void penalizeDislikedHourGap() {
710707
likedGap1, likedGap2)
711708
.penalizesBy(2);
712709
}
713-
}
714710

711+
@Test
712+
@DisplayName("Penalty: room prescheduling blocks lab and studio lecture")
713+
void roomPrescheduleConflict() {
714+
EnumSet<Days> MWF = EnumSet.of(Days.MONDAY, Days.WEDNESDAY, Days.FRIDAY);
715+
716+
BitSet blockedLessonBits = BitSetHelper.timeSlotBitSet(LocalTime.parse("9:00AM", formatter), 2, MWF);
717+
BitSet blockedLessonBits2 = BitSetHelper.timeSlotBitSet(LocalTime.parse("8:00AM", formatter), 2, MWF);
718+
Timeslot blockedTimeslot = Timeslot.test_lecLabBitAndDays(1, blockedLessonBits, ConstraintTestHelper.EMPTY_BS,
719+
MWF, ConstraintTestHelper.NO_DAYS);
720+
Timeslot blockedTimeslot_LecLab = Timeslot.test_lecLabBitAndDays(2, blockedLessonBits2, blockedLessonBits,
721+
MWF, MWF);
722+
723+
Lesson blockedLessonLab = Lesson.test_buildLesson("room-blocked-lab", 2, "", "", "",
724+
"3-1-0", 1, ConstraintTestHelper.DUMMY_TEACHER,blockedTimeslot_LecLab,
725+
ConstraintTestHelper.TEST_ROOM_PRESCHEDULED);
726+
Lesson blockedStudio = Lesson.test_buildLesson("room-blocked-studio", 3, ConstraintTestHelper.DUMMY_STUDIO,
727+
"", "", "1-0-0", Constants.COURSE_ID_BIMAP.get(ConstraintTestHelper.DUMMY_STUDIO),
728+
ConstraintTestHelper.DUMMY_TEACHER, blockedTimeslot, ConstraintTestHelper.TEST_ROOM_PRESCHEDULED);
729+
730+
constraintVerifier.verifyThat(TimetableConstraintProvider::roomPreschedule)
731+
.given(blockedLessonLab, blockedStudio)
732+
.penalizesBy(2);
733+
}
734+
735+
@Test
736+
@DisplayName("No Penalty: room prescheduling skip branches")
737+
void noRoomPrescheduleConflict() {
738+
EnumSet<Days> MWF = EnumSet.of(Days.MONDAY, Days.WEDNESDAY, Days.FRIDAY);
739+
740+
BitSet roomBlocked = BitSetHelper.timeSlotBitSet(LocalTime.parse("9:00AM", formatter), 2, MWF);
741+
BitSet bs_10AM = BitSetHelper.timeSlotBitSet(LocalTime.parse("10:00AM", formatter), 2, MWF);
742+
743+
Timeslot blockedTimeslot = Timeslot.test_lecLabBitAndDays(2, roomBlocked, ConstraintTestHelper.EMPTY_BS,
744+
MWF, ConstraintTestHelper.NO_DAYS);
745+
Timeslot ts_9AM_10AM_MWF = Timeslot.test_lecLabBitAndDays(2, roomBlocked, bs_10AM, MWF, MWF);
746+
Timeslot ts_10AM_MWF = Timeslot.test_lecLabBitAndDays(2, bs_10AM, ConstraintTestHelper.EMPTY_BS, MWF,
747+
ConstraintTestHelper.NO_DAYS);
715748

749+
Lesson openLessonLec = Lesson.test_buildLesson("room-open-lec", 1, "", "", "",
750+
"3-1-0", 1, ConstraintTestHelper.DUMMY_TEACHER, ts_9AM_10AM_MWF,
751+
ConstraintTestHelper.TEST_ROOM_PRESCHEDULED);
752+
Lesson lecOnlyRoomLesson = Lesson.test_buildLesson("room-lec-only", 3, "", "", "",
753+
"1-0-0", 1, ConstraintTestHelper.DUMMY_TEACHER, blockedTimeslot,
754+
ConstraintTestHelper.TEST_ROOM_PRESCHEDULED);
755+
Lesson emptyRoomLesson = Lesson.test_buildLesson("room-empty", 4, "", "", "",
756+
"1-0-0", 1, ConstraintTestHelper.DUMMY_TEACHER, blockedTimeslot, ConstraintTestHelper.DUMMY_ROOM);
757+
758+
constraintVerifier.verifyThat(TimetableConstraintProvider::roomPreschedule)
759+
.given(openLessonLec, lecOnlyRoomLesson, emptyRoomLesson)
760+
.penalizesBy(0);
761+
}
762+
}

0 commit comments

Comments
 (0)