-
Notifications
You must be signed in to change notification settings - Fork 3
/
schedule_csp.py
218 lines (163 loc) · 7.35 KB
/
schedule_csp.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
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
'''
Construct and return a Schedule CSP model.
'''
from cspbase import *
import math
import itertools
'''
return a csp object of the schedule problem, a list of variables.
profs - dictionary
key: prof name;
value: availability of the prof;
students - dictionary
key: student name;
value[0]: student preferred prof name;
value[1]: availability of the student;
'''
def schedule_csp_model(profs, students, locations, distance):
# CREATE THE VARIABLES
var_array = []
for student in students:
availabilities = students[student][1]
# create the domain of each student
# free time of the student will be saved, time is separated by 1 hour.
dom = []
for start,finish in availabilities:
dom.extend(list(range(start,finish,1)))
# create the variable for student.prof
for prof in students[student][0]:
# restrict the domain given the prof availability
final_dom = set(dom)
prof_avail = set()
# time availability for each prof preferred by the student
for start,finish in profs[prof]:
prof_avail.update(list(range(start,finish,1)))
# the intersection of availabilities between the prof and the student
final_dom = final_dom & set(prof_avail)
# probably want to do something else then exiting
if len(final_dom) == 0:
print("{} can never meet {}!".format(student,prof))
exit()
name = '{}.{}'.format(student, prof)
var_array.append(Variable(name,student,prof,list(final_dom)))
constraints = []
# CREATE THE CONSTRAINTS [(1) - PROF CAN ONLY MEET 1 STUDENT PER HOUR]
# construct the binary constraint of each student pair
for i,student in enumerate(var_array):
for student2 in var_array[i+1:]:
if student.prof_name == student2.prof_name:
# construct the tuples for the constraint
sat_tuples = []
for v1,v2 in itertools.product(student.dom,student2.dom):
if v1 != v2:
sat_tuples.append((v1,v2))
# construct the constraint
name = "prof_diff({},{})".format(student.name,student2.name)
con = Constraint(name, [student, student2])
con.add_satisfying_tuples(sat_tuples)
constraints.append(con)
# CREATE THE CONSTRAINTS [(2) - STUDENT CAN ONLY MEET 1 PROF PER HOUR]
for i,student in enumerate(var_array):
for student2 in var_array[i+1:]:
if student.stud_name == student2.stud_name:
# construct the tuples for the constraint
sat_tuples = []
for v1,v2 in itertools.product(student.dom,student2.dom):
if v1 != v2:
sat_tuples.append((v1,v2))
# construct the constraint
name = "student_diff({},{})".format(student.name,student2.name)
con = Constraint(name, [student, student2])
con.add_satisfying_tuples(sat_tuples)
constraints.append(con)
# CREATE THE CONSTRAINTS [(3) - STUDENT TRAVEL TIME BETWEEN PROFS]
for i,student in enumerate(var_array):
for student2 in var_array[i+1:]:
if student.stud_name == student2.stud_name:
# the commute time in hours
c_time = get_commute_time(student.prof_name, student2.prof_name, locations, distance)
c_time = c_time + 1
# construct the tuples for the constraint
sat_tuples = []
for v1,v2 in itertools.product(student.dom,student2.dom):
if abs(v1 - v2) >= c_time:
sat_tuples.append((v1,v2))
# construct the constraint
name = "travel({},{})".format(student.name,student2.name)
con = Constraint(name, [student, student2])
con.add_satisfying_tuples(sat_tuples)
constraints.append(con)
# CONSTRUCT THE SCHEDULING CSP
schedule_csp = CSP("SCHEDULE")
for var in var_array:
schedule_csp.add_var(var)
for con in constraints:
schedule_csp.add_constraint(con)
return schedule_csp,var_array
'''
Calculate the travle time between the locations of two professors
@param prof1 professor
prof2 professor
locations locations read from locations file
distance distance read from distance file
return time it takes to travel between prof1 and prof2
'''
def get_commute_time(prof1,prof2,locations,distance):
prof1_loc = locations[prof1][0]
prof2_loc = locations[prof2][0]
d = distance[(prof1_loc,prof2_loc)]
# distance is short enough
if d < 800:
return 0
else:
# 15000m is the regular walking distance.
return math.ceil(d/15000)
'''
Print the solution in a nicer format.
(Student C is assigned to see Prof D at 12am to 1pm)
example: Var--Student C.Prof D = 12am to 1pm
'''
def print_soln(var_array):
for var in var_array:
start = var.get_assigned_value()
if not start:
print("No Solution Found")
return
end = start + 1
if start > 12: start = "{}pm".format(start - 12)
elif start == 12: start = "{}pm".format(start)
else: start = "{}am".format(start)
if end > 12: end = "{}pm".format(end - 12)
elif end == 12: end = "{}pm".format(end)
else: end = "{}am".format(end)
print("{} = {} to {}".format(var,start,end))
'''
Print the schedule with the solution of each student has been assigned to
see his preferred professor in both his and the professor's free time.
'''
def print_table(var_array):
#print(len(var_array))
#print("\t\t| 9am to 10am |\t10am to 11am\t|\t11am to 12pm\t| \t12pm to 1pm\t|\t1pm to 2pm\t|\t2pm to 3pm\t|\t3pm to 4pm\t|\t4pm to 5pm\t|")
print('\t\t|{:^20}|{:^20}|{:^20}|{:^20}|{:^20}|{:^20}|{:^20}|{:^20}'.format\
('9am to 10am','10am to 11am','11am to 12pm','12pm to 1pm',\
'1pm to 2pm','2pm to 3pm','3pm to 4pm','4pm to 5pm'))
print("-"*190) #printing the header
profs = set()
for v in var_array:
profs.add(v.prof_name)
d = [" "+"-"*18+" "] #print dash for empty slot
s = [" "*20 ]#print space for empty slot
time_slot = dict()
for prof in profs:
time_slot[prof] = s * 8
map_time = { i+9:i for i in range(8)}
for v in var_array: #filling up the table
name = v.prof_name
value = v.get_assigned_value()
display_name = '{:^20.20}'.format(v.stud_name)
time_slot[name][map_time[value]]= display_name
for prof in sorted(profs) :
print('{:<15.15}'.format(prof),end=" :") #printing the table
for t in time_slot[prof]:
print(t,end="|")
print()