diff --git a/java/conference-scheduling/src/main/java/org/acme/conferencescheduling/solver/ConferenceSchedulingConstraintProvider.java b/java/conference-scheduling/src/main/java/org/acme/conferencescheduling/solver/ConferenceSchedulingConstraintProvider.java index 3d3eb95373..1c470010e1 100644 --- a/java/conference-scheduling/src/main/java/org/acme/conferencescheduling/solver/ConferenceSchedulingConstraintProvider.java +++ b/java/conference-scheduling/src/main/java/org/acme/conferencescheduling/solver/ConferenceSchedulingConstraintProvider.java @@ -4,11 +4,7 @@ import static ai.timefold.solver.core.api.score.stream.ConstraintCollectors.countBi; import static ai.timefold.solver.core.api.score.stream.ConstraintCollectors.max; import static ai.timefold.solver.core.api.score.stream.ConstraintCollectors.min; -import static ai.timefold.solver.core.api.score.stream.Joiners.equal; -import static ai.timefold.solver.core.api.score.stream.Joiners.filtering; -import static ai.timefold.solver.core.api.score.stream.Joiners.greaterThan; -import static ai.timefold.solver.core.api.score.stream.Joiners.lessThan; -import static ai.timefold.solver.core.api.score.stream.Joiners.overlapping; +import static ai.timefold.solver.core.api.score.stream.Joiners.*; import static java.util.stream.Collectors.joining; import static org.acme.conferencescheduling.domain.ConferenceConstraintProperties.AUDIENCE_LEVEL_DIVERSITY; import static org.acme.conferencescheduling.domain.ConferenceConstraintProperties.AUDIENCE_TYPE_DIVERSITY; @@ -151,8 +147,8 @@ Constraint speakerUnavailableTimeslot(ConstraintFactory factory) { return factory.forEachIncludingUnassigned(Talk.class) .filter(talk -> talk.getTimeslot() != null) .join(Speaker.class, - filtering((talk, speaker) -> talk.hasSpeaker(speaker) - && speaker.getUnavailableTimeslots().contains(talk.getTimeslot()))) + contain(Talk::getSpeakers, speaker -> speaker), + containedIn(Talk::getTimeslot, Speaker::getUnavailableTimeslots)) .penalize(HardSoftScore.ofHard(100), (talk, speaker) -> talk.getDurationInMinutes()) .justifyWith( (talk, speaker, score) -> new UnavailableTimeslotJustification(talk, speaker)) @@ -173,7 +169,7 @@ Constraint talkPrerequisiteTalks(ConstraintFactory factory) { return factory.forEach(Talk.class) .join(Talk.class, greaterThan(t -> t.getTimeslot().getEndDateTime(), t -> t.getTimeslot().getStartDateTime()), - filtering((talk1, talk2) -> talk2.getPrerequisiteTalks().contains(talk1))) + containedIn(talk -> talk, Talk::getPrerequisiteTalks)) .penalize(HardSoftScore.ofHard(10), Talk::combinedDurationInMinutes) .justifyWith( (talk, talk2, score) -> new ConferenceSchedulingJustification( @@ -184,7 +180,7 @@ Constraint talkPrerequisiteTalks(ConstraintFactory factory) { Constraint talkMutuallyExclusiveTalksTags(ConstraintFactory factory) { return factory.forEachUniquePair(Talk.class, overlapping(t -> t.getTimeslot().getStartDateTime(), t -> t.getTimeslot().getEndDateTime()), - filtering((talk1, talk2) -> talk2.overlappingMutuallyExclusiveTalksTagCount(talk1) > 0)) + containAny(Talk::getMutuallyExclusiveTalksTags)) .penalize(HardSoftScore.ofHard(1), (talk1, talk2) -> talk1.overlappingMutuallyExclusiveTalksTagCount(talk2) * talk1.overlappingDurationInMinutes(talk2)) .justifyWith((talk, talk2, score) -> new ConflictTalkJustification("mutually-exclusive-talks tags", talk, @@ -341,7 +337,7 @@ Constraint talkProhibitedRoomTags(ConstraintFactory factory) { Constraint themeTrackConflict(ConstraintFactory factory) { return factory.forEachUniquePair(Talk.class, overlapping(t -> t.getTimeslot().getStartDateTime(), t -> t.getTimeslot().getEndDateTime()), - filtering((talk1, talk2) -> talk2.overlappingThemeTrackCount(talk1) > 0)) + containAny(Talk::getThemeTrackTags)) .penalize(HardSoftScore.ofSoft(10), (talk1, talk2) -> talk1.overlappingThemeTrackCount(talk2) * talk1.overlappingDurationInMinutes(talk2)) .justifyWith( @@ -353,7 +349,7 @@ Constraint themeTrackConflict(ConstraintFactory factory) { Constraint themeTrackRoomStability(ConstraintFactory factory) { return factory.forEachUniquePair(Talk.class, equal(talk -> talk.getTimeslot().getStartDateTime().toLocalDate()), - filtering((talk1, talk2) -> talk2.overlappingThemeTrackCount(talk1) > 0)) + containAny(Talk::getThemeTrackTags)) .filter((talk1, talk2) -> !talk1.getRoom().equals(talk2.getRoom())) .penalize(HardSoftScore.ofSoft(10), (talk1, talk2) -> talk1.overlappingThemeTrackCount(talk2) * talk1.combinedDurationInMinutes(talk2)) @@ -371,7 +367,7 @@ Constraint themeTrackRoomStability(ConstraintFactory factory) { Constraint sectorConflict(ConstraintFactory factory) { return factory.forEachUniquePair(Talk.class, overlapping(t -> t.getTimeslot().getStartDateTime(), t -> t.getTimeslot().getEndDateTime()), - filtering((talk1, talk2) -> talk2.overlappingSectorCount(talk1) > 0)) + containAny(Talk::getSectorTags)) .penalize(HardSoftScore.ofSoft(10), (talk1, talk2) -> talk1.overlappingSectorCount(talk2) * talk1.overlappingDurationInMinutes(talk2)) .justifyWith((talk, talk2, score) -> new ConflictTalkJustification("sector", talk, talk.getSectorTags(), talk2, @@ -382,7 +378,7 @@ Constraint sectorConflict(ConstraintFactory factory) { Constraint audienceTypeDiversity(ConstraintFactory factory) { return factory.forEachUniquePair(Talk.class, equal(Talk::getTimeslot), - filtering((talk1, talk2) -> talk2.overlappingAudienceTypeCount(talk1) > 0)) + containAny(Talk::getAudienceTypes)) .reward(HardSoftScore.ofSoft(1), (talk1, talk2) -> talk1.overlappingAudienceTypeCount(talk2) * talk1.getTimeslot().getDurationInMinutes()) .justifyWith((talk, talk2, score) -> new DiversityTalkJustification("audience types", talk, @@ -393,8 +389,8 @@ Constraint audienceTypeDiversity(ConstraintFactory factory) { Constraint audienceTypeThemeTrackConflict(ConstraintFactory factory) { return factory.forEachUniquePair(Talk.class, overlapping(t -> t.getTimeslot().getStartDateTime(), t -> t.getTimeslot().getEndDateTime()), - filtering((talk1, talk2) -> talk2.overlappingThemeTrackCount(talk1) > 0), - filtering((talk1, talk2) -> talk2.overlappingAudienceTypeCount(talk1) > 0)) + containAny(Talk::getThemeTrackTags), + containAny(Talk::getAudienceTypes)) .penalize(HardSoftScore.ofSoft(1), (talk1, talk2) -> talk1.overlappingThemeTrackCount(talk2) * talk1.overlappingAudienceTypeCount(talk2) * talk1.overlappingDurationInMinutes(talk2)) @@ -420,7 +416,7 @@ Constraint contentAudienceLevelFlowViolation(ConstraintFactory factory) { lessThan(Talk::getAudienceLevel), greaterThan(talk1 -> talk1.getTimeslot().getEndDateTime(), talk2 -> talk2.getTimeslot().getStartDateTime()), - filtering((talk1, talk2) -> talk2.overlappingContentCount(talk1) > 0)) + containAny(Talk::getContentTags)) .penalize(HardSoftScore.ofSoft(10), (talk1, talk2) -> talk1.overlappingContentCount(talk2) * talk1.combinedDurationInMinutes(talk2)) .justifyWith((talk, talk2, score) -> new ConferenceSchedulingJustification( @@ -435,7 +431,7 @@ Constraint contentAudienceLevelFlowViolation(ConstraintFactory factory) { Constraint contentConflict(ConstraintFactory factory) { return factory.forEachUniquePair(Talk.class, overlapping(t -> t.getTimeslot().getStartDateTime(), t -> t.getTimeslot().getEndDateTime()), - filtering((talk1, talk2) -> talk2.overlappingContentCount(talk1) > 0)) + containAny(Talk::getContentTags)) .penalize(HardSoftScore.ofSoft(100), (talk1, talk2) -> talk1.overlappingContentCount(talk2) * talk1.overlappingDurationInMinutes(talk2)) .justifyWith(