You are on page 1of 44

Python for Prescriptive

Data Analytics

Dr. R K Jena
IMT, Nagpur
Assignment Problem
Assignment Problem is a combinatorial optimization problem.
Let there be n agents and n tasks. Any agent can be assigned to perform
any task, incurring some cost that may vary depending on the agent-task
assignment. It is required to perform all tasks by assigning exactly one
agent to each task and exactly one task to each agent in such a way that
the total cost of the assignment is minimized.

2
Solution : Hungarian Algorithm
The Hungarian algorithm, aka Munkres assignment algorithm, utilizes the following
theorem for polynomial runtime complexity (worst case O(n3)) and guaranteed
optimality.
Steps:
1. For each row of the matrix, find the smallest element and subtract it from every
element in its row.
2. Do the same (as step 1) for all columns.
3. Cover all zeros in the matrix using minimum number of horizontal and vertical
lines.
4. Test for Optimality: If the minimum number of covering lines is n, an optimal
assignment is possible and we are finished. Else if lines are lesser than n, we
haven’t found the optimal assignment, and must proceed to step 5.
5. Create additional zeros : Find the smallest element, call it c, that is not covered
by a line. Subtract c from all uncovered elements in the matrix and add it to any3
element that is covered twice. Go back to step 3.
Solution : Hungarian Algorithm
Example:

The optimal cost is 4000 + 2000 + 2500 = 8500

4
Examples
Example: You work as a manager for a chip manufacturer, and you
currently have 3 people on the road meeting clients. Your salespeople
are in Jaipur, Pune and Bangalore, and you want them to fly to three
other cities: Delhi, Mumbai and Kerala. The table below shows the cost
of airline tickets in INR between the cities:

• The question: where would you send each of your salespeople in


order to minimize fair?
5
Implementation Using Python
• from scipy.optimize import linear_sum_assignment
• cost = np.array([[2500, 4000, 3500], [4000, 6000,3500],
[2000,4000, 2500]])
• row_ind, col_ind = linear_sum_assignment(cost)
• print(“Column Index:”,col_ind)
• print(“Row Index:”,row_ind)
• Print ( “Optimal Value”, cost[row_ind, col_ind].sum())
6
Class Exercise

The workers are represented by nodes 1 through 3,


while the jobs are represented with nodes A, B and
C. The cost of assigning a worker to a job is shown
on each arc. The objective is to minimize the total
assignment cost. Again, the constraints can be seen
as flow conservation constraints. The first three
constraints state that each job is filled by exactly
one person, while the last three constraints state
that each person is assigned to exactly one job. The
variables should now take a value of 1 if worker i is
assigned to job j, and zero otherwise.
7
Dual Problem
For every linear program there is a dual linear program. The dual of
the standard maximum problem is defined to be the standard
minimum problem:

8
Dual Problem
• Why Duality???
Consider a farmer who may grow wheat and barley with
the set provision of some L land, F fertilizer and P
pesticide. To grow one unit of wheat, one unit of land, (F1)
units of fertilizer and (P1) units of pesticide must be used.
The primal problem would be the farmer deciding how
much wheat (x1) and barley (x2) to grow if their sell prices
are(S1) and (S2) per unit.
9
Dual Problem

10
Dual Problem
For the dual problem assume that y unit prices for each of
these means of production (inputs) are set by a planning
board. The planning board's job is to minimize the total cost
of procuring the set amounts of inputs while providing the
farmer with a floor on the unit price of each of his crops
(outputs), S1 for wheat and S2 for barley.

11
Dual Problem
Find numbers x1 and x2 that maximize the sum x1 + x2
subject to the constraints x1 ≥ 0, x2 ≥ 0, and

Minimize : 4*y1 + 12*y2 + y3


y1 + 4*y2 - y3 >= 1
2*y1 + 2*y2 + y3 >= 1
y1,y2,y3>=0 12
Dual Problem
• prob = LpProblem("Dual problem",LpMinimize)
• # nonnegativity constraints
• y1=LpVariable("y1",0)
• y2=LpVariable("y2",0)
• y3=LpVariable("y3",0)
• # objective function
• prob += 4*y1 + 12*y2 + y3, "Minimum value of 4*y1 + 12*y2 + y3"
• # main constraints
• prob += y1 + 4*y2 - y3 >= 1, "constraint 1"
• prob += 2*y1 + 2*y2 + y3 >= 1, "constraint 2"
13
Dual Problem
• # The problem is solved using PuLP's choice of Solver
• prob.solve()
• # status of the solution
• print("Status:", LpStatus[prob.status])
• for v in prob.variables():
• print(v.name, "=",
str(Fraction(v.varValue).limit_denominator()))
• # maximum value of the objective function
• print("min (4*y1 + 12*y2 + y3) =",
{str(Fraction(value(prob.objective)).limit_denominator())})
14
Python for Prescriptive
Data Analytics

Dr. R K Jena
IMT, Nagpur
Integer Programming
• Integer programming is like linear programming with an
additional allowance for some or all of the variables to be
integer values. While this may not seem like a large
improvement at LP, but it allows us to solve many problems that
could have remained unsolved using linear programming alone.
• Example :Knapsack problem
Given a set of items with assigned values and weights and are
asked to find the highest value combination of items which can
fit into given knapsack.
A linear programming model will not be able to solve this because there is no
way to express the idea that you can either put an item into your knapsack or
not, but you cannot put part of an item into your knapsack—every variable is
a continuous variable! 16
Integer Programming
• Example:

17
Integer Programming
• Example:

18
Integer Programming
• import pulp as pl
• # declare some variables
• # each variable is a binary variable that is either 0 or 1
• # 1 means the item will go into the knapsack
• a = pl.LpVariable("a", 0, 1, pl.LpInteger)
• b = pl.LpVariable("b", 0, 1, pl.LpInteger)
• c = pl.LpVariable("c", 0, 1, pl.LpInteger)
• d = pl.LpVariable("d", 0, 1, pl.LpInteger)
• # define the problem
• prob = pl.LpProblem("knapsack", pl.LpMaximize)
• # objective function - maximize value of objects in knapsack
• prob += 5 * a + 7 * b + 2 * c + 10 * d 19
Integer Programming
• # constraint - weight of objects cannot exceed 15
• prob += 2 * a + 4 * b + 7 * c + 10 * d <= 15
• status = prob.solve() # solve using the default solver, which is cbc
• print(pl.LpStatus[status]) # print the human-readable status
• # print the values
• print("a", pl.value(a))
• print("b", pl.value(b))
• print("c", pl.value(c))
• print("d", pl.value(d))
• Print Objective Value
• print("Objective = %f" % pl.value(prob.objective)) 20
Integer Programming
Example ( Staffing):
• Today, we will explore the problem of staffing in a factory.
As the manager of the factory, you will want to minimize
labor costs, but you want to ensure sufficient coverage for
every shift to meet production demand.

21
Integer Programming
Suppose you have five shifts with the following staffing demands:

Suppose you have the following workers:

22
Integer Programming
• import pulp as pl
• import collections as cl
• shift_requirements = [1, 4, 3, 5, 2]
• workers = {
• "Melisandre": {
• "availability": [0, 1, 4],
• "cost": 20
• },
• "Bran": {
• "availability": [1, 2, 3, 4],
• "cost": 15
• } , # create for all other workers’ 23
Integer Programming
• # Next define the model:
prob = pl.LpProblem("scheduling", pl.LpMinimize)
cost = []
vars_by_shift = cl.defaultdict(list)
for worker, info in workers.items():
for shift in info['availability']:
worker_var = pl.LpVariable("%s_%s" % (worker, shift), 0, 1, pl.LpInteger)
vars_by_shift[shift].append(worker_var)
cost.append(worker_var * info['cost'])
• # set the objective to be the sum of cost
prob += sum(cost) 24
Integer Programming
# set the shift requirements
for shift, requirement in enumerate(shift_requirements):
prob += sum(vars_by_shift[shift]) >= requirement
status = prob.solve()
print("Result:", pl.LpStatus[status])
results = []
for shift, vars in vars_by_shift.items():
results.append({
"shift": shift,
"workers": [var.name for var in vars if var.varValue == 1],
}) 25
Integer Programming
• #Showing Results
for result in sorted(results, key=lambda x: x['shift']):
print("Shift:", result['shift'], 'workers:', ', '.join (result['workers']))
# Print Objective Value
print("Objective = %f" % pl.value(prob.objective))

26
Python for Prescriptive
Data Analytics

Dr. R K Jena
IMT, Nagpur
TRANSHIPMENT PROBLEM
Objective: The objective of the transshipment problem is to determine
how many units should be shipped over each node so that all the
demand requirements are met with the minimum transportation cost.
Example:
Considering a company with its manufacturing facilities situated at two
places, Coimbatore and Pune. The units produced at each facility are
shipped to either of the company’s warehouse hubs located at Chennai
and Mumbai. The company has its own retail outlets in Delhi, Hyderabad,
Bangalore and Thiruvananthapuram. The network diagram representing
the nodes and transportation per unit cost is shown in Figure ( next Slide)

28
TRANSHIPMENT PROBLEM

Constraints:
1.The number of units shipped from Coimbatore <=800. Similarly the
number of unit shipped from Pune <=600
2.Demand: Pune-350, Hyderabad-200, Bangalore-400,
Thiruvanatapuram-450 29
TRANSHIPMENT PROBLEM

TP Cost

30
TRANSHIPMENT PROBLEM

• Let
xij be the number of units shipped from node i to node j,
x13 be the number of units shipped from Coimbatore to Chennai,
x24 be the number of units shipped from Pune to Mumbai, and so on

31
TRANSHIPMENT PROBLEM
Linear Programming formulation,
Minimize Z = 4x13+7x14+6x23+3x24+7x35+4x36+3x37+5x38+5x45+6x46+7x47+8x48
Subject to constraints

32
Solution
• from pulp import *
• # declare your variables
• x13=LpVariable("x13",0)
• x14=LpVariable("x14",0)
• x23=LpVariable("x23",0)
• x24=LpVariable("x24",0)
• x35=LpVariable("x35",0)
• x36=LpVariable("x36",0)
• x37=LpVariable("x37",0)
• x38=LpVariable("x38",0)
• x45=LpVariable("x45",0)
• x46=LpVariable("x46",0)
• x47=LpVariable("x47",0)
• x48=LpVariable("x48",0)
• # defines the problem
• prob = LpProblem("problem", LpMinimize) 33
Solution
• # defines the constraints
• prob += x13+x14 <=800
• prob += x23+x24 <=600
• prob += -x13-x23+x35+x36+x37+x38==0
• prob += -x14-x24+x45+x46+x47+x48==0
• prob += x35+x45 ==350
• prob += x36+x46 ==200
• prob += x37+x47 ==400
• prob += x38+x48 ==450
• # defines the objective function to minimize
• prob+=
4*x13+7*x14+6*x23+3*x24+7*x35+4*x36+3*x37+5*x38+5*x45+6*x4
6+7*x47+8*x48 34
Solution
• # solve the problem
• status = prob.solve()
• LpStatus[status]
• # print the results x1, x2, x3
• value(x13)
• value(x14)
• value(x23)
• value(x24)
• value(x35)
• value(x36)
• value(x37)
• value(x38)
• value(x45)
• value(x46)
• value(x47)
• value(x48)
• # Print the value of the objective
• print("Objective = %f" % value(prob.objective)) 35
Non-Linear Problem
•• Min
 

•S.t.

• + + + =50

This problem has a nonlinear objective that the optimizer attempts to
minimize. The variable values at the optimal solution are subject to (s.t.)
both equality (=40) and inequality (>25) constraints. The product of the
four variables must be greater than 25 while the sum of squares of the
variables must also equal 40. In addition, all variables must be between 1
and 5 and the initial guess is x1 = 1, x2 = 5, x3 = 5, and x4 = 1. 36
Non-Linear Problem
•For this problem determine:
• A potential feasible solution
• Identify the constraints on the contour plot
• Mark the set of feasible solutions on the contour
plot
• Identify the minimum objective feasible solution
• Identify the maximum objective feasible solution
• Use a nonlinear programming solver to find a
solution
37
Non-Linear Problem

38
Non-Linear Problem
• import numpy as np
• from scipy.optimize import minimize

• def objective(x):
return x[0]*x[3]*(x[0]+x[1]+x[2])+x[2]
• def constraint1(x):
return x[0]*x[1]*x[2]*x[3]-25.0

39
Non-Linear Problem
• def constraint2(x):
sum_eq = 40.0
for i in range(4):
sum_eq = sum_eq - x[i]**2
return sum_eq
• # initial guesses
•n = 4
• x0 = np.zeros(n)
• x0[0] = 1.0
• x0[1] = 5.0
• x0[2] = 5.0
• x0[3] = 1.0
40
Non-Linear Problem
• # show initial objective
• print('Initial SSE Objective: ' + str(objective(x0)))

# optimize
• b = (1.0,5.0)
• bnds = (b, b, b, b)
• con1 = {'type': 'ineq', 'fun': constraint1}
• con2 = {'type': 'eq', 'fun': constraint2}
• cons = ([con1,con2])
• solution =
minimize(objective,x0,method='SLSQP',bounds=bnds,constraints=co
ns) 41
Non-Linear Problem
• # show final objective
• print('Final SSE Objective: ' + str(objective(x)))
• # print solution
• print('Solution')
• print('x1 = ' + str(x[0]))
• print('x2 = ' + str(x[1]))
• print('x3 = ' + str(x[2]))
• print('x4 = ' + str(x[3]))
42
Class Exercise

3.9511649783 43
Thanks

44

You might also like