Skip to content

Commit 219463e

Browse files
committed
Convert more constraints
1 parent ab2784a commit 219463e

5 files changed

Lines changed: 65 additions & 31 deletions

File tree

src/main/java/ai/timefold/solver/benchmarks/examples/conferencescheduling/app/ConferenceSchedulingApp.java

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,6 @@
11

22
package ai.timefold.solver.benchmarks.examples.conferencescheduling.app;
33

4-
import java.io.File;
5-
64
import ai.timefold.solver.benchmarks.examples.common.app.CommonApp;
75
import ai.timefold.solver.benchmarks.examples.conferencescheduling.domain.ConferenceSolution;
86
import ai.timefold.solver.benchmarks.examples.conferencescheduling.persistence.ConferenceSchedulingSolutionFileIO;
@@ -19,7 +17,6 @@ public class ConferenceSchedulingApp
1917
public static void main(String[] args) {
2018
var app = new ConferenceSchedulingApp();
2119
var solution = app.solve("216talks-18timeslots-20rooms.json");
22-
app.createSolutionFileIO().write(solution, new File("conferencescheduling-216-18-20.json"));
2320
System.out.println("Done: " + solution);
2421
}
2522

src/main/java/ai/timefold/solver/benchmarks/examples/conferencescheduling/domain/ConferenceConstraintProperties.java

Lines changed: 2 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,6 @@
99
@JsonIdentityInfo(generator = JacksonUniqueIdGenerator.class)
1010
public class ConferenceConstraintProperties extends AbstractPersistable {
1111

12-
public static final String ROOM_UNAVAILABLE_TIMESLOT = "Room unavailable timeslot";
1312
public static final String ROOM_CONFLICT = "Room conflict";
1413
public static final String SPEAKER_UNAVAILABLE_TIMESLOT = "Speaker unavailable timeslot";
1514
public static final String SPEAKER_CONFLICT = "Speaker conflict";
@@ -18,31 +17,26 @@ public class ConferenceConstraintProperties extends AbstractPersistable {
1817
public static final String CONSECUTIVE_TALKS_PAUSE = "Consecutive talks pause";
1918
public static final String CROWD_CONTROL = "Crowd control";
2019

21-
public static final String SPEAKER_REQUIRED_TIMESLOT_TAGS = "Speaker required timeslot tags";
22-
public static final String SPEAKER_PROHIBITED_TIMESLOT_TAGS = "Speaker prohibited timeslot tags";
23-
public static final String TALK_REQUIRED_TIMESLOT_TAGS = "Talk required timeslot tags";
24-
public static final String TALK_PROHIBITED_TIMESLOT_TAGS = "Talk prohibited timeslot tags";
2520
public static final String SPEAKER_REQUIRED_ROOM_TAGS = "Speaker required room tags";
2621
public static final String SPEAKER_PROHIBITED_ROOM_TAGS = "Speaker prohibited room tags";
2722
public static final String TALK_REQUIRED_ROOM_TAGS = "Talk required room tags";
2823
public static final String TALK_PROHIBITED_ROOM_TAGS = "Talk prohibited room tags";
2924

3025
public static final String THEME_TRACK_CONFLICT = "Theme track conflict";
3126
public static final String THEME_TRACK_ROOM_STABILITY = "Theme track room stability";
27+
public static final String THEME_TRACK_CONFLICT_SAME_DAY_TALKS = "Same day talks (Theme track)";
3228
public static final String SECTOR_CONFLICT = "Sector conflict";
3329
public static final String AUDIENCE_TYPE_DIVERSITY = "Audience type diversity";
3430
public static final String AUDIENCE_TYPE_THEME_TRACK_CONFLICT = "Audience type theme track conflict";
3531
public static final String AUDIENCE_LEVEL_DIVERSITY = "Audience level diversity";
3632
public static final String CONTENT_AUDIENCE_LEVEL_FLOW_VIOLATION = "Content audience level flow violation";
3733
public static final String CONTENT_CONFLICT = "Content conflict";
34+
public static final String CONTENT_CONFLICT_SAME_DAY_TALKS = "Same day talks (Content)";
3835
public static final String LANGUAGE_DIVERSITY = "Language diversity";
39-
public static final String SAME_DAY_TALKS = "Same day talks";
4036
public static final String POPULAR_TALKS = "Popular talks";
4137

4238
public static final String SPEAKER_PREFERRED_TIMESLOT_TAGS = "Speaker preferred timeslot tags";
4339
public static final String SPEAKER_UNDESIRED_TIMESLOT_TAGS = "Speaker undesired timeslot tags";
44-
public static final String TALK_PREFERRED_TIMESLOT_TAGS = "Talk preferred timeslot tags";
45-
public static final String TALK_UNDESIRED_TIMESLOT_TAGS = "Talk undesired timeslot tags";
4640
public static final String SPEAKER_PREFERRED_ROOM_TAGS = "Speaker preferred room tags";
4741
public static final String SPEAKER_UNDESIRED_ROOM_TAGS = "Speaker undesired room tags";
4842
public static final String TALK_PREFERRED_ROOM_TAGS = "Talk preferred room tags";

src/main/java/ai/timefold/solver/benchmarks/examples/conferencescheduling/score/ConferenceSchedulingConstraintProvider.java

Lines changed: 18 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
package ai.timefold.solver.benchmarks.examples.conferencescheduling.score;
22

3+
import static ai.timefold.solver.benchmarks.examples.conferencescheduling.domain.ConferenceConstraintProperties.*;
34
import static ai.timefold.solver.benchmarks.examples.conferencescheduling.domain.ConferenceConstraintProperties.AUDIENCE_LEVEL_DIVERSITY;
45
import static ai.timefold.solver.benchmarks.examples.conferencescheduling.domain.ConferenceConstraintProperties.AUDIENCE_TYPE_DIVERSITY;
56
import static ai.timefold.solver.benchmarks.examples.conferencescheduling.domain.ConferenceConstraintProperties.AUDIENCE_TYPE_THEME_TRACK_CONFLICT;
@@ -10,7 +11,6 @@
1011
import static ai.timefold.solver.benchmarks.examples.conferencescheduling.domain.ConferenceConstraintProperties.LANGUAGE_DIVERSITY;
1112
import static ai.timefold.solver.benchmarks.examples.conferencescheduling.domain.ConferenceConstraintProperties.POPULAR_TALKS;
1213
import static ai.timefold.solver.benchmarks.examples.conferencescheduling.domain.ConferenceConstraintProperties.ROOM_CONFLICT;
13-
import static ai.timefold.solver.benchmarks.examples.conferencescheduling.domain.ConferenceConstraintProperties.SAME_DAY_TALKS;
1414
import static ai.timefold.solver.benchmarks.examples.conferencescheduling.domain.ConferenceConstraintProperties.SECTOR_CONFLICT;
1515
import static ai.timefold.solver.benchmarks.examples.conferencescheduling.domain.ConferenceConstraintProperties.SPEAKER_CONFLICT;
1616
import static ai.timefold.solver.benchmarks.examples.conferencescheduling.domain.ConferenceConstraintProperties.SPEAKER_MAKESPAN;
@@ -92,7 +92,8 @@ public Constraint[] defineConstraints(ConstraintFactory factory) {
9292
contentAudienceLevelFlowViolation(factory),
9393
contentConflict(factory),
9494
languageDiversity(factory),
95-
sameDayTalks(factory),
95+
contentConflictSameDay(factory),
96+
themeTrackConflictSameDay(factory),
9697
popularTalks(factory),
9798
speakerPreferredTimeslotTags(factory),
9899
speakerUndesiredTimeslotTags(factory),
@@ -303,11 +304,10 @@ Constraint contentAudienceLevelFlowViolation(ConstraintFactory factory) {
303304

304305
Constraint contentConflict(ConstraintFactory factory) {
305306
return factory.forEachUniquePair(Talk.class,
306-
overlapping(t -> t.getTimeslot().getStartDateTime(), t -> t.getTimeslot().getEndDateTime()))
307-
.expand((talk1, talk2) -> talk2.overlappingContentCount(talk1))
308-
.filter((talk1, talk2, overlappingContentCount) -> overlappingContentCount > 0)
307+
overlapping(t -> t.getTimeslot().getStartDateTime(), t -> t.getTimeslot().getEndDateTime()),
308+
intersecting(Talk::getContentTagSet))
309309
.penalize(HardSoftScore.ofSoft(100),
310-
(talk1, talk2, overlappingContentCount) -> overlappingContentCount
310+
(talk1, talk2) -> talk2.overlappingContentCount(talk1)
311311
* talk1.overlappingDurationInMinutes(talk2))
312312
.asConstraint(CONTENT_CONFLICT);
313313
}
@@ -320,18 +320,20 @@ Constraint languageDiversity(ConstraintFactory factory) {
320320
.asConstraint(LANGUAGE_DIVERSITY);
321321
}
322322

323-
Constraint sameDayTalks(ConstraintFactory factory) {
324-
return factory.forEachUniquePair(Talk.class)
323+
Constraint contentConflictSameDay(ConstraintFactory factory) {
324+
return factory.forEachUniquePair(Talk.class, intersecting(Talk::getContentTagSet))
325325
.filter((talk1, talk2) -> !talk1.getTimeslot().isOnSameDayAs(talk2.getTimeslot()))
326-
.expand((talk1, talk2) -> {
327-
var overlappingContentCount = talk2.overlappingContentCount(talk1);
328-
var overlappingThemeTrackCount = talk2.overlappingThemeTrackCount(talk1);
329-
return overlappingContentCount + overlappingThemeTrackCount;
330-
})
331-
.filter((talk1, talk2, overlap) -> overlap > 0)
332326
.penalize(HardSoftScore.ofSoft(10),
333-
(talk1, talk2, overlap) -> overlap * talk1.combinedDurationInMinutes(talk2))
334-
.asConstraint(SAME_DAY_TALKS);
327+
(talk1, talk2) -> talk2.overlappingContentCount(talk1) * talk1.combinedDurationInMinutes(talk2))
328+
.asConstraint(CONTENT_CONFLICT_SAME_DAY_TALKS);
329+
}
330+
331+
Constraint themeTrackConflictSameDay(ConstraintFactory factory) {
332+
return factory.forEachUniquePair(Talk.class, intersecting(Talk::getThemeTrackTagSet))
333+
.filter((talk1, talk2) -> !talk1.getTimeslot().isOnSameDayAs(talk2.getTimeslot()))
334+
.penalize(HardSoftScore.ofSoft(10),
335+
(talk1, talk2) -> talk2.overlappingThemeTrackCount(talk1) * talk1.combinedDurationInMinutes(talk2))
336+
.asConstraint(THEME_TRACK_CONFLICT_SAME_DAY_TALKS);
335337
}
336338

337339
Constraint popularTalks(ConstraintFactory factory) {

src/main/resources/logback.xml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
</encoder>
99
</appender>
1010

11-
<logger name="ai.timefold.solver" level="${logback.level.ai.timefold.solver:-warn}"/>
11+
<logger name="ai.timefold.solver" level="${logback.level.ai.timefold.solver:-info}"/>
1212
<logger name="ai.timefold.solver.benchmarks" level="${logback.level.ai.timefold.solver:-info}"/>
1313
<logger name="ai.timefold.solver.benchmarks.examples" level="${logback.level.ai.timefold.solver:-warn}"/>
1414

src/test/java/ai/timefold/solver/benchmarks/examples/conferencescheduling/score/ConferenceSchedulingConstraintProviderTest.java

Lines changed: 44 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -568,7 +568,7 @@ void languageDiversity(
568568
}
569569

570570
@ConstraintProviderTest
571-
void sameDayTalks(
571+
void contentConflictSameDayTalks(
572572
ConstraintVerifier<ConferenceSchedulingConstraintProvider, ConferenceSolution> constraintVerifier) {
573573
Room room = new Room(0);
574574
Talk talk1 = new Talk(1)
@@ -603,9 +603,50 @@ void sameDayTalks(
603603
.withTimeslot(TUESDAY_9_TO_10);
604604

605605
constraintVerifier.verifyThat(
606-
ConferenceSchedulingConstraintProvider::sameDayTalks)
606+
ConferenceSchedulingConstraintProvider::contentConflictSameDay)
607607
.given(talk1, talk2, talk3, talk4, talk5, talk6)
608-
.penalizesBy(960);
608+
.penalizesBy(480);
609+
}
610+
611+
@ConstraintProviderTest
612+
void themeTrackConflictSameDayTalks(
613+
ConstraintVerifier<ConferenceSchedulingConstraintProvider, ConferenceSolution> constraintVerifier) {
614+
Room room = new Room(0);
615+
Talk talk1 = new Talk(1)
616+
.withRoom(room)
617+
.withContentTagSet(singleton("a"))
618+
.withThemeTrackTagSet(singleton("a"))
619+
.withTimeslot(MONDAY_9_TO_10);
620+
Talk talk2 = new Talk(3)
621+
.withRoom(room)
622+
.withContentTagSet(singleton("b"))
623+
.withThemeTrackTagSet(singleton("a"))
624+
.withTimeslot(TUESDAY_9_TO_10);
625+
Talk talk3 = new Talk(4)
626+
.withRoom(room)
627+
.withContentTagSet(singleton("a"))
628+
.withThemeTrackTagSet(singleton("a"))
629+
.withTimeslot(TUESDAY_9_TO_10);
630+
Talk talk4 = new Talk(5)
631+
.withRoom(room)
632+
.withContentTagSet(singleton("a"))
633+
.withThemeTrackTagSet(singleton("b"))
634+
.withTimeslot(MONDAY_9_TO_10);
635+
Talk talk5 = new Talk(7)
636+
.withRoom(room)
637+
.withContentTagSet(singleton("b"))
638+
.withThemeTrackTagSet(singleton("b"))
639+
.withTimeslot(TUESDAY_9_TO_10);
640+
Talk talk6 = new Talk(8)
641+
.withRoom(room)
642+
.withContentTagSet(singleton("a"))
643+
.withThemeTrackTagSet(singleton("b"))
644+
.withTimeslot(TUESDAY_9_TO_10);
645+
646+
constraintVerifier.verifyThat(
647+
ConferenceSchedulingConstraintProvider::themeTrackConflictSameDay)
648+
.given(talk1, talk2, talk3, talk4, talk5, talk6)
649+
.penalizesBy(480);
609650
}
610651

611652
@ConstraintProviderTest

0 commit comments

Comments
 (0)