### SHIPPING SETS AND PARAMETERS ###
set whse 'warehouses'; # Locations from which demand is satisfied
set dctr 'distribution centers' within whse;
# Locations from which product may be shipped
param sc 'shipping cost' {dctr,whse} >= 0;
# Shipping costs, to whse from dctr, in $ / 100 lb
param huge 'largest shipping cost' > 0;
# Largest cost allowed for a usable shipping route
param msr 'minimum size restriction' {dctr,whse} logical;
# True indicates a minimum-size restriction on
# direct shipments using this dctr --> whse route
param dsr 'direct shipment requirement' {dctr} >= 0;
# Minimum total demand, in pallets, needed to
# allow shipment on routes subject to the
# minimum size restriction
### PLANT SETS AND PARAMETERS ###
set fact 'factories' within dctr;
# Locations where product is manufactured
param rtmin 'regular-time total minimum' >= 0;
# Lower limit on (average) total regular-time
# crews employed at all factories
param rtmax 'regular-time total maximum' >= rtmin;
# Upper limit on (average) total regular-time
# crews employed at all factories
param otmin 'overtime total minimum' >= 0;
# Lower limit on total overtime hours at all factories
param otmax 'overtime total maximum' >= otmin;
# Upper limit on total overtime hours at all factories
param rmin 'regular-time minimums' {fact} >= 0;
# Lower limits on (average) regular-time crews
param rmax 'regular-time maximums' {f in fact} >= rmin[f];
# Upper limits on (average) regular-time crews
param omin 'overtime minimums' {fact} >= 0;
# Lower limits on overtime hours
param omax 'overtime maximums' {f in fact} >= omin[f];
# Upper limits on overtime hours
param hd 'hours per day' {fact} >= 0;
# Regular-time hours per working day
param dp 'days in period' {fact} > 0;
# Working days in the current planning period
### PRODUCT SETS AND PARAMETERS ###
set prod 'products'; # Elements of the product group
param wt 'weight' {prod} > 0;
# Weight in 100 lb / 1000 cases
param cpp 'cases per pallet' {prod} > 0;
# Cases of product per shipping pallet
param tc 'transshipment cost' {prod} >= 0;
# Transshipment cost in $ / 1000 cases
param pt 'production time' {prod,fact} >= 0;
# Crew-hours to produce 1000 cases
param rpc 'regular-time production cost' {prod,fact} >= 0;
# Cost of production on regular time,
# in $ / 1000 cases
param opc 'overtime production cost' {prod,fact} >= 0;
# Cost of production on overtime, in $ / 1000 cases
### DEMAND SETS AND PARAMETERS ###
param dt 'total demand' {prod} >= 0;
# Total demands for products, in 1000s
param ds 'demand shares' {prod,whse} >= 0.0, <= 1.0;
# Historical demand data, from which each
# warehouse's share of total demand is deduced
param dstot {p in prod} := sum {w in whse} ds[p,w];
# Total of demand shares; should be 1, but often isn't
param dem 'demand' {p in prod, w in whse} := dt[p] * ds[p,w] / dstot[p];
# Projected demands to be satisfied, in 1000s
set rt 'shipping routes available' :=
{d in dctr, w in whse:
d <> w and sc[d,w] < huge and
(w in dctr or sum {p in prod} dem[p,w] > 0) and
not (msr[d,w] and sum {p in prod} 1000*dem[p,w]/cpp[p] < dsr[d]) };
# List of ordered pairs that represent routes
# on which shipments are allowed
### OBJECTIVE ###
minimize cost; # Total cost: regular production, overtime
# production, shipping, and transshipment
### NODES ###
node RT: rtmin <= net_out <= rtmax;
# Source of all regular-time crews allocated
node OT: otmin <= net_out <= otmax;
# Source of all overtime hours allocated
node P_RT {fact}; # Sources of regular-time crews at factories
node P_OT {fact}; # Sources of overtime hours at factories
node M {prod,fact}; # Sources of manufacturing:
# send to factory's W node for local demand;
# send to factory's D node for distribution
node D {prod,dctr}; # Sources of distribution:
# receive transshipped goods from center's W node;
# receive manufactured goods from center's M node;
# send to W nodes elsewhere
node W {p in prod, w in whse}: net_in = dem[p,w];
# Locations of warehousing:
# receive from D nodes and local M node (if any),
# to satisfy local demand;
# send to local D node (if any) for transshipment
### ARCS ###
arc Work_RT {f in fact}
from RT to P_RT[f] >= rmin[f], <= rmax[f];
# Regular-time crews allocated to each factory
arc Work_OT {f in fact}
from OT to P_OT[f] >= omin[f], <= omax[f];
# Overtime hours allocated to each factory
arc Manu_RT {p in prod, f in fact: rpc[p,f] <> 0} >= 0
from P_RT[f] to M[p,f] (dp[f] * hd[f] / pt[p,f])
obj cost (rpc[p,f] * dp[f] * hd[f] / pt[p,f]);
# Regular-time crews allocated to
# manufacture of each product at each factory
arc Manu_OT {p in prod, f in fact: opc[p,f] <> 0} >= 0
from P_OT[f] to M[p,f] (1 / pt[p,f]) obj cost (opc[p,f] / pt[p,f]);
# Overtime hours allocated to
# manufacture of each product at each factory
arc Prod_L {p in prod, f in fact} >= 0
from M[p,f] to W[p,f];
# Manufacture of each product at each factory
# to satisfy local demand, in 1000s of units
arc Prod_D {p in prod, f in fact} >= 0
from M[p,f] to D[p,f];
# Manufacture of each product at each factory,
# for distribution elsewhere, in 1000s of units
arc Ship {p in prod, (d,w) in rt} >= 0
from D[p,d] to W[p,w] obj cost (sc[d,w] * wt[p]);
# Shipments of each product on each allowed route
arc Trans {p in prod, d in dctr} >= 0
from W[p,d] to D[p,d] obj cost (tc[p]);
# Transshipments of each product at each
# distribution center