752 lines
56 KiB
Plaintext
752 lines
56 KiB
Plaintext
{
|
|
"nbformat": 4,
|
|
"nbformat_minor": 2,
|
|
"metadata": {
|
|
"language_info": {
|
|
"name": "python",
|
|
"codemirror_mode": {
|
|
"name": "ipython",
|
|
"version": 3
|
|
},
|
|
"version": "3.7.5-final"
|
|
},
|
|
"orig_nbformat": 2,
|
|
"file_extension": ".py",
|
|
"mimetype": "text/x-python",
|
|
"name": "python",
|
|
"npconvert_exporter": "python",
|
|
"pygments_lexer": "ipython3",
|
|
"version": 3,
|
|
"kernelspec": {
|
|
"name": "python37564bit5ba0d1a6f89f489d9799b0f9b976a56e",
|
|
"display_name": "Python 3.7.5 64-bit"
|
|
}
|
|
},
|
|
"cells": [
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": 1,
|
|
"metadata": {},
|
|
"outputs": [],
|
|
"source": [
|
|
"from pyomo.environ import *\n",
|
|
"from pyomo.opt import SolverFactory\n",
|
|
"\n",
|
|
"import datetime\n",
|
|
"import itertools"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": 2,
|
|
"metadata": {},
|
|
"outputs": [],
|
|
"source": [
|
|
"night_balance_offset = 2\n",
|
|
"twighlight_balance_offset = 1\n",
|
|
"weeks_to_rota = 26"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": 3,
|
|
"metadata": {},
|
|
"outputs": [],
|
|
"source": [
|
|
"# Import trainee data\n",
|
|
"#import csv\n",
|
|
"#with open('trainees.csv', newline='') as f:\n",
|
|
"# lines = csv.reader(f, delimiter=',', quotechar='|')\n",
|
|
"# for row in lines[1:]:\n",
|
|
"# name, site, grade, fte, end_date, nwds = line.split(\",\")"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": 4,
|
|
"metadata": {},
|
|
"outputs": [],
|
|
"source": [
|
|
"# Define days (1 week)\n",
|
|
"days = ['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun']\n",
|
|
"\n",
|
|
"weeks = [i for i in range(1,weeks_to_rota+1)]\n",
|
|
"\n",
|
|
"weeks_days_product = list(itertools.product(weeks, days))\n",
|
|
"\n",
|
|
"sites = (\"truro\", \"exeter\", \"torbay\", \"barnstaple\", \"plymouth\")\n",
|
|
"\n",
|
|
"class shiftsClass:\n",
|
|
" def __init__(self, sites, shift, length, days, balance_by_site=True)\n",
|
|
" self.site = sites\n",
|
|
" self.shift = shift\n",
|
|
" self.length = length\n",
|
|
" self.days = days\n",
|
|
"\n",
|
|
" def GetShift(self):\n",
|
|
" return self.shift\n",
|
|
"\n",
|
|
"shifts = []\n",
|
|
"shifts.append(\n",
|
|
" shiftsClass((\"truro\"), \"truro_twighlight\", 12.5, days[:5]),\n",
|
|
" shiftsClass((\"plymouth\"), \"plymouth_twighlight\", 12.5, days[:5]), \n",
|
|
" shiftsClass((sites), \"night\", 12.5, days, balance_by_site=False), \n",
|
|
")\n",
|
|
"\n",
|
|
"# Enter shifts of each day\n",
|
|
"#shifts = ['morning', 'evening', 'night', 'truro_twighlight'] # 3 shifts of 8 hours\n",
|
|
"#shifts = ['night', 'truro_twighlight', 'plymouth_twighlight'] # 3 shifts of 8 hours\n",
|
|
"\n",
|
|
"# Generate\n",
|
|
"\n",
|
|
"#site_and_shifts_to_balance = ((\"truro\", \"truro_twighlight\"),\n",
|
|
"# (\"plymouth\", \"plymouth_twighlight\"))\n",
|
|
"\n",
|
|
"#shift_len = [12.5, 12.5, 12.5]\n",
|
|
"\n",
|
|
"night_blocks = [\"weekday\", \"weekend\", \"none\"]\n",
|
|
"\n",
|
|
"shift_lengths = dict(zip(shifts, shift_len))\n",
|
|
"\n",
|
|
"days_shifts = {day: shifts for day in days} # dict with day as key and list of its shifts as value\n",
|
|
"\n",
|
|
"start_date = datetime.date(2020,9,7)\n",
|
|
"rota_days_length = len(weeks) * 7\n",
|
|
"rota_end_date = start_date + datetime.timedelta(rota_days_length)\n",
|
|
"\n",
|
|
"unavailable_to_work = set()\n",
|
|
"\n",
|
|
"class workerClass:\n",
|
|
" def __init__(self, id, name, site, grade, fte=100, nwd=\"\", end_date=None, oop=None):\n",
|
|
" self.id = id\n",
|
|
" self.name = name\n",
|
|
" self.site = site\n",
|
|
" self.grade = grade\n",
|
|
" self.fte = fte\n",
|
|
" self.nwd = nwd\n",
|
|
" self.proportion_rota_to_work = 1\n",
|
|
"\n",
|
|
" days_to_work = rota_days_length\n",
|
|
"\n",
|
|
" if end_date is None:\n",
|
|
" self.end_date = None\n",
|
|
" else:\n",
|
|
" y, m, d = [int(i) for i in end_date.split(\"/\")]\n",
|
|
" self.end_date = datetime.date(y, m, d)\n",
|
|
"\n",
|
|
" if self.end_date > rota_end_date:\n",
|
|
" self.end_date = rota_end_date\n",
|
|
" else:\n",
|
|
" days_to_work = (self.end_date - start_date).days\n",
|
|
"\n",
|
|
" # add unavalabilities\n",
|
|
" for weeks_days in weeks_days_product[days_to_work:]:\n",
|
|
" week, day = weeks_days\n",
|
|
" unavailable_to_work.add((self.id, week, day))\n",
|
|
" \n",
|
|
" if oop is not None:\n",
|
|
" start_oop, end_oop = oop\n",
|
|
" start_oop_date = datetime.datetime.strptime(start_oop, '%Y/%m/%d').date()\n",
|
|
" end_oop_date = datetime.datetime.strptime(end_oop, '%Y/%m/%d').date()\n",
|
|
"\n",
|
|
" if end_oop_date > rota_end_date:\n",
|
|
" end_oop_date = rota_end_date\n",
|
|
" \n",
|
|
" oop_length = (end_oop_date - start_oop_date).days\n",
|
|
" days_to_work = days_to_work - oop_length\n",
|
|
"\n",
|
|
" days_until_oop = (start_oop_date - start_date).days\n",
|
|
"\n",
|
|
" for weeks_days in weeks_days_product[days_until_oop:days_until_oop+oop_length]:\n",
|
|
" week, day = weeks_days\n",
|
|
" unavailable_to_work.add((self.id, week, day))\n",
|
|
"\n",
|
|
" \n",
|
|
" self.proportion_rota_to_work = days_to_work / rota_days_length\n",
|
|
"\n",
|
|
" # We had to adjust the full time equivalent for people who CCT / leave the rota early\n",
|
|
" self.fte_adj = self.fte * self.proportion_rota_to_work\n",
|
|
" \n",
|
|
" def GetDetails(self):\n",
|
|
" return \"{} {} {}\".format(self.id, self.site[0], self.grade)\n",
|
|
"\n",
|
|
"# Enter workers ids (name, number, ...)\n",
|
|
"workers = [workerClass(i, \"Test Person {}\".format(i), \"truro\", 4) for i in range(1, 20)] \n",
|
|
"workers.extend([workerClass(i, \"Test Person {}\".format(i), \"plymouth\", 4) for i in range(21, 58)])\n",
|
|
"#workers.extend([workerClass(i, \"Test Person {}\".format(i), 4, 200, \"\") for i in range(48, 49)])\n",
|
|
"\n",
|
|
"\n",
|
|
"#unavailable_to_work.update([(\"W1\", 1, \"Mon\"),(\"W1\", 1, \"Fri\"),(\"W1\", 1, \"Thu\"),(\"W3\", 1, \"Mon\"),(\"W2\", 1, \"Mon\"),(\"W2\", 1, \"Tue\"),(\"W2\", 1, \"Wed\"),(\"W6\", 1, \"Thu\"),(\"W5\", 1, \"Fri\"),(\"W9\", 1, \"Fri\"),(\"W14\", 1, \"Fri\"),(\"W21\", 1, \"Fri\")])\n",
|
|
"\n",
|
|
"full_time_equivalent = sum([w.fte_adj for w in workers])\n",
|
|
"full_time_equivalent_sites = {}\n",
|
|
"\n",
|
|
"for site in [\"truro\", \"plymouth\"]:\n",
|
|
" full_time_equivalent_sites[site] = sum([w.fte_adj for w in workers if w.site == site])\n",
|
|
"\n",
|
|
"\n",
|
|
"#for i in range(11,30):"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": 5,
|
|
"metadata": {},
|
|
"outputs": [
|
|
{
|
|
"output_type": "execute_result",
|
|
"data": {
|
|
"text/plain": "{'truro': 1900.0, 'plymouth': 3700.0}"
|
|
},
|
|
"metadata": {},
|
|
"execution_count": 5
|
|
}
|
|
],
|
|
"source": [
|
|
"weeks_days_product = list(itertools.product(weeks, days))\n",
|
|
"full_time_equivalent_sites"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": 6,
|
|
"metadata": {
|
|
"tags": [
|
|
"outputPrepend",
|
|
"outputPrepend",
|
|
"outputPrepend",
|
|
"outputPrepend",
|
|
"outputPrepend",
|
|
"outputPrepend",
|
|
"outputPrepend",
|
|
"outputPrepend",
|
|
"outputPrepend"
|
|
]
|
|
},
|
|
"outputs": [],
|
|
"source": [
|
|
"# Initialize model\n",
|
|
"model = ConcreteModel()\n",
|
|
"\n",
|
|
"# binary variables representing if a worker is scheduled somewhere\n",
|
|
"model.works = Var(((worker.id, week, day, shift) for worker in workers for week in weeks for day in days for shift.GetShift() in days_shifts[day]),\n",
|
|
" within=Binary, initialize=0)\n",
|
|
"\n",
|
|
"model.nights = Var(((worker.id, week, block) for worker in workers for week in weeks for block in night_blocks),\n",
|
|
" within=Binary, initialize=0)\n",
|
|
"\n",
|
|
"#model.unavailable = Var(((worker, week, day) for worker in workers for week in weeks for day in days),\n",
|
|
"# within=Binary, initialize=0)\n",
|
|
"def availability_init(model, wid, week, day):\n",
|
|
" if (wid, week, day) in unavailable_to_work:\n",
|
|
" print((wid, week, day))\n",
|
|
" return 0\n",
|
|
" return 1\n",
|
|
"model.available = Param(((worker.id, week, day) for worker in workers for week in weeks for day in days), initialize=availability_init) \n",
|
|
"\n",
|
|
"# binary variables representing if a worker is necessary\n",
|
|
"model.needed = Var([worker.id for worker in workers], within=Binary, initialize=0)\n",
|
|
"\n",
|
|
"# binary variables representing if a worker worked on sunday but not on saturday (avoid if possible)\n",
|
|
"model.no_pref = Var([worker.id for worker in workers], within=Binary, initialize=0)"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": 7,
|
|
"metadata": {},
|
|
"outputs": [],
|
|
"source": [
|
|
"# Define an objective function with model as input, to pass later\n",
|
|
"def obj_rule(m):\n",
|
|
" c = len(workers)\n",
|
|
" return sum(m.no_pref[worker.id] for worker in workers)\n",
|
|
" #return sum(m.no_pref[worker] for worker in workers) + sum(c * m.needed[worker] for worker in workers)\n",
|
|
"# we multiply the second term by a constant to make sure that it is the primary objective\n",
|
|
"# since sum(m.no_prefer) is at most len(workers), len(workers) + 1 is a valid constant.\n",
|
|
"\n",
|
|
"\n",
|
|
"# add objective function to the model. rule (pass function) or expr (pass expression directly)\n",
|
|
"model.obj = Objective(rule=obj_rule, sense=minimize)"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": 8,
|
|
"metadata": {},
|
|
"outputs": [
|
|
{
|
|
"output_type": "execute_result",
|
|
"data": {
|
|
"text/plain": "[(1, 100.0, ('truro', 'truro_twighlight')),\n (2, 100.0, ('truro', 'truro_twighlight')),\n (3, 100.0, ('truro', 'truro_twighlight')),\n (4, 100.0, ('truro', 'truro_twighlight')),\n (5, 100.0, ('truro', 'truro_twighlight')),\n (6, 100.0, ('truro', 'truro_twighlight')),\n (7, 100.0, ('truro', 'truro_twighlight')),\n (8, 100.0, ('truro', 'truro_twighlight')),\n (9, 100.0, ('truro', 'truro_twighlight')),\n (10, 100.0, ('truro', 'truro_twighlight')),\n (11, 100.0, ('truro', 'truro_twighlight')),\n (12, 100.0, ('truro', 'truro_twighlight')),\n (13, 100.0, ('truro', 'truro_twighlight')),\n (14, 100.0, ('truro', 'truro_twighlight')),\n (15, 100.0, ('truro', 'truro_twighlight')),\n (16, 100.0, ('truro', 'truro_twighlight')),\n (17, 100.0, ('truro', 'truro_twighlight')),\n (18, 100.0, ('truro', 'truro_twighlight')),\n (19, 100.0, ('truro', 'truro_twighlight')),\n (21, 100.0, ('plymouth', 'plymouth_twighlight')),\n (22, 100.0, ('plymouth', 'plymouth_twighlight')),\n (23, 100.0, ('plymouth', 'plymouth_twighlight')),\n (24, 100.0, ('plymouth', 'plymouth_twighlight')),\n (25, 100.0, ('plymouth', 'plymouth_twighlight')),\n (26, 100.0, ('plymouth', 'plymouth_twighlight')),\n (27, 100.0, ('plymouth', 'plymouth_twighlight')),\n (28, 100.0, ('plymouth', 'plymouth_twighlight')),\n (29, 100.0, ('plymouth', 'plymouth_twighlight')),\n (30, 100.0, ('plymouth', 'plymouth_twighlight')),\n (31, 100.0, ('plymouth', 'plymouth_twighlight')),\n (32, 100.0, ('plymouth', 'plymouth_twighlight')),\n (33, 100.0, ('plymouth', 'plymouth_twighlight')),\n (34, 100.0, ('plymouth', 'plymouth_twighlight')),\n (35, 100.0, ('plymouth', 'plymouth_twighlight')),\n (36, 100.0, ('plymouth', 'plymouth_twighlight')),\n (37, 100.0, ('plymouth', 'plymouth_twighlight')),\n (38, 100.0, ('plymouth', 'plymouth_twighlight')),\n (39, 100.0, ('plymouth', 'plymouth_twighlight')),\n (40, 100.0, ('plymouth', 'plymouth_twighlight')),\n (41, 100.0, ('plymouth', 'plymouth_twighlight')),\n (42, 100.0, ('plymouth', 'plymouth_twighlight')),\n (43, 100.0, ('plymouth', 'plymouth_twighlight')),\n (44, 100.0, ('plymouth', 'plymouth_twighlight')),\n (45, 100.0, ('plymouth', 'plymouth_twighlight')),\n (46, 100.0, ('plymouth', 'plymouth_twighlight')),\n (47, 100.0, ('plymouth', 'plymouth_twighlight')),\n (48, 100.0, ('plymouth', 'plymouth_twighlight')),\n (49, 100.0, ('plymouth', 'plymouth_twighlight')),\n (50, 100.0, ('plymouth', 'plymouth_twighlight')),\n (51, 100.0, ('plymouth', 'plymouth_twighlight')),\n (52, 100.0, ('plymouth', 'plymouth_twighlight')),\n (53, 100.0, ('plymouth', 'plymouth_twighlight')),\n (54, 100.0, ('plymouth', 'plymouth_twighlight')),\n (55, 100.0, ('plymouth', 'plymouth_twighlight')),\n (56, 100.0, ('plymouth', 'plymouth_twighlight')),\n (57, 100.0, ('plymouth', 'plymouth_twighlight'))]"
|
|
},
|
|
"metadata": {},
|
|
"execution_count": 8
|
|
}
|
|
],
|
|
"source": [
|
|
"#[(worker.id, worker.fte_adj, ss) for ss in site_and_shifts for worker in workers if worker.site == ss[0]]"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": 9,
|
|
"metadata": {},
|
|
"outputs": [],
|
|
"source": [
|
|
"model.constraints = ConstraintList() # Create a set of constraints\n",
|
|
"\n",
|
|
"# Constraint: all shifts are assigned\n",
|
|
"for week in weeks:\n",
|
|
" for day in days:\n",
|
|
" for shiftClass in days_shifts[day]:\n",
|
|
" shift = shiftClass.GetShift()\n",
|
|
" # 3 people per night\n",
|
|
" if shift in ['night']:\n",
|
|
" model.constraints.add( # to add a constraint to model.constraints set\n",
|
|
" 3 == sum(model.works[worker.id, week, day, shift] for worker in workers)\n",
|
|
" )\n",
|
|
" elif day in days[:5] and shift in ['truro_twighlight']: \n",
|
|
" model.constraints.add( # to add a constraint to model.constraints set\n",
|
|
" 1 == sum(model.works[worker.id, week, day, shift] for worker in workers if worker.site == \"truro\")\n",
|
|
" )\n",
|
|
" elif day in days[:5] and shift in ['plymouth_twighlight']: \n",
|
|
" model.constraints.add( # to add a constraint to model.constraints set\n",
|
|
" 1 == sum(model.works[worker.id, week, day, shift] for worker in workers if worker.site == \"plymouth\")\n",
|
|
" ) \n",
|
|
" # make sure twighlights are not assigned on a weekend\n",
|
|
" elif day in days[5:] and shift in ['truro_twighlight', 'plymouth_twighlight']:\n",
|
|
" model.constraints.add( # to add a constraint to model.constraints set\n",
|
|
" 0 == sum(model.works[worker.id, week, day, shift] for worker in workers)\n",
|
|
" )\n",
|
|
" \n",
|
|
" #elif day in days[:-1] and shift in ['truro_twighlight', 'plymouth_twighlight']:\n",
|
|
" # # weekdays' and Saturdays' day shifts have exactly two workers\n",
|
|
" # model.constraints.add( # to add a constraint to model.constraints set\n",
|
|
" # 1 == sum(model.works[worker.id, week, day, shift] for worker in workers)\n",
|
|
" # )\n",
|
|
" #else:\n",
|
|
" # # Sunday shifts have exactly one worker\n",
|
|
" # model.constraints.add(\n",
|
|
" # 1 == sum(model.works[worker.id, week, day, shift] for worker in workers)\n",
|
|
" # )\n",
|
|
"\n",
|
|
"# Constraint: total hours worked hours worked\n",
|
|
"#for worker in workers:\n",
|
|
"# model.constraints.add(\n",
|
|
"# 1200 >= sum(shift_lengths[shift] * model.works[worker, week, day, shift] for week in weeks for day in days for shift in days_shifts[day])\n",
|
|
"# )\n",
|
|
"\n",
|
|
"#for week in weeks:\n",
|
|
"# for worker in workers:\n",
|
|
"# model.constraints.add(\n",
|
|
"# 48 >= sum(shift_lengths[shift] * model.works[worker, week, day, shift] for day in days for shift in days_shifts[day])\n",
|
|
"# )\n",
|
|
"\n",
|
|
"def maxHoursPerWeekRule(model, wid, week):\n",
|
|
" return(72 >= sum(shift_lengths[shift] * model.works[wid, week, day, shift.GetShift()]for day in days for shift in days_shifts[day]))\n",
|
|
"model.max_hours_per_week_constraint = Constraint([worker.id for worker in workers], weeks, rule=maxHoursPerWeekRule)\n",
|
|
"\n",
|
|
"def maxHoursRule(model, wid):\n",
|
|
" return(8000 >= sum(shift_lengths[shift] * model.works[wid, week, day, shift.GetShift()] for week in weeks for day in days for shift in days_shifts[day]))\n",
|
|
"model.max_hours_constraint = Constraint([worker.id for worker in workers], rule=maxHoursRule)\n",
|
|
"\n",
|
|
"# Shifts should not be allocated on nwds (excepting night shifts)\n",
|
|
"def nwdRule(model, wid, nwds):\n",
|
|
" if nwds != \"\":\n",
|
|
" return(1 >= sum(model.works[wid, week, day, shift.GetShift()] for week in weeks for day in nwds.split(\",\") for shift in [\"truro_twighlight\",\"plymouth_twighlight\"]) + 1)\n",
|
|
" return Constraint.Skip\n",
|
|
"model.nwd_constraint = Constraint([(worker.id, worker.nwd) for worker in workers], rule=nwdRule)\n",
|
|
"\n",
|
|
"# set a rule to even night shifts (could also be done in blocks, which may be quicker?)\n",
|
|
"# takes into accound both LTFT, OOP and leaving the training scheme\n",
|
|
"total_night_shifts = len(weeks) * 7 * 3\n",
|
|
"\n",
|
|
"def nightShiftNumberRule(model, wid, fte_adj):\n",
|
|
" max_shifts = total_night_shifts / full_time_equivalent * fte_adj + night_balance_offset\n",
|
|
" min_shifts = total_night_shifts / full_time_equivalent * fte_adj - night_balance_offset\n",
|
|
" \n",
|
|
" return inequality(min_shifts, sum(model.works[wid, week, day, \"night\"] for week in weeks for day in days), max_shifts)\n",
|
|
"model.night_shifts_constraint = Constraint([(worker.id, worker.fte_adj) for worker in workers], rule=nightShiftNumberRule)\n",
|
|
"\n",
|
|
"\n",
|
|
"twighlight_constraints = {}\n",
|
|
"\n",
|
|
"# Set a rule to even twighlight shifts:\n",
|
|
"total_twighlight_shifts = len(weeks) * 5 * 1 # One person per site\n",
|
|
"\n",
|
|
"def truroTwighlightShiftNumberRule(model, wid, fte_adj, site, shift):\n",
|
|
" #site, shift = site_and_shift\n",
|
|
" max_shifts = total_twighlight_shifts / full_time_equivalent_sites[site] * fte_adj + twighlight_balance_offset\n",
|
|
" min_shifts = total_twighlight_shifts / full_time_equivalent_sites[site] * fte_adj - twighlight_balance_offset\n",
|
|
" \n",
|
|
" return inequality(min_shifts, sum(model.works[wid, week, day, shift.GetShift()] for week in weeks for day in days), max_shifts)\n",
|
|
"model.twighlight_shifts_truro_constraint = Constraint([(worker.id, worker.fte_adj, ss[0], ss[1]) for ss in site_and_shifts for worker in workers if worker.site == ss[0]], rule=truroTwighlightShiftNumberRule)\n",
|
|
"\n",
|
|
"#def plymouthTwighlightShiftNumberRule(model, wid, fte_adj):\n",
|
|
"# max_shifts = total_twighlight_shifts / full_time_equivalent_sites[\"plymouth\"] * fte_adj + twighlight_balance_offset\n",
|
|
"# min_shifts = total_twighlight_shifts / full_time_equivalent_sites[\"plymouth\"] * fte_adj - twighlight_balance_offset\n",
|
|
"# \n",
|
|
"# return inequality(min_shifts, sum(model.works[wid, week, day, \"plymouth_twighlight\"] for week in weeks for day in days), max_shifts)\n",
|
|
"#model.twighlight_shifts_plymouth_constraint = Constraint([(worker.id, worker.fte_adj) for worker in workers if worker.site == \"plymouth\"], #rule=plymouthTwighlightShiftNumberRule)\n",
|
|
"\n",
|
|
"\n",
|
|
"# Limit to 1 ST2 (or below) on a night shift\n",
|
|
"def nightShiftMaxSTRule(model, week, block):\n",
|
|
" single_workers = [w for w in workers if w.grade < 3]\n",
|
|
" if not single_workers:\n",
|
|
" return Constraint.Skip\n",
|
|
" return (sum(model.nights[w.id, week, block] for w in single_workers) <= 1)\n",
|
|
"model.night_shifts_max_st_constraint = Constraint([week for week in weeks], [block for block in [\"weekday\", \"weekend\"]], rule=nightShiftMaxSTRule)\n",
|
|
"\n",
|
|
"# Enusre at least 1 ST4+ on a night shift\n",
|
|
"def nightShiftMinST4Rule(model, week, block):\n",
|
|
" single_workers = [w for w in workers if w.grade > 3]\n",
|
|
" if not single_workers:\n",
|
|
" return Constraint.Skip\n",
|
|
" return (sum(model.nights[w.id, week, block] for w in single_workers) >= 1)\n",
|
|
"model.night_shifts_min_st4_constraint = Constraint([week for week in weeks], [block for block in [\"weekday\", \"weekend\"]], rule=nightShiftMinST4Rule)\n",
|
|
"\n",
|
|
"# Constraint: rest between two shifts is of 12 hours (i.e., at least two shifts)\n",
|
|
"for worker in workers:\n",
|
|
" for week in weeks:\n",
|
|
" #model.constraints.add(\n",
|
|
" #0 == sum(model.works[worker, week, day, shift] for day in days for shift in [\"night\"]) * (sum(model.works[worker, week, day, shift] for day in days for shift in [\"night\"]) - 4) * (sum(model.works[worker, week, day, shift] for day in days for shift in [\"night\"]) - 3)\n",
|
|
" # 0 == (sum(model.works[worker, week, day, shift] for day in days for shift in [\"night\"]) - 4) * (sum(model.works[worker, week, day, shift] for day in days for shift in [\"night\"]) - 3)\n",
|
|
" # )\n",
|
|
"\n",
|
|
" # Force nights to be assigned in blocks\n",
|
|
" model.constraints.add(\n",
|
|
" 1 == sum(model.nights[worker.id, week, block] for block in night_blocks)\n",
|
|
" )\n",
|
|
" \n",
|
|
" # if night block is weekday make sure Mon - Thurs is assigned as nights\n",
|
|
" model.constraints.add(\n",
|
|
" model.nights[worker.id, week, \"weekday\"] * 4 == sum(model.works[worker.id, week, day, \"night\"] for day in days[:4])\n",
|
|
" )\n",
|
|
" model.constraints.add(\n",
|
|
" model.nights[worker.id, week, \"weekend\"] * 3 == sum(model.works[worker.id, week, day, \"night\"] for day in days[4:])\n",
|
|
" )\n",
|
|
" \n",
|
|
"\n",
|
|
"\n",
|
|
" for j in range(len(days)):\n",
|
|
" nweek = min(week + (j + 1) // 7, weeks[-1])\n",
|
|
" pweek = week\n",
|
|
" if j == 0:\n",
|
|
" pweek = max(week - 1, 1)\n",
|
|
"\n",
|
|
" # Unable to work (hard constraint not preference)\n",
|
|
" model.constraints.add(\n",
|
|
" model.available[(worker.id, week, days[j])] >= \\\n",
|
|
" sum(model.works[worker.id, week, days[j], shift] for shift in days_shifts[days[j]]) \n",
|
|
" )\n",
|
|
" model.constraints.add(\n",
|
|
" model.available[(worker.id, week, days[j])] >= \\\n",
|
|
" model.works[worker.id, pweek, days[(j - 1) % 7], \"night\"]\n",
|
|
" )\n",
|
|
"\n",
|
|
"\n",
|
|
" # single shift per day\n",
|
|
" model.constraints.add(\n",
|
|
" 1 >= sum(model.works[worker.id, week, days[j], shift] for shift in days_shifts[days[j]])\n",
|
|
" )\n",
|
|
" ## if working in evening, until next evening (note that after sunday comes next monday)\n",
|
|
" #model.constraints.add(\n",
|
|
" # 1 >= sum(model.works[worker.id, week, days[j], shift] for shift in ['evening', 'night']) +\n",
|
|
" # model.works[worker.id, nweek, days[(j + 1) % 7], 'truro_twighlight']\n",
|
|
" #)\n",
|
|
"\n",
|
|
" # if working a night ensure preceeding (1) or subsequent (2) shifts can only be nights\n",
|
|
" model.constraints.add(\n",
|
|
" 1 >= model.works[worker.id, week, days[j], \"night\"] +\n",
|
|
" sum(model.works[worker.id, nweek, days[(j + 1) % 7], shift] for shift in ['truro_twighlight', 'plymouth_twighlight']) +\n",
|
|
" sum(model.works[worker.id, nweek, days[(j + 2) % 7], shift] for shift in ['truro_twighlight', 'plymouth_twighlight']) +\n",
|
|
" sum(model.works[worker.id, pweek, days[(j - 1) % 7], shift] for shift in ['truro_twighlight', 'plymouth_twighlight'])\n",
|
|
" )\n",
|
|
"\n",
|
|
"# Constraint (def of model.needed)\n",
|
|
"#for worker in workers:\n",
|
|
"# model.constraints.add(\n",
|
|
"# 10000 * model.needed[worker.id] >= sum(model.works[worker.id, week, day, shift] for week in weeks for day in days for shift in days_shifts[day])\n",
|
|
"# ) # if any model.works[worker, ·, ·] non-zero, model.needed[worker] must be one; else is zero to reduce the obj function\n",
|
|
" # 10000 is to remark, but 5 was enough since max of 40 hours yields max of 5 shifts, the maximum possible sum\n",
|
|
"\n",
|
|
"# Constraint (def of model.no_pref)\n",
|
|
"#for worker in workers:\n",
|
|
"# for week in weeks:\n",
|
|
"# model.constraints.add(\n",
|
|
"# model.no_pref[worker.id] >= sum(model.works[worker.id, week, 'Sat', shift] for shift in days_shifts['Sat'])\n",
|
|
"# - sum(model.works[worker.id, week, 'Sun', shift] for shift in days_shifts['Sun'])\n",
|
|
"# ) # if not working on sunday but working saturday model.needed must be 1; else will be zero to reduce the obj function\n"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": 10,
|
|
"metadata": {},
|
|
"outputs": [],
|
|
"source": [
|
|
"opt = SolverFactory('cbc') # choose a solver\n",
|
|
"results = opt.solve(model) # solve the model with the selected solver"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": 11,
|
|
"metadata": {
|
|
"tags": [
|
|
"outputPrepend",
|
|
"outputPrepend"
|
|
]
|
|
},
|
|
"outputs": [],
|
|
"source": [
|
|
"def get_workers_needed(needed):\n",
|
|
" \"\"\"Extract to a list the needed workers for the optimal solution.\"\"\"\n",
|
|
" workers_needed = []\n",
|
|
" for worker in workers:\n",
|
|
" if needed[worker.id].value == 1:\n",
|
|
" workers_needed.append(worker.name)\n",
|
|
" return workers_needed\n",
|
|
"\n",
|
|
"\n",
|
|
"def get_work_table(works):\n",
|
|
" \"\"\"Build a timetable of the week as a dictionary from the model's optimal solution.\"\"\"\n",
|
|
" week_table = {week :{day: {shift: [] for shift in days_shifts[day]} for day in days} for week in weeks}\n",
|
|
" for week in weeks:\n",
|
|
" for worker in workers:\n",
|
|
" for day in days:\n",
|
|
" for shift in days_shifts[day]:\n",
|
|
" if works[worker.id, week, day, shift].value == 1:\n",
|
|
" week_table[week][day][shift].append(worker.GetDetails())\n",
|
|
" return week_table\n",
|
|
"\n",
|
|
"def get_worker_timetable(works):\n",
|
|
" timetable = { worker.name : { week : { day: \"\" for day in days } for week in weeks } for worker in workers }\n",
|
|
" for worker in workers:\n",
|
|
" for week in weeks:\n",
|
|
" for day in days:\n",
|
|
" for shift in days_shifts[day]:\n",
|
|
" if works[worker.id, week, day, shift].value == 1:\n",
|
|
" timetable[worker.name][week][day] = shift\n",
|
|
" return timetable\n",
|
|
"\n",
|
|
"def get_shift_summary(works):\n",
|
|
" timetable = { worker.GetDetails() : { shift : \"\" for shift in shifts } for worker in workers }\n",
|
|
" #timetable = { worker.GetDetails() : { shift : \"\" for shift in [\"truro_twighlight\"] } for worker in workers } \n",
|
|
" for worker in workers:\n",
|
|
"\n",
|
|
" for shift in shifts:\n",
|
|
" #for shift in [\"truro_twighlight\"]:\n",
|
|
" timetable[worker.GetDetails()][shift] = [works[worker.id, week, day, shift] for week in weeks for day in days].count(1)\n",
|
|
" return timetable \n",
|
|
"\n",
|
|
"def get_no_preference(no_pref):\n",
|
|
" \"\"\"Extract to a list the workers not satisfied with their weekend preference.\"\"\"\n",
|
|
" return [worker.id for worker in workers if no_pref[worker.id].value == 1]\n",
|
|
"\n",
|
|
"def get_night_blocks(nights):\n",
|
|
" timetable = { worker.name : { week : { block: \"\" for block in night_blocks } for week in weeks } for worker in workers }\n",
|
|
" for worker in workers:\n",
|
|
" for week in weeks:\n",
|
|
" for block in night_blocks:\n",
|
|
" if nights[worker.id, week, block].value == 1:\n",
|
|
" timetable[worker.name][week][block] = \"true\"\n",
|
|
" return timetable\n",
|
|
"\n",
|
|
"\n",
|
|
"workers_needed = get_workers_needed(model.needed) # dict with the optimal timetable\n",
|
|
"week_table = get_work_table(model.works) # list with the required workers\n",
|
|
"worker_timetable = get_worker_timetable(model.works)\n",
|
|
"workers_no_pref = get_no_preference(model.no_pref) # list with the non-satisfied workers (work on Sat but not on Sun)\n",
|
|
"worker_night_block = get_night_blocks(model.nights)\n",
|
|
"worker_shift_summary = get_shift_summary(model.works)"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": 12,
|
|
"metadata": {},
|
|
"outputs": [
|
|
{
|
|
"output_type": "execute_result",
|
|
"data": {
|
|
"text/plain": "{'1 t 4': {'night': 10, 'truro_twighlight': 7, 'plymouth_twighlight': 0},\n '2 t 4': {'night': 10, 'truro_twighlight': 7, 'plymouth_twighlight': 0},\n '3 t 4': {'night': 9, 'truro_twighlight': 6, 'plymouth_twighlight': 0},\n '4 t 4': {'night': 9, 'truro_twighlight': 7, 'plymouth_twighlight': 0},\n '5 t 4': {'night': 11, 'truro_twighlight': 7, 'plymouth_twighlight': 0},\n '6 t 4': {'night': 11, 'truro_twighlight': 7, 'plymouth_twighlight': 0},\n '7 t 4': {'night': 9, 'truro_twighlight': 7, 'plymouth_twighlight': 0},\n '8 t 4': {'night': 10, 'truro_twighlight': 7, 'plymouth_twighlight': 0},\n '9 t 4': {'night': 9, 'truro_twighlight': 7, 'plymouth_twighlight': 0},\n '10 t 4': {'night': 10, 'truro_twighlight': 7, 'plymouth_twighlight': 0},\n '11 t 4': {'night': 11, 'truro_twighlight': 6, 'plymouth_twighlight': 0},\n '12 t 4': {'night': 10, 'truro_twighlight': 7, 'plymouth_twighlight': 0},\n '13 t 4': {'night': 11, 'truro_twighlight': 7, 'plymouth_twighlight': 0},\n '14 t 4': {'night': 8, 'truro_twighlight': 7, 'plymouth_twighlight': 0},\n '15 t 4': {'night': 8, 'truro_twighlight': 7, 'plymouth_twighlight': 0},\n '16 t 4': {'night': 8, 'truro_twighlight': 6, 'plymouth_twighlight': 0},\n '17 t 4': {'night': 11, 'truro_twighlight': 7, 'plymouth_twighlight': 0},\n '18 t 4': {'night': 10, 'truro_twighlight': 7, 'plymouth_twighlight': 0},\n '19 t 4': {'night': 10, 'truro_twighlight': 7, 'plymouth_twighlight': 0},\n '21 p 4': {'night': 10, 'truro_twighlight': 0, 'plymouth_twighlight': 3},\n '22 p 4': {'night': 8, 'truro_twighlight': 0, 'plymouth_twighlight': 4},\n '23 p 4': {'night': 11, 'truro_twighlight': 0, 'plymouth_twighlight': 4},\n '24 p 4': {'night': 10, 'truro_twighlight': 0, 'plymouth_twighlight': 4},\n '25 p 4': {'night': 9, 'truro_twighlight': 0, 'plymouth_twighlight': 4},\n '26 p 4': {'night': 10, 'truro_twighlight': 0, 'plymouth_twighlight': 4},\n '27 p 4': {'night': 9, 'truro_twighlight': 0, 'plymouth_twighlight': 4},\n '28 p 4': {'night': 9, 'truro_twighlight': 0, 'plymouth_twighlight': 3},\n '29 p 4': {'night': 11, 'truro_twighlight': 0, 'plymouth_twighlight': 4},\n '30 p 4': {'night': 10, 'truro_twighlight': 0, 'plymouth_twighlight': 4},\n '31 p 4': {'night': 10, 'truro_twighlight': 0, 'plymouth_twighlight': 3},\n '32 p 4': {'night': 10, 'truro_twighlight': 0, 'plymouth_twighlight': 4},\n '33 p 4': {'night': 11, 'truro_twighlight': 0, 'plymouth_twighlight': 3},\n '34 p 4': {'night': 11, 'truro_twighlight': 0, 'plymouth_twighlight': 4},\n '35 p 4': {'night': 11, 'truro_twighlight': 0, 'plymouth_twighlight': 4},\n '36 p 4': {'night': 9, 'truro_twighlight': 0, 'plymouth_twighlight': 4},\n '37 p 4': {'night': 11, 'truro_twighlight': 0, 'plymouth_twighlight': 3},\n '38 p 4': {'night': 8, 'truro_twighlight': 0, 'plymouth_twighlight': 3},\n '39 p 4': {'night': 11, 'truro_twighlight': 0, 'plymouth_twighlight': 4},\n '40 p 4': {'night': 10, 'truro_twighlight': 0, 'plymouth_twighlight': 3},\n '41 p 4': {'night': 10, 'truro_twighlight': 0, 'plymouth_twighlight': 3},\n '42 p 4': {'night': 11, 'truro_twighlight': 0, 'plymouth_twighlight': 3},\n '43 p 4': {'night': 10, 'truro_twighlight': 0, 'plymouth_twighlight': 4},\n '44 p 4': {'night': 8, 'truro_twighlight': 0, 'plymouth_twighlight': 3},\n '45 p 4': {'night': 11, 'truro_twighlight': 0, 'plymouth_twighlight': 4},\n '46 p 4': {'night': 11, 'truro_twighlight': 0, 'plymouth_twighlight': 3},\n '47 p 4': {'night': 10, 'truro_twighlight': 0, 'plymouth_twighlight': 3},\n '48 p 4': {'night': 11, 'truro_twighlight': 0, 'plymouth_twighlight': 4},\n '49 p 4': {'night': 8, 'truro_twighlight': 0, 'plymouth_twighlight': 3},\n '50 p 4': {'night': 8, 'truro_twighlight': 0, 'plymouth_twighlight': 3},\n '51 p 4': {'night': 8, 'truro_twighlight': 0, 'plymouth_twighlight': 3},\n '52 p 4': {'night': 11, 'truro_twighlight': 0, 'plymouth_twighlight': 3},\n '53 p 4': {'night': 8, 'truro_twighlight': 0, 'plymouth_twighlight': 4},\n '54 p 4': {'night': 10, 'truro_twighlight': 0, 'plymouth_twighlight': 3},\n '55 p 4': {'night': 11, 'truro_twighlight': 0, 'plymouth_twighlight': 3},\n '56 p 4': {'night': 8, 'truro_twighlight': 0, 'plymouth_twighlight': 4},\n '57 p 4': {'night': 8, 'truro_twighlight': 0, 'plymouth_twighlight': 4}}"
|
|
},
|
|
"metadata": {},
|
|
"execution_count": 12
|
|
}
|
|
],
|
|
"source": [
|
|
"#worker_timetable\n",
|
|
"worker_shift_summary"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": 13,
|
|
"metadata": {},
|
|
"outputs": [
|
|
{
|
|
"output_type": "execute_result",
|
|
"data": {
|
|
"text/plain": "[]"
|
|
},
|
|
"metadata": {},
|
|
"execution_count": 13
|
|
}
|
|
],
|
|
"source": [
|
|
"workers_needed"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": 14,
|
|
"metadata": {},
|
|
"outputs": [
|
|
{
|
|
"output_type": "execute_result",
|
|
"data": {
|
|
"text/plain": " t 4'],\n 'plymouth_twighlight': ['43 p 4']},\n 'Wed': {'night': ['11 t 4', '16 t 4', '46 p 4'],\n 'truro_twighlight': ['18 t 4'],\n 'plymouth_twighlight': ['24 p 4']},\n 'Thu': {'night': ['11 t 4', '16 t 4', '46 p 4'],\n 'truro_twighlight': ['8 t 4'],\n 'plymouth_twighlight': ['40 p 4']},\n 'Fri': {'night': ['12 t 4', '21 p 4', '43 p 4'],\n 'truro_twighlight': ['4 t 4'],\n 'plymouth_twighlight': ['31 p 4']},\n 'Sat': {'night': ['12 t 4', '21 p 4', '43 p 4'],\n 'truro_twighlight': [],\n 'plymouth_twighlight': []},\n 'Sun': {'night': ['12 t 4', '21 p 4', '43 p 4'],\n 'truro_twighlight': [],\n 'plymouth_twighlight': []}},\n 4: {'Mon': {'night': ['8 t 4', '37 p 4', '41 p 4'],\n 'truro_twighlight': ['6 t 4'],\n 'plymouth_twighlight': ['24 p 4']},\n 'Tue': {'night': ['8 t 4', '37 p 4', '41 p 4'],\n 'truro_twighlight': ['7 t 4'],\n 'plymouth_twighlight': ['46 p 4']},\n 'Wed': {'night': ['8 t 4', '37 p 4', '41 p 4'],\n 'truro_twighlight': ['4 t 4'],\n 'plymouth_twighlight': ['35 p 4']},\n 'Thu': {'night': ['8 t 4', '37 p 4', '41 p 4'],\n 'truro_twighlight': ['12 t 4'],\n 'plymouth_twighlight': ['54 p 4']},\n 'Fri': {'night': ['32 p 4', '42 p 4', '48 p 4'],\n 'truro_twighlight': ['11 t 4'],\n 'plymouth_twighlight': ['29 p 4']},\n 'Sat': {'night': ['32 p 4', '42 p 4', '48 p 4'],\n 'truro_twighlight': [],\n 'plymouth_twighlight': []},\n 'Sun': {'night': ['32 p 4', '42 p 4', '48 p 4'],\n 'truro_twighlight': [],\n 'plymouth_twighlight': []}},\n 5: {'Mon': {'night': ['12 t 4', '35 p 4', '44 p 4'],\n 'truro_twighlight': ['8 t 4'],\n 'plymouth_twighlight': ['56 p 4']},\n 'Tue': {'night': ['12 t 4', '35 p 4', '44 p 4'],\n 'truro_twighlight': ['18 t 4'],\n 'plymouth_twighlight': ['34 p 4']},\n 'Wed': {'night': ['12 t 4', '35 p 4', '44 p 4'],\n 'truro_twighlight': ['11 t 4'],\n 'plymouth_twighlight': ['41 p 4']},\n 'Thu': {'night': ['12 t 4', '35 p 4', '44 p 4'],\n 'truro_twighlight': ['13 t 4'],\n 'plymouth_twighlight': ['51 p 4']},\n 'Fri': {'night': ['34 p 4', '45 p 4', '54 p 4'],\n 'truro_twighlight': ['3 t 4'],\n 'plymouth_twighlight': ['50 p 4']},\n 'Sat': {'night': ['34 p 4', '45 p 4', '54 p 4'],\n 'truro_twighlight': [],\n 'plymouth_twighlight': []},\n 'Sun': {'night': ['34 p 4', '45 p 4', '54 p 4'],\n 'truro_twighlight': [],\n 'plymouth_twighlight': []}},\n 6: {'Mon': {'night': ['32 p 4', '37 p 4', '45 p 4'],\n 'truro_twighlight': ['6 t 4'],\n 'plymouth_twighlight': ['26 p 4']},\n 'Tue': {'night': ['32 p 4', '37 p 4', '45 p 4'],\n 'truro_twighlight': ['11 t 4'],\n 'plymouth_twighlight': ['36 p 4']},\n 'Wed': {'night': ['32 p 4', '37 p 4', '45 p 4'],\n 'truro_twighlight': ['10 t 4'],\n 'plymouth_twighlight': ['39 p 4']},\n 'Thu': {'night': ['32 p 4', '37 p 4', '45 p 4'],\n 'truro_twighlight': ['2 t 4'],\n 'plymouth_twighlight': ['42 p 4']},\n 'Fri': {'night': ['9 t 4', '13 t 4', '27 p 4'],\n 'truro_twighlight': ['1 t 4'],\n 'plymouth_twighlight': ['49 p 4']},\n 'Sat': {'night': ['9 t 4', '13 t 4', '27 p 4'],\n 'truro_twighlight': [],\n 'plymouth_twighlight': []},\n 'Sun': {'night': ['9 t 4', '13 t 4', '27 p 4'],\n 'truro_twighlight': [],\n 'plymouth_twighlight': []}},\n 7: {'Mon': {'night': ['13 t 4', '23 p 4', '24 p 4'],\n 'truro_twighlight': ['1 t 4'],\n 'plymouth_twighlight': ['33 p 4']},\n 'Tue': {'night': ['13 t 4', '23 p 4', '24 p 4'],\n 'truro_twighlight': ['14 t 4'],\n 'plymouth_twighlight': ['37 p 4']},\n 'Wed': {'night': ['13 t 4', '23 p 4', '24 p 4'],\n 'truro_twighlight': ['9 t 4'],\n 'plymouth_twighlight': ['56 p 4']},\n 'Thu': {'night': ['13 t 4', '23 p 4', '24 p 4'],\n 'truro_twighlight': ['2 t 4'],\n 'plymouth_twighlight': ['53 p 4']},\n 'Fri': {'night': ['10 t 4', '28 p 4', '30 p 4'],\n 'truro_twighlight': ['15 t 4'],\n 'plymouth_twighlight': ['39 p 4']},\n 'Sat': {'night': ['10 t 4', '28 p 4', '30 p 4'],\n 'truro_twighlight': [],\n 'plymouth_twighlight': []},\n 'Sun': {'night': ['10 t 4', '28 p 4', '30 p 4'],\n 'truro_twighlight': [],\n 'plymouth_twighlight': []}},\n 8: {'Mon': {'night': ['45 p 4', '51 p 4', '56 p 4'],\n 'truro_twighlight': ['15 t 4'],\n 'plymouth_twighlight': ['26 p 4']},\n 'Tue': {'night': ['45 p 4', '51 p 4', '56 p 4'],\n 'truro_twighlight': ['6 t 4'],\n 'plymouth_twighlight': ['23 p 4']},\n 'Wed': {'night': ['45 p 4', '51 p 4', '56 p 4'],\n 'truro_twighlight': ['12 t 4'],\n 'plymouth_twighlight': ['28 p 4']},\n 'Thu': {'night': ['45 p 4', '51 p 4', '56 p 4'],\n 'truro_twighlight': ['17 t 4'],\n 'plymouth_twighlight': ['32 p 4']},\n 'Fri': {'night': ['18 t 4', '24 p 4', '37 p 4'],\n 'truro_twighlight': ['3 t 4'],\n 'plymouth_twighlight': ['42 p 4']},\n 'Sat': {'night': ['18 t 4', '24 p 4', '37 p 4'],\n 'truro_twighlight': [],\n 'plymouth_twighlight': []},\n 'Sun': {'night': ['18 t 4', '24 p 4', '37 p 4'],\n 'truro_twighlight': [],\n 'plymouth_twighlight': []}},\n 9: {'Mon': {'night': ['16 t 4', '22 p 4', '54 p 4'],\n 'truro_twighlight': ['3 t 4'],\n 'plymouth_twighlight': ['32 p 4']},\n 'Tue': {'night': ['16 t 4', '22 p 4', '54 p 4'],\n 'truro_twighlight': ['2 t 4'],\n 'plymouth_twighlight': ['25 p 4']},\n 'Wed': {'night': ['16 t 4', '22 p 4', '54 p 4'],\n 'truro_twighlight': ['5 t 4'],\n 'plymouth_twighlight': ['43 p 4']},\n 'Thu': {'night': ['16 t 4', '22 p 4', '54 p 4'],\n 'truro_twighlight': ['1 t 4'],\n 'plymouth_twighlight': ['52 p 4']},\n 'Fri': {'night': ['4 t 4', '23 p 4', '27 p 4'],\n 'truro_twighlight': ['14 t 4'],\n 'plymouth_twighlight': ['57 p 4']},\n 'Sat': {'night': ['4 t 4', '23 p 4', '27 p 4'],\n 'truro_twighlight': [],\n 'plymouth_twighlight': []},\n 'Sun': {'night': ['4 t 4', '23 p 4', '27 p 4'],\n 'truro_twighlight': [],\n 'plymouth_twighlight': []}},\n 10: {'Mon': {'night': ['31 p 4', '48 p 4', '55 p 4'],\n 'truro_twighlight': ['2 t 4'],\n 'plymouth_twighlight': ['42 p 4']},\n 'Tue': {'night': ['31 p 4', '48 p 4', '55 p 4'],\n 'truro_twighlight': ['15 t 4'],\n 'plymouth_twighlight': ['25 p 4']},\n 'Wed': {'night': ['31 p 4', '48 p 4', '55 p 4'],\n 'truro_twighlight': ['18 t 4'],\n 'plymouth_twighlight': ['27 p 4']},\n 'Thu': {'night': ['31 p 4', '48 p 4', '55 p 4'],\n 'truro_twighlight': ['10 t 4'],\n 'plymouth_twighlight': ['36 p 4']},\n 'Fri': {'night': ['8 t 4', '17 t 4', '47 p 4'],\n 'truro_twighlight': ['13 t 4'],\n 'plymouth_twighlight': ['34 p 4']},\n 'Sat': {'night': ['8 t 4', '17 t 4', '47 p 4'],\n 'truro_twighlight': [],\n 'plymouth_twighlight': []},\n 'Sun': {'night': ['8 t 4', '17 t 4', '47 p 4'],\n 'truro_twighlight': [],\n 'plymouth_twighlight': []}},\n 11: {'Mon': {'night': ['5 t 4', '14 t 4', '43 p 4'],\n 'truro_twighlight': ['7 t 4'],\n 'plymouth_twighlight': ['27 p 4']},\n 'Tue': {'night': ['5 t 4', '14 t 4', '43 p 4'],\n 'truro_twighlight': ['4 t 4'],\n 'plymouth_twighlight': ['31 p 4']},\n 'Wed': {'night': ['5 t 4', '14 t 4', '43 p 4'],\n 'truro_twighlight': ['1 t 4'],\n 'plymouth_twighlight': ['52 p 4']},\n 'Thu': {'night': ['5 t 4', '14 t 4', '43 p 4'],\n 'truro_twighlight': ['10 t 4'],\n 'plymouth_twighlight': ['57 p 4']},\n 'Fri': {'night': ['3 t 4', '26 p 4', '28 p 4'],\n 'truro_twighlight': ['11 t 4'],\n 'plymouth_twighlight': ['23 p 4']},\n 'Sat': {'night': ['3 t 4', '26 p 4', '28 p 4'],\n 'truro_twighlight': [],\n 'plymouth_twighlight': []},\n 'Sun': {'night': ['3 t 4', '26 p 4', '28 p 4'],\n 'truro_twighlight': [],\n 'plymouth_twighlight': []}},\n 12: {'Mon': {'night': ['5 t 4', '26 p 4', '49 p 4'],\n 'truro_twighlight': ['19 t 4'],\n 'plymouth_twighlight': ['36 p 4']},\n 'Tue': {'night': ['5 t 4', '26 p 4', '49 p 4'],\n 'truro_twighlight': ['10 t 4'],\n 'plymouth_twighlight': ['41 p 4']},\n 'Wed': {'night': ['5 t 4', '26 p 4', '49 p 4'],\n 'truro_twighlight': ['11 t 4'],\n 'plymouth_twighlight': ['30 p 4']},\n 'Thu': {'night': ['5 t 4', '26 p 4', '49 p 4'],\n 'truro_twighlight': ['8 t 4'],\n 'plymouth_twighlight': ['34 p 4']},\n 'Fri': {'night': ['11 t 4', '39 p 4', '40 p 4'],\n 'truro_twighlight': ['16 t 4'],\n 'plymouth_twighlight': ['48 p 4']},\n 'Sat': {'night': ['11 t 4', '39 p 4', '40 p 4'],\n 'truro_twighlight': [],\n 'plymouth_twighlight': []},\n 'Sun': {'night': ['11 t 4', '39 p 4', '40 p 4'],\n 'truro_twighlight': [],\n 'plymouth_twighlight': []}},\n 13: {'Mon': {'night': ['38 p 4', '49 p 4', '51 p 4'],\n 'truro_twighlight': ['9 t 4'],\n 'plymouth_twighlight': ['52 p 4']},\n 'Tue': {'night': ['38 p 4', '49 p 4', '51 p 4'],\n 'truro_twighlight': ['1 t 4'],\n 'plymouth_twighlight': ['21 p 4']},\n 'Wed': {'night': ['38 p 4', '49 p 4', '51 p 4'],\n 'truro_twighlight': ['13 t 4'],\n 'plymouth_twighlight': ['40 p 4']},\n 'Thu': {'night': ['38 p 4', '49 p 4', '51 p 4'],\n 'truro_twighlight': ['16 t 4'],\n 'plymouth_twighlight': ['44 p 4']},\n 'Fri': {'night': ['4 t 4', '7 t 4', '30 p 4'],\n 'truro_twighlight': ['18 t 4'],\n 'plymouth_twighlight': ['54 p 4']},\n 'Sat': {'night': ['4 t 4', '7 t 4', '30 p 4'],\n 'truro_twighlight': [],\n 'plymouth_twighlight': []},\n 'Sun': {'night': ['4 t 4', '7 t 4', '30 p 4'],\n 'truro_twighlight': [],\n 'plymouth_twighlight': []}},\n 14: {'Mon': {'night': ['1 t 4', '22 p 4', '40 p 4'],\n 'truro_twighlight': ['9 t 4'],\n 'plymouth_twighlight': ['55 p 4']},\n 'Tue': {'night': ['1 t 4', '22 p 4', '40 p 4'],\n 'truro_twighlight': ['8 t 4'],\n 'plymouth_twighlight': ['37 p 4']},\n 'Wed': {'night': ['1 t 4', '22 p 4', '40 p 4'],\n 'truro_twighlight': ['15 t 4'],\n 'plymouth_twighlight': ['30 p 4']},\n 'Thu': {'night': ['1 t 4', '22 p 4', '40 p 4'],\n 'truro_twighlight': ['4 t 4'],\n 'plymouth_twighlight': ['33 p 4']},\n 'Fri': {'night': ['3 t 4', '7 t 4', '29 p 4'],\n 'truro_twighlight': ['14 t 4'],\n 'plymouth_twighlight': ['43 p 4']},\n 'Sat': {'night': ['3 t 4', '7 t 4', '29 p 4'],\n 'truro_twighlight': [],\n 'plymouth_twighlight': []},\n 'Sun': {'night': ['3 t 4', '7 t 4', '29 p 4'],\n 'truro_twighlight': [],\n 'plymouth_twighlight': []}},\n 15: {'Mon': {'night': ['17 t 4', '42 p 4', '53 p 4'],\n 'truro_twighlight': ['9 t 4'],\n 'plymouth_twighlight': ['21 p 4']},\n 'Tue': {'night': ['17 t 4', '42 p 4', '53 p 4'],\n 'truro_twighlight': ['10 t 4'],\n 'plymouth_twighlight': ['45 p 4']},\n 'Wed': {'night': ['17 t 4', '42 p 4', '53 p 4'],\n 'truro_twighlight': ['12 t 4'],\n 'plymouth_twighlight': ['44 p 4']},\n 'Thu': {'night': ['17 t 4', '42 p 4', '53 p 4'],\n 'truro_twighlight': ['19 t 4'],\n 'plymouth_twighlight': ['46 p 4']},\n 'Fri': {'night': ['1 t 4', '3 t 4', '31 p 4'],\n 'truro_twighlight': ['16 t 4'],\n 'plymouth_twighlight': ['50 p 4']},\n 'Sat': {'night': ['1 t 4', '3 t 4', '31 p 4'],\n 'truro_twighlight': [],\n 'plymouth_twighlight': []},\n 'Sun': {'night': ['1 t 4', '3 t 4', '31 p 4'],\n 'truro_twighlight': [],\n 'plymouth_twighlight': []}},\n 16: {'Mon': {'night': ['2 t 4', '15 t 4', '57 p 4'],\n 'truro_twighlight': ['18 t 4'],\n 'plymouth_twighlight': ['25 p 4']},\n 'Tue': {'night': ['2 t 4', '15 t 4', '57 p 4'],\n 'truro_twighlight': ['19 t 4'],\n 'plymouth_twighlight': ['24 p 4']},\n 'Wed': {'night': ['2 t 4', '15 t 4', '57 p 4'],\n 'truro_twighlight': ['17 t 4'],\n 'plymouth_twighlight': ['28 p 4']},\n 'Thu': {'night': ['2 t 4', '15 t 4', '57 p 4'],\n 'truro_twighlight': ['13 t 4'],\n 'plymouth_twighlight': ['50 p 4']},\n 'Fri': {'night': ['7 t 4', '19 t 4', '36 p 4'],\n 'truro_twighlight': ['6 t 4'],\n 'plymouth_twighlight': ['27 p 4']},\n 'Sat': {'night': ['7 t 4', '19 t 4', '36 p 4'],\n 'truro_twighlight': [],\n 'plymouth_twighlight': []},\n 'Sun': {'night': ['7 t 4', '19 t 4', '36 p 4'],\n 'truro_twighlight': [],\n 'plymouth_twighlight': []}},\n 17: {'Mon': {'night': ['6 t 4', '15 t 4', '34 p 4'],\n 'truro_twighlight': ['17 t 4'],\n 'plymouth_twighlight': ['38 p 4']},\n 'Tue': {'night': ['6 t 4', '15 t 4', '34 p 4'],\n 'truro_twighlight': ['5 t 4'],\n 'plymouth_twighlight': ['23 p 4']},\n 'Wed': {'night': ['6 t 4', '15 t 4', '34 p 4'],\n 'truro_twighlight': ['14 t 4'],\n 'plymouth_twighlight': ['45 p 4']},\n 'Thu': {'night': ['6 t 4', '15 t 4', '34 p 4'],\n 'truro_twighlight': ['9 t 4'],\n 'plymouth_twighlight': ['55 p 4']},\n 'Fri': {'night': ['4 t 4', '25 p 4', '36 p 4'],\n 'truro_twighlight': ['16 t 4'],\n 'plymouth_twighlight': ['33 p 4']},\n 'Sat': {'night': ['4 t 4', '25 p 4', '36 p 4'],\n 'truro_twighlight': [],\n 'plymouth_twighlight': []},\n 'Sun': {'night': ['4 t 4', '25 p 4', '36 p 4'],\n 'truro_twighlight': [],\n 'plymouth_twighlight': []}},\n 18: {'Mon': {'night': ['6 t 4', '10 t 4', '42 p 4'],\n 'truro_twighlight': ['7 t 4'],\n 'plymouth_twighlight': ['40 p 4']},\n 'Tue': {'night': ['6 t 4', '10 t 4', '42 p 4'],\n 'truro_twighlight': ['5 t 4'],\n 'plymouth_twighlight': ['35 p 4']},\n 'Wed': {'night': ['6 t 4', '10 t 4', '42 p 4'],\n 'truro_twighlight': ['13 t 4'],\n 'plymouth_twighlight': ['38 p 4']},\n 'Thu': {'night': ['6 t 4', '10 t 4', '42 p 4'],\n 'truro_twighlight': ['11 t 4'],\n 'plymouth_twighlight': ['23 p 4']},\n 'Fri': {'night': ['18 t 4', '28 p 4', '35 p 4'],\n 'truro_twighlight': ['17 t 4'],\n 'plymouth_twighlight': ['26 p 4']},\n 'Sat': {'night': ['18 t 4', '28 p 4', '35 p 4'],\n 'truro_twighlight': [],\n 'plymouth_twighlight': []},\n 'Sun': {'night': ['18 t 4', '28 p 4', '35 p 4'],\n 'truro_twighlight': [],\n 'plymouth_twighlight': []}},\n 19: {'Mon': {'night': ['13 t 4', '18 t 4', '19 t 4'],\n 'truro_twighlight': ['10 t 4'],\n 'plymouth_twighlight': ['53 p 4']},\n 'Tue': {'night': ['13 t 4', '18 t 4', '19 t 4'],\n 'truro_twighlight': ['4 t 4'],\n 'plymouth_twighlight': ['47 p 4']},\n 'Wed': {'night': ['13 t 4', '18 t 4', '19 t 4'],\n 'truro_twighlight': ['15 t 4'],\n 'plymouth_twighlight': ['29 p 4']},\n 'Thu': {'night': ['13 t 4', '18 t 4', '19 t 4'],\n 'truro_twighlight': ['9 t 4'],\n 'plymouth_twighlight': ['54 p 4']},\n 'Fri': {'night': ['5 t 4', '12 t 4', '25 p 4'],\n 'truro_twighlight': ['3 t 4'],\n 'plymouth_twighlight': ['51 p 4']},\n 'Sat': {'night': ['5 t 4', '12 t 4', '25 p 4'],\n 'truro_twighlight': [],\n 'plymouth_twighlight': []},\n 'Sun': {'night': ['5 t 4', '12 t 4', '25 p 4'],\n 'truro_twighlight': [],\n 'plymouth_twighlight': []}},\n 20: {'Mon': {'night': ['38 p 4', '44 p 4', '53 p 4'],\n 'truro_twighlight': ['9 t 4'],\n 'plymouth_twighlight': ['22 p 4']},\n 'Tue': {'night': ['38 p 4', '44 p 4', '53 p 4'],\n 'truro_twighlight': ['6 t 4'],\n 'plymouth_twighlight': ['39 p 4']},\n 'Wed': {'night': ['38 p 4', '44 p 4', '53 p 4'],\n 'truro_twighlight': ['7 t 4'],\n 'plymouth_twighlight': ['34 p 4']},\n 'Thu': {'night': ['38 p 4', '44 p 4', '53 p 4'],\n 'truro_twighlight': ['19 t 4'],\n 'plymouth_twighlight': ['29 p 4']},\n 'Fri': {'night': ['6 t 4', '8 t 4', '31 p 4'],\n 'truro_twighlight': ['14 t 4'],\n 'plymouth_twighlight': ['32 p 4']},\n 'Sat': {'night': ['6 t 4', '8 t 4', '31 p 4'],\n 'truro_twighlight': [],\n 'plymouth_twighlight': []},\n 'Sun': {'night': ['6 t 4', '8 t 4', '31 p 4'],\n 'truro_twighlight': [],\n 'plymouth_twighlight': []}},\n 21: {'Mon': {'night': ['14 t 4', '21 p 4', '23 p 4'],\n 'truro_twighlight': ['12 t 4'],\n 'plymouth_twighlight': ['57 p 4']},\n 'Tue': {'night': ['14 t 4', '21 p 4', '23 p 4'],\n 'truro_twighlight': ['2 t 4'],\n 'plymouth_twighlight': ['38 p 4']},\n 'Wed': {'night': ['14 t 4', '21 p 4', '23 p 4'],\n 'truro_twighlight': ['18 t 4'],\n 'plymouth_twighlight': ['53 p 4']},\n 'Thu': {'night': ['14 t 4', '21 p 4', '23 p 4'],\n 'truro_twighlight': ['5 t 4'],\n 'plymouth_twighlight': ['45 p 4']},\n 'Fri': {'night': ['9 t 4', '32 p 4', '43 p 4'],\n 'truro_twighlight': ['19 t 4'],\n 'plymouth_twighlight': ['56 p 4']},\n 'Sat': {'night': ['9 t 4', '32 p 4', '43 p 4'],\n 'truro_twighlight': [],\n 'plymouth_twighlight': []},\n 'Sun': {'night': ['9 t 4', '32 p 4', '43 p 4'],\n 'truro_twighlight': [],\n 'plymouth_twighlight': []}},\n 22: {'Mon': {'night': ['17 t 4', '55 p 4', '57 p 4'],\n 'truro_twighlight': ['1 t 4'],\n 'plymouth_twighlight': ['41 p 4']},\n 'Tue': {'night': ['17 t 4', '55 p 4', '57 p 4'],\n 'truro_twighlight': ['16 t 4'],\n 'plymouth_twighlight': ['30 p 4']},\n 'Wed': {'night': ['17 t 4', '55 p 4', '57 p 4'],\n 'truro_twighlight': ['12 t 4'],\n 'plymouth_twighlight': ['45 p 4']},\n 'Thu': {'night': ['17 t 4', '55 p 4', '57 p 4'],\n 'truro_twighlight': ['18 t 4'],\n 'plymouth_twighlight': ['29 p 4']},\n 'Fri': {'night': ['19 t 4', '27 p 4', '40 p 4'],\n 'truro_twighlight': ['6 t 4'],\n 'plymouth_twighlight': ['35 p 4']},\n 'Sat': {'night': ['19 t 4', '27 p 4', '40 p 4'],\n 'truro_twighlight': [],\n 'plymouth_twighlight': []},\n 'Sun': {'night': ['19 t 4', '27 p 4', '40 p 4'],\n 'truro_twighlight': [],\n 'plymouth_twighlight': []}},\n 23: {'Mon': {'night': ['39 p 4', '48 p 4', '50 p 4'],\n 'truro_twighlight': ['6 t 4'],\n 'plymouth_twighlight': ['35 p 4']},\n 'Tue': {'night': ['39 p 4', '48 p 4', '50 p 4'],\n 'truro_twighlight': ['8 t 4'],\n 'plymouth_twighlight': ['46 p 4']},\n 'Wed': {'night': ['39 p 4', '48 p 4', '50 p 4'],\n 'truro_twighlight': ['7 t 4'],\n 'plymouth_twighlight': ['31 p 4']},\n 'Thu': {'night': ['39 p 4', '48 p 4', '50 p 4'],\n 'truro_twighlight': ['14 t 4'],\n 'plymouth_twighlight': ['24 p 4']},\n 'Fri': {'night': ['33 p 4', '52 p 4', '55 p 4'],\n 'truro_twighlight': ['2 t 4'],\n 'plymouth_twighlight': ['26 p 4']},\n 'Sat': {'night': ['33 p 4', '52 p 4', '55 p 4'],\n 'truro_twighlight': [],\n 'plymouth_twighlight': []},\n 'Sun': {'night': ['33 p 4', '52 p 4', '55 p 4'],\n 'truro_twighlight': [],\n 'plymouth_twighlight': []}},\n 24: {'Mon': {'night': ['35 p 4', '46 p 4', '52 p 4'],\n 'truro_twighlight': ['12 t 4'],\n 'plymouth_twighlight': ['48 p 4']},\n 'Tue': {'night': ['35 p 4', '46 p 4', '52 p 4'],\n 'truro_twighlight': ['5 t 4'],\n 'plymouth_twighlight': ['53 p 4']},\n 'Wed': {'night': ['35 p 4', '46 p 4', '52 p 4'],\n 'truro_twighlight': ['17 t 4'],\n 'plymouth_twighlight': ['55 p 4']},\n 'Thu': {'night': ['35 p 4', '46 p 4', '52 p 4'],\n 'truro_twighlight': ['15 t 4'],\n 'plymouth_twighlight': ['47 p 4']},\n 'Fri': {'night': ['9 t 4', '25 p 4', '41 p 4'],\n 'truro_twighlight': ['8 t 4'],\n 'plymouth_twighlight': ['57 p 4']},\n 'Sat': {'night': ['9 t 4', '25 p 4', '41 p 4'],\n 'truro_twighlight': [],\n 'plymouth_twighlight': []},\n 'Sun': {'night': ['9 t 4', '25 p 4', '41 p 4'],\n 'truro_twighlight': [],\n 'plymouth_twighlight': []}},\n 25: {'Mon': {'night': ['29 p 4', '33 p 4', '39 p 4'],\n 'truro_twighlight': ['17 t 4'],\n 'plymouth_twighlight': ['30 p 4']},\n 'Tue': {'night': ['29 p 4', '33 p 4', '39 p 4'],\n 'truro_twighlight': ['14 t 4'],\n 'plymouth_twighlight': ['48 p 4']},\n 'Wed': {'night': ['29 p 4', '33 p 4', '39 p 4'],\n 'truro_twighlight': ['16 t 4'],\n 'plymouth_twighlight': ['51 p 4']},\n 'Thu': {'night': ['29 p 4', '33 p 4', '39 p 4'],\n 'truro_twighlight': ['8 t 4'],\n 'plymouth_twighlight': ['22 p 4']},\n 'Fri': {'night': ['2 t 4', '10 t 4', '36 p 4'],\n 'truro_twighlight': ['19 t 4'],\n 'plymouth_twighlight': ['47 p 4']},\n 'Sat': {'night': ['2 t 4', '10 t 4', '36 p 4'],\n 'truro_twighlight': [],\n 'plymouth_twighlight': []},\n 'Sun': {'night': ['2 t 4', '10 t 4', '36 p 4'],\n 'truro_twighlight': [],\n 'plymouth_twighlight': []}},\n 26: {'Mon': {'night': ['47 p 4', '52 p 4', '56 p 4'],\n 'truro_twighlight': ['12 t 4'],\n 'plymouth_twighlight': ['39 p 4']},\n 'Tue': {'night': ['47 p 4', '52 p 4', '56 p 4'],\n 'truro_twighlight': ['19 t 4'],\n 'plymouth_twighlight': ['25 p 4']},\n 'Wed': {'night': ['47 p 4', '52 p 4', '56 p 4'],\n 'truro_twighlight': ['2 t 4'],\n 'plymouth_twighlight': ['27 p 4']},\n 'Thu': {'night': ['47 p 4', '52 p 4', '56 p 4'],\n 'truro_twighlight': ['17 t 4'],\n 'plymouth_twighlight': ['44 p 4']},\n 'Fri': {'night': ['2 t 4', '24 p 4', '41 p 4'],\n 'truro_twighlight': ['13 t 4'],\n 'plymouth_twighlight': ['49 p 4']},\n 'Sat': {'night': ['2 t 4', '24 p 4', '41 p 4'],\n 'truro_twighlight': [],\n 'plymouth_twighlight': []},\n 'Sun': {'night': ['2 t 4', '24 p 4', '41 p 4'],\n 'truro_twighlight': [],\n 'plymouth_twighlight': []}}}"
|
|
},
|
|
"metadata": {},
|
|
"execution_count": 14
|
|
}
|
|
],
|
|
"source": [
|
|
"week_table"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": 15,
|
|
"metadata": {},
|
|
"outputs": [],
|
|
"source": [
|
|
"#worker_night_block"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": 16,
|
|
"metadata": {},
|
|
"outputs": [],
|
|
"source": [
|
|
"#[[worker, week, day, shift] for day in days for shift in [\"night\"]]"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": 17,
|
|
"metadata": {},
|
|
"outputs": [
|
|
{
|
|
"output_type": "execute_result",
|
|
"data": {
|
|
"text/plain": "1"
|
|
},
|
|
"metadata": {},
|
|
"execution_count": 17
|
|
}
|
|
],
|
|
"source": [
|
|
"1 if 4 in [4, 1, 0] else 0"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": 18,
|
|
"metadata": {},
|
|
"outputs": [
|
|
{
|
|
"output_type": "execute_result",
|
|
"data": {
|
|
"text/plain": "0"
|
|
},
|
|
"metadata": {},
|
|
"execution_count": 18
|
|
}
|
|
],
|
|
"source": [
|
|
"(4 + 1) // 7"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": 19,
|
|
"metadata": {},
|
|
"outputs": [],
|
|
"source": [
|
|
"#for worker in workers:\n",
|
|
"# for shift in shifts:\n",
|
|
"# a = [model.works[worker.id, week, day, shift].value for week in weeks for day in days]"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": 20,
|
|
"metadata": {},
|
|
"outputs": [
|
|
{
|
|
"output_type": "error",
|
|
"ename": "NameError",
|
|
"evalue": "name 'a' is not defined",
|
|
"traceback": [
|
|
"\u001b[0;31m---------------------------------------------------------------------------\u001b[0m",
|
|
"\u001b[0;31mNameError\u001b[0m Traceback (most recent call last)",
|
|
"\u001b[0;32m<ipython-input-20-3f786850e387>\u001b[0m in \u001b[0;36m<module>\u001b[0;34m\u001b[0m\n\u001b[0;32m----> 1\u001b[0;31m \u001b[0ma\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m",
|
|
"\u001b[0;31mNameError\u001b[0m: name 'a' is not defined"
|
|
]
|
|
}
|
|
],
|
|
"source": [
|
|
"a"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": 21,
|
|
"metadata": {},
|
|
"outputs": [
|
|
{
|
|
"output_type": "execute_result",
|
|
"data": {
|
|
"text/plain": "0"
|
|
},
|
|
"metadata": {},
|
|
"execution_count": 21
|
|
}
|
|
],
|
|
"source": [
|
|
"0 % 7"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": 22,
|
|
"metadata": {},
|
|
"outputs": [
|
|
{
|
|
"output_type": "execute_result",
|
|
"data": {
|
|
"text/plain": "6"
|
|
},
|
|
"metadata": {},
|
|
"execution_count": 22
|
|
}
|
|
],
|
|
"source": [
|
|
"-1 % 7"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": null,
|
|
"metadata": {},
|
|
"outputs": [],
|
|
"source": []
|
|
}
|
|
]
|
|
} |