103 KiB
103 KiB
In [1]:
from pyomo.environ import *
from pyomo.opt import SolverFactory
from shifts import SingleShift, RotaBuilder, days, sites
from workers import Worker
import math
import scipy.stats as stats
import csv
import statistics
import datetime
import itertools
import operator
from functools import reduce
def prod(iterable):
return reduce(operator.mul, iterable, 1)In [2]:
#night_balance_offset = 2
#twilight_balance_offset = 1
weeks_to_rota = 16
use_test_workers = TrueIn [3]:
Rota = RotaBuilder(weeks_to_rota=weeks_to_rota)
Rota.add_shifts(
SingleShift(("exeter",), "exeter_twilight", 12.5, days[:5]),
SingleShift(("truro",), "truro_twilight", 12.5, days[:5]),
SingleShift(("torquay",), "torquay_twilight", 12.5, days[:5]),
SingleShift(("plymouth",), "plymouth_twilight", 12.5, days[:5]),
SingleShift(("exeter",), "weekend_exeter", 12.5, days[5:]),
SingleShift(("truro",), "weekend_truro", 12.5, days[5:]),
SingleShift(("torquay",), "weekend_torquay", 12.5, days[5:]),
SingleShift(("plymouth",), "weekend_plymouth", 8, days[5:], workers_required=2),
SingleShift((sites), "night", 12.5, days, balance_offset=2, balance_weighting=2, workers_required=3, rota_on_nwds=True),
)
#Rota2 = RotaBuilder(weeks_to_rota=weeks_to_rota)
#Rota2.add_shifts(
# SingleShift(("exeter",), "exeter_twilight", 12.5, days[:5], balance_offset=3),
# SingleShift(("exeter",), "weekend_exeter", 12.5, days[5:], balance_offset=3, balance_weighting=1),
# SingleShift((sites), "night", 12.5, days, balance_offset=2, balance_weighting=4, workers_required=3, rota_on_nwds=True),
#)
#Rota = Rota2
In [4]:
if use_test_workers:
# Enter workers ids (name, number, ...)
#workers.extend([Worker(Rota, i, "Test Person {}".format(i), "truro", 3, nwd=['Fri', "Sat", "Sun"]) for i in range(1, 2)])
Rota.add_workers([Worker(Rota,i, "Test Person {}".format(i), "truro", 4, ) for i in range(1, 15)])
Rota.add_workers([Worker(Rota,i, "Test Person {}".format(i), "plymouth", 4) for i in range(15, 30)])
Rota.add_workers([Worker(Rota,i, "Test Person {}".format(i), "exeter", 4) for i in range(30, 45)])
Rota.add_workers([Worker(Rota,i, "Test Person {}".format(i), "torquay", 4) for i in range(45, 60)])
#workers.extend([workerClass(i, "Test Person {}".format(i), 4, 200, "") for i in range(48, 49)])
#workers.extend([Worker(Rota,i, "Test Person {}".format(i), "exeter", 4) for i in range(34, 45)])
else:
# Import trainee data
import csv
with open('trainees.csv', newline='') as f:
reader = csv.reader(f, delimiter=',', quotechar='|')
next(reader) # skip header
n = 0
for row in reader:
n = n + 1
#print(row)
name, site, grade, fte, nwd, end_date, oop, extra = row
# Ignore trainees if fte == 0 (what are they doing here anyway)
if fte == 0:
continue
nwds = nwd.split(",").title() if nwd else None
end_date = end_date if end_date else None
oop = oop.split("-") if oop else None
#print(nwds, end_date, oop)
Rota.add_worker(Worker(Rota, n, name, site.lower(), int(grade[2]), int(fte), nwds, end_date, oop))
In [5]:
Rota.build_workers()
Rota.build_model()In [6]:
opt = SolverFactory('cbc') # choose a solver
#opt = SolverFactory('ipopt') # choose a solver
results = opt.solve(Rota.model, tee=True, options={"seconds":600, "allow": 25}) # solve the model with the, options="seconds=60" selected solverWelcome to the CBC MILP Solver Version: 2.9.9 Build Date: Aug 7 2019 command line - /usr/bin/cbc -seconds 600 -allow 25 -printingOptions all -import /tmp/tmpua24r1de.pyomo.lp -stat=1 -solve -solu /tmp/tmpua24r1de.pyomo.soln (default strategy 1) seconds was changed from 1e+100 to 600 allowableGap was changed from 1e-10 to 25 Option for printingOptions changed from normal to all Presolve 8525 (-7679) rows, 33158 (-28852) columns and 138886 (-135111) elements Statistics for presolved model Original problem has 61360 integers (61360 of which binary) Presolved problem has 33040 integers (33040 of which binary) ==== 33040 zero objective 2 different 33040 variables have objective of 0 118 variables have objective of 1 ==== absolute objective values 2 different 33040 variables have objective of 0 118 variables have objective of 1 ==== for integers 33040 zero objective 1 different 33040 variables have objective of 0 ==== for integers absolute objective values 1 different 33040 variables have objective of 0 ===== end objective counts Problem has 8525 rows, 33158 columns (118 with objective) and 138886 elements There are 118 singletons with objective Column breakdown: 118 of type 0.0->inf, 0 of type 0.0->up, 0 of type lo->inf, 0 of type lo->up, 0 of type free, 0 of type fixed, 0 of type -inf->0.0, 0 of type -inf->up, 33040 of type 0.0->1.0 Row breakdown: 0 of type E 0.0, 416 of type E 1.0, 0 of type E -1.0, 203 of type E other, 0 of type G 0.0, 0 of type G 1.0, 177 of type G other, 0 of type L 0.0, 6608 of type L 1.0, 1121 of type L other, 0 of type Range 0.0->1.0, 0 of type Range other, 0 of type Free Continuous objective value is 0 - 0.33 seconds Cgl0002I 26432 variables fixed Cgl0004I processed model has 8348 rows, 21350 columns (21232 integer (21232 of which binary)) and 90246 elements Cbc0038I Initial state - 159 integers unsatisfied sum - 34.8044 Cbc0038I Pass 1: (0.88 seconds) suminf. 9.38095 (36) obj. 40.5517 iterations 464 Cbc0038I Pass 2: (0.88 seconds) suminf. 9.38095 (36) obj. 40.5517 iterations 0 Cbc0038I Pass 3: (0.90 seconds) suminf. 5.00952 (20) obj. 48.6712 iterations 122 Cbc0038I Pass 4: (0.92 seconds) suminf. 4.34286 (19) obj. 49.0712 iterations 31 Cbc0038I Pass 5: (0.94 seconds) suminf. 2.60952 (10) obj. 51.7785 iterations 80 Cbc0038I Pass 6: (0.96 seconds) suminf. 2.60952 (10) obj. 51.7785 iterations 11 Cbc0038I Pass 7: (0.98 seconds) suminf. 2.60952 (10) obj. 52.9747 iterations 60 Cbc0038I Pass 8: (1.00 seconds) suminf. 2.60952 (10) obj. 51.1296 iterations 60 Cbc0038I Pass 9: (1.04 seconds) suminf. 27.94802 (95) obj. 192.581 iterations 537 Cbc0038I Pass 10: (1.07 seconds) suminf. 16.67684 (61) obj. 186.06 iterations 303 Cbc0038I Pass 11: (1.08 seconds) suminf. 15.67119 (61) obj. 186.941 iterations 34 Cbc0038I Pass 12: (1.10 seconds) suminf. 12.72768 (49) obj. 180.727 iterations 106 Cbc0038I Pass 13: (1.12 seconds) suminf. 12.33785 (48) obj. 179.814 iterations 48 Cbc0038I Pass 14: (1.14 seconds) suminf. 12.33785 (48) obj. 179.814 iterations 2 Cbc0038I Pass 15: (1.16 seconds) suminf. 9.84068 (39) obj. 180.049 iterations 116 Cbc0038I Pass 16: (1.18 seconds) suminf. 9.84068 (39) obj. 180.049 iterations 24 Cbc0038I Pass 17: (1.20 seconds) suminf. 7.43874 (31) obj. 180.126 iterations 58 Cbc0038I Pass 18: (1.22 seconds) suminf. 7.43874 (31) obj. 180.126 iterations 26 Cbc0038I Pass 19: (1.24 seconds) suminf. 5.72446 (25) obj. 179.71 iterations 70 Cbc0038I Pass 20: (1.26 seconds) suminf. 5.72446 (25) obj. 179.71 iterations 26 Cbc0038I Pass 21: (1.29 seconds) suminf. 5.85779 (21) obj. 179.251 iterations 110 Cbc0038I Pass 22: (1.30 seconds) suminf. 5.19112 (21) obj. 179.651 iterations 58 Cbc0038I Pass 23: (1.33 seconds) suminf. 5.59112 (21) obj. 175.843 iterations 122 Cbc0038I Pass 24: (1.34 seconds) suminf. 5.19112 (21) obj. 176.243 iterations 43 Cbc0038I Pass 25: (1.36 seconds) suminf. 5.59112 (21) obj. 176.051 iterations 85 Cbc0038I Pass 26: (1.38 seconds) suminf. 5.19112 (21) obj. 176.451 iterations 52 Cbc0038I Pass 27: (1.40 seconds) suminf. 5.59112 (21) obj. 175.843 iterations 75 Cbc0038I Pass 28: (1.42 seconds) suminf. 5.19112 (21) obj. 176.243 iterations 36 Cbc0038I Pass 29: (1.44 seconds) suminf. 5.59112 (21) obj. 177.518 iterations 118 Cbc0038I Pass 30: (1.46 seconds) suminf. 5.19112 (21) obj. 177.918 iterations 42 Cbc0038I No solution found this major pass Cbc0038I Before mini branch and bound, 20552 integers at bound fixed and 25 continuous Cbc0038I Full problem 8348 rows 21350 columns, reduced to 251 rows 531 columns Cbc0038I Mini branch and bound did not improve solution (1.77 seconds) Cbc0038I Full problem 8349 rows 21350 columns, reduced to 8349 rows 21350 columns - too large Cbc0038I After 2.19 seconds - Feasibility pump exiting - took 1.40 seconds Cbc0012I Integer solution of 19.715254 found by DiveCoefficient after 3604 iterations and 0 nodes (6.37 seconds) Cbc0031I 124 added rows had average density of 258.29032 Cbc0013I At root node, 124 cuts changed objective from 0 to 10.135593 in 10 passes Cbc0014I Cut generator 0 (Probing) - 0 row cuts average 0.0 elements, 0 column cuts (0 active) in 0.389 seconds - new frequency is -100 Cbc0014I Cut generator 1 (Gomory) - 408 row cuts average 742.9 elements, 0 column cuts (0 active) in 0.874 seconds - new frequency is 1 Cbc0014I Cut generator 2 (Knapsack) - 0 row cuts average 0.0 elements, 0 column cuts (0 active) in 0.049 seconds - new frequency is -100 Cbc0014I Cut generator 3 (Clique) - 0 row cuts average 0.0 elements, 0 column cuts (0 active) in 0.007 seconds - new frequency is -100 Cbc0014I Cut generator 4 (MixedIntegerRounding2) - 322 row cuts average 223.6 elements, 0 column cuts (0 active) in 0.191 seconds - new frequency is 1 Cbc0014I Cut generator 5 (FlowCover) - 0 row cuts average 0.0 elements, 0 column cuts (0 active) in 0.054 seconds - new frequency is -100 Cbc0014I Cut generator 6 (TwoMirCuts) - 274 row cuts average 277.7 elements, 0 column cuts (0 active) in 0.458 seconds - new frequency is 1 Cbc0011I Exiting as integer gap of 9.579661 less than 25 or 0%% Cbc0001I Search completed - best objective 19.71525423728813, took 3604 iterations and 0 nodes (6.39 seconds) Cbc0035I Maximum depth 0, 0 variables fixed on reduced cost Cuts at root node changed objective from 0 to 10.1356 Probing was tried 10 times and created 0 cuts of which 0 were active after adding rounds of cuts (0.389 seconds) Gomory was tried 10 times and created 408 cuts of which 0 were active after adding rounds of cuts (0.874 seconds) Knapsack was tried 10 times and created 0 cuts of which 0 were active after adding rounds of cuts (0.049 seconds) Clique was tried 10 times and created 0 cuts of which 0 were active after adding rounds of cuts (0.007 seconds) MixedIntegerRounding2 was tried 10 times and created 322 cuts of which 0 were active after adding rounds of cuts (0.191 seconds) FlowCover was tried 10 times and created 0 cuts of which 0 were active after adding rounds of cuts (0.054 seconds) TwoMirCuts was tried 10 times and created 274 cuts of which 0 were active after adding rounds of cuts (0.458 seconds) Result - Optimal solution found (within gap tolerance) Objective value: 19.71525424 Lower bound: 10.136 Gap: 0.95 Enumerated nodes: 0 Total iterations: 3604 Time (CPU seconds): 6.56 Time (Wallclock seconds): 6.66 Total time (CPU seconds): 7.38 (Wallclock seconds): 7.51
In [7]:
results.solver.statusOut [7]:
EnumValue(<pyutilib.enum.enum.Enum object at 0x7fbb9a1ae2d0>, 0, 'ok')
In [83]:
#def get_workers_needed(needed):
# """Extract to a list the needed workers for the optimal solution."""
# workers_needed = []
# for worker in workers:
# if needed[worker.id].value == 1:
# workers_needed.append(worker.name)
# return workers_needed
def get_work_table(works):
"""Build a timetable of the week as a dictionary from the model's optimal solution."""
week_table = {week :{day: {shift: [] for shift in Rota.GetShiftNames()} for day in days} for week in Rota.weeks}
for week in Rota.weeks:
for worker in Rota.workers:
for day, shift in Rota.GetAllDayShiftAsNames():
if works[worker.id, week, day, shift].value == 1:
week_table[week][day][shift].append(worker.get_details())
return week_table
def get_worker_timetable(works):
timetable = { worker.name : { week : { day: "" for day in days } for week in Rota.weeks } for worker in Rota.workers }
for worker in Rota.workers:
for week in Rota.weeks:
for day, shift in Rota.GetAllDayShiftAsNames():
if works[worker.id, week, day, shift].value == 1:
timetable[worker.name][week][day] = shift
return timetable
def get_worker_timetable_brief(works):
timetable = []
timetable.append("{:20}".format("Worker") + "".join([7*str("{}".format(w))[-1:] for w in Rota.weeks]))
for worker in Rota.workers:
w = ["{:20}".format(worker.name)]
for week, day in Rota.GetAllWeeksDays():
a = "-"
for shift in Rota.GetShiftNamesByDay(day):
if works[worker.id, week, day, shift].value == 1:
a = shift[0]
w.append(a)
timetable.append("".join(w))
return "\n".join(timetable)
def get_shift_summary(works):
timetable = { worker.get_details() : { shift[0] : "" for shift in Rota.GetShiftNames() } for worker in Rota.workers }
#timetable = { worker.get_details() : { shift : "" for shift in ["truro_twilight"] } for worker in workers }
t = []
for worker in Rota.workers:
l = [worker.get_details()+": "]
for shift in Rota.GetShiftNames():
#for shift in ["truro_twilight"]:
c = [works[worker.id, week, day, shift] for week in Rota.weeks for day in days].count(1)
if c > 0:
l.append("{} ({})".format(shift,c))
#print(worker.id, shift)
timetable[worker.get_details()][shift[0]] = c
t.append(",".join(l))
return "\n".join(t)
#def get_no_preference(no_pref):
# """Extract to a list the workers not satisfied with their weekend preference."""
# return [worker.id for worker in workers if no_pref[worker.id].value == 1]
def get_night_blocks(nights):
timetable = { worker.name : { week : { block: "" for block in Rota.night_blocks } for week in Rota.weeks } for worker in Rota.workers }
for worker in Rota.workers:
for week in Rota.weeks:
for block in Rota.night_blocks:
if nights[worker.id, week, block].value == 1:
timetable[worker.name][week][block] = "true"
return timetable
#workers_needed = get_workers_needed(model.needed) # dict with the optimal timetable
week_table = get_work_table(Rota.model.works) # list with the required workers
worker_timetable = get_worker_timetable(Rota.model.works)
worker_timetable_brief = get_worker_timetable_brief(Rota.model.works)
#workers_no_pref = get_no_preference(Rota.model.no_pref) # list with the non-satisfied workers (work on Sat but not on Sun)
worker_night_block = get_night_blocks(Rota.model.nights)
worker_shift_summary = get_shift_summary(Rota.model.works)In [98]:
def ExportRotaToCSV(works):
with open("rota.csv", 'w', newline='') as f:
wr = csv.writer(f, quoting=csv.QUOTE_ALL)
l = ["Name"]
l.extend([worker.name for worker in Rota.workers])
wr.writerow(l)
l2 = ["Site"]
l2.extend([worker.site for worker in Rota.workers])
wr.writerow(l2)
l3 = ["Grade"]
l3.extend([worker.grade for worker in Rota.workers])
wr.writerow(l3)
l4 = ["FTE"]
l4.extend([worker.fte for worker in Rota.workers])
wr.writerow(l4)
for week, day in Rota.GetAllWeeksDays():
d = ["Week {} Day {}".format(week, day)]
for worker in Rota.workers:
i = ""
for shift in Rota.GetShiftNamesByDay(day):
if works[worker.id, week, day, shift].value == 1:
i = shift
d.append(i)
wr.writerow(d)
ExportRotaToCSV(Rota.model.works)In [99]:
print(worker_timetable_brief)
Worker 1111111222222233333334444444555555566666667777777888888899999990000000111111122222223333333444444455555556666666 Test Person 30 eee------n-------------------------n-e--w---e--------n-w------------w----ne------------------------n------------ Test Person 31 ---ee------------------e--nn-n----------------n-------w---e-------------------e------n------------------w-----n- Test Person 32 -----------n--------ne----------e---------------w----------n----------e-----------w-n--ee--e--n------n---------- Test Person 33 ------------w--------------------n-e-----------------------ee-------n-------nnn--------n--------------ew---e---- Test Person 34 -----wwe-----------nn----------n-------e----------------n------n---------------------e-------n------e-------e--- Test Person 35 -------n-------en--w----------e------n---w------ne--n---e------e-------------------------n---------------------- Test Person 36 ------------------------e-w---n--------------ee---------------n----e------------------n--w---------nn--n--e----- Test Person 37 -n-n----e--------------------------n-------n----------------nn---------e---w----------------------e--e-------e-w Test Person 38 -----------e---------------w--n--------n---e--------e------------e---w-ne--n------------n------------n---------- Test Person 39 --------------e---e---------nen---w---n----------------------ww-e-n------------e-------------------e---n-------- Test Person 40 --------n---n---e-----------e---------------n-----e------e------n------------e--e-------------n--w------------w- Test Person 41 ---------e---w---e---n---n----------e------------------n------n------------------e--------w---en------------n--- Test Person 42 ----------e-----------e-----n---------e---n----------e-------------------e--w---------n-----e--nw------------n-- Test Person 43 -------------------------e-------w--------e----w----------------n-e-------n---------e-e---------n-----n----n-n-- Test Person 44 --------------------w----n-----e-------n-----------e--------n--------n-------------w----nn---e-e---------e------ Test Person 15 pnppn-w--------p---n------w------w----------------n----w--n----------w------------------------p------p---------- Test Person 16 ----pwwp----w--------------w----------------------nn-------n----pn-----n--p-------------pw---p------------------ Test Person 17 --n--w--p-p--w---------np-------n-------w----------------------n--p-------------p-n--------n------------w------- Test Person 18 --n--------pww-----------p---n------n--------------p-n------p-w------n-----w---------------p-------------n------ Test Person 19 -pn-----------p----w-------------------p----------------nn----w---------p-----------n-----------n------w-----pwn Test Person 20 ---n------------pppwwp-----wp----------------------------n-----------------w-----n----------n-n-------------n--- Test Person 21 ----------n----------------------n-------w---p--w------------------n---p-------n---w--------p--p-wp-----nn------ Test Person 22 ------------nn---------------------------------wwp--n---p--------p-p-wp------------np-----w-------n-------n----- Test Person 23 ----------------------p---w--p----wp--nn-wn--n---np-------------------------w--------------------w-p--------p--- Test Person 24 ------n---------------np-------p--w------n----------p--w-------p--------n-------n-w---------n---w---------p----- Test Person 25 ----n----p--------------------p----------------w-----nw------------n--n------np--p-n--------------------w--p--w- Test Person 26 ---------------------n----------pn----p----p---------p-------w---n--w-n-----w--------pp--nw-----w--------------- Test Person 27 ---------------------------------wn-p-----n------n-n------p--w-n-n-------p---------w----------------p----p-----w Test Person 28 --------------------w----------------p--------p------------p-------------n--np----w------wnnn---------pw-------n Test Person 29 ------n-------------------------n-------w-p-pn--------w--p--n-----n-w---n------p-------p-----------------------w Test Person 45 t-t--n-------------w-----t------n-----------------------n----n-----------------------n-------t-t--n----w-------- Test Person 46 ----t--n----------------n------n------------n---------------t-------------t-----t-------t-w----n------n-------w- Test Person 47 -----w---tt------------tn---t------------n--t-t-------n----------------n----w--------n----------n--------------- Test Person 48 ------w-t--------t---------------------------------t-----n----w---------------------------nn--------n-tnn--t---- Test Person 49 ------------w----n---t----w-------------n---------n-------------t------------t--nn-----t--n------------------t-- Test Person 50 --------------nn-----n--t--w------------w-----n-n------n-------t------t-------t-------------------t------------- Test Person 51 -t--------------t--------------------------n------t-t-n-----------t-ww----------n-n--t-----------n-------------- Test Person 52 -----n-t--------n---------------------t---t----w-n-n---------w-----t-------n----------n--------------t---------- Test Person 53 ---------------n------------n-----------------n--------------n--nt---------------t-------w-ttnt-w--------------- Test Person 54 --------n--t--------w---n------tt----------------------------------n---t---w--n--------------------t--n-n------- Test Person 55 -----------n-w-nn-------------------tn-t-------nw---------t------------------------wt---------------t----t------ Test Person 56 ------------------nn---------t-------------------t---t-wt------------------nn---------t-n--------w------w---t--- Test Person 57 ------------------t---t------nt----t-----w-----n------n--t---------------------------------------n--------nn---w Test Person 58 ---------n----tt-----------------ww--t-----n---------------t----------n--t----n-----n--n------------------t----- Test Person 59 ---t------n------n-----------------------n-t-t--------w----n------------t-n----t-nw----------------------------- Test Person 1 n---n--tt-n---t-tt---------w----------t-w---n----------------------------------n---------------------------n---- Test Person 10 --------------n---------------------------ttt--------t-------w--------------------------t----------nt----n--nnww Test Person 11 n-tt-n---t---n---------------------------------n-------n--n-----t-----------------w------------t--------w------- Test Person 12 ------------------n--t---nnn--------------------w---------n---------------t---tt------t-------------n--w--t----- Test Person 13 -t--------t-----------n---w-------n----------------t----------w-----n--t-------------------t-nt------n---------- Test Person 14 t---------------------nn-------------------------------w--t-------nt----n---w--n----t-------t--------------t---- Test Person 2 nn--tww----twn-t--n----n--------------------------------t----------------t----------------------------t--------- Test Person 3 ---n--------n----------------t--t------------tt-n---t----------t-----n-----w-------w-------------n-------------- Test Person 4 ------nn-----w------n-t---nn---n----t--------------------------------wt---------t-----------------t------------- Test Person 5 --------n-----n--n----------t----w-t-------------t-------t--t-n--------------------------w-------------------tnn Test Person 6 -----------n------t------t--------w--n--n------w------w-----------t----------n---t---t----------------------t-n- Test Person 7 -----------------------tt---------n-n--------n----------------------w---t-n------------n--------w--t-----tn----- Test Person 8 ---------n---------ww---------tt---n-t-tn---------t-------------------------------nn------w--t------------------ Test Person 9 ------------------------------------n-n--w----------n------t-----t--n----n---t---------t---------wn--t----------
In [100]:
#workers_needed
print(worker_shift_summary)
30 e 4: ,exeter_twilight (6),weekend_exeter (3),night (5) 31 e 4: ,exeter_twilight (5),weekend_exeter (2),night (6) 32 e 4: ,exeter_twilight (6),weekend_exeter (2),night (6) 33 e 4: ,exeter_twilight (5),weekend_exeter (2),night (6) 34 e 4: ,exeter_twilight (5),weekend_exeter (2),night (6) 35 e 4: ,exeter_twilight (5),weekend_exeter (2),night (6) 36 e 4: ,exeter_twilight (5),weekend_exeter (2),night (6) 37 e 4: ,exeter_twilight (5),weekend_exeter (2),night (6) 38 e 4: ,exeter_twilight (5),weekend_exeter (2),night (6) 39 e 4: ,exeter_twilight (6),weekend_exeter (3),night (5) 40 e 4: ,exeter_twilight (6),weekend_exeter (2),night (5) 41 e 4: ,exeter_twilight (5),weekend_exeter (2),night (6) 42 e 4: ,exeter_twilight (6),weekend_exeter (2),night (5) 43 e 4: ,exeter_twilight (5),weekend_exeter (2),night (6) 44 e 4: ,exeter_twilight (5),weekend_exeter (2),night (6) 15 p 4: ,plymouth_twilight (6),weekend_plymouth (5),night (5) 16 p 4: ,plymouth_twilight (6),weekend_plymouth (5),night (5) 17 p 4: ,plymouth_twilight (5),weekend_plymouth (4),night (6) 18 p 4: ,plymouth_twilight (5),weekend_plymouth (4),night (6) 19 p 4: ,plymouth_twilight (5),weekend_plymouth (4),night (6) 20 p 4: ,plymouth_twilight (5),weekend_plymouth (4),night (6) 21 p 4: ,plymouth_twilight (5),weekend_plymouth (4),night (6) 22 p 4: ,plymouth_twilight (6),weekend_plymouth (4),night (6) 23 p 4: ,plymouth_twilight (6),weekend_plymouth (5),night (5) 24 p 4: ,plymouth_twilight (5),weekend_plymouth (4),night (6) 25 p 4: ,plymouth_twilight (5),weekend_plymouth (4),night (6) 26 p 4: ,plymouth_twilight (6),weekend_plymouth (5),night (5) 27 p 4: ,plymouth_twilight (5),weekend_plymouth (4),night (6) 28 p 4: ,plymouth_twilight (5),weekend_plymouth (4),night (6) 29 p 4: ,plymouth_twilight (5),weekend_plymouth (4),night (6) 45 t 4: ,torquay_twilight (5),weekend_torquay (2),night (6) 46 t 4: ,torquay_twilight (5),weekend_torquay (2),night (6) 47 t 4: ,torquay_twilight (6),weekend_torquay (2),night (6) 48 t 4: ,torquay_twilight (5),weekend_torquay (2),night (6) 49 t 4: ,torquay_twilight (5),weekend_torquay (2),night (6) 50 t 4: ,torquay_twilight (5),weekend_torquay (2),night (6) 51 t 4: ,torquay_twilight (6),weekend_torquay (2),night (5) 52 t 4: ,torquay_twilight (5),weekend_torquay (2),night (6) 53 t 4: ,torquay_twilight (5),weekend_torquay (2),night (6) 54 t 4: ,torquay_twilight (5),weekend_torquay (2),night (6) 55 t 4: ,torquay_twilight (6),weekend_torquay (3),night (5) 56 t 4: ,torquay_twilight (6),weekend_torquay (3),night (5) 57 t 4: ,torquay_twilight (5),weekend_torquay (2),night (6) 58 t 4: ,torquay_twilight (6),weekend_torquay (2),night (6) 59 t 4: ,torquay_twilight (5),weekend_torquay (2),night (6) 1 t 4: ,truro_twilight (6),weekend_truro (2),night (6) 10 t 4: ,truro_twilight (6),weekend_truro (3),night (5) 11 t 4: ,truro_twilight (5),weekend_truro (2),night (6) 12 t 4: ,truro_twilight (6),weekend_truro (2),night (6) 13 t 4: ,truro_twilight (6),weekend_truro (2),night (5) 14 t 4: ,truro_twilight (6),weekend_truro (2),night (5) 2 t 4: ,truro_twilight (6),weekend_truro (3),night (5) 3 t 4: ,truro_twilight (6),weekend_truro (2),night (5) 4 t 4: ,truro_twilight (5),weekend_truro (2),night (6) 5 t 4: ,truro_twilight (6),weekend_truro (2),night (6) 6 t 4: ,truro_twilight (6),weekend_truro (3),night (5) 7 t 4: ,truro_twilight (5),weekend_truro (2),night (6) 8 t 4: ,truro_twilight (6),weekend_truro (3),night (5) 9 t 4: ,truro_twilight (5),weekend_truro (2),night (6)
In [101]:
week_tableOut [101]:
'truro_twilight': ['10 t 4'],
'torquay_twilight': ['47 t 4'],
'plymouth_twilight': ['29 p 4'],
'weekend_exeter': [],
'weekend_truro': [],
'weekend_torquay': [],
'weekend_plymouth': [],
'night': ['40 e 4', '46 t 4', '1 t 4']},
'Thu': {'exeter_twilight': ['36 e 4'],
'truro_twilight': ['3 t 4'],
'torquay_twilight': ['59 t 4'],
'plymouth_twilight': ['21 p 4'],
'weekend_exeter': [],
'weekend_truro': [],
'weekend_torquay': [],
'weekend_plymouth': [],
'night': ['23 p 4', '29 p 4', '7 t 4']},
'Fri': {'exeter_twilight': ['36 e 4'],
'truro_twilight': ['3 t 4'],
'torquay_twilight': ['47 t 4'],
'plymouth_twilight': ['28 p 4'],
'weekend_exeter': [],
'weekend_truro': [],
'weekend_torquay': [],
'weekend_plymouth': [],
'night': ['31 e 4', '50 t 4', '53 t 4']},
'Sat': {'exeter_twilight': [],
'truro_twilight': [],
'torquay_twilight': [],
'plymouth_twilight': [],
'weekend_exeter': ['43 e 4'],
'weekend_truro': ['6 t 4'],
'weekend_torquay': ['52 t 4'],
'weekend_plymouth': ['22 p 4', '25 p 4'],
'night': ['55 t 4', '57 t 4', '11 t 4']},
'Sun': {'exeter_twilight': [],
'truro_twilight': [],
'torquay_twilight': [],
'plymouth_twilight': [],
'weekend_exeter': ['32 e 4'],
'weekend_truro': ['12 t 4'],
'weekend_torquay': ['55 t 4'],
'weekend_plymouth': ['21 p 4', '22 p 4'],
'night': ['35 e 4', '50 t 4', '3 t 4']}},
8: {'Mon': {'exeter_twilight': ['35 e 4'],
'truro_twilight': ['5 t 4'],
'torquay_twilight': ['56 t 4'],
'plymouth_twilight': ['22 p 4'],
'weekend_exeter': [],
'weekend_truro': [],
'weekend_torquay': [],
'weekend_plymouth': [],
'night': ['23 p 4', '27 p 4', '52 t 4']},
'Tue': {'exeter_twilight': ['40 e 4'],
'truro_twilight': ['8 t 4'],
'torquay_twilight': ['51 t 4'],
'plymouth_twilight': ['23 p 4'],
'weekend_exeter': [],
'weekend_truro': [],
'weekend_torquay': [],
'weekend_plymouth': [],
'night': ['15 p 4', '16 p 4', '49 t 4']},
'Wed': {'exeter_twilight': ['44 e 4'],
'truro_twilight': ['13 t 4'],
'torquay_twilight': ['48 t 4'],
'plymouth_twilight': ['18 p 4'],
'weekend_exeter': [],
'weekend_truro': [],
'weekend_torquay': [],
'weekend_plymouth': [],
'night': ['16 p 4', '27 p 4', '52 t 4']},
'Thu': {'exeter_twilight': ['38 e 4'],
'truro_twilight': ['3 t 4'],
'torquay_twilight': ['51 t 4'],
'plymouth_twilight': ['24 p 4'],
'weekend_exeter': [],
'weekend_truro': [],
'weekend_torquay': [],
'weekend_plymouth': [],
'night': ['35 e 4', '22 p 4', '9 t 4']},
'Fri': {'exeter_twilight': ['42 e 4'],
'truro_twilight': ['10 t 4'],
'torquay_twilight': ['56 t 4'],
'plymouth_twilight': ['26 p 4'],
'weekend_exeter': [],
'weekend_truro': [],
'weekend_torquay': [],
'weekend_plymouth': [],
'night': ['30 e 4', '18 p 4', '25 p 4']},
'Sat': {'exeter_twilight': [],
'truro_twilight': [],
'torquay_twilight': [],
'plymouth_twilight': [],
'weekend_exeter': ['31 e 4'],
'weekend_truro': ['6 t 4'],
'weekend_torquay': ['59 t 4'],
'weekend_plymouth': ['25 p 4', '29 p 4'],
'night': ['47 t 4', '51 t 4', '57 t 4']},
'Sun': {'exeter_twilight': [],
'truro_twilight': [],
'torquay_twilight': [],
'plymouth_twilight': [],
'weekend_exeter': ['30 e 4'],
'weekend_truro': ['14 t 4'],
'weekend_torquay': ['56 t 4'],
'weekend_plymouth': ['15 p 4', '24 p 4'],
'night': ['41 e 4', '50 t 4', '11 t 4']}},
9: {'Mon': {'exeter_twilight': ['35 e 4'],
'truro_twilight': ['2 t 4'],
'torquay_twilight': ['56 t 4'],
'plymouth_twilight': ['22 p 4'],
'weekend_exeter': [],
'weekend_truro': [],
'weekend_torquay': [],
'weekend_plymouth': [],
'night': ['34 e 4', '19 p 4', '45 t 4']},
'Tue': {'exeter_twilight': ['40 e 4'],
'truro_twilight': ['5 t 4'],
'torquay_twilight': ['57 t 4'],
'plymouth_twilight': ['29 p 4'],
'weekend_exeter': [],
'weekend_truro': [],
'weekend_torquay': [],
'weekend_plymouth': [],
'night': ['19 p 4', '20 p 4', '48 t 4']},
'Wed': {'exeter_twilight': ['31 e 4'],
'truro_twilight': ['14 t 4'],
'torquay_twilight': ['55 t 4'],
'plymouth_twilight': ['27 p 4'],
'weekend_exeter': [],
'weekend_truro': [],
'weekend_torquay': [],
'weekend_plymouth': [],
'night': ['15 p 4', '11 t 4', '12 t 4']},
'Thu': {'exeter_twilight': ['33 e 4'],
'truro_twilight': ['9 t 4'],
'torquay_twilight': ['58 t 4'],
'plymouth_twilight': ['28 p 4'],
'weekend_exeter': [],
'weekend_truro': [],
'weekend_torquay': [],
'weekend_plymouth': [],
'night': ['32 e 4', '16 p 4', '59 t 4']},
'Fri': {'exeter_twilight': ['33 e 4'],
'truro_twilight': ['5 t 4'],
'torquay_twilight': ['46 t 4'],
'plymouth_twilight': ['18 p 4'],
'weekend_exeter': [],
'weekend_truro': [],
'weekend_torquay': [],
'weekend_plymouth': [],
'night': ['37 e 4', '44 e 4', '29 p 4']},
'Sat': {'exeter_twilight': [],
'truro_twilight': [],
'torquay_twilight': [],
'plymouth_twilight': [],
'weekend_exeter': ['39 e 4'],
'weekend_truro': ['10 t 4'],
'weekend_torquay': ['52 t 4'],
'weekend_plymouth': ['26 p 4', '27 p 4'],
'night': ['37 e 4', '45 t 4', '53 t 4']},
'Sun': {'exeter_twilight': [],
'truro_twilight': [],
'torquay_twilight': [],
'plymouth_twilight': [],
'weekend_exeter': ['39 e 4'],
'weekend_truro': ['13 t 4'],
'weekend_torquay': ['48 t 4'],
'weekend_plymouth': ['18 p 4', '19 p 4'],
'night': ['36 e 4', '41 e 4', '5 t 4']}},
10: {'Mon': {'exeter_twilight': ['35 e 4'],
'truro_twilight': ['3 t 4'],
'torquay_twilight': ['50 t 4'],
'plymouth_twilight': ['24 p 4'],
'weekend_exeter': [],
'weekend_truro': [],
'weekend_torquay': [],
'weekend_plymouth': [],
'night': ['34 e 4', '17 p 4', '27 p 4']},
'Tue': {'exeter_twilight': ['39 e 4'],
'truro_twilight': ['11 t 4'],
'torquay_twilight': ['49 t 4'],
'plymouth_twilight': ['16 p 4'],
'weekend_exeter': [],
'weekend_truro': [],
'weekend_torquay': [],
'weekend_plymouth': [],
'night': ['40 e 4', '43 e 4', '53 t 4']},
'Wed': {'exeter_twilight': ['38 e 4'],
'truro_twilight': ['9 t 4'],
'torquay_twilight': ['53 t 4'],
'plymouth_twilight': ['22 p 4'],
'weekend_exeter': [],
'weekend_truro': [],
'weekend_torquay': [],
'weekend_plymouth': [],
'night': ['16 p 4', '26 p 4', '27 p 4']},
'Thu': {'exeter_twilight': ['43 e 4'],
'truro_twilight': ['6 t 4'],
'torquay_twilight': ['51 t 4'],
'plymouth_twilight': ['17 p 4'],
'weekend_exeter': [],
'weekend_truro': [],
'weekend_torquay': [],
'weekend_plymouth': [],
'night': ['39 e 4', '29 p 4', '14 t 4']},
'Fri': {'exeter_twilight': ['36 e 4'],
'truro_twilight': ['14 t 4'],
'torquay_twilight': ['52 t 4'],
'plymouth_twilight': ['22 p 4'],
'weekend_exeter': [],
'weekend_truro': [],
'weekend_torquay': [],
'weekend_plymouth': [],
'night': ['21 p 4', '25 p 4', '54 t 4']},
'Sat': {'exeter_twilight': [],
'truro_twilight': [],
'torquay_twilight': [],
'plymouth_twilight': [],
'weekend_exeter': ['30 e 4'],
'weekend_truro': ['7 t 4'],
'weekend_torquay': ['51 t 4'],
'weekend_plymouth': ['26 p 4', '29 p 4'],
'night': ['33 e 4', '13 t 4', '9 t 4']},
'Sun': {'exeter_twilight': [],
'truro_twilight': [],
'torquay_twilight': [],
'plymouth_twilight': [],
'weekend_exeter': ['38 e 4'],
'weekend_truro': ['4 t 4'],
'weekend_torquay': ['51 t 4'],
'weekend_plymouth': ['15 p 4', '22 p 4'],
'night': ['44 e 4', '18 p 4', '3 t 4']}},
11: {'Mon': {'exeter_twilight': ['32 e 4'],
'truro_twilight': ['4 t 4'],
'torquay_twilight': ['50 t 4'],
'plymouth_twilight': ['22 p 4'],
'weekend_exeter': [],
'weekend_truro': [],
'weekend_torquay': [],
'weekend_plymouth': [],
'night': ['25 p 4', '26 p 4', '58 t 4']},
'Tue': {'exeter_twilight': ['37 e 4'],
'truro_twilight': ['13 t 4'],
'torquay_twilight': ['54 t 4'],
'plymouth_twilight': ['21 p 4'],
'weekend_exeter': [],
'weekend_truro': [],
'weekend_torquay': [],
'weekend_plymouth': [],
'night': ['38 e 4', '16 p 4', '47 t 4']},
'Wed': {'exeter_twilight': ['38 e 4'],
'truro_twilight': ['7 t 4'],
'torquay_twilight': ['59 t 4'],
'plymouth_twilight': ['19 p 4'],
'weekend_exeter': [],
'weekend_truro': [],
'weekend_torquay': [],
'weekend_plymouth': [],
'night': ['24 p 4', '29 p 4', '14 t 4']},
'Thu': {'exeter_twilight': ['42 e 4'],
'truro_twilight': ['2 t 4'],
'torquay_twilight': ['58 t 4'],
'plymouth_twilight': ['27 p 4'],
'weekend_exeter': [],
'weekend_truro': [],
'weekend_torquay': [],
'weekend_plymouth': [],
'night': ['30 e 4', '28 p 4', '9 t 4']},
'Fri': {'exeter_twilight': ['30 e 4'],
'truro_twilight': ['12 t 4'],
'torquay_twilight': ['46 t 4'],
'plymouth_twilight': ['16 p 4'],
'weekend_exeter': [],
'weekend_truro': [],
'weekend_torquay': [],
'weekend_plymouth': [],
'night': ['43 e 4', '59 t 4', '7 t 4']},
'Sat': {'exeter_twilight': [],
'truro_twilight': [],
'torquay_twilight': [],
'plymouth_twilight': [],
'weekend_exeter': ['37 e 4'],
'weekend_truro': ['3 t 4'],
'weekend_torquay': ['54 t 4'],
'weekend_plymouth': ['18 p 4', '20 p 4'],
'night': ['38 e 4', '52 t 4', '56 t 4']},
'Sun': {'exeter_twilight': [],
'truro_twilight': [],
'torquay_twilight': [],
'plymouth_twilight': [],
'weekend_exeter': ['42 e 4'],
'weekend_truro': ['14 t 4'],
'weekend_torquay': ['47 t 4'],
'weekend_plymouth': ['23 p 4', '26 p 4'],
'night': ['33 e 4', '28 p 4', '56 t 4']}},
12: {'Mon': {'exeter_twilight': ['40 e 4'],
'truro_twilight': ['9 t 4'],
'torquay_twilight': ['49 t 4'],
'plymouth_twilight': ['28 p 4'],
'weekend_exeter': [],
'weekend_truro': [],
'weekend_torquay': [],
'weekend_plymouth': [],
'night': ['33 e 4', '25 p 4', '6 t 4']},
'Tue': {'exeter_twilight': ['31 e 4'],
'truro_twilight': ['12 t 4'],
'torquay_twilight': ['50 t 4'],
'plymouth_twilight': ['25 p 4'],
'weekend_exeter': [],
'weekend_truro': [],
'weekend_torquay': [],
'weekend_plymouth': [],
'night': ['33 e 4', '54 t 4', '58 t 4']},
'Wed': {'exeter_twilight': ['39 e 4'],
'truro_twilight': ['12 t 4'],
'torquay_twilight': ['59 t 4'],
'plymouth_twilight': ['29 p 4'],
'weekend_exeter': [],
'weekend_truro': [],
'weekend_torquay': [],
'weekend_plymouth': [],
'night': ['21 p 4', '1 t 4', '14 t 4']},
'Thu': {'exeter_twilight': ['40 e 4'],
'truro_twilight': ['4 t 4'],
'torquay_twilight': ['46 t 4'],
'plymouth_twilight': ['17 p 4'],
'weekend_exeter': [],
'weekend_truro': [],
'weekend_torquay': [],
'weekend_plymouth': [],
'night': ['24 p 4', '49 t 4', '51 t 4']},
'Fri': {'exeter_twilight': ['41 e 4'],
'truro_twilight': ['6 t 4'],
'torquay_twilight': ['53 t 4'],
'plymouth_twilight': ['25 p 4'],
'weekend_exeter': [],
'weekend_truro': [],
'weekend_torquay': [],
'weekend_plymouth': [],
'night': ['20 p 4', '49 t 4', '59 t 4']},
'Sat': {'exeter_twilight': [],
'truro_twilight': [],
'torquay_twilight': [],
'plymouth_twilight': [],
'weekend_exeter': ['32 e 4'],
'weekend_truro': ['11 t 4'],
'weekend_torquay': ['59 t 4'],
'weekend_plymouth': ['24 p 4', '28 p 4'],
'night': ['17 p 4', '51 t 4', '8 t 4']},
'Sun': {'exeter_twilight': [],
'truro_twilight': [],
'torquay_twilight': [],
'plymouth_twilight': [],
'weekend_exeter': ['44 e 4'],
'weekend_truro': ['3 t 4'],
'weekend_torquay': ['55 t 4'],
'weekend_plymouth': ['21 p 4', '27 p 4'],
'night': ['22 p 4', '25 p 4', '8 t 4']}},
13: {'Mon': {'exeter_twilight': ['43 e 4'],
'truro_twilight': ['14 t 4'],
'torquay_twilight': ['55 t 4'],
'plymouth_twilight': ['22 p 4'],
'weekend_exeter': [],
'weekend_truro': [],
'weekend_torquay': [],
'weekend_plymouth': [],
'night': ['32 e 4', '19 p 4', '58 t 4']},
'Tue': {'exeter_twilight': ['34 e 4'],
'truro_twilight': ['6 t 4'],
'torquay_twilight': ['51 t 4'],
'plymouth_twilight': ['26 p 4'],
'weekend_exeter': [],
'weekend_truro': [],
'weekend_torquay': [],
'weekend_plymouth': [],
'night': ['31 e 4', '45 t 4', '47 t 4']},
'Wed': {'exeter_twilight': ['43 e 4'],
'truro_twilight': ['12 t 4'],
'torquay_twilight': ['56 t 4'],
'plymouth_twilight': ['26 p 4'],
'weekend_exeter': [],
'weekend_truro': [],
'weekend_torquay': [],
'weekend_plymouth': [],
'night': ['36 e 4', '42 e 4', '52 t 4']},
'Thu': {'exeter_twilight': ['32 e 4'],
'truro_twilight': ['9 t 4'],
'torquay_twilight': ['49 t 4'],
'plymouth_twilight': ['29 p 4'],
'weekend_exeter': [],
'weekend_truro': [],
'weekend_torquay': [],
'weekend_plymouth': [],
'night': ['33 e 4', '58 t 4', '7 t 4']},
'Fri': {'exeter_twilight': ['32 e 4'],
'truro_twilight': ['10 t 4'],
'torquay_twilight': ['46 t 4'],
'plymouth_twilight': ['16 p 4'],
'weekend_exeter': [],
'weekend_truro': [],
'weekend_torquay': [],
'weekend_plymouth': [],
'night': ['38 e 4', '44 e 4', '56 t 4']},
'Sat': {'exeter_twilight': [],
'truro_twilight': [],
'torquay_twilight': [],
'plymouth_twilight': [],
'weekend_exeter': ['36 e 4'],
'weekend_truro': ['5 t 4'],
'weekend_torquay': ['53 t 4'],
'weekend_plymouth': ['16 p 4', '28 p 4'],
'night': ['35 e 4', '44 e 4', '26 p 4']},
'Sun': {'exeter_twilight': [],
'truro_twilight': [],
'torquay_twilight': [],
'plymouth_twilight': [],
'weekend_exeter': ['41 e 4'],
'weekend_truro': ['8 t 4'],
'weekend_torquay': ['46 t 4'],
'weekend_plymouth': ['22 p 4', '26 p 4'],
'night': ['28 p 4', '48 t 4', '49 t 4']}},
14: {'Mon': {'exeter_twilight': ['32 e 4'],
'truro_twilight': ['13 t 4'],
'torquay_twilight': ['53 t 4'],
'plymouth_twilight': ['18 p 4'],
'weekend_exeter': [],
'weekend_truro': [],
'weekend_torquay': [],
'weekend_plymouth': [],
'night': ['17 p 4', '28 p 4', '48 t 4']},
'Tue': {'exeter_twilight': ['42 e 4'],
'truro_twilight': ['14 t 4'],
'torquay_twilight': ['53 t 4'],
'plymouth_twilight': ['21 p 4'],
'weekend_exeter': [],
'weekend_truro': [],
'weekend_torquay': [],
'weekend_plymouth': [],
'night': ['20 p 4', '24 p 4', '28 p 4']},
'Wed': {'exeter_twilight': ['44 e 4'],
'truro_twilight': ['8 t 4'],
'torquay_twilight': ['45 t 4'],
'plymouth_twilight': ['16 p 4'],
'weekend_exeter': [],
'weekend_truro': [],
'weekend_torquay': [],
'weekend_plymouth': [],
'night': ['34 e 4', '53 t 4', '13 t 4']},
'Thu': {'exeter_twilight': ['41 e 4'],
'truro_twilight': ['13 t 4'],
'torquay_twilight': ['53 t 4'],
'plymouth_twilight': ['15 p 4'],
'weekend_exeter': [],
'weekend_truro': [],
'weekend_torquay': [],
'weekend_plymouth': [],
'night': ['32 e 4', '40 e 4', '20 p 4']},
'Fri': {'exeter_twilight': ['44 e 4'],
'truro_twilight': ['11 t 4'],
'torquay_twilight': ['45 t 4'],
'plymouth_twilight': ['21 p 4'],
'weekend_exeter': [],
'weekend_truro': [],
'weekend_torquay': [],
'weekend_plymouth': [],
'night': ['41 e 4', '42 e 4', '46 t 4']},
'Sat': {'exeter_twilight': [],
'truro_twilight': [],
'torquay_twilight': [],
'plymouth_twilight': [],
'weekend_exeter': ['42 e 4'],
'weekend_truro': ['7 t 4'],
'weekend_torquay': ['53 t 4'],
'weekend_plymouth': ['24 p 4', '26 p 4'],
'night': ['43 e 4', '19 p 4', '47 t 4']},
'Sun': {'exeter_twilight': [],
'truro_twilight': [],
'torquay_twilight': [],
'plymouth_twilight': [],
'weekend_exeter': ['40 e 4'],
'weekend_truro': ['9 t 4'],
'weekend_torquay': ['56 t 4'],
'weekend_plymouth': ['21 p 4', '23 p 4'],
'night': ['51 t 4', '57 t 4', '3 t 4']}},
15: {'Mon': {'exeter_twilight': ['37 e 4'],
'truro_twilight': ['4 t 4'],
'torquay_twilight': ['50 t 4'],
'plymouth_twilight': ['21 p 4'],
'weekend_exeter': [],
'weekend_truro': [],
'weekend_torquay': [],
'weekend_plymouth': [],
'night': ['22 p 4', '45 t 4', '9 t 4']},
'Tue': {'exeter_twilight': ['39 e 4'],
'truro_twilight': ['7 t 4'],
'torquay_twilight': ['54 t 4'],
'plymouth_twilight': ['23 p 4'],
'weekend_exeter': [],
'weekend_truro': [],
'weekend_torquay': [],
'weekend_plymouth': [],
'night': ['30 e 4', '36 e 4', '10 t 4']},
'Wed': {'exeter_twilight': ['34 e 4'],
'truro_twilight': ['10 t 4'],
'torquay_twilight': ['55 t 4'],
'plymouth_twilight': ['27 p 4'],
'weekend_exeter': [],
'weekend_truro': [],
'weekend_torquay': [],
'weekend_plymouth': [],
'night': ['36 e 4', '48 t 4', '12 t 4']},
'Thu': {'exeter_twilight': ['37 e 4'],
'truro_twilight': ['9 t 4'],
'torquay_twilight': ['52 t 4'],
'plymouth_twilight': ['15 p 4'],
'weekend_exeter': [],
'weekend_truro': [],
'weekend_torquay': [],
'weekend_plymouth': [],
'night': ['32 e 4', '38 e 4', '13 t 4']},
'Fri': {'exeter_twilight': ['33 e 4'],
'truro_twilight': ['2 t 4'],
'torquay_twilight': ['48 t 4'],
'plymouth_twilight': ['28 p 4'],
'weekend_exeter': [],
'weekend_truro': [],
'weekend_torquay': [],
'weekend_plymouth': [],
'night': ['43 e 4', '46 t 4', '54 t 4']},
'Sat': {'exeter_twilight': [],
'truro_twilight': [],
'torquay_twilight': [],
'plymouth_twilight': [],
'weekend_exeter': ['33 e 4'],
'weekend_truro': ['12 t 4'],
'weekend_torquay': ['45 t 4'],
'weekend_plymouth': ['19 p 4', '28 p 4'],
'night': ['36 e 4', '39 e 4', '48 t 4']},
'Sun': {'exeter_twilight': [],
'truro_twilight': [],
'torquay_twilight': [],
'plymouth_twilight': [],
'weekend_exeter': ['31 e 4'],
'weekend_truro': ['11 t 4'],
'weekend_torquay': ['56 t 4'],
'weekend_plymouth': ['17 p 4', '25 p 4'],
'night': ['21 p 4', '48 t 4', '54 t 4']}},
16: {'Mon': {'exeter_twilight': ['44 e 4'],
'truro_twilight': ['7 t 4'],
'torquay_twilight': ['55 t 4'],
'plymouth_twilight': ['27 p 4'],
'weekend_exeter': [],
'weekend_truro': [],
'weekend_torquay': [],
'weekend_plymouth': [],
'night': ['18 p 4', '21 p 4', '10 t 4']},
'Tue': {'exeter_twilight': ['36 e 4'],
'truro_twilight': ['12 t 4'],
'torquay_twilight': ['58 t 4'],
'plymouth_twilight': ['24 p 4'],
'weekend_exeter': [],
'weekend_truro': [],
'weekend_torquay': [],
'weekend_plymouth': [],
'night': ['22 p 4', '57 t 4', '7 t 4']},
'Wed': {'exeter_twilight': ['33 e 4'],
'truro_twilight': ['14 t 4'],
'torquay_twilight': ['48 t 4'],
'plymouth_twilight': ['25 p 4'],
'weekend_exeter': [],
'weekend_truro': [],
'weekend_torquay': [],
'weekend_plymouth': [],
'night': ['43 e 4', '57 t 4', '1 t 4']},
'Thu': {'exeter_twilight': ['34 e 4'],
'truro_twilight': ['6 t 4'],
'torquay_twilight': ['56 t 4'],
'plymouth_twilight': ['23 p 4'],
'weekend_exeter': [],
'weekend_truro': [],
'weekend_torquay': [],
'weekend_plymouth': [],
'night': ['41 e 4', '20 p 4', '10 t 4']},
'Fri': {'exeter_twilight': ['37 e 4'],
'truro_twilight': ['5 t 4'],
'torquay_twilight': ['49 t 4'],
'plymouth_twilight': ['19 p 4'],
'weekend_exeter': [],
'weekend_truro': [],
'weekend_torquay': [],
'weekend_plymouth': [],
'night': ['42 e 4', '43 e 4', '10 t 4']},
'Sat': {'exeter_twilight': [],
'truro_twilight': [],
'torquay_twilight': [],
'plymouth_twilight': [],
'weekend_exeter': ['40 e 4'],
'weekend_truro': ['10 t 4'],
'weekend_torquay': ['46 t 4'],
'weekend_plymouth': ['19 p 4', '25 p 4'],
'night': ['31 e 4', '5 t 4', '6 t 4']},
'Sun': {'exeter_twilight': [],
'truro_twilight': [],
'torquay_twilight': [],
'plymouth_twilight': [],
'weekend_exeter': ['37 e 4'],
'weekend_truro': ['10 t 4'],
'weekend_torquay': ['57 t 4'],
'weekend_plymouth': ['27 p 4', '29 p 4'],
'night': ['19 p 4', '28 p 4', '5 t 4']}}}In [102]:
#worker_night_blockIn [103]:
#[[worker, week, day, shift] for day in days for shift in ["night"]]In [104]:
1 if 4 in [4, 1, 0] else 0Out [104]:
1
In [105]:
(4 + 1) // 7Out [105]:
0
In [106]:
#for worker in workers:
# for shift in shifts:
# a = [model.works[worker.id, week, day, shift].value for week in weeks for day in days]In [107]:
a[0;31m---------------------------------------------------------------------------[0m [0;31mNameError[0m Traceback (most recent call last) [0;32m<ipython-input-107-3f786850e387>[0m in [0;36m<module>[0;34m[0m [0;32m----> 1[0;31m [0ma[0m[0;34m[0m[0;34m[0m[0m [0m [0;31mNameError[0m: name 'a' is not defined
In [108]:
0 % 7Out [108]:
0
In [109]:
-1 % 7Out [109]:
6
In [110]:
model.shift_count[(5, "night")].value[0;31m---------------------------------------------------------------------------[0m [0;31mNameError[0m Traceback (most recent call last) [0;32m<ipython-input-110-4d45c109f633>[0m in [0;36m<module>[0;34m[0m [0;32m----> 1[0;31m [0mmodel[0m[0;34m.[0m[0mshift_count[0m[0;34m[[0m[0;34m([0m[0;36m5[0m[0;34m,[0m [0;34m"night"[0m[0;34m)[0m[0;34m][0m[0;34m.[0m[0mvalue[0m[0;34m[0m[0;34m[0m[0m [0m [0;31mNameError[0m: name 'model' is not defined
In [111]:
[w.id for w in workers][0;31m---------------------------------------------------------------------------[0m [0;31mNameError[0m Traceback (most recent call last) [0;32m<ipython-input-111-2f761ca0465d>[0m in [0;36m<module>[0;34m[0m [0;32m----> 1[0;31m [0;34m[[0m[0mw[0m[0;34m.[0m[0mid[0m [0;32mfor[0m [0mw[0m [0;32min[0m [0mworkers[0m[0;34m][0m[0;34m[0m[0;34m[0m[0m [0m [0;31mNameError[0m: name 'workers' is not defined
In [ ]: