 FICO Xpress Optimization Examples Repository
 FICO Optimization Community FICO Xpress Optimization Home   Transport

Description
A company produces the same product at different plants. Every plant has a different production cost per unit and a limited total capacity. The customers (grouped into customer regions) may receive the product from different production locations. The transport cost is proportional to the distance between plants and customers, and the capacity on every delivery route is limited. The objective is to minimize the total cost, whilst satisfying the demands of all customers.

Further explanation of this example: 'Mosel User Guide', Section 3.1 'A transport example', Section 10.1 'Producing formatted output'. Similar problem: 'Applications of optimization with Xpress-MP', Section 10.1 'Car rental' (e1carrent.mos)

Source Files
By clicking on a file name, a preview is opened at the bottom of this page.

Data Files

transport_graph.mos

(!******************************************************
Mosel Example Problems
======================

file transport.mos

TYPE:         Transport problem
DIFFICULTY:   2
FEATURES:     simple LP problem, using dynamic arrays for data and
decision variables, formatted output printing, inline if',
format of data files
DESCRIPTION:  A company produces the same product at different plants.
Every plant has a different production cost per unit and
a limited total capacity. The customers (grouped into
customer regions) may receive the product from different
production locations. The transport cost is proportional
to the distance between plants and customers, and the
capacity on every delivery route is limited. The objective
is to minimize the total cost, whilst satisfying the
demands of all customers.
FURTHER INFO: Mosel User Guide', Section 3.1 A transport example',
Section 10.1 Producing formatted output'.
Similar problem:
Applications of optimization with Xpress-MP',
Section 10.1 Car rental'

(c) 2008 Fair Isaac Corporation
author: S.Heipcke, Jan. 2001, rev. Nov. 2017
*******************************************************!)

model Transport
uses "mmxprs", "mmsvg"

forward procedure print_table
forward procedure draw_solution

declarations
REGION: set of string                 ! Set of customer regions
PLANT: set of string                  ! Set of plants

DEMAND: array(REGION) of real         ! Demand at regions
PLANTCAP: array(PLANT) of real        ! Production capacity at plants
PLANTCOST: array(PLANT) of real       ! Unit production cost at plants
TRANSCAP: dynamic array(PLANT,REGION) of real ! Capacity on each route plant->region
DISTANCE: dynamic array(PLANT,REGION) of real ! Distance of each route plant->region
FUELCOST: real                        ! Fuel cost per unit distance

flow: dynamic array(PLANT,REGION) of mpvar    ! Flow on each route
end-declarations

initializations from 'transport.dat'
DEMAND
[PLANTCAP,PLANTCOST] as 'PLANTDATA'
[DISTANCE,TRANSCAP] as 'ROUTES'
FUELCOST
end-initializations

! Create the flow variables that exist
forall(p in PLANT, r in REGION | exists(TRANSCAP(p,r)) ) create(flow(p,r))

! Objective: minimize total cost
MinCost:= sum(p in PLANT, r in REGION | exists(flow(p,r)))
(FUELCOST * DISTANCE(p,r) + PLANTCOST(p)) * flow(p,r)

! Limits on plant capacity
forall(p in PLANT) Capacity(p):= sum(r in REGION) flow(p,r) <= PLANTCAP(p)

! Satisfy all demands
forall(r in REGION) Demand(r):= sum(p in PLANT) flow(p,r) = DEMAND(r)

! Bounds on flows
forall(p in PLANT, r in REGION | exists(flow(p,r)))
flow(p,r) <= TRANSCAP(p,r)

! Solve the problem
minimize(MinCost)

! Solution printing
print_table

! Solution drawing
draw_solution

!***********************************************************************

procedure print_table
declarations
rsum: array(REGION) of integer    ! Auxiliary data table for printing
psum,prsum,ct,iflow: integer      ! Counters
end-declarations

! Print heading and the first line of the table
writeln("\nProduct Distribution\n--------------------")
writeln(strfmt("Sales Region",44))
write(strfmt("",14))
forall(r in REGION) write(strfmt(r,9))
writeln(strfmt("TOTAL",9), " Capacity")

! Print the solution values of the flow variables and
! calculate totals per region and per plant
ct:=0
forall(p in PLANT) do
ct += 1
write(if(ct=2,"Plant ","      "), strfmt(p,-8))
psum:=0
forall(r in REGION) do
iflow:=integer(getsol(flow(p,r)))
psum += iflow
rsum(r) += iflow
write(if( iflow<>0, strfmt(iflow,9), "      -- "))
end-do
writeln(strfmt(psum,9), strfmt(integer(PLANTCAP(p)),9))
end-do

! Print the column totals
write("\n", strfmt("TOTAL",-14))
prsum:=0
forall(r in REGION) do
prsum += rsum(r)
write(strfmt(rsum(r),9))
end-do
writeln(strfmt(prsum,9))

! Print demand of every region
write(strfmt("Demand",-14))
forall(r in REGION) write(strfmt(integer(DEMAND(r)),9))

! Print objective function value
writeln("\n\nTotal cost of distribution = ", strfmt(getobjval/1e6,0,3),
" million.")

end-procedure

!***********************************************************************
procedure draw_solution
declarations
YP: array(PLANT) of integer           ! y-coordinates of plants
YR: array(REGION) of integer          ! y-coordinates of sales regions
end-declarations

! Scale the size of the displayed graph
svgsetgraphviewbox(0,1,4,getsize(REGION)+1)
svgsetgraphscale(100)

! Determine y-coordinates for plants and regions
ct:= 1+floor((getsize(REGION)-getsize(PLANT))/2)
forall(p in PLANT, ct as counter) YP(p):= ct

ct:=1
forall(r in REGION, ct as counter) YR(r):= ct

! Draw the plants
forall(p in PLANT) svgaddtext(0.55, YP(p)-0.05, p)

! Draw the sales regions
forall(r in REGION) svgaddtext(3.1, YR(r)-0.05, r)

! Draw all transport routes
forall(p in PLANT, r in REGION | exists(TRANSCAP(p,r)) )

! Draw the routes used by the solution   