Search code examples
timefold

Handling recurrences from a template


I have MasterSchedule and LiveSchedule, TemplateShift, Shift and Employee domain models.

But I'm my timefold code, I'm only using Schedule Shift and Employee. The planning variable here is an employee assigned to an shift.

MasterSchedule and TemplateShifts allow a user to modify shifts for future planning and set a rollout date that will then apply the MasterSchedule to the LiveSchedule. But these TemplateShifts do not have dates but store the values of week, day, start, end. When building an shift from this template shift, it will generate the dates relative to the current week. E.g week 1 day 2 would be Tuesday of the current week. For more context, a shift can also be over 2 days e.g 8pm Monday - 6am Tuesday.

I need to optimize both the TemplateSchedule and the LiveSchedule. I was hoping to keep things simple by building shifts from the templates and sending them to timefold. Just so I don't have to handle the differences of a template shift vs a shift. But I'm not sure how to handle the reoccurrence of the template shifts. The MasterSchedule defines a number of weeks that shifts can be assigned to. Then when applied to the live schedule the shifts will repeat based on the template shifts from the master schedule. If I create 2 weeks worth of shifts from the MasterSchedule, then these 2 weeks would repeat when saved to a LiveSchedule from a rollout date.

The problem I'm facing is handling the reoccurrence. For example for a 1 week Master Schedule, If I have a template shift on day 1 from 1am - 5am, but on day 7 there is an shift from 10pm - 3am there could be conflicts. But I'm not sure how to penalize this in the constraints. I need to somehow set day 8 as day 1 after a solution has been found then apply the constraints and calculate the scores. What would be the best way to handle this?

Heres my Shift and Employee classes:

@PlanningEntity
public class Shift {
  @PlanningId
  Long id;

  Location location;
  LocalDateTime start;
  LocalDateTime end;
  boolean locked;

  @PlanningVariable(nullable = true)
  Employee employee;

  @PlanningPin
  public boolean isLocked() {
    return locked;
  }
}


public class Employee {
  @PlanningId
  Long id;
  String name;
  double rate;
}



Solution

  • I suggest you have two different planning problems, and you should not be treating them as one:

    1. Your templates need to be optimized independently of the live schedule; that's your strategic, long-term plan.
    2. Your live schedule is continuously updated; that is your tactical, short-term plan.

    Optimizing the templates should be relatively simple, as that is static data. Optimizing the live schedule is an example of continuous planning; Don't bother with any kind of recurrence, instead generate every instance of every shift you need within the given planning window. Maybe even generate shifts past the planning window, to let the solver know that there is a future and that it should not be entirely sacrified for the present.