1

In my optaplanner project i have periods with fixed duration. For some of them there is a medium constraint that they should be scheduled in a row, occupying for example 5 directly adjacent timeslots. I want to use Java constraints streams but dont manage to define this constraint using the timeslot-pattern.

I know that this constraint can be defined using the time-grain-pattern as suggested by https://stackoverflow.com/a/30702865. I have done this and it works. But I want to compare timeslot-pattern to time-grain-pattern because the have different behaviour when it comes to escape local maxima. The problem with time-grain-pattern is that those 5 periods could also be sheduled in every possible partition of 5 (eg. as 2 + 2 + 1).

Has anyone a hint on how to define the constraint using timeslot-pattern?

hornisgrinde
  • 152
  • 1
  • 10

2 Answers2

2

You may want to try using the newly added ifExists() building block. Without knowing your actual domain model, I imagine the constraint to look like this:

private Constraint twoConsecutivePeriods(ConstraintFactory constraintFactory) {
    return constraintFactory.from(Period.class)
            .ifExists(Period.class, equal(Period::getDay, period -> period.getDay() + 1))
            .penalize("2 consecutive periods", period -> ...);
}

Consequently, ifNotExists() may be used to achieve the opposite. We have examples of both in Traveling Tournament OptaPlanner example.

Please note that this API is only available since OptaPlanner 7.33.0.Final onward.

Lukáš Petrovický
  • 3,945
  • 1
  • 11
  • 20
0

I solved the problem using ConstraintCollectors.toList() as follows:

factory.from(Period.class).groupBy(Period::getCourse, ConstraintCollectors.toList())
                    .penalize(id, score, (course,list)->dayDistributionPenalize(course,list));

and

public int dayDistributionPenalize(Course course, List<Period> list) {
        var penalize = 0;
        var dayCodes = dayCodesFromPeriodList(list);

        for (var dayCode : dayCodes)
            if (!getAllowedDayCodes(course).contains(dayCode))
                penalize++;
        return penalize;
    }

Where getAllowedDayCodes() returns for example 0111110000, 0230000000 or 0005000000 etc. from a hash-map if a course has to have 5 consecutive periods.

hornisgrinde
  • 152
  • 1
  • 10