Operations 8 min read

Solving the Transshipment Problem with Python PuLP: A Step-by-Step Guide

This article explains the transshipment problem—a special case of transportation with intermediate warehouses—provides its mathematical formulation, defines indices, decision variables, parameters, objective function and constraints, and demonstrates a complete Python implementation using the PuLP library, including sample data and solution output.

Model Perspective
Model Perspective
Model Perspective
Solving the Transshipment Problem with Python PuLP: A Step-by-Step Guide

1. Transshipment Problem

In real life logistics companies often use warehouses as intermediate nodes before delivering to the final destination; this situation is called the transshipment problem.

The transshipment problem is a special case of the transportation problem where there are intermediate nodes in the transport path, e.g., shipping from A to B via C may be cheaper than direct shipping.

2. Case Study – Sand Transport

A sand company manager decides to use two intermediate nodes as temporary storage transshipment points. The network diagram is shown below.

The numbers on the arcs represent unit costs; the left and right sides of the diagram show the factories' supply and the project's demand for sand.

2.1 Indices

Set of factories

Set of warehouses

Set of projects

2.2 Decision Variables

Quantity shipped from a factory to a warehouse

Quantity shipped from a warehouse to a project

2.3 Parameters

Unit transportation cost from a factory to a warehouse

Unit transportation cost from a warehouse to a project

Maximum supply of each factory

Demand of each project

2.4 Objective Function

Minimize the total transportation cost, i.e., the sum of costs on all factory‑to‑warehouse and warehouse‑to‑project arcs.

2.5 Constraints

The total amount shipped out of each factory cannot exceed its maximum supply.

The amount received by each project must equal its demand.

The amount entering a warehouse must equal the amount leaving it.

2.6 Code Implementation

<code># Import PuLP modeler functions
from pulp import *
# Creates a list of all the supply nodes
factories = ["A", "B", "C"]
# Creates a dictionary for the number of units of supply for each supply node
supply = {"A": 100, "B": 200, "C":200}
# Creates a list of all demand nodes
projects = ["1", "2", "3"]
# Creates a dictionary for the number of units of demand for each demand node

demand = {
    "1": 50,
    "2": 150,
    "3": 300,
}
# Intermediate nodes
warehouses=["P","Q"]
# Creates a list of costs of each transportation path
costs_1 = [  # warehouses
    [3,2],  # A factories
    [4,3],  # B
    [2.5,3.5] # C
]
costs_2 = [  # projects
    [2,1,4],  # P warehouses
    [3,2,5],  # Q
]
# The cost data is made into a dictionary
costs_1 = makeDict([factories, warehouses], costs_1, 0)
# The cost data is made into a dictionary
costs_2 = makeDict([warehouses, projects], costs_2, 0)
# Creates the 'prob' variable to contain the problem data
prob = LpProblem("Material_Supply_Problem", LpMinimize)
# Creates a list of tuples containing all the possible routes for transport
Routes_1 = [(f, w) for f in factories for w in warehouses]
# A dictionary called 'Vars' is created to contain the referenced variables(the routes)
vars_1 = LpVariable.dicts("Route1", (factories, warehouses), 0, None, LpInteger)
# Creates a list of tuples containing all the possible routes for transport
Routes_2 = [(w, b) for w in warehouses for b in projects]
# A dictionary called 'Vars_2' is created to contain the referenced variables(the routes)
vars_2 = LpVariable.dicts("Route2", (warehouses, projects), 0, None, LpInteger)
# The objective function is added to 'prob' first
prob += (
    lpSum([vars_1[f][w] * costs_1[f][w] for (f, w) in Routes_1]) + lpSum([vars_2[w][b] * costs_2[w][b] for (w, b) in Routes_2]),
    "Sum_of_Transporting_Costs",
)
# The supply maximum constraints are added to prob for each supply node (factories)
for f in factories:
    prob += lpSum([vars_1[f][w] for w in warehouses]) <= supply[f], f"Sum_of_Products_out_of_factories_{f}"
# The demand minimum constraints are added to prob for each demand node (project)
for b in projects:
    prob += (
        lpSum([vars_2[w][b] for w in warehouses]) == demand[b],
        f"Sum_of_Products_into_projects_{b}",
    )
# Transshipment constraints: What is shipped into a transshipment node must be shipped out.
for w in warehouses:
    prob += (
        lpSum([vars_1[f][w] for f in factories]) - lpSum([vars_2[w][p] for p in projects]) == 0,
        f"Sum_of_Products_out_of_warehouse_{w}",
    )
# The problem is solved using PuLP's choice of Solver
prob.solve()
# Print the variables optimized value
for v in prob.variables():
    print(v.name, "=", v.varValue)
# The optimised objective function value is printed to the screen
print("Value of Objective Function = ", value(prob.objective))
</code>

2.7 Output Results

<code>Route1_A_P = 100.0
Route1_A_Q = 0.0
Route1_B_P = 200.0
Route1_B_Q = 0.0
Route1_C_P = 200.0
Route1_C_Q = 0.0
Route2_P_1 = 50.0
Route2_P_2 = 150.0
Route2_P_3 = 300.0
Route2_Q_1 = 0.0
Route2_Q_2 = 0.0
Route2_Q_3 = 0.0
Value of Objective Function =  3050.0
</code>

2.8 Summary

In this article we learned the transshipment problem, its mathematical formulation, and its implementation using Python's PuLP library to solve a linear programming model.

References

https://machinelearninggeek.com/transshipment-problem-in-python-using-pulp/

Pythonsupply chainLinear ProgrammingPuLPtransshipment
Model Perspective
Written by

Model Perspective

Insights, knowledge, and enjoyment from a mathematical modeling researcher and educator. Hosted by Haihua Wang, a modeling instructor and author of "Clever Use of Chat for Mathematical Modeling", "Modeling: The Mathematics of Thinking", "Mathematical Modeling Practice: A Hands‑On Guide to Competitions", and co‑author of "Mathematical Modeling: Teaching Design and Cases".

0 followers
Reader feedback

How this landed with the community

login Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.