-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathtalent-cp.py
97 lines (92 loc) · 4.23 KB
/
talent-cp.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
# this script models a talent scheduling problem from Cplex Stuodio Tutorial, refer the attached pdf
# author: oddo z
from ortools.sat.python import cp_model
def createModel():
numActors = 5
actors = range(numActors)
numScenes = 9
scenes = range(numScenes)
sceneDuration = [2,4,1,3,3,2,5,7,6]
actorPay = [1,1,1,1,1]
actorInScene =[[1, 1, 0, 1, 0, 1, 1, 0, 1],
[1, 1, 0, 1, 1, 1, 0, 1, 0],
[1, 1, 0, 0, 0, 0, 1, 1, 0],
[1, 0, 0, 0, 1, 1, 0, 0, 1],
[0, 0, 1, 0, 1, 1, 1, 1, 0]];
model = cp_model.CpModel()
sceneVars = []
slotVars = []
for scene in scenes:
suffix = 'slot of scene' + str(scene)
# define the slot for each scene
sceneVar = model.NewIntVar(0,numScenes-1,name=suffix)
sceneVars.append(sceneVar)
suffix = 'scene id for slot '+str(scene)
slotVar = model.NewIntVar(0, numScenes-1, name= suffix)
slotVars.append(slotVar)
firstSlots = []
lastSlots = []
waitTimes = []
for actor in actors:
suffix = 'first slot of actor '+str(actor)
firstVar = model.NewIntVar(0, numScenes-1, name=suffix)
firstSlots.append(firstVar)
suffix= 'last slot of actor' + str(actor)
lastVar = model.NewIntVar(0, numScenes-1,name=suffix)
lastSlots.append(lastVar)
suffix = 'wait time of actor' + str(actor)
waitVar = model.NewIntVar(0,1000,name=suffix)
waitTimes.append(waitVar)
# first add inverse constraint
model.AddInverse(sceneVars,slotVars)
# define the first slot var and lost slot var
for actor in actors:
scenesIn = []
for scene in scenes:
if actorInScene[actor][scene] == 1:
scenesIn.append(slotVars[scene])
# this is the slot number for each scene, not the scene number in each slot
model.AddMinEquality(firstSlots[actor], scenesIn)
model.AddMaxEquality(lastSlots[actor], scenesIn)
# define the wait time
waitExper = {}
for actor in actors:
waitExper[actor] = []
for scene in scenes:
if actorInScene[actor][scene] == 1: continue
# this is how to use bools to define constraints under different variable values
# must consider all possible scenarios, only one scenario will happen. So every scenario has a bool
# the sum of the bools is 1
waitSlot = model.NewBoolVar(name='between first and second for actor_%i at slot %i' % (actor, scene))
waitExper[actor].append ((waitSlot, sceneDuration[scene]))
# if waitSlot is True, the slot of the scene is between the frist and last
model.Add(slotVars[scene] >= firstSlots[actor]).OnlyEnforceIf(waitSlot)
model.Add(slotVars[scene] <= lastSlots[actor]).OnlyEnforceIf(waitSlot)
# if waitSlot is False, the slot of this scene is outside, either before first or after last, need two new bools to consider each scenario
afterLast = model.NewBoolVar(name='after last for actor_%i' % (actor))
beforeFirst = model.NewBoolVar(name='before first for actor _%i' % (actor))
# only one of these bools will be true
model.Add(waitSlot + afterLast + beforeFirst== 1)
model.Add(slotVars[scene] <= firstSlots[actor] -1).OnlyEnforceIf(beforeFirst)
model.Add(slotVars[scene] >= lastSlots[actor] +1).OnlyEnforceIf(afterLast)
# get total wait time for each actor
for actor in actors:
model.Add(sum(wait[0]*wait[1] for wait in waitExper[actor]) == waitTimes[actor])
# get objective
obj = model.NewIntVar(0,100000,name='obj')
model.Add(sum(actorPay[actor] * waitTimes[actor] for actor in actors)==obj)
model.Minimize(obj)
solver = cp_model.CpSolver()
solver.parameters.linearization_level = 0
status = solver.Solve(model)
print(status)
if status == cp_model.OPTIMAL:
print('total cost is', solver.Value(obj))
print('slot for each scene:')
for scene in scenes:
s = ("scene {} is at slot {}".format(scene, solver.Value(sceneVars[scene])))
print(s)
for scene in scenes:
s = ("slot {} is doing scene {}".format(scene, solver.Value(slotVars[scene])))
print(s)
createModel()