Lecture 15: Python Programming

Lecture 15: Python Programming#

Note

In the previous lecture, we used spreadsheet-based methods to solve \(n\)-dimensional linear programming problems. In this lecture, we will explore Python libraries to tackle these problems more effectively.


Example #1#

Consider a textile firm operating in Kochi. This company needs to ship 100 tons of textile goods from Kanchipuram and can rent two types of trucks: \(\text{T}_1\) and \(\text{T}_2\). Each truck of type \(\text{T}_1\) can carry 10 tons of goods and costs ₹5000 per trip, while each truck of type \(\text{T}_2\) can carry 20 tons and costs ₹8000 per trip. Considering the managerial capacity of the firm (warehouse capacity, staff numbers, etc.), the management committee has imposed an upper limit on truck rental of 20 trucks in total, with a maximum of 12 any individual type of truck. Thus, all things considered, how many \(\text{T}_1\) and \(\text{T}_2\) type trucks should the company deploy so as to minimize the total costs?

Objective:

\[ \min_{x_1, x_2} \ z = 5000x_1 + 8000x_2 \]

Subject to:

\[\begin{split} \begin{aligned} 10x_1 + 20x_2 & \geq 100 \\ x_1 + x_2 & \leq 20 \\ x_1 & \leq 12 \\ x_2 & \leq 12 \\ x_1, x_2 & \in \mathbb{Z}_+ \end{aligned} \end{split}\]
import numpy as np
from scipy.optimize import linprog

# Cost Parameter
c = [5000, 8000]

# Constraint Parameter (Coefficients)
a = [[10, 20], [-1, -1], [-1, 0], [0, -1]]

# Constraint Parameter (Limits)
b = [100, -20, -12, -12]

# Domain Constraints
x1_bounds = (0, None)
x2_bounds = (0, None)
bounds = [x1_bounds, x2_bounds]
integrality = [1, 1]

# Solve
result = linprog(np.array(c), A_ub=-np.array(a), b_ub=-np.array(b), bounds=bounds, integrality=integrality, method='highs')
print(f"Optimal number of T1 trucks: {result.x[0]}, T2 trucks: {result.x[1]}")
print(f"Minimum Cost: {result.fun}")
Optimal number of T1 trucks: 0.0, T2 trucks: 5.0
Minimum Cost: 40000.0

Example #2#

The Southern Railways wants to start a new daily Vande-Bharat (VB) service between Chennai and Rameshwaram. However, the daily passenger demand is stochastic (uncertain) and follows a normal distribution – with a mean of 900 and standard deviation of 100 for the economy class, and a mean of 30 and standard deviation of 10 for the executive class. Note, the standard 78-capacity economy class coach amounts to ₹50,000 in daily operational costs and generates an average revenue of ₹750 per seat. On the other hand, the standard 52-capacity executive class coach amounts to ₹55,000 in daily operational costs and generates an average revenue of ₹2000 per seat. Assuming that a minimum of 16 coaches must be deployed, how many economy and executive coaches should the Southern Railways deploy in the VB so as to maximize the profits while maintaining a 95% service level (satisfying passenger demand on 95% of the days)?

Objective:

\[ \min_{x_1, x_2} \ z = 50000x_1 + 55000x_2 \]

Subject to:

\[\begin{split} \begin{aligned} 78x_1 & \geq 1064.5 \\ 52x_2 & \geq 46.4 \\ x_1 + x_2 & \geq 16 \\ x_1, x_2 & \in \mathbb{Z}_+ \end{aligned} \end{split}\]
import numpy as np
from scipy.optimize import linprog

# Cost Parameter
c = [50000, 55000]

# Constraint Parameter (Coefficients)
a = [[78, 0], [0, 52], [1, 1]]

# Constraint Parameter (Limits)
b = [1064.5, 46.4, 16]

# Domain Constraints
bounds = [(0, None), (0, None)]
integrality = [1, 1]

# Solve
result = linprog(np.array(c), A_ub=-np.array(a), b_ub=-np.array(b), bounds=bounds, integrality=integrality, method='highs')
print(f"Optimal number of economy class coach: {result.x[0]}, executive class coach: {result.x[1]}")
print(f"Maximum Profit: {1000 * 750 + 30 * 20000 - result.fun}")
Optimal number of economy class coach: 15.0, executive class coach: 1.0
Maximum Profit: 545000.0

Example #3#

Consider a public bus operator (government-owned) providing service between Chennai and Tirumala. Owing to the variation of demand through the day, the operator requires a different number of buses during different time periods of the day (see table below). Further, due to congestion, the operational costs of a bus – which include driver, fuel, and maintenance costs, also vary through the day (see table below). Note, to maintain a minimum level of service, the operator is regulated to not reduce service by more than 3 buses between any two consecutive time periods. Thus, how many buses should the operator run during different time periods so as to minimize the costs?

Time-period

Number of buses required

Operational cost

06 AM – 09 AM

20

₹1500

09 AM – 12 PM

15

₹900

12 PM – 03 PM

8

₹600

03 PM – 06 PM

10

₹800

06 PM – 09 PM

18

₹1400

09 PM – 12 AM

4

₹1000

Objective:

\[ \min_{\mathbf{x}} \ z = 1500x_1 + 900x_2 + 600x_3 + 800x_4 + 1400x_5 + 1000x_6 \]

Subject to:

\[\begin{split} \begin{aligned} x_1 & \geq 20 \\ x_2 & \geq 15 \\ x_3 & \geq 8 \\ x_4 & \geq 10 \\ x_5 & \geq 18 \\ x_6 & \geq 4 \\ x_1 - x_2 & \leq 3 \\ x_2 - x_3 & \leq 3 \\ x_3 - x_4 & \leq 3 \\ x_4 - x_5 & \leq 3 \\ x_5 - x_6 & \leq 3 \\ x_i & \in \mathbb{Z}_+ \ \forall \ i \end{aligned} \end{split}\]
import numpy as np
from scipy.optimize import linprog

# Cost Parameter
c = [1500, 900, 600, 800, 1400, 1000]

# Constraint Parameter (Coefficients)
a = [[1, 0, 0, 0, 0, 0], [0, 1, 0, 0, 0, 0], [0, 0, 1, 0, 0, 0], [0, 0, 0, 1, 0, 0], [0, 0, 0, 0, 1, 0], [0, 0, 0, 0, 0, 1],
     [-1, 1, 0, 0, 0, 0], [0, -1, 1, 0, 0, 0], [0, 0, -1, 1, 0, 0], [0, 0, 0, -1, 1, 0], [0, 0, 0, 0, -1, 1]]

# Constraint Parameter (Limits)
b = [20, 15, 8, 10, 18, 4, -3, -3, -3, -3, -3]

# Domain Constraints
bounds = [(0, None), (0, None), (0, None), (0, None), (0, None), (0, None)]
integrality = [1, 1, 1, 1, 1, 1]

# Solve
result = linprog(np.array(c), A_ub=-np.array(a), b_ub=-np.array(b), bounds=bounds, integrality=integrality, method='highs')
print(f"Optimal number of buses in each time period are: {result.x}")
print(f"Minimum Cost: {result.fun}")
Optimal number of buses in each time period are: [20. 17. 14. 11. 18. 15.]
Minimum Cost: 102700.0

Here again, the following problem is non-linear, we shall briefly explore use of Python programming language to address non-linear optimisation through this problem. However, later in this course, we will explore solution methods for non-linear optimisation problems in transportation engineering in more detail.

Example #4#

Consider a highway management firm that operates and maintains the expressway connecting Chennai with Bangalore. The highway management firm wants to set toll price \(p_1\) for private vehicles and \(p_2\) for commercial vehicles, to collect toll revenue on this highway. However, the National Highways Authority of India (NHAI) wants to facilitate sufficient flow between Chennai and Bangalore, ensuring that at least 1000 private and 1500 commercial vehicles each use the expressway during the peak hour. Note, the peak hour expressway traffic for private and commercial vehicles is subject to respective toll prices, and is given by \(Q_1(p_1)\) and \(Q_2(p_2)\), respectively. Nonetheless, the NHAI also wants to ensure sufficient tax collection, requiring toll price to at least be ₹150. Considering these regulations, what toll prices should the firm set so as to maximize the toll revenue?

Obective:

\[ \max_{p_1, p_2} \ z = p_1 (5000 - 20p_1) + p_2 \left(6000 - 0.05p_2^2 \right) \]

Subject to:

\[\begin{split} \begin{aligned} 5000 - 20p_1 & \geq 1000 \\ 6000 - 0.05p_2^2 & \geq 1500 \\ p_1 & \geq 150 \\ p_2 & \geq 150 \\ p_1, p_2 & \in \mathbb{Z}_+ \end{aligned} \end{split}\]
from scipy.optimize import minimize

# Objective function
def toll_revenue(x):
    p1, p2 = x
    return -(p1 * (5000 - 20 * p1) + p2 * (6000 - 0.05 * p2 ** 2))

# Constraints
constraints = [
    {"type": "ineq", "fun": lambda x: 5000 - 20 * x[0] - 1000},
    {"type": "ineq", "fun": lambda x: 6000 - 0.05 * x[1] ** 2 - 1500},
    {"type": "ineq", "fun": lambda x: x[0] - 150},
    {"type": "ineq", "fun": lambda x: x[1] - 150}
]

# Initial guess
initial_guess = [200, 200]

# Solve the nonlinear program
result = minimize(toll_revenue, initial_guess, constraints=constraints)
p1_opt, p2_opt = result.x
print(f"Optimal toll price for private vehicles: ₹{p1_opt}")
print(f"Optimal toll price for commercial vehicles: ₹{p2_opt}")
print(f"Maximum Toll Revenue: ₹{-result.fun}")
Optimal toll price for private vehicles: ₹149.99999999991076
Optimal toll price for commercial vehicles: ₹200.0
Maximum Toll Revenue: ₹1100000.0000000892

Note

The computational tools discussed in the recent lectures deploy the Simplex Algorithm in the backend to solve the linear optimisation problems. In the next few lectures we shall discuss this Simplex Algorithm in more detail to develop fundamental knowledge on how to solve the \(n\)-dimensional linear problems.