Linear programming in Python (2)

Share on:

Here's an example of a transportation problem, with information given as a table:

Demands
300 360 280 340 220
750 100 150 200 140 35
Supplies  400 50 70 80 65 80
350 40 90 100 150 130

This is an example of a balanced, non-degenerate transportation problem. It is balanced since the sum of supplies equals the sum of demands, and it is non-degenerate as there is no proper subset of supplies whose sum is equal to that of a proper subset of demands. That is, there are no balanced "sub-problems".

In such a problem, the array values may be considered to be the costs of transporting one object from a supplier to a demand. (In the version of the problem I pose to my students it's cars between distributors and car-yards; in another version it's tubs of ice-cream between dairies and supermarkets.) The idea of course is to move all objects from supplies to demands while minimizing the total cost.

This is a standard linear optimization problem, and it can be solved by any method used to solve such problems, although generally specialized methods are used.

But the intention here is to show how easily this problem can be managed using myMathProg (and with numpy, for the simple use of printing an array):

 1import pymprog as py
 2import numpy as np
 3py.begin('transport')
 4M = range(3)  # number of rows and columns
 5N = range(5)
 6A = py.iprod(M,N) # Cartesian product
 7x = py.var('x', A, kind=int) # all the decision variables are integers
 8costs = [[100,150,200,140,35],[50,70,80,65,80],[40,90,100,150,130]]
 9supplies = [750,400,350]
10demands = [300,360,280,340,220]
11py.minimize(sum(costs[i][j]*x[i,j] for i,j in A))
12# the total sum in each row must equal the supplies
13for k in M:
14    sum(x[k,j] for j in N)==supplies[k]
15# the total sum in each column must equal the demands
16for k in N:
17    sum(x[i,k] for i in M)==demands[k]
18py.solve()
19print('\nMinimum cost: ',py.vobj())
20A = np.array([[x[i,j].primal for j in N] for i in M])
21print('\n')
22print(A)
23print('\n')
24#py.sensitivity()
25py.end()

with solution:

 1GLPK Simplex Optimizer, v4.65
 2n8 rows, 15 columns, 30 non-zeros
 3      0: obj =   0.000000000e+00 inf =   3.000e+03 (8)
 4      7: obj =   1.789500000e+05 inf =   0.000e+00 (0)
 5*    12: obj =   1.311000000e+05 inf =   0.000e+00 (0)
 6OPTIMAL LP SOLUTION FOUND
 7GLPK Integer Optimizer, v4.65
 88 rows, 15 columns, 30 non-zeros
 915 integer variables, none of which are binary
10Integer optimization begins...
11Long-step dual simplex will be used
12+    12: mip =     not found yet >=              -inf        (1; 0)
13+    12: >>>>>   1.311000000e+05 >=   1.311000000e+05   0.0% (1; 0)
14+    12: mip =   1.311000000e+05 >=     tree is empty   0.0% (0; 1)
15INTEGER OPTIMAL SOLUTION FOUND
16
17Minimum cost:  131100.0
18
19[[  0. 190.   0. 340. 220.]
20 [  0. 120. 280.   0.   0.]
21 [300.  50.   0.   0.   0.]]

As you see, the definition of the problem in Python is very straightforward.