.
This commit is contained in:
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user