optimizationcplexor-toolsoperations-researchcp-sat

Using NewBoolVar in Google OR-Tools


I am wondering the syntax for logical constraints in Google OR-Tools. I have a nurse scheduling project I have done in CPLEX that I am translating over to Google OR-Tools. I have come across the documentation for channeling constraints in Google OR-Tools, but I am confused. Can you help me understand how I would implement this CPLEX logical constraint in Google OR-Tools? I have an attempt, but it is not working as intended :(

Context:

working_assignment_vars_long[r,h,i] is a binary decision variable that denotes whether nurse i in role r is working at the 15-minute interval h (i.e. 1:15PM).

lunch_break_assignment_vars_long[r,h,i] is a binary decision variable that denotes whether nurse i in role r is on break at the 15-minute interval h (i.e. 1:15PM).

simple_break_assignment_vars_long[r,h,i] is a binary decision variable that denotes whether nurse i in role r is on break at 15-minute interval h.

Thus, this constraint in CPLEX is saying that if a given nurse is working 31 or less 15-minute intervals, then they should have 0 lunch breaks and 1 simple break.

CPLEX logical constraint:

for r, num_role in role_dict.items():

   for i in range(0,num_role):

      model.add_if_then(

         model.sum(model.working_assignment_vars_long[r,h,i] for h in range(0,144)) 
         <= 31,

         (model.sum(model.lunch_break_assignment_vars_long[r,h,i] for h in range(0,144)) == 
         0) + (model.sum(model.simple_break_assignment_vars_long[r,h,i] for h in range(0,144)) == 
         1) >= 2, 

         'less_than_8_hr_0_lunch_break_1_simple_break'

      ) 

I have attempted this in OR-Tools with the following code:

for r, num_role in role_dict.items():

   for i in range(0,num_role):

      b=model.NewBoolVar(‘b’)

      model.Add(sum(working.assignment_vars_long[r,h,i] for h in range(0,144)) <= 31).OnlyEnforceIf(b)

      model.Add(sum(lunch_break_assignment_vars_long[r,h,i] for h in range(0,144)) == 0).OnlyEnforceIf(b)

      model.Add(sum(simple_break_assignment_vars_long[r,h,i] for h in range(0,144)) == 1).OnlyEnforceIf(b) 

This is not working as intended though :( as I see nurses working less than 32 15-minute intervals with both no lunch breaks and no simple breaks. Any insight/help is greatly appreciated. I have been stuck on this problem for so long now :(


Solution

  • In the official documentation it is documented how to do an If-Then-Else expression.

    You aren't constraining b.Not():

    model.Add(sum(working.assignment_vars_long[r,h,i] for h in range(0,144)) > 31).OnlyEnforceIf(b.Not())