This commit is contained in:
Ross
2022-01-30 21:23:58 +00:00
parent dcb79a30c2
commit cbe99ea3d8
4 changed files with 217 additions and 74 deletions
+52 -47
View File
@@ -43,7 +43,23 @@ SHIFT_BOUNDS = {
class SingleShift(object):
"""Class to hold all details for a shift"""
"""Class to hold all details for a shift
Valid constraints
balance_across_groups (requires block assignment)
postclear(2) / preclear(2)
limit_grade_number:
options: {grade: max_number, grade2: max_number2}
minimum_grade_number:
options: (grade, min_number)
"""
def __init__(
self,
@@ -171,7 +187,6 @@ class RotaBuilder(object):
self.max_weekend_frequency = max_weekend_frequency
self.constraint_options = {
"limit_to_1_st2_on_nights": True,
"ensure_1_st4_plus_on_nights": True,
"ensure_derriford_reg_for_nights": True,
"balance_nights": True,
@@ -722,27 +737,6 @@ class RotaBuilder(object):
# self.model.max_hours_constraint = Constraint(
# [worker.id for worker in self.workers], rule=maxHoursRule)
# Limit to 1 ST2 (or below) on a night shift
def nightShiftMaxSTRule(model, week, shift):
"""Limits to 1 ST2 (or below) per night"""
single_workers = [w for w in self.workers if w.grade < 3]
if not single_workers:
return Constraint.Skip
return (
sum(
model.shift_week_worker_assigned[shift, week, w.id]
for w in single_workers
)
<= 1
)
if self.constraint_options["limit_to_1_st2_on_nights"]:
self.model.night_shifts_max_st_constraint = Constraint(
[week for week in self.weeks],
[shift.name for shift in self.get_shifts_with_constraint("night")],
rule=nightShiftMaxSTRule,
)
# Limit grades
def limitGradesRule(model, week, shift, grade, limit):
workers = [w for w in self.workers if w.grade == grade]
@@ -771,25 +765,34 @@ class RotaBuilder(object):
#name=f"limit_grades_constraint_{shift.name}_{grade}"
))
def nightShiftMinST4Rule(model, week, shift):
single_workers = [w for w in self.workers if w.grade >= 4]
if not single_workers:
return Constraint.Skip
def minimumGradesRule(model, week, shift, grade, limit):
workers = [w for w in self.workers if w.grade >= grade]
if len(workers) < limit:
#return Constraint.Skip
raise ValueError("minimum_grade_number: not enough valid workers")
return (
sum(
model.shift_week_worker_assigned[shift, week, w.id]
for w in single_workers
model.shift_week_worker_assigned[shift.name, week, w.id]
for w in workers
)
>= 1
>= limit
)
if self.constraint_options["ensure_1_st4_plus_on_nights"]:
self.model.night_shifts_min_st4_constraint = Constraint(
for shift in self.get_shifts_with_constraint("minimum_grade_number"):
if not shift.constraint_options["minimum_grade_number"]:
raise ValueError("Constraint option must be defined for 'minimum_grade_number'")
grade, min_required = shift.constraint_options["minimum_grade_number"]
#self.model.limit_grades_constraint = Constraint(
setattr(self.model, f"minimum_grade_number_{shift.name}", Constraint(
[week for week in self.weeks],
[shift.name for shift in self.get_shifts_with_constraint("night")],
rule=nightShiftMinST4Rule,
)
#[shift for shift in self.get_shifts_with_constraint("limit_grade_number")],
[shift],
[grade],
[min_required],
rule=minimumGradesRule,
#name=f"limit_grades_constraint_{shift.name}_{grade}"
))
# def nightShiftDerrifordRule(model, week, shift):
# derriford_workers = [w for w in self.workers if w.night_at_derriford >= 1]
@@ -810,9 +813,9 @@ class RotaBuilder(object):
# rule=nightShiftDerrifordRule,
# )
def presenceAtSiteOvernight(model, week, shift, required_site):
def presenceAtHomeSite(model, week, shift, required_site, required_number):
required_site_workers = [
w for w in self.workers if required_site == w.night_site
w for w in self.workers if required_site == w.home_site
]
return (
@@ -820,18 +823,20 @@ class RotaBuilder(object):
model.shift_week_worker_assigned[shift, week, w.id]
for w in required_site_workers
)
>= 1
>= required_number
)
if self.constraint_options["require_presence_at_site_overnight"]:
for site in self.constraint_options["require_presence_at_site_overnight"]:
self.model.require_presence_at_site_overnight_rule = Constraint(
[week for week in self.weeks],
[shift.name for shift in self.get_shifts_with_constraint("night")],
[site],
rule=presenceAtSiteOvernight,
)
for shift in self.get_shifts_with_constraint("require_home_site_presence"):
site, required_number = shift.constraint_options["require_home_site_presence"]
#self.model.require_presence_at_site_overnight_rule = Constraint(
setattr(self.model, f"require_home_site_presence_{shift.name}", Constraint(
[week for week in self.weeks],
[shift.name],
[site],
[required_number],
rule=presenceAtHomeSite,
))
# # 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