-
Notifications
You must be signed in to change notification settings - Fork 1
Expand file tree
/
Copy pathProjectPlanning.py
More file actions
201 lines (151 loc) · 8.56 KB
/
Copy pathProjectPlanning.py
File metadata and controls
201 lines (151 loc) · 8.56 KB
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
# -*- coding: utf-8 -*-
"""
Created on Fri Mar 20 04:04:17 2020
@author: karth
"""
# Importing relevant packages
from ortools.sat.python import cp_model
import pandas as pd
# Reading Data from the files
projects_data = pd.read_excel("Assignment_DA_1_data.xlsx", sheet_name = "Projects", index_col=0)
projects = projects_data.index.tolist()
print(projects)
months = projects_data.columns.tolist()
print(months)
contractors_data = pd.read_excel("Assignment_DA_1_data.xlsx", sheet_name = "Quotes", index_col=0)
contractors = contractors_data.index.tolist()
print(contractors)
dependencies_data = pd.read_excel("Assignment_DA_1_data.xlsx", sheet_name = "Dependencies", index_col = 0 )
value_data = pd.read_excel("Assignment_DA_1_data.xlsx", sheet_name = "Value", index_col = 0 )
values = value_data['Value'].tolist()
print(values)
jobs = contractors_data.columns.tolist()
print(jobs)
# Initializing Solution Printer
class SolutionPrinter(cp_model.CpSolverSolutionCallback):
def __init__(self, projects_taken , contractors_project , t):
cp_model.CpSolverSolutionCallback.__init__(self)
self.projects_taken_ = projects_taken
self.contractors_project_ = contractors_project
self.profit_margin_ = t
self.__solution_count = 0
def on_solution_callback(self):
self.__solution_count += 1
print("Solution {} Profit Margin: {}".format(self.__solution_count,self.Value(self.profit_margin_)))
for p in range(len(projects)):
if self.Value(self.projects_taken_[p]):
print("{} is Taken".format(projects[p]))
print("______________________\n")
else:
print("{} not taken".format(projects[p]))
print("______________________\n")
for m in range(len(months)):
for c in range(len(contractors)):
if self.Value(self.contractors_project_[(p,m,c)]):
print("{} , {} done by {}\n".format(months[m],projects_data.loc[projects[p]][months[m]], contractors[c]))
# solution_df.loc[projects[p]][months[m]] = contractors[c]
#
print()
def solution_count(self):
return self.__solution_count
def main():
model = cp_model.CpModel()
########################################### Task A ##########################################
########## Contractor Skill set ###########################################
#Creating a dictionary of contractor as key and jobs the contractor can do as values
contractors_skill_set = {}
for ind in contractors_data.index:
skills = []
for col in contractors_data.columns:
if pd.notnull(contractors_data.loc[ind][col]):
skills.append(col)
contractors_skill_set[ind] = skills
# print(contractors_skill_set)
####################################### Task B #################################################
########## Creating decision Variables ###################################
# (i) Decision Variable for deciding to take a project or not
projects_taken = {}
for p in range(len(projects)):
projects_taken[p] = model.NewBoolVar("P{}".format(projects[p].split(" ")[1]))
# (ii) Decision Variable for deciding which contractor is working on which project and when
# Considered only if the Contractor is skilled to work on that particular job of the project
# Considered that all projects does not run on all months
contractor_project = {}
for p in range(len(projects)):
for m in range(len(months)):
for c in range(len(contractors)):
#Creation of boolVar for every combination of project,month and contractor
contractor_project[(p,m,c)] = model.NewBoolVar('p%i_m%i_c%i'%(p,m,c))
#Adding the constraint that if the job is in the skill set of the contractor then the boolVar
# Can have True or False.
if projects_data.loc[projects[p]][months[m]] in contractors_skill_set[contractors[c]]:
model.Add(contractor_project[(p,m,c)] <=1)
# Else the combination of the
else:
model.Add(contractor_project[(p,m,c)] == 0)
######################################## Task C ######################################################
# Constraint that Contractor cannot work on two projects simultaneously
for c in range(len(contractors)):
for m in range(len(months)):
model.Add( sum( contractor_project[(p,m,c)] for p in range(len(projects))) <=1 )
#
######################################## Task D ######################################################
# #Constraint : if a project is accepted to be delivered then exactly one contractor per job of the project needs to work on it
for p in range(len(projects)):
for m in range(len(months)):
if pd.notnull(projects_data.loc[projects[p]][months[m]]):
model.Add( sum( contractor_project[(p,m,c)] for c in range(len(contractors))) == 1 ).OnlyEnforceIf(projects_taken[p])
######################################### Task E #####################################################
#Constraint: If a project is not taken then none of the jobs should be taken by any contractor
for p in range(len(projects)):
for m in range(len(months)):
model.Add(sum(contractor_project[(p,m,c)] for c in range(len(contractors))) == 0 ).OnlyEnforceIf(projects_taken[p].Not())
# #################################### Task F #########################################################
# creating project dependencies
project_dependency = {}
for project in projects:
variables = {}
for p2 in projects:
variables[p2] = model.NewBoolVar(project+p2)
project_dependency[project] = variables
# Setting the project dependency Constraints
for i in range(len(projects)):
for j in range(len(projects)):
if dependencies_data[projects[i]][projects[j]] == "x":
model.AddBoolAnd([project_dependency[projects[i]][projects[j]]])
else:
model.AddBoolAnd([project_dependency[projects[i]][projects[j]].Not()])
# Adding Constraint that a particular project can be taken only if the dependency is satisfied
for i in range(len(projects)):
for j in range(len(projects)):
model.AddBoolAnd([projects_taken[i]]).OnlyEnforceIf([project_dependency[projects[i]][projects[j]]])
##################################### Task G #########################
#Calculating the total value of all the projects
value_of_all_projects_delivered = []
for i in range(len(projects)):
value_of_all_projects_delivered.append(projects_taken[i]*values[i])
total_value = sum(value_of_all_projects_delivered)
#Calculating the cost involved for each solution
cost = []
for p in range(len(projects)):
for c in range(len(contractors)):
for m in range(len(months)):
if pd.notnull(projects_data.loc[projects[p]][months[m]]):
job = str(projects_data.loc[projects[p]][months[m]])
if pd.notnull(contractors_data.loc[contractors[c]][job]) and projects_taken[p]:
cost.append(contractor_project[(p,m,c)]* int(contractors_data.loc[contractors[c]][job]))
total_cost = sum(cost)
# Adding the constraint that the profit margin should atleast be 2500
profit_margin = total_value - total_cost
model.Add(profit_margin >= 2500)
# Creating a new variable to pass it to the solution printer
t = model.NewIntVar(0,sum(values), 't')
model.Add(t == profit_margin)
################################## Task H #######################################################
#### Solution Printer ####
solver = cp_model.CpSolver()
solution_printer = SolutionPrinter(projects_taken, contractor_project, t)
solver.SearchForAllSolutions(model, solution_printer)
print('Number of solutions found: %i' %(solution_printer.solution_count()))
#
main()