Notebook 3.6 - Shortest paths using PuLP

   

image.png

In [1]:
# Setting up

!pip install pulp --progress-bar off

from pulp import *

prob = LpProblem('prob', LpMinimize)
Requirement already satisfied: pulp in /Users/pan/anaconda3/lib/python3.7/site-packages (2.0)
Requirement already satisfied: pyparsing>=2.0.1 in /Users/pan/anaconda3/lib/python3.7/site-packages (from pulp) (2.4.7)
In [2]:
# Defining problem instance

N = ['A', 'B', 'C', 'D', 'E', 'F']

C = {'A': {'B': 5, 'C': 2}, 
     'B': {'C': 1, 'D': 4, 'E': 3}, 
     'C': {'D': 8}, 
     'D': {'E': 2, 'F': 2}, 
     'E': {'F': 4}}

D = {node: 1 if node is 'A' else -1 if node is 'F' else 0 for node in N}
In [3]:
# Preparing "tables"

E = [(i,j) for i in N for j in N if i in C.keys() if j in C[i].keys()]
In [4]:
# Declaring decision variables. 

x = LpVariable.dicts('x', E,  lowBound = 0, upBound = 1, cat = LpInteger)

PuLP does not have a built-in type for Boolean decision variables. To overcome this limitation we will be declaring our $x_{ij}$ variables as integers (using LpInteger), while constraining them to take values between 0 and 1.

In [5]:
# Declaring objectives

prob += lpSum([C[i][j]*x[i,j] for (i,j) in E])

for i in N:
    prob += (lpSum([x[i,j] for j in N if (i,j) in E]) 
             - lpSum([x[k,i] for k in N if (k,i) in E])) == D[i]
In [6]:
# Solving problem

status = prob.solve()

print(f'STATUS\n{LpStatus[status]}\n')

print('SOLUTION')
for v in prob.variables():
    print(v.name, '=', v.varValue)
STATUS
Optimal

SOLUTION
x_('A',_'B') = 1.0
x_('A',_'C') = 0.0
x_('B',_'C') = 0.0
x_('B',_'D') = 1.0
x_('B',_'E') = 0.0
x_('C',_'D') = 0.0
x_('D',_'E') = 0.0
x_('D',_'F') = 1.0
x_('E',_'F') = 0.0
In [7]:
import networkx as nx
from matplotlib import pyplot, collections
position = {'A': [0,0.5], 'B': [3,1], 'C': [3,0],'D': [7,0], 'E': [9, 1], 'F': [11,0]}
flow = [v.varValue*3 for v in prob.variables()]
G = nx.Graph()
G.add_nodes_from(N)
G.add_edges_from(E)
fig, ax = pyplot.subplots()
nx.draw(G, pos=position, with_labels=True)
lines = []
for (i,j) in E:
    lines.append([(position[i][0], position[i][1]),(position[j][0], position[j][1])])
lc = collections.LineCollection(lines, linewidth=flow, colors='r')
ax.add_collection(lc)
Out[7]:
<matplotlib.collections.LineCollection at 0x7f9e79c983d0>