Tutorial 2 Solutions

Question 1

With precisely 2700 sq. cm. of cardboard, you wish to construct a box (width: \(x\), depth: \(y\), height: \(z\)) containing a volume \(V\). You require the width to double its depth. You would like to maximise the volume of the box. Which values of \(x, y, z\) will maximise the volume?

  1. Construct the objective function and constraints:

\[ \begin{aligned} \max\; &f(x,y,z) = xyz \\ \text{st:} \quad &x = 2y \\ &2(xy + xz + yz) = 2700 \\ &x, y, z \ge 0 \end{aligned} \]

  Convert the maximisation problem to a minimisation problem in the standard form:

\[ \begin{aligned} \min\; &f(x,y,z) = -xyz \\ \text{st:} \quad &x - 2y = 0 \\ &2(xy + xz + yz) - 2700 = 0 \\ &-x, -y, -z \le 0 \end{aligned} \]

  1. Set up a Lagrangian function

\[ \begin{aligned} L(x,y,z,\lambda_1,\lambda_2,\mu_1, \mu_2, \mu_3) = xyz &+ \lambda_1(2(xy + xz + yz) - 2700) \\ &+ \lambda_2(x-2y) \\ &+ \mu_1 x + \mu_2 y +\mu_3 z \end{aligned} \]

Since the optimum has \(x,y,z>0,\) the non-negativity constraints are not binding, so \(\mu_1=\mu_2=\mu_3=0\). Therefore,

\[ \begin{aligned} L(x,y,z,\lambda_1,\lambda_2,\mu_1, \mu_2, \mu_3) = xyz &+ \lambda_1(2(xy + xz + yz) - 2700) \\ &+ \lambda_2(x-2y) \end{aligned} \]

From this, KKT’s dual feasibility and complementary slackness conditions are satisfied, so we can proceed to the stationarity and primal feasibility conditions.

  1. KKT’s stationarity

Solve for partial derivatives and set them equal to 0:

\[ \begin{aligned} L_x &= yz - 2\lambda_1(y+z) - \lambda_2 + \mu_1 = 0 \\ L_y &= xz - 2\lambda_1(x+z) + 2\lambda_2 + \mu_2 = 0 \\ L_z &= xy - 2\lambda_1(x+y) + \mu_3 = 0 \\ L_{\lambda_1} &= 2(xy + xz + yz) - 2700 = 0 \\ L_{\lambda_2} &= x - 2y = 0 \\ \end{aligned} \]

From \(L_{\lambda_2}\),

\[ x = 2y \]

From \(L_{\lambda_1}\), substitute \(x=2y\):

\[ 2(2y^2+2yz+yz)=2700 \]

\[ 4y^2+6yz=2700 \]

Solve for \(z\):

\[ z=\frac{2700-4y^2}{6y}= \frac{450}{y}-\frac{2y}{3} \]

Volume:

\[ V=xyz=(2y)(y)(z)=2y^2z \]

Substitute \(z\):

\[ V(y)=2y^2\left(\frac{450}{y}-\frac{2y}{3}\right) =900y-\frac{4}{3}y^3 \]

Differentiate and set it equal to 0:

\[ \begin{aligned} V'(y)=900-4y^2&=0 \\ y^2&=225 \\ y&=15 \end{aligned} \]

Then:

\[ x=2y=30 \]

\[ z=\frac{450}{15}-\frac{2(15)}{3}=30-10=20 \]

So the optimal dimensions are:

\[ \boxed{x=30,\quad y=15,\quad z=20} \]

  1. Verify KKT’s primal feasibility

Substitute the optimal dimensions into the constraints \(L_{\lambda_1}\) and \(L_{\lambda_2}\):

\[ L_{\lambda_1} = 2(2(15)^2+2(15)(20)+(15)(20)) - 2700 = 0 \quad \text{(Satisfied)} \]

\[ L_{\lambda_2} = 30 - 2(15) = 0 \quad \text{(Satisfied)} \]

  1. Calculate the maximum volume

\[ V=30(15)(20)=\boxed{9000\text{ cm}^3} \]

import sympy as sp

# Variables
x, y, z = sp.symbols("x y z", positive=True)
lambda1, lambda2 = sp.symbols("lambda1 lambda2")

# Objective and constraints
V = x * y * z
g1 = 2 * (x*y + x*z + y*z) - 2700
g2 = x - 2*y

# Lagrangian
L = V - lambda1 * g1 - lambda2 * g2

# First-order conditions
equations = [
    sp.diff(L, x),
    sp.diff(L, y),
    sp.diff(L, z),
    g1,
    g2,
]

solution = sp.solve(
    equations,
    [x, y, z, lambda1, lambda2],
    dict=True
)

print("Solutions:")
for sol in solution:
    print(sol)

# Keep positive real solution
positive_solutions = [
    sol for sol in solution
    if sol[x].is_real and sol[y].is_real and sol[z].is_real
    and sol[x] > 0 and sol[y] > 0 and sol[z] > 0
]

best = max(positive_solutions, key=lambda sol: V.subs(sol))

print("\nOptimal dimensions:")
print(f"x = {sp.simplify(best[x])} = {float(best[x]):.4f} cm")
print(f"y = {sp.simplify(best[y])} = {float(best[y]):.4f} cm")
print(f"z = {sp.simplify(best[z])} = {float(best[z]):.4f} cm")

print("\nMaximum volume:")
print(f"V = {sp.simplify(V.subs(best))} = {float(V.subs(best)):.4f} cubic cm")
Solutions:
{lambda1: 5, lambda2: -50, x: 30, y: 15, z: 20}

Optimal dimensions:
x = 30 = 30.0000 cm
y = 15 = 15.0000 cm
z = 20 = 20.0000 cm

Maximum volume:
V = 9000 = 9000.0000 cubic cm

Question 2

A manufacturing facility produces four types of wood panelling: Tahoe, Pacific, Savannah, and Aspen. Each product is manufactured using pine chips and oak chips and requires both gluing and pressing processes.

The profit earned per pallet is as follows:

  • $450 for Tahoe,
  • $1140 for Pacific,
  • $800 for Savannah, and
  • $400 for Aspen.

The factory operates under limited resource availability. During the planning period, there are 5,800 quarts of glue available, 730 pressing machine hours, and 29,200 pounds of pine chips. In addition, the supply of oak chips is limited to a fixed total amount.

Tahoe Pacific Savannah Aspen Capacity
Glueing (quarts) 50 50 100 50 5800 quarts
Pressing (hours) 5 15 10 5 730 hours
Pine chips (pounds) 500 400 300 200 29200 pounds
Oak chips (pounds) 500 750 250 500 60500 pounds
Profit per pallet ($) 450 1150 800 400 -

Let decision variables be \(X_1,X_2,X_3,X_4\) (pallets of Tahoe, Pacific, Savannah, Aspen). Write down the optimisation model to maximise profit, and solve for the optimal production plan. What is the maximum profit?

Objective function:

\[ \max\; 450x_1 + 1150x_2 + 800x_3 + 400x_4 \]

Constraints:

\[ \begin{aligned} 50x_1 + 50x_2 + 100x_3 + 50x_4 &\le 5800 \quad \text{(Glueing)} \\ 5x_1 + 15x_2 + 10x_3 + 5x_4 &\le 730 \quad \text{(Pressing)} \\ 500x_1 + 400x_2 + 300x_3 + 200x_4 &\le 29200 \quad \text{(Pine chips)} \\ 500x_1 + 750x_2 + 250x_3 + 500x_4 &\le 60500 \quad \text{(Oak chips)} \\ x_1, x_2, x_3, x_4 &\ge 0 \end{aligned} \]

This can be solved using KKT. However, it is usually not the preferred manual method for solving linear programming problems, especially with 4 variables. Instead, we can use the Simplex method or an LP solver.

import numpy as np
from scipy.optimize import linprog

# Maximise: 450x1 + 1150x2 + 800x3 + 400x4
# linprog minimises, so use negative coefficients
c = np.array([-450, -1150, -800, -400])

A = np.array([
    [50, 50, 100, 50],      # Glueing
    [5, 15, 10, 5],         # Pressing
    [500, 400, 300, 200],   # Pine chips
    [500, 750, 250, 500]    # Oak chips
])

b = np.array([5800, 730, 29200, 60500])

result = linprog(
    c,
    A_ub=A,
    b_ub=b,
    bounds=[(0, None)] * 4,
    method="highs"
)

print(result.x)
print(-result.fun)
[23. 15. 39.  0.]
58800.0

Optimal solution

\[ \boxed{x_10=23,\quad x_2=15,\quad x_3=39,\quad x_4=0} \]

So the optimal production plan is:

\[ \boxed{\text{Tahoe: 23, Pacific: 15, Savannah: 39, Aspen: 0}} \]

Maximum profit:

\[ Z=450(23)+1150(15)+800(39)+400(0)=\boxed{58,800} \]

Resources used:

\[ \begin{aligned} \text{Glueing} &= 50(23)+50(15)+100(39)+50(0) = 5800\\ \text{Pressing} &= 5(23)+15(15)+10(39)+5(0) = 730\\ \text{Pine chips} &= 500(23)+400(15)+300(39)+200(0) = 29200\\ \text{Oak chips} &= 500(23)+750(15)+250(39)+500(0) = 32500 \end{aligned} \]

So all requirements are satisfied.


Question 3

Consider the problem of diet optimisation. There are four different types of food: Brownies, Ice Cream, Cola, and Cheese Cake. The nutrition values and cost per unit are as follows:

Brownies Ice Cream Cola Cheese Cake
Calories 400 200 150 500
Chocolate 3 2 0 0
Sugar 2 2 4 4
Fat 2 4 1 5
Cost ($) $0.50 $0.20 $0.30 $0.80

The objective is to minimise the cost of the diet while satisfying the following nutritional requirements:

  • At least 500 calories,
  • At least 6 units of chocolate,
  • At least 10 units of sugar, and
  • At least 8 units of fat.

Formulate the optimisation model and solve for the optimal diet plan.

Objective function: \[ \min\; 0.50x_0+0.20x_1+0.30x_2+0.80x_3 \]

Constraints: \[ \begin{aligned} 400x_0 + 200x_1 + 150x_2 + 500x_3 &\ge 500,\\ 3x_0 + 2x_1 + 0x_2 + 0x_3 &\ge 6,\\ 2x_0 + 2x_1 + 4x_2 + 4x_3 &\ge 10,\\ 2x_0 + 4x_1 + 1x_2 + 5x_3 &\ge 8,\\ x_0,x_1,x_2,x_3 &\ge 0. \end{aligned} \]

import numpy as np
from scipy.optimize import linprog

# Cost coefficients
c = np.array([0.50, 0.20, 0.30, 0.80])

# Nutrient matrix
A = np.array([
    [400, 200, 150, 500],  # Calories
    [3,   2,   0,   0],    # Chocolate
    [2,   2,   4,   4],    # Sugar
    [2,   4,   1,   5]     # Fat
])

# Minimum requirements
b = np.array([500, 6, 10, 8])

# linprog uses <= constraints, so multiply by -1
result = linprog(
    c,
    A_ub=-A,
    b_ub=-b,
    bounds=[(0, None)] * 4,
    method="highs"
)

print(result.x)
print(result.fun)
print(A @ result.x)
[0. 3. 1. 0.]
0.9000000000000001
[750.   6.  10.  13.]

Optimal solution

\[ \boxed{x_0=0,\quad x_1=3,\quad x_2=1,\quad x_3=0} \]

So the optimal diet is:

\[ \boxed{\text{0 Brownies, 3 Ice Cream, 1 Cola, 0 Cheese Cake}} \]

Minimum cost:

\[ Z=0.20(3)+0.30(1)=\boxed{0.90} \]

Nutrients obtained:

\[ \begin{aligned} \text{Calories} &= 750\\ \text{Chocolate} &= 6\\ \text{Sugar} &= 10\\ \text{Fat} &= 13 \end{aligned} \]

So all requirements are satisfied.


Question 4

TowAlong makes trailers at Kansas City, Denver, and Raleigh plants and ships these units to Birmingham, Milwaukee, Los Angeles, and Seattle distribution centres. In planning production for the next year, TowAlong estimates Kansas City, Denver, and Raleigh plant’s unit shipping cost between any plant and distribution centre, plant capacities, and distribution centre demands. These numbers are given in the table.

Plant/DC Birmingham Milwaukee LA Seattle Capacity
Kansas City $35 $40 $60 $120 12,000
Denver $30 $30 $45 $130 8,000
Raleigh $60 $65 $50 $100 5,000
Demand 9,000 3,000 9,500 1,500 -

Formulate the optimisation model to minimise the total shipping cost, and solve for the optimal shipping plan. What is the minimum total cost?

Objective function:

\[ \begin{aligned} \min \; &35x_{11} + 40x_{12} + 60x_{13} + 120x_{14} \\ &+ 30x_{21} + 30x_{22} + 45x_{23} + 130x_{24} \\ &+ 60x_{31} + 65x_{32} + 50x_{33} + 100x_{34} \end{aligned} \]

Capacity constraints: \[ \begin{aligned} x_{11}+x_{12}+x_{13}+x_{14} &\le 12000 \quad \text{(Kansas City)}\\ x_{21}+x_{22}+x_{23}+x_{24} &\le 8000 \quad \text{(Denver)}\\ x_{31}+x_{32}+x_{33}+x_{34} &\le 5000 \quad \text{(Raleigh)} \end{aligned} \]

Demand constraints: \[ \begin{aligned} x_{11}+x_{21}+x_{31} &= 9000 \quad \text{(Birmingham)}\\ x_{12}+x_{22}+x_{32} &= 3000 \quad \text{(Milwaukee)}\\ x_{13}+x_{23}+x_{33} &= 9500 \quad \text{(Los Angeles)}\\ x_{14}+x_{24}+x_{34} &= 1500 \quad \text{(Seattle)}\\ x_{ij} &\ge 0. \end{aligned} \]

import numpy as np
from scipy.optimize import linprog

# Cost coefficients
# Order:
# x11, x12, x13, x14,
# x21, x22, x23, x24,
# x31, x32, x33, x34

c = np.array([
    35, 40, 60, 120,
    30, 30, 45, 130,
    60, 65, 50, 100
])

# Capacity constraints: <=
A_ub = np.array([
    [1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0],  # Kansas City
    [0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0],  # Denver
    [0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1]   # Raleigh
])

b_ub = np.array([12000, 8000, 5000])

# Demand constraints: =
A_eq = np.array([
    [1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0],  # Birmingham
    [0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0],  # Milwaukee
    [0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0],  # Los Angeles
    [0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1]   # Seattle
])

b_eq = np.array([9000, 3000, 9500, 1500])

bounds = [(0, None)] * 12

result = linprog(
    c,
    A_ub=A_ub,
    b_ub=b_ub,
    A_eq=A_eq,
    b_eq=b_eq,
    bounds=bounds,
    method="highs"
)

print(result.success)
print(result.fun)
print(result.x)
True
1010000.0
[9000. 1000.    0.    0.    0. 2000. 6000.    0.    0.    0. 3500. 1500.]

Optimal solution:

Python returns variable order as:

\[[x_{11},x_{12},x_{13},x_{14},x_{21},x_{22},x_{23},x_{24},x_{31},x_{32},x_{33},x_{34}] \]

So the optimal shipping plan is:

From / To Birmingham Milwaukee Los Angeles Seattle Supply Used
Kansas City 9000 1000 0 0 10000
Denver 0 2000 6000 0 8000
Raleigh 0 0 3500 1500 5000

Demands:

\[ \begin{aligned} \text{Birmingham} &= 9000\\ \text{Milwaukee} &= 1000+2000=3000\\ \text{Los Angeles} &= 6000+3500=9500\\ \text{Seattle} &= 1500 \end{aligned} \]

Minimum cost:

\[ 35(9000)+40(1000)+30(2000)+45(6000)+50(3500)+100(1500) \]

So:

\[ \boxed{\text{Minimum cost} = 1{,}010{,}000} \]


Question 5

Sunchem, a manufacturer of printing inks, has five manufacturing plants worldwide. Their locations and capacities are shown in Table 4 along with the cost of producing 1 ton of ink at each facility. The production costs are in the local currency of the country where the plant is located. The major markets for the inks are North America, South America, Europe, Japan, and the rest of Asia. Demand at each market is shown in Table 4. Transportation costs from each plant to each market in U.S. dollars are shown in Table 4. Management must come up with a production plan for the next year.

  1. If exchange rates are expected as in Table 2, and no plant can run below 50 percent of capacity, how much should each plant produce and which markets should each plant supply?
  2. If there are no limits on the amount produced in a plant, how much should each plant produce?
  3. Can adding 10 percent of capacity in any plant reduce costs?
  4. How should Sunchem account for the fact that exchange rates fluctuate over time?
Table 1. Transportation costs, production capacity, and cost by region
Supply Region N. America S. America Europe Japan Asia Capacity (tons/year) Production cost/ton
USA 600 1,200 1,300 2,000 1,700 185 $10,000
GER 1,300 1,400 600 1,400 1,300 475 €15,000
JAP 2,000 2,100 1,400 300 900 50 ¥1,800,000
BRA 1,200 800 1,400 2,100 2,100 210 BRL13,000
IND 2,200 2,300 1,300 1,000 800 80 INR400,000
Table 2. Exchange Rates as of April 2025
USD EUR JPY BRL INR
USD 1.0000 0.8794 141.94 5.6336 85.282
EUR 1.1374 1.0000 161.45 6.408 97.0
JPY 0.0070 0.0062 1.0000 0.045 0.60
BRL 0.1775 0.1560 22.22 1.0000 15.14
INR 0.0117 0.0103 1.67 0.066 1.0000

Sets

\[ \begin{aligned} I &= \{\text{US},\text{DE},\text{JP},\text{BR},\text{IN}\} \quad \text{(plants)} \\ J &= \{\text{NA},\text{SA},\text{EU},\text{JP},\text{AS}\} \quad \text{(markets)} \end{aligned} \]

Parameters

  • \(D_j\) : demand in market \(j\) (tons/year)
  • \(K_i\) : capacity of plant \(i\) (tons/year)
  • \(c_{ij}\) : transportation cost from plant \(i\) to market \(j\) (USD/ton)
  • \(p_i\) : production cost at plant \(i\) (local currency/ton)
  • \(r_i\) : USD per unit of local currency at plant \(i\)

Exchange rates (USD per local currency unit):

\[ r_{\text{US}}=1,\; r_{\text{DE}}=1.1374,\; r_{\text{JP}}=0.0070,\; r_{\text{BR}}=0.1775,\; r_{\text{IN}}=0.0117 \]

Define total unit delivered cost in USD:

\[ u_{ij} = r_i p_i + c_{ij} \]

Decision Variables

  • \(x_{ij}\) : tons shipped from plant \(i\) to market \(j\)
  • \(y_i = \sum_{j\in J} x_{ij}\) : total production at plant \(i\)

(a) Fixed Exchange Rates, Minimum 50% Utilisation

\[ \begin{aligned} \min \; &\sum_{i\in I}\sum_{j\in J} u_{ij} x_{ij} \\ \text{s.t. } &\sum_{i\in I} x_{ij} = D_j \quad \forall j\in J \quad \text{Demand satisfaction} \\ &\sum_{j\in J} x_{ij} \le K_i\quad \forall i\in I \quad \text{Capacity constraints} \\ &\sum_{j\in J} x_{ij} \ge 0.5 K_i \quad \forall i\in I \quad \text{Minimum 50\% utilisation} \\ &x_{ij} \ge 0 \quad \forall i\in I, j\in J \quad \text{Non-negativity} \end{aligned} \]

(b) No Production Limits

In this case, capacity constraints and minimum utilisation constraints are removed.

\[ \begin{aligned} \min \; &\sum_{i\in I}\sum_{j\in J} u_{ij} x_{ij} \\ \text{s.t. } &\sum_{i\in I} x_{ij} = D_j \quad \forall j\in J \quad \text{Demand satisfaction} \\ &x_{ij} \ge 0 \quad \forall i\in I, j\in J \quad \text{Non-negativity} \end{aligned} \]

This is the classical uncapacitated transportation problem.

(c) Allow 10% Capacity Expansion

Introduce binary decision variables:

\[ z_i = \begin{cases} 1 & \text{if plant } i \text{ expands by 10\%} \\ 0 & \text{otherwise} \end{cases} \]

Expanded capacity:

\[ (1+0.1 z_i)K_i \]

\[ \begin{aligned} \min \; &\sum_{i\in I}\sum_{j\in J} u_{ij} x_{ij} \\ \text{s.t. } &\sum_{i\in I} x_{ij} = D_j \quad \forall j\in J \quad \text{Demand satisfaction} \\ &\sum_{j\in J} x_{ij} \le (1+0.1 z_i)K_i\quad \forall i\in I \quad \text{Expanded capacity constraints} \\ &\sum_{j\in J} x_{ij} \ge 0.5 K_i \quad \forall i\in I \quad \text{Minimum 50\% utilisation} \\ &z_i \in \{0,1\} \quad \forall i\in I \quad \text{Binary expansion decision} \\ &x_{ij} \ge 0 \quad \forall i\in I, j\in J \quad \text{Non-negativity} \end{aligned} \]

To determine whether expansion reduces cost, compare the optimal objective value of this model with that of part (a)

(d) Accounting for Exchange Rate Uncertainty

Exchange rates should be treated as uncertain parameters.

  • Stochastic Programming

Let \(s\in S\) be scenarios with probability \(\pi_s\) and exchange rates \(r_i^{(s)}\).

\[ \min \sum_{s\in S} \pi_s \sum_{i\in I}\sum_{j\in J} \left( r_i^{(s)} p_i + c_{ij} \right) x_{ij}^{(s)} \]

subject to demand and capacity constraints (with optional non-anticipativity constraints if decisions must be made before rates are known).

  • Robust Optimisation

If exchange rates lie in uncertainty set \(\mathcal{R}\):

\[ \min_{x} \; \max_{r\in \mathcal{R}} \sum_{i\in I}\sum_{j\in J} \left( r_i p_i + c_{ij} \right) x_{ij} \]

This protects against worst-case exchange rate realizations.

  • Financial Hedging

Operational optimisation can be combined with financial instruments (forwards/options) to hedge currency exposure.

  • Rolling Horizon Re-optimisation

Re-solve the optimisation model periodically using updated exchange rates and demand forecasts.