night shift balancing now works!

This commit is contained in:
Ross
2020-05-16 19:01:35 +01:00
parent 12f7b5270c
commit 63dcc7ce78
4 changed files with 136 additions and 185 deletions
+95 -35
View File
@@ -241,19 +241,25 @@ class RotaBuilder(object):
initialize=0,
)
self.model.worker_weekend_assigned = Var(
((worker.id, week) for worker in self.workers
for week in self.weeks),
domain=NonNegativeReals,
initialize=0,
)
self.model.night_shift_count_w = Var(
((worker.id) for worker in self.workers),
domain=NonNegativeReals,
initialize=0,
)
self.model.works_weekend_count = Var(
((worker.id, week) for worker in self.workers
for week in self.weeks),
domain=NonNegativeIntegers,
initialize=0,
)
# self.model.worker_weekend_assigned = Var(
# ((worker.id, week) for worker in self.workers
# for week in self.weeks),
# domain=NonNegativeReals,
# initialize=0,
# )
# self.model.works_weekend_count = Var(
# ((worker.id, week) for worker in self.workers
# for week in self.weeks),
# domain=NonNegativeIntegers,
# initialize=0,
# )
# self.model.works_saturday = Var(
# ((worker.id, week) for worker in self.workers
# for week in self.weeks),
@@ -274,18 +280,39 @@ class RotaBuilder(object):
# initialize=0,
# )
self.model.works_weekend = Var(
((worker.id, week) for worker in self.workers
for week in self.weeks),
domain=Binary,
initialize=0,
)
if self.constraint_options["balance_weekends"]:
self.model.worker_weekend_count = Var(
((worker.id) for worker in self.workers),
domain=NonNegativeIntegers,
initialize=0,
)
self.model.works_weekend = Var(
((worker.id, week) for worker in self.workers
for week in self.weeks),
domain=Binary,
initialize=0,
)
self.model.worker_weekend_count = Var(
((worker.id) for worker in self.workers),
domain=NonNegativeIntegers,
initialize=0,
)
self.model.weekend_shift_count_t1 = Var(
((worker.id) for worker in self.workers),
domain=NonNegativeReals,
initialize=0,
)
self.model.weekend_shift_count_t2 = Var(
((worker.id) for worker in self.workers),
domain=NonNegativeReals,
initialize=0,
)
self.model.weekend_shift_count_w = Var(
((worker.id) for worker in self.workers),
domain=NonNegativeReals,
initialize=0,
)
# self.model.weekend_count_t1 = Var(
# ((worker.id) for worker in self.workers),
@@ -418,12 +445,12 @@ class RotaBuilder(object):
)
def nightShiftMinST4Rule(model, week, shift):
single_workers = [w for w in self.workers if w.grade > 3]
single_workers = [w for w in self.workers if w.grade >= 4]
if not single_workers:
print(single_workers)
return Constraint.Skip
return sum(model.shift_week_worker_assigned[shift, week, w.id]
for w in single_workers) >= 2
for w in single_workers) >= 1
if self.constraint_options["ensure_1_st4_plus_on_nights"]:
self.model.night_shifts_min_st4_constraint = Constraint(
@@ -592,6 +619,31 @@ class RotaBuilder(object):
self.model.night_shift_count[worker.id] -
night_shift_target_number)
xU = 6
xL = 1
self.model.constraints.add(
inequality(
xL,
self.model.night_shift_count_t1[worker.id] +
self.model.night_shift_count_t2[worker.id] + 1,
xU,
))
self.model.constraints.add(
self.model.night_shift_count_w[worker.id] >= xL *
(self.model.night_shift_count_t1[worker.id] +
self.model.night_shift_count_t2[worker.id] + 1) * 2 -
xL * xL)
self.model.constraints.add(
self.model.night_shift_count_w[worker.id] >= xU *
(self.model.night_shift_count_t1[worker.id] +
self.model.night_shift_count_t2[worker.id] + 1) * 2 -
xU * xU)
# self.model.constraints.add(
# self.model.night_shift_count_w[worker.id] >= 0)
# Ensure worker is not allocated shifts on non working days
if worker.nwd:
for week, day, shift in self.get_all_shiftclass_combinations():
@@ -775,11 +827,12 @@ class RotaBuilder(object):
shift_balancing = 0
if self.constraint_options["balance_nights"]:
night_balance_modifier_constant = 2000
night_balance_modifier_constant = 1
night_shift_balancing = sum(
night_balance_modifier_constant *
(self.model.night_shift_count_t1[(worker.id)] +
self.model.night_shift_count_t2[(worker.id)])
self.model.night_shift_count_w[(worker.id)]
# (self.model.night_shift_count_t1[(worker.id)] +
# self.model.night_shift_count_t2[(worker.id)])
for worker in self.workers)
else:
night_shift_balancing = 0
@@ -816,7 +869,7 @@ class RotaBuilder(object):
return night_shift_balancing
#return shift_balancing + preferences + blocks_balancing
#return shift_balancing + preferences + nights_site_balancing + blocks_balancing
return shift_balancing + night_shift_balancing + preferences + nights_site_balancing + blocks_balancing
#return shift_balancing + night_shift_balancing + preferences + nights_site_balancing + blocks_balancing
# add objective function to the model. rule (pass function) or expr (pass expression directly)
self.model.obj = Objective(rule=obj_rule, sense=minimize)
@@ -1267,9 +1320,16 @@ class RotaResults(object):
def get_night_details(self):
for worker in self.rota.workers:
print(
worker.name,
self.rota.model.night_shift_count[(worker.id)].value,
self.rota.model.night_shift_count_t1[(worker.id)].value,
self.rota.model.night_shift_count_t2[(worker.id)].value,
worker.shift_target_number["night_weekday"] +
worker.shift_target_number["night_weekend"])
"{:20}".format(worker.name),
"worked: {},".format(
self.rota.model.night_shift_count[(worker.id)].value),
"target: {},".format(
worker.shift_target_number["night_weekday"] +
worker.shift_target_number["night_weekend"]),
"target_diff: {},".format(
self.rota.model.night_shift_count_t1[(worker.id)].value +
self.rota.model.night_shift_count_t2[(worker.id)].value +
1),
"balance: {},".format(
self.rota.model.night_shift_count_w[worker.id].value),
)