'Ortools - scheduling - task periodic conditions

I am trying to model a job scheduling problem with demand constraints for a 24 period. I am trying to figure out a way to model a job that can run past midnight, e.g. start at 23:45 and end at 00:30. I want these jobs to have periodic boundary conditions, i.e. a job that runs past midnight shows up in the morning.

As an example, I will use a time-discretized version where the time spans from 0 to 10. The question is how do I enforce Job2 to "rollback" at 1 time unit, rather than end at 11 time units. Note that a simple post-processing doesn't help because we want to ensure the capacity constraints are calculated properly.

enter image description here

from ortools.sat.python import cp_model
import pandas as pd
import numpy as np

model = cp_model.CpModel()
solver = cp_model.CpSolver()

TIME_HORIZON = 10 #Time Units

df = pd.DataFrame({
    'job':['j1', 'j2'],
    'earliest_start':[6,8],
    'latest_start':[10,10],
    'duration':[2,3],
    'resource_requirement':[2,2]
})

# Create Variables
df['start_vars'] = df.apply(lambda x: model.NewIntVar(lb=x['earliest_start'],
                                                     ub=x['latest_start'],
                                                     name= f'x_start_{x["job"]}'),
                           axis = 1)

df['end_vars'] = df.apply(lambda x: model.NewIntVar(lb=x['earliest_start'] + x['duration'],
                                                     ub=x['latest_start'] + x['duration'],
                                                     name= f'x_end_{x["job"]}'),
                           axis = 1)


df['interval_vars'] = df.apply(lambda x: model.NewIntervalVar(start=x['start_vars'],
                                                              size=x['duration'],
                                                              end=x['end_vars'],
                                                              name= f'interval_{x["job"]}'),
                           axis = 1)

enter image description here

# Specify capacity and set as objective

peak_capacity = int(df['resource_requirement'].sum())
capacity = model.NewIntVar(lb=0, ub=peak_capacity, name='capacity')
model.AddCumulative(df['interval_vars'].tolist(), 
                    df['resource_requirement'].tolist(),
                    capacity)

model.Minimize(capacity)

status = solver.Solve(model)
print(solver.StatusName(status))

print("Optimal Results")
df[['start_vars','end_vars']] = df[['start_vars','end_vars']].applymap(lambda x: solver.Value(x))

enter image description here



Solution 1:[1]

just create a double horizon, duplicate all jobs, and make sure the copy starts exactly 24h after the first day.

Also make sure that the non duplicate job is constrained to be within the first 24 hour

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 Laurent Perron