I have been using Google OR-tools and trying to follow along with their examples for scheduling problems. However, the python documentation is sometimes hard to follow, and the more complex example ( https://github.com/google/or-tools/blob/master/examples/python/shift_scheduling_sat.py) is not described well.
I want to be able to set hard and soft constraints on the amount of shifts employees work. In the above example I believe the function add_soft_sum_constraint()
(I've put its exact code below) does what I want to do. I would like to replicate its functionality but I don't understand how it is doing it.
In the 2 if statements Im unsure what the delta
and excess
variables represent, and why they are adding more constraints, rather than just add more to the 2 cost lists which will be used when they minimize the objective later.
If anyone has any insight into this example I would be grateful, thanks.
def add_soft_sum_constraint(model, works, hard_min, soft_min, min_cost,
soft_max, hard_max, max_cost, prefix):
cost_variables = []
cost_coefficients = []
sum_var = model.NewIntVar(hard_min, hard_max, '')
# This adds the hard constraints on the sum.
model.Add(sum_var == sum(works))
# Penalize sums below the soft_min target.
if soft_min > hard_min and min_cost > 0:
delta = model.NewIntVar(-len(works), len(works), '')
model.Add(delta == soft_min - sum_var)
# TODO(user): Compare efficiency with only excess >= soft_min - sum_var.
excess = model.NewIntVar(0, 7, prefix + ': under_sum')
model.AddMaxEquality(excess, [delta, 0])
cost_variables.append(excess)
cost_coefficients.append(min_cost)
# Penalize sums above the soft_max target.
if soft_max < hard_max and max_cost > 0:
delta = model.NewIntVar(-7, 7, '')
model.Add(delta == sum_var - soft_max)
excess = model.NewIntVar(0, 7, prefix + ': over_sum')
model.AddMaxEquality(excess, [delta, 0])
cost_variables.append(excess)
cost_coefficients.append(max_cost)
return cost_variables, cost_coefficients
delta:
distance to the soft_min soft_min - sum_var
, if it is negative it means that we are above that soft_constraint so the penalty should be 0, model.AddMaxEquality(excess, [delta, 0])
.
excess:
how far are we from the soft_min, used to discard negative deltas, this is what we will multiply by min_cost
.
It is pretty much the same but reversed.
delta:
distance to the soft_max sum_var - soft_max
, if it is negative it means that we are below that soft_constraint so the penalty should be 0, model.AddMaxEquality(excess, [delta, 0])
excess:
how far are we from the soft_max, used to discard negative deltas, this is what we will multiply by max_cost
.
It returns the coefficients and variables, for example:
Let's say that the soft_min is 3 and the min_cost is 2:
Let's also say that the soft_max is 5 and the max_cost is 3:
Our variables are [1, 2, 1] and their coefficients [2, 2, 3].
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With