title: "Lecture 2: Introduction to Linear Programming" author: "Junaid Hasan" date: "June 23, 2021"¶

A sample problem¶

  • Jack wants to buy oranges and apples.

  • Suppose apples are priced at 3 dollars a pound and oranges at 4 dollars a pound.

  • Each pound of apples has 70 grams of protein while each pound of orange has 50 grams of protein.

  • A pound of apples has 50 grams of fiber while a pound of oranges has 60 grams of fiber.

  • He wants to have at least 100 grams of fiber and at least 50 grams of protein.

  • How much apples and oranges should he buy to minimize cost.

The Mathematical Model¶

  • Suppose Jack buys $x$ pounds of apples and $y$ pounds of oranges.
  • He wants to minimize $3x + 4y$.
  • However he must ensure that $70x + 50y \geq 50$ (protein requirement) and
  • that $50 x + 60 y \geq 60$ for the fiber requirement.

Discussion¶

  • What do you notice here?

Solution by hand¶

  • Lets plot something

(continued)..¶

In [1]:
from pyscipopt import Model
model = Model("Apple and Oranges")

x = model.addVar("x")
y = model.addVar("y")

model.addCons(70*x + 50*y >=50, "protein requirement")
model.addCons(50*x + 80*y >=60, "fiber requirement")

model.setObjective(3*x + 4*y, "minimize")

model.optimize()

if model.getStatus() == "optimal":
    print("Optimal value:", model.getObjVal())
    print("Solution:")
    print("  x = ", model.getVal(x))
    print("  y = ", model.getVal(y))
else:
    print("Problem could not be solved to optimaly")
Optimal value: 3.161290322580645
Solution:
  x =  0.3225806451612903
  y =  0.5483870967741935

Takeaways¶

  • The problem has a linear (objective function) max/min objective.
  • The constraints are linear as well.
  • Implicit non-negativity constraints.
  • Sometimes could be integer constraints (Integer LP).
  • This kind of problem is known as a Linear Programming Problem.
  • If you are interested in the history check out Wikipedia.

Standard Terminology¶

  • A problem of the form $$ \begin{aligned} \text{maximize/minimize } & c_1 x_1 + c_2 x_2 \cdots + c_n x_n\\ \text{subject to } & a_{1,1} x_1 + \cdots + a_{1,n}x_n \leq \text{(or)} \geq & b_1 \\ & a_{2,1} x_1 + \cdots + a_{2,n}x_n \leq \text{(or)} \geq & b_2 \\ & \vdots \\ & a_{m,1} x_1 + \cdots + a_{m,n}x_n \leq \text{(or)} \geq & b_m \\ & x_1, x_2, \ldots, x_n \geq 0 \end{aligned} $$

  • is called a standard linear programming problem.

Another Example: Transportation Problem¶

  • A sports equipment company XYZ has products manufactured at three factories(j =1,2,3) and delivered to five stores(i = 1,2,3,4,5). What to do to minimize cost.
  • Lets us draw the scenario

Transportation Problem contd.¶

  • As a table it is given by

Problem Formulation¶

  • Let $x_{ij}$ be the amount of goods transported from factory j to customer i.
  • Then can you write the optimization problem.

Answer:¶

  • $$ \begin{aligned} \text{minimize } & \sum_{i \in I}\sum_{j \in J} c_{ij}x_{ij}\\ \text{subject to demand } & \ \sum_{j \in J}x_{ij} = d_i & \forall i \in I\\ \text{ and factory capacity }& \sum_{i \in I}x_{ij} \leq M_j & \forall j \in J \\ & x_{ij} \geq 0 &\forall i \in I, j \in J \end{aligned} $$

Solution via code¶

  • We will use a special datatype in Python to our advantage. It is a dictionary(or arrays would work fine as well). It allows to specify the keys and the values at the keys {key1:value1, key2:value2, ...}
  • For demand demand = {1:80, 2:270, 3:250, 4:160, 5:180}
  • For capacity capacity = {1:500, 2:500, 3:500}
  • List(arrays in Python are called lists) of customers I = [1,2,3,4,5]
  • Factories J = [1,2,3]
  • Shipping cost would be a 2D array. We use dictionaries as cost = {(1,1):4, (1,2):6, (1,3):9 (2,1):5, (2,2):4, (2,3):7, (3,1):6, (3,2):3, (3,3):3, (4,1):8, (4,2):5, (4,3):3,
(5,1):10,
}
In [7]:
from pyscipopt import Model, quicksum

demand = {1:80, 2:270, 3:250, 4:160, 5:180}
capacity = {1:500, 2:500, 3:500}


I = [1,2,3,4,5]
J = [1,2,3]

cost = {(1,1):4,    (1,2):6,    (1,3):9,
     (2,1):5,    (2,2):4,    (2,3):7,
     (3,1):6,    (3,2):3,    (3,3):3,
     (4,1):8,    (4,2):5,    (4,3):3,
     (5,1):10,   (5,2):8,    (5,3):4,
     }
In [8]:
model = Model("transportation")
x = {}
for i in I:
    for j in J:
        x[i,j] = model.addVar(vtype="C", name="x(%s,%s)" % (i,j))

The quicksum function below is available in SCIP to sum over a for loop (iterator) and saves us a for loop

In [9]:
for i in I:
    model.addCons(quicksum(x[i,j] for j in J) == demand[i], name="Demand(%s)" % i)

for j in J:
    model.addCons(quicksum(x[i,j] for i in I) <= capacity[j], name="Capacity(%s)" % j)
In [10]:
model.setObjective(quicksum(cost[i,j]*x[i,j]  for (i,j) in x), "minimize")

model.optimize()
In [11]:
print("Optimal value:", model.getObjVal())

for (i,j) in x:
    print("sending quantity %10s from factory %3s to customer %3s" % (model.getVal(x[i,j]),j,i))
Optimal value: 3350.0
sending quantity       80.0 from factory   1 to customer   1
sending quantity        0.0 from factory   2 to customer   1
sending quantity        0.0 from factory   3 to customer   1
sending quantity        0.0 from factory   1 to customer   2
sending quantity      270.0 from factory   2 to customer   2
sending quantity        0.0 from factory   3 to customer   2
sending quantity        0.0 from factory   1 to customer   3
sending quantity      230.0 from factory   2 to customer   3
sending quantity       20.0 from factory   3 to customer   3
sending quantity        0.0 from factory   1 to customer   4
sending quantity        0.0 from factory   2 to customer   4
sending quantity      160.0 from factory   3 to customer   4
sending quantity        0.0 from factory   1 to customer   5
sending quantity        0.0 from factory   2 to customer   5
sending quantity      180.0 from factory   3 to customer   5

We can avoid the 0.0 by an if statement

In [13]:
"x%s" %1
Out[13]:
'x1'
In [12]:
print("Optimal value:", model.getObjVal())

for (i,j) in x:
    if model.getVal(x[i,j]) > 0.000001:
        print("sending quantity %10s from factory %3s to customer %3s" % (model.getVal(x[i,j]),j,i))
Optimal value: 3350.0
sending quantity       80.0 from factory   1 to customer   1
sending quantity      270.0 from factory   2 to customer   2
sending quantity      230.0 from factory   2 to customer   3
sending quantity       20.0 from factory   3 to customer   3
sending quantity      160.0 from factory   3 to customer   4
sending quantity      180.0 from factory   3 to customer   5