Lumber Transportation Problem#

  1. Reeb and S. Leavengood

Millco has three wood mills and is planning three new logging sites. Each mill has a maximum capacity and each logging site can harvest a certain number of truckloads of lumber per day. The cost of a haul is $2/mile of distance. If distances from logging sites to mills are given below, how should the hauls be routed to minimize hauling costs while meeting all demands?

Logging Site

Mill A

Mill B

Mill C

Max loads per day

1

8

15

50

20

2

10

17

20

30

3

30

26

15

45

Mill demand

30

35

30

[1]:
from gamspy import Container, Set, Alias, Parameter, Variable, Equation, Model, Sum, Sense
import numpy as np
[2]:
m = Container()

# Model sets and parameters
sites = Set(container=m, name="sites", records=["1", "2", "3"])
mills = Set(container=m, name="mills", records=["Mill A", "Mill B", "Mill C"])
dist = Parameter(
    container=m,
    name="dist",
    domain=[sites, mills],
    records=np.array([[8, 15, 50], [10, 17, 20], [30, 26, 15]]),
)
supply = Parameter(
    container=m, name="supply", domain=sites, records=np.array([20, 30, 45])
)
demand = Parameter(
    container=m, name="demand", domain=mills, records=np.array([30, 35, 30])
)
cost_per_haul = 4

# Model variables
ship = Variable(container=m, name="ship", type="positive", domain=[sites, mills])

defcost = cost_per_haul * Sum([sites, mills], ship[sites, mills] * dist[sites, mills])

defsupply = Equation(container=m, name="defsupply", domain=sites)
defsupply[sites] = Sum(mills, ship[sites, mills]) == supply[sites]

defdemand = Equation(container=m, name="defdemand", domain=mills)
defdemand[mills] = Sum(sites, ship[sites, mills]) == demand[mills]

millco = Model(
    container=m,
    name="millco",
    equations=m.getEquations(),
    problem="LP",
    sense=Sense.MIN,
    objective=defcost,
)
[3]:
millco.solve()
[3]:
Solver Status Model Status Objective Num of Equations Num of Variables Model Type Solver Solver Time
0 Normal OptimalGlobal 5760 7 10 LP CPLEX 0
[4]:
ship.records.pivot(index='sites', columns='mills', values='level')
[4]:
mills Mill A Mill B Mill C
sites
1 0.0 20.0 0.0
2 30.0 0.0 0.0
3 0.0 15.0 30.0
[5]:
print(f'Total cost will be {millco.objective_value}')
Total cost will be 5760.0
[6]:
m = Container()

# Generic Model sets and parameters
i = Set(
    container=m,
    name="i",
    records=["i" + str(i) for i in range(6)],
    description="equation index",
)
j = Set(
    container=m,
    name="j",
    records=["j" + str(j) for j in range(9)],
    description="variable index",
)
A = Parameter(
    container=m,
    name="A",
    domain=[i, j],
    records=np.array(
        [
            [1, 1, 1, 0, 0, 0, 0, 0, 0],
            [0, 0, 0, 1, 1, 1, 0, 0, 0],
            [0, 0, 0, 0, 0, 0, 1, 1, 1],
            [1, 0, 0, 1, 0, 0, 1, 0, 0],
            [0, 1, 0, 0, 1, 0, 0, 1, 0],
            [0, 0, 1, 0, 0, 1, 0, 0, 1],
        ]
    ),
)
b = Parameter(
    container=m, name="b", domain=i, records=np.array([20, 30, 45, 30, 35, 30])
)
c = Parameter(
    container=m,
    name="c",
    domain=j,
    records=np.array([8, 15, 50, 10, 17, 20, 30, 26, 15]),
)
x = Variable(container=m, name="x", type="positive", domain=j)

obj = 4 * Sum(j, c[j] * x[j])

e = Equation(container=m, name="e", domain=i)
e[i] = Sum(j, A[i, j] * x[j]) == b[i]

generic_model = Model(
    container=m,
    name="generic_model",
    equations=m.getEquations(),
    problem="LP",
    sense=Sense.MIN,
    objective=obj,
)
[7]:
generic_model.solve()
[7]:
Solver Status Model Status Objective Num of Equations Num of Variables Model Type Solver Solver Time
0 Normal OptimalGlobal 5760 7 10 LP CPLEX 0
[8]:
x.records
[8]:
j level marginal lower upper scale
0 j0 0.0 -0.0 0.0 inf 1.0
1 j1 20.0 0.0 0.0 inf 1.0
2 j2 0.0 184.0 0.0 inf 1.0
3 j3 30.0 0.0 0.0 inf 1.0
4 j4 0.0 0.0 0.0 inf 1.0
5 j5 0.0 56.0 0.0 inf 1.0
6 j6 0.0 44.0 0.0 inf 1.0
7 j7 15.0 0.0 0.0 inf 1.0
8 j8 30.0 0.0 0.0 inf 1.0
[9]:
print(f'Total cost will be {generic_model.objective_value}')
Total cost will be 5760.0