remove some old code

This commit is contained in:
Ross
2022-02-21 16:56:41 +00:00
parent b1ce9cc447
commit 7807e3b1e8
+127 -163
View File
@@ -266,7 +266,6 @@ class RotaBuilder(object):
self.solve_model(options=options) self.solve_model(options=options)
def build_model(self): def build_model(self):
# Initialize model # Initialize model
self.model = ConcreteModel() self.model = ConcreteModel()
@@ -283,15 +282,6 @@ class RotaBuilder(object):
initialize=0, initialize=0,
) )
# The nights self.model is used to ensure nights are assigned as a block (and limit the number of workers required)
# self.model.nights = Var(
# ((worker.id, week, block) for worker in self.workers
# for week in self.weeks for block in self.night_blocks),
# within=Binary,
# initialize=0,
# )
# The nights self.model is used to ensure nights are assigned as a block (and limit the number of workers required)
self.model.shift_week_worker_assigned = Var( self.model.shift_week_worker_assigned = Var(
( (
(shift, week, worker.id) (shift, week, worker.id)
@@ -347,13 +337,6 @@ class RotaBuilder(object):
within=NonNegativeIntegers, within=NonNegativeIntegers,
initialize=0, initialize=0,
) )
# self.model.bank_holiday_count = Var(
# ((worker.id, week, day) for worker in self.workers
# for week, day in self.get_week_day_combinations() if self.week_day_date_map[(week, day)] in bank_holiday_map
# ),
# within=Binary,
# initialize=0,
# )
# Used to limit number of workers on night shift per site # Used to limit number of workers on night shift per site
# if we force a binary it will in effect hard constrain to < 2 # if we force a binary it will in effect hard constrain to < 2
@@ -466,7 +449,10 @@ class RotaBuilder(object):
initialize=0, initialize=0,
) )
if self.constraint_options["balance_shifts"] or self.constraint_options["balance_shifts_quadratic"]: if (
self.constraint_options["balance_shifts"]
or self.constraint_options["balance_shifts_quadratic"]
):
self.model.shift_count_t1 = Var( self.model.shift_count_t1 = Var(
( (
(worker.id, shift.name) (worker.id, shift.name)
@@ -558,7 +544,6 @@ class RotaBuilder(object):
# initialize=0, # initialize=0,
# ) # )
self.model.works_weekend = Var( self.model.works_weekend = Var(
((worker.id, week) for worker in self.workers for week in self.weeks), ((worker.id, week) for worker in self.workers for week in self.weeks),
domain=Binary, domain=Binary,
@@ -696,16 +681,6 @@ class RotaBuilder(object):
# self.model.works[worker.id, week, day, shift] # self.model.works[worker.id, week, day, shift]
# for worker in self.workers if worker.site not in site_required)) # for worker in self.workers if worker.site not in site_required))
# THIS SHOULD NO LONGER BE REQUIRED
# Ensure no workers are assigned to shifts that are not required
#for week, day, shift in self.get_not_required_shifts():
# self.model.constraints.add(
# 0
# == sum(
# self.model.works[worker.id, week, day, shift.name]
# for worker in self.workers
# )
# )
# Constraint: total hours worked hours worked # Constraint: total hours worked hours worked
# for worker in self.workers: # for worker in self.workers:
@@ -757,10 +732,15 @@ class RotaBuilder(object):
for shift in self.get_shifts_with_constraint("limit_grade_number"): for shift in self.get_shifts_with_constraint("limit_grade_number"):
if not shift.constraint_options["limit_grade_number"]: if not shift.constraint_options["limit_grade_number"]:
raise ValueError("Constraint option must be defined for 'limit_grade_number'") raise ValueError(
"Constraint option must be defined for 'limit_grade_number'"
)
for grade in shift.constraint_options["limit_grade_number"]: for grade in shift.constraint_options["limit_grade_number"]:
# self.model.limit_grades_constraint = Constraint( # self.model.limit_grades_constraint = Constraint(
setattr(self.model, f"limit_grades_constraint_{shift.name}_{grade}", Constraint( setattr(
self.model,
f"limit_grades_constraint_{shift.name}_{grade}",
Constraint(
[week for week in self.weeks], [week for week in self.weeks],
# [shift for shift in self.get_shifts_with_constraint("limit_grade_number")], # [shift for shift in self.get_shifts_with_constraint("limit_grade_number")],
[shift], [shift],
@@ -768,7 +748,8 @@ class RotaBuilder(object):
[shift.constraint_options["limit_grade_number"][grade]], [shift.constraint_options["limit_grade_number"][grade]],
rule=limitGradesRule, rule=limitGradesRule,
# name=f"limit_grades_constraint_{shift.name}_{grade}" # name=f"limit_grades_constraint_{shift.name}_{grade}"
)) ),
)
def minimumGradesRule(model, week, shift, grade, limit): def minimumGradesRule(model, week, shift, grade, limit):
workers = [w for w in self.workers if w.grade >= grade] workers = [w for w in self.workers if w.grade >= grade]
@@ -785,10 +766,15 @@ class RotaBuilder(object):
for shift in self.get_shifts_with_constraint("minimum_grade_number"): for shift in self.get_shifts_with_constraint("minimum_grade_number"):
if not shift.constraint_options["minimum_grade_number"]: if not shift.constraint_options["minimum_grade_number"]:
raise ValueError("Constraint option must be defined for 'minimum_grade_number'") raise ValueError(
"Constraint option must be defined for 'minimum_grade_number'"
)
grade, min_required = shift.constraint_options["minimum_grade_number"] grade, min_required = shift.constraint_options["minimum_grade_number"]
# self.model.limit_grades_constraint = Constraint( # self.model.limit_grades_constraint = Constraint(
setattr(self.model, f"minimum_grade_number_{shift.name}", Constraint( setattr(
self.model,
f"minimum_grade_number_{shift.name}",
Constraint(
[week for week in self.weeks], [week for week in self.weeks],
# [shift for shift in self.get_shifts_with_constraint("limit_grade_number")], # [shift for shift in self.get_shifts_with_constraint("limit_grade_number")],
[shift], [shift],
@@ -796,8 +782,8 @@ class RotaBuilder(object):
[min_required], [min_required],
rule=minimumGradesRule, rule=minimumGradesRule,
# name=f"limit_grades_constraint_{shift.name}_{grade}" # name=f"limit_grades_constraint_{shift.name}_{grade}"
)) ),
)
# def nightShiftDerrifordRule(model, week, shift): # def nightShiftDerrifordRule(model, week, shift):
# derriford_workers = [w for w in self.workers if w.night_at_derriford >= 1] # derriford_workers = [w for w in self.workers if w.night_at_derriford >= 1]
@@ -831,17 +817,22 @@ class RotaBuilder(object):
>= required_number >= required_number
) )
for shift in self.get_shifts_with_constraint("require_home_site_presence"): for shift in self.get_shifts_with_constraint("require_home_site_presence"):
site, required_number = shift.constraint_options["require_home_site_presence"] site, required_number = shift.constraint_options[
"require_home_site_presence"
]
# self.model.require_presence_at_site_overnight_rule = Constraint( # self.model.require_presence_at_site_overnight_rule = Constraint(
setattr(self.model, f"require_home_site_presence_{shift.name}", Constraint( setattr(
self.model,
f"require_home_site_presence_{shift.name}",
Constraint(
[week for week in self.weeks], [week for week in self.weeks],
[shift.name], [shift.name],
[site], [site],
[required_number], [required_number],
rule=presenceAtHomeSite, rule=presenceAtHomeSite,
)) ),
)
# # Count the number of workers from each site on each night shift # # Count the number of workers from each site on each night shift
# # As 1 or 0 is optimum we can simply subtract 1 from the number # # As 1 or 0 is optimum we can simply subtract 1 from the number
@@ -1035,9 +1026,7 @@ class RotaBuilder(object):
# if self.constraint_options["balance_weekends"]: # if self.constraint_options["balance_weekends"]:
self.model.constraints.add( self.model.constraints.add(
self.model.worker_weekend_count[worker.id] self.model.worker_weekend_count[worker.id]
== sum( == sum(self.model.works_weekend[worker.id, week] for week in self.weeks)
self.model.works_weekend[worker.id, week] for week in self.weeks
)
) )
if self.constraint_options["max_weekends"] > -1: if self.constraint_options["max_weekends"] > -1:
@@ -1102,7 +1091,9 @@ class RotaBuilder(object):
min_shifts, min_shifts,
sum( sum(
self.model.works[worker.id, week, day, shift.name] self.model.works[worker.id, week, day, shift.name]
for week, day in self.get_week_day_combinations_for_shift(shift) for week, day in self.get_week_day_combinations_for_shift(
shift
)
# for week, day in self.get_week_day_combinations() # for week, day in self.get_week_day_combinations()
# if shift.name in self.get_shift_names_by_week_day(week, day) # if shift.name in self.get_shift_names_by_week_day(week, day)
), ),
@@ -1115,7 +1106,9 @@ class RotaBuilder(object):
0 0
== sum( == sum(
self.model.works[worker.id, week, day, shift.name] self.model.works[worker.id, week, day, shift.name]
for week, day in self.get_week_day_combinations_for_shift(shift) for week, day in self.get_week_day_combinations_for_shift(
shift
)
# for week, day in self.get_week_day_combinations() # for week, day in self.get_week_day_combinations()
) )
) )
@@ -1143,7 +1136,6 @@ class RotaBuilder(object):
== self.model.shift_count_diff[worker.id, shift.name] == self.model.shift_count_diff[worker.id, shift.name]
) )
if self.constraint_options["balance_shifts_quadratic"]: if self.constraint_options["balance_shifts_quadratic"]:
# This may need to be updated # This may need to be updated
xU = 25 xU = 25
@@ -1182,7 +1174,6 @@ class RotaBuilder(object):
- xU * xU - xU * xU
) )
# Define worker_shift_count_t1 and worker_shift_count_t2 constraints for the object # Define worker_shift_count_t1 and worker_shift_count_t2 constraints for the object
# Thus bypassing the need for a quadratic solver # Thus bypassing the need for a quadratic solver
# t1-t2 is the target # t1-t2 is the target
@@ -1241,7 +1232,9 @@ class RotaBuilder(object):
self.model.night_shift_count[worker.id] self.model.night_shift_count[worker.id]
== sum( == sum(
self.model.works[worker.id, week, day, shift.name] self.model.works[worker.id, week, day, shift.name]
for week, day, shift in self.get_week_day_shift_combinations_for_constraint("night") for week, day, shift in self.get_week_day_shift_combinations_for_constraint(
"night"
)
# for week, day in self.get_week_day_combinations_for_shift(shift) # for week, day in self.get_week_day_combinations_for_shift(shift)
# for shift in self.get_shifts_with_constraint("night") # for shift in self.get_shifts_with_constraint("night")
) )
@@ -1388,9 +1381,7 @@ class RotaBuilder(object):
) )
# if self.constraint_options["balance_weekends"]: # if self.constraint_options["balance_weekends"]:
for week_blocks in self.get_week_block_iterator( for week_blocks in self.get_week_block_iterator(self.max_weekend_frequency):
self.max_weekend_frequency
):
# Prevent weekend shifts more than once every n weeks # Prevent weekend shifts more than once every n weeks
self.model.constraints.add( self.model.constraints.add(
1 1
@@ -1408,7 +1399,9 @@ class RotaBuilder(object):
self.model.works[worker.id, week, day, shiftname] self.model.works[worker.id, week, day, shiftname]
# for shiftname in self.get_shift_names_by_week_day(week, day) # for shiftname in self.get_shift_names_by_week_day(week, day)
# for day in self.days # for day in self.days
for w, day, shiftname in self.get_all_shiftname_combinations(week=week) for w, day, shiftname in self.get_all_shiftname_combinations(
week=week
)
) )
) )
@@ -1431,16 +1424,22 @@ class RotaBuilder(object):
self.model.constraints.add( self.model.constraints.add(
full_weekend_count full_weekend_count
>= sum( >= sum(
self.model.works[worker.id, week, "Sat", shift.name] self.model.works[worker.id, week, "Sat", shift]
for shift in self.get_shifts() for shift in self.get_shift_names_by_week_day(
week, "Sat"
)
) )
+ sum( + sum(
self.model.works[worker.id, week, "Sun", shift.name] self.model.works[worker.id, week, "Sun", shift]
for shift in self.get_shifts() for shift in self.get_shift_names_by_week_day(
week, "Sun"
)
) )
+ sum( + sum(
self.model.works[worker.id, week + 1, "Mon", shift.name] self.model.works[worker.id, week + 1, "Mon", shift]
for shift in self.get_shifts() for shift in self.get_shift_names_by_week_day(
week+1, "Mon"
)
) )
) )
if ( if (
@@ -1454,20 +1453,31 @@ class RotaBuilder(object):
self.model.constraints.add( self.model.constraints.add(
full_weekend_count full_weekend_count
>= sum( >= sum(
self.model.works[worker.id, week, "Sat", shift.name] self.model.works[worker.id, week, "Sat", shift]
for shift in self.get_shifts() for shift in self.get_shift_names_by_week_day(
week, "Sat"
)
) )
+ sum( + sum(
self.model.works[worker.id, week, "Sun", shift.name] self.model.works[worker.id, week, "Sun", shift]
for shift in self.get_shifts() for shift in self.get_shift_names_by_week_day(
week, "Sun"
)
# for shift in self.get_shifts()
) )
+ sum( + sum(
self.model.works[worker.id, week + 1, "Mon", shift.name] self.model.works[worker.id, week + 1, "Mon", shift]
for shift in self.get_shifts() for shift in self.get_shift_names_by_week_day(
week + 1, "Mon"
)
# for shift in self.get_shifts()
) )
+ sum( + sum(
self.model.works[worker.id, week + 1, "Tue", shift.name] self.model.works[worker.id, week + 1, "Tue", shift]
for shift in self.get_shifts() for shift in self.get_shift_names_by_week_day(
week + 1, "Tue"
)
# for shift in self.get_shifts()
) )
) )
if ( if (
@@ -1533,7 +1543,10 @@ class RotaBuilder(object):
self.model.works_weekend[worker.id, week] self.model.works_weekend[worker.id, week]
>= sum( >= sum(
self.model.works[worker.id, week, day, shiftname] self.model.works[worker.id, week, day, shiftname]
for w, day, shiftname in self.get_all_shiftname_combinations(week=week) if day in self.days[5:] for w, day, shiftname in self.get_all_shiftname_combinations(
week=week
)
if day in self.days[5:]
) )
/ 2 / 2
) )
@@ -1541,7 +1554,10 @@ class RotaBuilder(object):
self.model.works_weekend[worker.id, week] self.model.works_weekend[worker.id, week]
<= sum( <= sum(
self.model.works[worker.id, week, day, shiftname] self.model.works[worker.id, week, day, shiftname]
for w, day, shiftname in self.get_all_shiftname_combinations(week=week) if day in self.days[5:] for w, day, shiftname in self.get_all_shiftname_combinations(
week=week
)
if day in self.days[5:]
) )
) )
# self.model.constraints.add( # self.model.constraints.add(
@@ -1663,10 +1679,14 @@ class RotaBuilder(object):
if day in constraint_shift.shift_days: if day in constraint_shift.shift_days:
self.model.constraints.add( self.model.constraints.add(
1 1
>= self.model.works[worker.id, week, day, constraint_shift.name] >= self.model.works[
worker.id, week, day, constraint_shift.name
]
+ sum( + sum(
p1 * self.model.works[w.id, pweek, pday, shiftname] p1 * self.model.works[w.id, pweek, pday, shiftname]
for shiftname in self.get_shift_names_by_week_day(pweek, pday) for shiftname in self.get_shift_names_by_week_day(
pweek, pday
)
if shiftname != constraint_shift.name if shiftname != constraint_shift.name
for w in workers for w in workers
) )
@@ -1676,10 +1696,14 @@ class RotaBuilder(object):
if day in constraint_shift.shift_days: if day in constraint_shift.shift_days:
self.model.constraints.add( self.model.constraints.add(
1 1
>= self.model.works[worker.id, week, day, constraint_shift.name] >= self.model.works[
worker.id, week, day, constraint_shift.name
]
+ sum( + sum(
p2 * self.model.works[w.id, p2week, p2day, shiftname] p2 * self.model.works[w.id, p2week, p2day, shiftname]
for shiftname in self.get_shift_names_by_week_day(p2week, p2day) for shiftname in self.get_shift_names_by_week_day(
p2week, p2day
)
if shiftname != constraint_shift.name if shiftname != constraint_shift.name
for w in workers for w in workers
) )
@@ -1691,10 +1715,14 @@ class RotaBuilder(object):
if day in constraint_shift.shift_days: if day in constraint_shift.shift_days:
self.model.constraints.add( self.model.constraints.add(
1 1
>= self.model.works[worker.id, week, day, constraint_shift.name] >= self.model.works[
worker.id, week, day, constraint_shift.name
]
+ sum( + sum(
n1 * self.model.works[w.id, nweek, nday, shiftname] n1 * self.model.works[w.id, nweek, nday, shiftname]
for shiftname in self.get_shift_names_by_week_day(nweek, nday) for shiftname in self.get_shift_names_by_week_day(
nweek, nday
)
if shiftname != constraint_shift.name if shiftname != constraint_shift.name
for w in workers for w in workers
) )
@@ -1704,18 +1732,28 @@ class RotaBuilder(object):
if day in constraint_shift.shift_days: if day in constraint_shift.shift_days:
self.model.constraints.add( self.model.constraints.add(
1 1
>= self.model.works[worker.id, week, day, constraint_shift.name] >= self.model.works[
worker.id, week, day, constraint_shift.name
]
+ sum( + sum(
n2 * self.model.works[w.id, n2week, n2day, shiftname] n2 * self.model.works[w.id, n2week, n2day, shiftname]
for shiftname in self.get_shift_names_by_week_day(n2week, n2day) for shiftname in self.get_shift_names_by_week_day(
n2week, n2day
)
if shiftname != constraint_shift.name if shiftname != constraint_shift.name
for w in workers for w in workers
) )
) )
# Night constraint means we won't assign a shift the day before
# an unavailability
for constraint_shift in self.get_shifts_with_constraint("night"): for constraint_shift in self.get_shifts_with_constraint("night"):
#if day in constraint_shift.shift_days: if (
if (worker.id, pweek, pday, constraint_shift.name) in self.model.works: worker.id,
pweek,
pday,
constraint_shift.name,
) in self.model.works:
# Ensure night prior to unavalibity is not assigned # Ensure night prior to unavalibity is not assigned
self.model.constraints.add( self.model.constraints.add(
self.model.available[worker.id, week, day] self.model.available[worker.id, week, day]
@@ -1723,86 +1761,6 @@ class RotaBuilder(object):
worker.id, pweek, pday, constraint_shift.name worker.id, pweek, pday, constraint_shift.name
] ]
) )
# # NOTE: use pre / post clear instead
# # DEPRECATED
# # if working a night ensure preceeding (1) or subsequent (2) shifts can only be nights
# if self.constraint_options["constrain_time_off_after_nights"]:
# for constraint_shift in self.get_shifts_with_constraint("night"):
# if day in constraint_shift.shift_days:
# # Ensure night prior to unavalibity is not assigned
# self.model.constraints.add(
# self.model.available[worker.id, week, day]
# >= self.model.works[
# worker.id, pweek, pday, constraint_shift.name
# ]
# )
#
# # print("Workers", workers)
#
# self.model.constraints.add(
# 1
# >= self.model.works[
# worker.id, week, day, constraint_shift.name
# ]
# + sum(
# n1 * self.model.works[w.id, nweek, nday, shift]
# for shift in self.get_shift_names_by_week_day(
# nweek, nday
# )
# if shift != constraint_shift.name
# for w in workers
# )
# )
#
# self.model.constraints.add(
# 1
# >= self.model.works[
# worker.id, week, day, constraint_shift.name
# ]
# + sum(
# n2 * self.model.works[w.id, n2week, n2day, shift]
# for shift in self.get_shift_names_by_week_day(
# n2week, n2day
# )
# if shift != constraint_shift.name
# for w in workers
# )
# )
# # self.model.constraints.add(
# # 1 >= self.model.works[worker.id, week, day,
# # constraint_shift.name] +
# # sum(n3 * self.model.works[worker.id, n3week, n3day,
# # shift]
# # for shift in self.get_shift_names_by_week_day(week, n3day)
# # if shift != constraint_shift.name))
# self.model.constraints.add(
# 1
# >= self.model.works[
# worker.id, week, day, constraint_shift.name
# ]
# + sum(
# p1 * self.model.works[w.id, pweek, pday, shift]
# for shift in self.get_shift_names_by_week_day(
# pweek, pday
# )
# if shift != constraint_shift.name
# for w in workers
# )
# )
# self.model.constraints.add(
# 1
# >= self.model.works[
# worker.id, week, day, constraint_shift.name
# ]
# + sum(
# p2 * self.model.works[w.id, p2week, p2day, shift]
# for shift in self.get_shift_names_by_week_day(
# p2week, p2day
# )
# if shift != constraint_shift.name
# for w in workers
# )
# )
self.define_objectives() self.define_objectives()
@@ -1932,7 +1890,6 @@ class RotaBuilder(object):
else: else:
nights_site_balancing = 0 nights_site_balancing = 0
if self.get_shifts_with_constraint("balance_across_groups"): if self.get_shifts_with_constraint("balance_across_groups"):
block_site_balancing = sum( block_site_balancing = sum(
( (
@@ -1942,7 +1899,9 @@ class RotaBuilder(object):
* 2000 * 2000
# self.model.night_per_site2[week, block, site] # self.model.night_per_site2[week, block, site]
for week in self.weeks for week in self.weeks
for shift in self.get_shifts_with_constraint("balance_across_groups") for shift in self.get_shifts_with_constraint(
"balance_across_groups"
)
for site in self.sites for site in self.sites
) )
else: else:
@@ -2137,7 +2096,9 @@ class RotaBuilder(object):
# """ # """
# return self.day_shiftclass_product # return self.day_shiftclass_product
def get_all_shiftname_combinations(self, week: int =None, day: int =None) -> List[Tuple[WeekInt, DayStr, ShiftName]]: def get_all_shiftname_combinations(
self, week: int = None, day: int = None
) -> List[Tuple[WeekInt, DayStr, ShiftName]]:
"""Returns a list of all possible week / day / shift combinations """Returns a list of all possible week / day / shift combinations
Returns: Returns:
@@ -2181,7 +2142,11 @@ class RotaBuilder(object):
return self.weeks_days_product return self.weeks_days_product
def get_week_day_combinations_for_shift(self, shift) -> list: def get_week_day_combinations_for_shift(self, shift) -> list:
return [(week, day) for week, day in self.get_week_day_combinations() if shift.name in self.get_shift_names_by_week_day(week, day)] return [
(week, day)
for week, day in self.get_week_day_combinations()
if shift.name in self.get_shift_names_by_week_day(week, day)
]
def get_week_day_shift_combinations_for_constraint(self, constraint) -> list: def get_week_day_shift_combinations_for_constraint(self, constraint) -> list:
constraint_shifts = self.get_shifts_with_constraint(constraint) constraint_shifts = self.get_shifts_with_constraint(constraint)
@@ -2605,7 +2570,6 @@ class RotaBuilder(object):
bank_holiday_count = -1 bank_holiday_count = -1
bank_holiday_count_w = -1 bank_holiday_count_w = -1
# print(worker.name, bank_holiday_count, bank_holiday_count_w) # print(worker.name, bank_holiday_count, bank_holiday_count_w)
timetable.append( timetable.append(
f"<tr class='worker-row'>{worker_td}{''.join(shift_tds)}</tr>" f"<tr class='worker-row'>{worker_td}{''.join(shift_tds)}</tr>"