Search code examples
constraintsschedulingoptaplanner

Optaplanner - Constraint streams groupBy


I am trying to solve a scheduling problem, which centers around the following arrangement:

Equipment <- Task <- ShiftAssignment(Planning Variable) -> Shift

Tasks have a problem fact of their equipment usage; each may reference a specific Equipment instance or instances, with an associated time in minutes. It takes up that time for that equipment in the Shift it's assigned to.

Should I be able to achieve the constraint with join() and groupBy()? I've tried pursuing the following route:

    private Constraint doNotOverbookEquipment(ConstraintFactory factory) {
        return factory.from(ShiftAssignment.class)
                // join shift assignments with the shifts they are assignments of
                .join(Shift.class, equal(ShiftAssignment::getShiftId, Shift::getId))
                // join with ALL pieces of equipment
                .join(Equipment.class)
                .groupBy([Shift and Equipment, summing the equipment-usage for each ShiftAssignment])
                .filter([equipment usage greater than a constant])
                .penalizeConfigurable("do not overbook Equipment");

I think the filter() should be no problem, but unsure exactly how to get this groupBy() to achieve what I want. Do I need a TriConstraintCollector here? Or is there a different, better overall approach?

For reference, the ShiftAssignment class can easily have a method like the following:

public LinkedHashSet<Equipment, Integer> getEquipmentUsage()

Solution

  • I think that your groupBy() would look something like this:

    .groupBy(
        (shiftAssignment, shift, equipment) -> shift,
        (shiftAssignment, shift, equipment) -> equipment,
        ConstraintCollectors.sum((shiftAssignment, shift, equipment) ->
            shiftAssignment.getUsage(shift, equipment)
    )
    

    The actual logic of what is to be summed should, in this case, be implemented in shiftAssignment.getUsage(...) or any other method you choose to use there.