Skip to content

Commit

Permalink
perf: conf scheduling reduces impact of unrelated code
Browse files Browse the repository at this point in the history
By using expand and map, we eliminate a lot of iteration in the domain model, which is unrelated to the performance of the example.
  • Loading branch information
triceo committed Dec 21, 2024
1 parent 5a4d4df commit 795edfc
Showing 1 changed file with 61 additions and 53 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -163,10 +163,11 @@ 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))
.penalize(HardSoftScore.ofHard(1), (talk1, talk2) -> talk1.overlappingMutuallyExclusiveTalksTagCount(talk2) *
talk1.overlappingDurationInMinutes(talk2))
overlapping(t -> t.getTimeslot().getStartDateTime(), t -> t.getTimeslot().getEndDateTime()))
.expand((talk1, talk2) -> talk2.overlappingMutuallyExclusiveTalksTagCount(talk1))
.filter((talk1, talk2, overlappingTagCount) -> overlappingTagCount > 0)
.penalize(HardSoftScore.ofHard(1),
(talk1, talk2, overlappingTagCount) -> overlappingTagCount * talk1.overlappingDurationInMinutes(talk2))
.asConstraint(TALK_MUTUALLY_EXCLUSIVE_TALKS_TAGS);
}

Expand Down Expand Up @@ -227,7 +228,6 @@ Constraint talkProhibitedTimeslotTags(ConstraintFactory factory) {
.filter((talk, prohibitedTagCount) -> prohibitedTagCount > 0)
.penalize(HardSoftScore.ofHard(1),
(talk, prohibitedTagCount) -> prohibitedTagCount * talk.getDurationInMinutes())
.indictWith((talk, prohibitedTagCount) -> Collections.singleton(talk))
.asConstraint(TALK_PROHIBITED_TIMESLOT_TAGS);
}

Expand All @@ -236,7 +236,6 @@ Constraint speakerRequiredRoomTags(ConstraintFactory factory) {
.expand(Talk::missingSpeakerRequiredRoomTagCount)
.filter((talk, missingTagCount) -> missingTagCount > 0)
.penalize(HardSoftScore.ofHard(1), (talk, missingTagCount) -> missingTagCount * talk.getDurationInMinutes())
.indictWith((talk, missingTagCount) -> Collections.singleton(talk))
.asConstraint(SPEAKER_REQUIRED_ROOM_TAGS);
}

Expand All @@ -246,7 +245,6 @@ Constraint speakerProhibitedRoomTags(ConstraintFactory factory) {
.filter((talk, prohibitedTagCount) -> prohibitedTagCount > 0)
.penalize(HardSoftScore.ofHard(1),
(talk, prohibitedTagCount) -> prohibitedTagCount * talk.getDurationInMinutes())
.indictWith((talk, prohibitedTagCount) -> Collections.singleton(talk))
.asConstraint(SPEAKER_PROHIBITED_ROOM_TAGS);
}

Expand All @@ -255,7 +253,6 @@ Constraint talkRequiredRoomTags(ConstraintFactory factory) {
.expand(Talk::missingRequiredRoomTagCount)
.filter((talk, missingTagCount) -> missingTagCount > 0)
.penalize(HardSoftScore.ofHard(1), (talk, missingTagCount) -> missingTagCount * talk.getDurationInMinutes())
.indictWith((talk, missingTagCount) -> Collections.singleton(talk))
.asConstraint(TALK_REQUIRED_ROOM_TAGS);
}

Expand All @@ -265,7 +262,6 @@ Constraint talkProhibitedRoomTags(ConstraintFactory factory) {
.filter((talk, prohibitedTagCount) -> prohibitedTagCount > 0)
.penalize(HardSoftScore.ofHard(1),
(talk, prohibitedTagCount) -> prohibitedTagCount * talk.getDurationInMinutes())
.indictWith((talk, prohibitedTagCount) -> Collections.singleton(talk))
.asConstraint(TALK_PROHIBITED_ROOM_TAGS);
}

Expand All @@ -275,49 +271,60 @@ 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))
.penalize(HardSoftScore.ofSoft(10), (talk1, talk2) -> talk1.overlappingThemeTrackCount(talk2) *
talk1.overlappingDurationInMinutes(talk2))
overlapping(t -> t.getTimeslot().getStartDateTime(), t -> t.getTimeslot().getEndDateTime()))
.expand((talk1, talk2) -> talk2.overlappingThemeTrackCount(talk1))
.filter((talk1, talk2, overlappingTrackCount) -> overlappingTrackCount > 0)
.penalize(HardSoftScore.ofSoft(10),
(talk1, talk2, overlappingTrackCount) -> overlappingTrackCount
* talk1.overlappingDurationInMinutes(talk2))
.asConstraint(THEME_TRACK_CONFLICT);
}

Constraint themeTrackRoomStability(ConstraintFactory factory) {
return factory.forEachUniquePair(Talk.class,
equal(talk -> talk.getTimeslot().getStartDateTime().toLocalDate()),
filtering((talk1, talk2) -> talk2.overlappingThemeTrackCount(talk1) > 0))
.filter((talk1, talk2) -> !talk1.getRoom().equals(talk2.getRoom()))
.penalize(HardSoftScore.ofSoft(10), (talk1, talk2) -> talk1.overlappingThemeTrackCount(talk2) *
talk1.combinedDurationInMinutes(talk2))
equal(talk -> talk.getTimeslot().getStartDateTime().toLocalDate()))
.expand((talk1, talk2) -> talk2.overlappingThemeTrackCount(talk1))
.filter((talk1, talk2, overlappingTrackCount) -> overlappingTrackCount > 0
&& !talk1.getRoom().equals(talk2.getRoom()))
.penalize(HardSoftScore.ofSoft(10),
(talk1, talk2, overlappingTrackCount) -> overlappingTrackCount * talk1.combinedDurationInMinutes(talk2))
.asConstraint(THEME_TRACK_ROOM_STABILITY);
}

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))
.penalize(HardSoftScore.ofSoft(10), (talk1, talk2) -> talk1.overlappingSectorCount(talk2)
* talk1.overlappingDurationInMinutes(talk2))
overlapping(t -> t.getTimeslot().getStartDateTime(), t -> t.getTimeslot().getEndDateTime()))
.expand((talk1, talk2) -> talk2.overlappingSectorCount(talk1))
.filter((talk1, talk2, overlappingSectorCount) -> overlappingSectorCount > 0)
.penalize(HardSoftScore.ofSoft(10),
(talk1, talk2, overlappingSectorCount) -> overlappingSectorCount
* talk1.overlappingDurationInMinutes(talk2))
.asConstraint(SECTOR_CONFLICT);
}

Constraint audienceTypeDiversity(ConstraintFactory factory) {
return factory.forEachUniquePair(Talk.class,
equal(Talk::getTimeslot),
filtering((talk1, talk2) -> talk2.overlappingAudienceTypeCount(talk1) > 0))
.reward(HardSoftScore.ofSoft(1), (talk1, talk2) -> talk1.overlappingAudienceTypeCount(talk2)
* talk1.getTimeslot().getDurationInMinutes())
equal(Talk::getTimeslot))
.expand((talk1, talk2) -> talk2.overlappingAudienceTypeCount(talk1))
.filter((talk1, talk2, overlappingAudienceTypeCount) -> overlappingAudienceTypeCount > 0)
.reward(HardSoftScore.ofSoft(1),
(talk1, talk2, overlappingAudienceTypeCount) -> overlappingAudienceTypeCount
* talk1.getTimeslot().getDurationInMinutes())
.asConstraint(AUDIENCE_TYPE_DIVERSITY);
}

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))
.penalize(HardSoftScore.ofSoft(1), (talk1, talk2) -> talk1.overlappingThemeTrackCount(talk2)
* talk1.overlappingAudienceTypeCount(talk2)
* talk1.overlappingDurationInMinutes(talk2))
overlapping(t -> t.getTimeslot().getStartDateTime(), t -> t.getTimeslot().getEndDateTime()))
.map((talk1, talk2) -> talk1,
(talk1, talk2) -> talk2,
Talk::overlappingThemeTrackCount,
Talk::overlappingAudienceTypeCount)
.filter((talk1, talk2, overlappingTrackCount, overlappingTypeCount) -> overlappingTrackCount > 0
&& overlappingTypeCount > 0)
.penalize(HardSoftScore.ofSoft(1),
(talk1, talk2, overlappingTrackCount, overlappingTypeCount) -> overlappingTrackCount
* overlappingTypeCount * talk1.overlappingDurationInMinutes(talk2))
.asConstraint(AUDIENCE_TYPE_THEME_TRACK_CONFLICT);
}

Expand All @@ -334,19 +341,23 @@ Constraint contentAudienceLevelFlowViolation(ConstraintFactory factory) {
.join(Talk.class,
lessThan(Talk::getAudienceLevel),
greaterThan(talk1 -> talk1.getTimeslot().getEndDateTime(),
talk2 -> talk2.getTimeslot().getStartDateTime()),
filtering((talk1, talk2) -> talk2.overlappingContentCount(talk1) > 0))
.penalize(HardSoftScore.ofSoft(10), (talk1, talk2) -> talk1.overlappingContentCount(talk2)
* talk1.combinedDurationInMinutes(talk2))
talk2 -> talk2.getTimeslot().getStartDateTime()))
.expand((talk1, talk2) -> talk2.overlappingContentCount(talk1))
.filter((talk1, talk2, overlappingContentCount) -> overlappingContentCount > 0)
.penalize(HardSoftScore.ofSoft(10),
(talk1, talk2, overlappingContentCount) -> overlappingContentCount
* talk1.combinedDurationInMinutes(talk2))
.asConstraint(CONTENT_AUDIENCE_LEVEL_FLOW_VIOLATION);
}

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))
.penalize(HardSoftScore.ofSoft(100), (talk1, talk2) -> talk1.overlappingContentCount(talk2)
* talk1.overlappingDurationInMinutes(talk2))
overlapping(t -> t.getTimeslot().getStartDateTime(), t -> t.getTimeslot().getEndDateTime()))
.expand((talk1, talk2) -> talk2.overlappingContentCount(talk1))
.filter((talk1, talk2, overlappingContentCount) -> overlappingContentCount > 0)
.penalize(HardSoftScore.ofSoft(100),
(talk1, talk2, overlappingContentCount) -> overlappingContentCount
* talk1.overlappingDurationInMinutes(talk2))
.asConstraint(CONTENT_CONFLICT);
}

Expand All @@ -360,11 +371,17 @@ Constraint languageDiversity(ConstraintFactory factory) {

Constraint sameDayTalks(ConstraintFactory factory) {
return factory.forEachUniquePair(Talk.class)
.filter((talk1, talk2) -> !talk1.getTimeslot().isOnSameDayAs(talk2.getTimeslot()) &&
(talk1.overlappingContentCount(talk2) > 0 || talk1.overlappingThemeTrackCount(talk2) > 0))
.filter((talk1, talk2) -> !talk1.getTimeslot().isOnSameDayAs(talk2.getTimeslot()))
.map((talk1, talk2) -> talk1,
(talk1, talk2) -> talk2,
Talk::overlappingContentCount,
Talk::overlappingThemeTrackCount)
.filter((talk1, talk2, overlappingContentCount, overlappingThemeTrackCount) -> overlappingContentCount > 0
|| overlappingThemeTrackCount > 0)
.penalize(HardSoftScore.ofSoft(10),
(talk1, talk2) -> (talk2.overlappingThemeTrackCount(talk1) + talk2.overlappingContentCount(talk1))
* talk1.combinedDurationInMinutes(talk2))
(talk1, talk2, overlappingContentCount,
overlappingThemeTrackCount) -> (overlappingContentCount + overlappingThemeTrackCount)
* talk1.combinedDurationInMinutes(talk2))
.asConstraint(SAME_DAY_TALKS);
}

Expand All @@ -382,7 +399,6 @@ Constraint speakerPreferredTimeslotTags(ConstraintFactory factory) {
.expand(Talk::missingSpeakerPreferredTimeslotTagCount)
.filter((talk, missingTagCount) -> missingTagCount > 0)
.penalize(HardSoftScore.ofSoft(20), (talk, missingTagCount) -> missingTagCount * talk.getDurationInMinutes())
.indictWith((talk, missingTagCount) -> Collections.singleton(talk))
.asConstraint(SPEAKER_PREFERRED_TIMESLOT_TAGS);
}

Expand All @@ -392,7 +408,6 @@ Constraint speakerUndesiredTimeslotTags(ConstraintFactory factory) {
.filter((talk, undesiredTagCount) -> undesiredTagCount > 0)
.penalize(HardSoftScore.ofSoft(20),
(talk, undesiredTagCount) -> undesiredTagCount * talk.getDurationInMinutes())
.indictWith((talk, undesiredTagCount) -> Collections.singleton(talk))
.asConstraint(SPEAKER_UNDESIRED_TIMESLOT_TAGS);
}

Expand All @@ -401,7 +416,6 @@ Constraint talkPreferredTimeslotTags(ConstraintFactory factory) {
.expand(Talk::missingPreferredTimeslotTagCount)
.filter((talk, missingTagCount) -> missingTagCount > 0)
.penalize(HardSoftScore.ofSoft(20), (talk, missingTagCount) -> missingTagCount * talk.getDurationInMinutes())
.indictWith((talk, missingTagCount) -> Collections.singleton(talk))
.asConstraint(TALK_PREFERRED_TIMESLOT_TAGS);
}

Expand All @@ -411,7 +425,6 @@ Constraint talkUndesiredTimeslotTags(ConstraintFactory factory) {
.filter((talk, undesiredTagCount) -> undesiredTagCount > 0)
.penalize(HardSoftScore.ofSoft(20),
(talk, undesiredTagCount) -> undesiredTagCount * talk.getDurationInMinutes())
.indictWith((talk, undesiredTagCount) -> Collections.singleton(talk))
.asConstraint(TALK_UNDESIRED_TIMESLOT_TAGS);
}

Expand All @@ -420,7 +433,6 @@ Constraint speakerPreferredRoomTags(ConstraintFactory factory) {
.expand(Talk::missingSpeakerPreferredRoomTagCount)
.filter((talk, missingTagCount) -> missingTagCount > 0)
.penalize(HardSoftScore.ofSoft(20), (talk, missingTagCount) -> missingTagCount * talk.getDurationInMinutes())
.indictWith((talk, missingTagCount) -> Collections.singleton(talk))
.asConstraint(SPEAKER_PREFERRED_ROOM_TAGS);
}

Expand All @@ -430,7 +442,6 @@ Constraint speakerUndesiredRoomTags(ConstraintFactory factory) {
.filter((talk, undesiredTagCount) -> undesiredTagCount > 0)
.penalize(HardSoftScore.ofSoft(20),
(talk, undesiredTagCount) -> undesiredTagCount * talk.getDurationInMinutes())
.indictWith((talk, undesiredTagCount) -> Collections.singleton(talk))
.asConstraint(SPEAKER_UNDESIRED_ROOM_TAGS);
}

Expand All @@ -439,7 +450,6 @@ Constraint talkPreferredRoomTags(ConstraintFactory factory) {
.expand(Talk::missingPreferredRoomTagCount)
.filter((talk, missingTagCount) -> missingTagCount > 0)
.penalize(HardSoftScore.ofSoft(20), (talk, missingTagCount) -> missingTagCount * talk.getDurationInMinutes())
.indictWith((talk, missingTagCount) -> Collections.singleton(talk))
.asConstraint(TALK_PREFERRED_ROOM_TAGS);
}

Expand All @@ -449,7 +459,6 @@ Constraint talkUndesiredRoomTags(ConstraintFactory factory) {
.filter((talk, undesiredTagCount) -> undesiredTagCount > 0)
.penalize(HardSoftScore.ofSoft(20),
(talk, undesiredTagCount) -> undesiredTagCount * talk.getDurationInMinutes())
.indictWith((talk, undesiredTagCount) -> Collections.singleton(talk))
.asConstraint(TALK_UNDESIRED_ROOM_TAGS);
}

Expand All @@ -469,7 +478,6 @@ Constraint speakerMakespan(ConstraintFactory factory) {
.filter((speaker, daysBetweenTalks) -> daysBetweenTalks > 1)
// Each such day counts for 8 hours.
.penalize(HardSoftScore.ofSoft(20), (speaker, daysBetweenTalks) -> (daysBetweenTalks - 1) * 8 * 60)
.indictWith((speaker, daysBetweenTalks) -> Collections.singleton(speaker))
.asConstraint(SPEAKER_MAKESPAN);
}

Expand Down

0 comments on commit 795edfc

Please sign in to comment.