Initializing help system before first use

E. Ground transport


Description:

Problem name and type, features Difficulty Related examples
E‑1 Car rental: Transport problem *** transport_graph.mos
data preprocessing, set operations, sqrt and ^2, if-then-elif
E‑2 Choosing the mode of transport: Minimum cost flow ** mincostflow_graph.mos
formulation with extra nodes for modes of transport; encoding of arcs, finalize, union of sets, nodes labeled with strings
E‑3 Depot location: Facility location problem *** facilityloc_graph.mos
modeling flows as fractions, definition of model cuts
E‑4 Heating oil delivery: Vehicle routing problem (VRP) **** vrp_graph.mos
elimination of inadmissible subtours, cuts; selection with `|', definition of model cuts
E‑5 Combining different modes of transport ***
modeling implications, weak and strong formulation of bounding constraints; triple indices
E‑6 Fleet planning for vans ***
maxlist, minlist, max, min


File(s): e1carrent.mos (Mar. 2002), e2minflow.mos (Mar. 2002), e3depot.mos (Mar. 2002), e4deliver.mos (Mar. 2002), e5combine.mos (Mar. 2002), e6vanrent.mos (Mar. 2002)
Data file(s): e1carrent.dat, e2minflow.dat, e3depot.dat, e4deliver.dat, e5combine.dat, e6vanrent.dat

e1carrent.mos
(!******************************************************
   Mosel Example Problems
   ======================

   file e1carrent.mos
   ``````````````````
   Fleet management in car rental

   A rental company has 94 cars at 10 locations. Assume the
   distance between each location is 1.3 times the Euclidean
   distance. Given the transport cost per km, determine how
   many cars to move between locations so that morning demand
   is met while minimizing total cost.

   Here the data is checked to confirm there are the number
   of cars required, exiting if stock does not meet demand.
   Then the locations are sorted into 'NEED' or 'EXCESS'
   locations with 'if-then-elif' to determine start (source) and 
   destination (sink) locations. To calculate distance, this 
   problem introduces the function 'sqrt' and the exponential 
   operator '^'.
 
   (c) 2008-2022 Fair Isaac Corporation
       author: S. Heipcke, Mar. 2002, rev. Mar. 2022
*******************************************************!)

model "E-1 Car rental"
 uses "mmxprs"

 declarations
  AGENTS = 1..10                     ! Car rental agencies

  REQ: array(AGENTS) of integer      ! Required number of cars
  STOCK: array(AGENTS) of integer    ! Number of cars in stock
  X,Y: array(AGENTS) of integer      ! Coordinates of rental agencies
  COST: real                         ! Cost per km of moving a car
  NEED: set of integer               ! Agencies needing more cars
  EXCESS: set of integer             ! Agencies with too many cars
 end-declarations

 initializations from 'e1carrent.dat'
  REQ STOCK X Y COST
 end-initializations

 if sum(a in AGENTS) (STOCK(a)-REQ(a)) <> 0 then
  writeln("Problem is infeasible")
  exit(0)
 end-if 

! Calculate sets of agencies with excess or deficit of cars
 forall(a in AGENTS)
  if STOCK(a) - REQ(a) < 0 then
   NEED += {a}
  elif STOCK(a) - REQ(a) > 0 then
   EXCESS += {a}
  end-if

 finalize(NEED); finalize(EXCESS)

 declarations
  DIST: array(EXCESS,NEED) of real   ! Distance between agencies
  move: array(EXCESS,NEED) of mpvar  ! Cars exchanged between agencies
 end-declarations

! Calculate distances between agencies
 forall(a in EXCESS,b in NEED) 
  DIST(a,b):= 1.3*sqrt((X(a)-X(b))^2 + (Y(a)-Y(b))^2)

! Objective: total transport cost
 Cost:= sum(a in EXCESS,b in NEED) COST*DIST(a,b)*move(a,b)

! Agencies with excess availability
 forall(a in EXCESS) sum(b in NEED) move(a,b) = STOCK(a) - REQ(a)

! Agencies in need of cars
 forall(b in NEED) sum(a in EXCESS) move(a,b) = REQ(b) - STOCK(b)

 forall(a in EXCESS,b in NEED) move(a,b) is_integer

! Solve the problem
 minimize(Cost)
 
! Solution printing
 writeln("Total cost: ", getobjval)
 write(" ->")
 forall(b in NEED) write(strfmt(b,3))
 writeln
 setparam("realfmt","%3g")
 forall(a in EXCESS) do
  write(a,"  ")
  forall(b in NEED) write(getsol(move(a,b)))
  writeln
 end-do 

end-model

e2minflow.mos
(!******************************************************
   Mosel Example Problems
   ======================

   file e2minflow.mos
   ``````````````````
   Choosing the mode of transport (Minimum cost flow)
   
   A company needs to transport chemical products stores in
   4 depots to 3 recycling centers by road or rail. Each depot
   transports to only specific recycling centers with varying
   cost per available transportation types. A single rail delivery
   must be between 10 and 50 tons. How should the company
   transport 180 tons of chemicals to minimize the total 
   transport cost?
   
   This contains the classical problem of coding a graph through 
   an N x N matrix with flow across arcs between pairs of nodes.
   The set of 'NODES' is the union of all nodes connected by elements
   in 'ARCS'.

   (c) 2008-2022 Fair Isaac Corporation
       author: S. Heipcke, Mar. 2002, rev. Mar. 2022
*******************************************************!)

model "E-2 Minimum cost flow"
 uses "mmxprs", "mmsystem"

 declarations
  NODES: set of string                  ! Set of nodes
  MINQ : integer                        ! Total quantity to transport
  A: array(ARCS:range,1..2) of string   ! Arcs
  COST: array(ARCS) of integer          ! Transport cost on arcs
  MINCAP,MAXCAP: array(ARCS) of integer ! Minimum and maximum arc capacities
 end-declarations

 initializations from 'e2minflow.dat'
  A MINQ MINCAP MAXCAP COST
 end-initializations

! Calculate the set of nodes
 NODES:=union(a in ARCS) {A(a,1),A(a,2)}

 declarations
  flow: array(ARCS) of mpvar            ! Flow on arcs
 end-declarations

! Objective: total transport cost
 Cost:= sum(a in ARCS) COST(a)*flow(a)

! Flow balance: inflow equals outflow
 forall(n in NODES | n<>"SOURCE" and n<>"SINK")
  sum(a in ARCS | A(a,2)=n) flow(a) = sum(a in ARCS | A(a,1)=n) flow(a)
   
! Min and max flow capacities
 forall(a in ARCS | MAXCAP(a) > 0) do
  flow(a) >= MINCAP(a)
  flow(a) <= MAXCAP(a)
 end-do
  
! Minimum total quantity to transport
 sum(a in ARCS | A(a,1)="SOURCE" ) flow(a) >= MINQ

! Solve the problem
 minimize(Cost)
 
! Solution printing
 writeln("Total cost: ", getobjval)
 forall(a in ARCS | flow(a).sol>0)
  writeln(formattext("%7s -> %-7s: %g", A(a,1), A(a,2), getsol(flow(a))))

end-model

e3depot.mos
(!******************************************************
   Mosel Example Problems
   ======================

   file e3depot.mos
   ````````````````
   Depot location
  
   A company is planning to open new locations to supply 
   its sales centers. Each new location has a fixed set-up
   cost. Each delivery from supply location to sales center
   has a distance dependent delivery cost. There are 12 possible
   new locations to supply 12 sales centers. Demand for sales 
   centers can be met by multiple supply locations. Which 
   locations should be opened to meet demand but also minimize
   total cost of set-up and delivery?

   The model formulation represents flows as fraction (percentage)
   of the demand (variables 'fflow'). It also shows how redundant
   constraints can be stated as model cuts (=additional constraints
   that do not form part of the problem matrix).

   (c) 2008 Fair Isaac Corporation
       author: S. Heipcke, Mar. 2002
*******************************************************!)

model "E-3 Depot location"
 uses "mmxprs"

 declarations
  DEPOTS = 1..12                       ! Set of depots
  CUST = 1..12                         ! Set of customers

  COST: array(DEPOTS,CUST) of integer  ! Delivery cost
  CFIX: array(DEPOTS) of integer       ! Fix cost of depot construction
  CAP: array(DEPOTS) of integer        ! Depot capacity
  DEM: array(CUST) of integer          ! Demand by customers

  fflow: array(DEPOTS,CUST) of mpvar   ! Perc. of demand supplied from depot
  build: array(DEPOTS) of mpvar        ! 1 if depot built, 0 otherwise
 end-declarations

 initializations from 'e3depot.dat'
  COST CFIX CAP DEM
 end-initializations

! Objective: total cost
 TotCost:= sum(d in DEPOTS, c in CUST) COST(d,c)*fflow(d,c) +
            sum(d in DEPOTS) CFIX(d)*build(d)

! Satisfy demands
 forall(c in CUST) sum(d in DEPOTS) fflow(d,c) = 1
   
! Capacity limits at depots
 forall(d in DEPOTS) sum(c in CUST) DEM(c)*fflow(d,c) <= CAP(d)*build(d)

! Additional constraints:
! If there is any delivery from depot d, then this depot must be built
(!
 declarations
  ModCut: array(DEPOTS,CUST) of linctr
 end-declarations

 forall(d in DEPOTS, c in CUST) do
  ModCut(d,c):= DEM(c) * fflow(d,c) <= CAP(d) * build(d)
  setmodcut(ModCut(d,c))
 end-do
!)

 forall(d in DEPOTS) build(d) is_binary
 forall(d in DEPOTS, c in CUST) fflow(d,c) <= 1

! Uncomment the following line to see the Optimizer log
! setparam("XPRS_VERBOSE",true)

! Solve the problem
 minimize(TotCost)
 
! Solution printing
 writeln("Total cost: ", getobjval)
 forall(d in DEPOTS, c in CUST | getsol(fflow(d,c))>0) 
   writeln(strfmt(d,2), " -> ", strfmt(c,2), ": ", 
           strfmt(getsol(fflow(d,c))*DEM(c),3) )

end-model

e4deliver.mos
(!******************************************************
   Mosel Example Problems
   ======================

   file e4deliver.mos
   ``````````````````
   Heating oil delivery (Traveling Salesman Problem)

   Heating oil is delivered from a refinery to 6 clients.
   Which routes should be schedules so that all clients
   receive their deliveries with the minimal total km
   driven by the tanker trucks?

   This problem formulation defines constraints to eliminate
   infeasible subtours. It introduces '|' to limit the index
   tuples that are enumerated in 'forall' loops or in sums. 
   An additional set of constraints can be added as model cuts.
   These must be declared as 'linctr' and are specified
   using 'setmodcut'.

   (c) 2008-2022 Fair Isaac Corporation
       author: S. Heipcke, Mar. 2002, rev. Mar. 2022
*******************************************************!)

model "E-4 Oil delivery"
 uses "mmxprs"

 declarations
  NS = 7
  SITES = 1..NS                       ! Set of locations, 1=refinery
  CLIENTS = 2..NS

  DEM: array(SITES) of integer        ! Demands
  DIST: array(SITES,SITES) of integer ! Distances between locations
  CAP: integer                        ! Lorry capacity

  prec: array(SITES,SITES) of mpvar   ! 1 if i immediately precedes j, 
                                      ! 0 otherwise 
  quant: array(CLIENTS) of mpvar      ! Quantity delivered up to i
 end-declarations

 initializations from 'e4deliver.dat'
  DEM DIST CAP
 end-initializations

! Objective: total distance driven
 Length:= sum(i,j in SITES | i<>j) DIST(i,j)*prec(i,j)

! Enter and leave every city only once (except the depot)
 forall(j in CLIENTS) sum(i in SITES| i<>j) prec(i,j) = 1
 forall(i in CLIENTS) sum(j in SITES| i<>j) prec(i,j) = 1

! If i is the first client of a tour, then quant(i)=DEM(i)
 forall(i in CLIENTS) quant(i) <= CAP + (DEM(i)-CAP)*prec(1,i)

! If j comes just after i in a tour, then quant(j) is greater than the 
! quantity delivered during the tour up to i plus the quantity to be 
! delivered at j (to avoid loops and keep capacity limit of the tanker)
 forall(i,j in CLIENTS| i<>j) quant(j) >= quant(i) + DEM(j) - CAP +
                           CAP*prec(i,j) + (CAP-DEM(j)-DEM(i))*prec(j,i)

! Additional constraints:
! If i is not the first client of a tour, quant(i) is larger than the sum 
! of the quantities to deliver to i and to his predecessor on the tour
(!
 declarations
  ModCut: array(CLIENTS) of linctr
 end-declarations

 forall(i in CLIENTS) do
  ModCut(i):= quant(i) >= DEM(i) + sum(j in SITES| i<>j) DEM(j)*prec(j,i)
  setmodcut(ModCut(i))
 end-do
!)

 forall(i in CLIENTS) do
  quant(i) <= CAP
  quant(i) >= DEM(i)
 end-do
 
 forall(i,j in SITES | i<>j) prec(i,j) is_binary

! Uncomment the following line to see the Optimizer log
! setparam("XPRS_VERBOSE",true)

! Solve the problem
 minimize(Length)

! Solution printing
 writeln("Total distance: ", getobjval)
 forall(i in CLIENTS | getsol(prec(1,i))>0) do
  ct:=DEM(i)
  writeln(1, " -> ", i)
  p:=i
  while(p<>1) do
   n:= round(sum(j in SITES) j*getsol(prec(p,j)))
   writeln(p, " -> ", n)
   ct+=DEM(n)
   p:=n
  end-do
  writeln("Quantity delivered: ", ct)
 end-do

end-model

e5combine.mos
(!******************************************************
   Mosel Example Problems
   ======================

   file e5combine.mos
   ``````````````````
   Combining different modes of transport

   A large load needs to be transported through 5 cities via 
   3 possible transportation modes. Transportation type can
   be changed in any of the three intermediate cities. How
   should this load be transported so that the total cost of
   transportation and changing modes is minimized?

   This problem introduces triple indices for the variable 
   'change' since this is the change from mode m to mode n
   for leg l.
   
   (c) 2008-2022 Fair Isaac Corporation
       author: S. Heipcke, Mar. 2002, rev. Mar. 2022
*******************************************************!)

model "E-5 Combined transport"
 uses "mmxprs"

 declarations
  NL = 4
  LEGS = 1..NL                          ! Legs of the transport
  MODES: set of string                  ! Modes of transport

  CTRANS: array(MODES,LEGS) of integer  ! Transport cost
  CCHG: array(MODES,MODES) of integer   ! Cost of changing mode of transport
 end-declarations

 initializations from 'e5combine.dat'
  CTRANS CCHG
 end-initializations

 declarations
  use: array(MODES,LEGS) of mpvar        ! 1 if a mode is used, 0 otherwise 
  change: array(MODES,MODES,1..NL-1) of mpvar  ! 1 if change from mode m to n
                                               ! at end of leg, 0 otherwise
 end-declarations

! Objective: total cost
 Cost:= sum(m in MODES, l in LEGS) CTRANS(m,l)*use(m,l) +
         sum(m,n in MODES,l in 1..NL-1) CCHG(m,n)*change(m,n,l)

! One mode of transport per leg        
 forall(l in LEGS) sum(m in MODES) use(m,l) = 1
 
! Change or maintain mode of transport between every pair of legs 
 forall(l in 1..NL-1) sum(m,n in MODES) change(m,n,l) = 1

! Relation between modes used and changes
 forall(m,n in MODES,l in 1..NL-1) use(m,l) + use(n,l+1) >= 2*change(m,n,l)

 forall(m in MODES, l in LEGS) use(m,l) is_binary
 forall(m,n in MODES,l in 1..NL-1) change(m,n,l) is_binary
 
! Solve the problem
 minimize(Cost)
 
! Solution printing
 writeln("Total cost: ", getobjval)
 forall(l in LEGS) do
  write("  ",l, "-", l+1,": ")
  forall(m in MODES | getsol(use(m,l))>0) do
   write(m)
   break
  end-do
 end-do 
 writeln

end-model

e6vanrent.mos
(!******************************************************
   Mosel Example Problems
   ======================

   file e6vanrent.mos
   ``````````````````
   Fleet planning for van rental
   
   A chain of stores uses a fleet of vans rented from
   multiple rental agencies. There is a choice between rental
   contracts of varying lengths. Which contracts should be 
   signed each month so that the number of vans meet the 
   requirements and there are no vans rented beyond the last month
   while minimizing rental costs?
   
   The implementation uses the Mosel functions 'maxlist' and 'minlist'
   to calculate the range of available months for each contract
   length. Note that these are different from the operators 'max'
   and 'min' which are used with set expressions.
   
   (c) 2008-2022 Fair Isaac Corporation
       author: S. Heipcke, Mar. 2002, rev. Mar. 2022
*******************************************************!)

model "E-6 Van rental"
 uses "mmxprs"

 declarations
  NM = 6
  MONTHS = 1..NM                      ! Months
  CONTR = 3..5                        ! Contract types

  REQ: array(MONTHS) of integer       ! Monthly requirements
  COST: array(CONTR) of integer       ! Cost of contract types
  NINIT: integer                      ! Vans rented at beginning of plan

  rent: array(CONTR,MONTHS) of mpvar  ! New rentals every month
 end-declarations

 initializations from 'e6vanrent.dat'
  REQ COST NINIT
 end-initializations

! Objective: total cost
 Cost:= sum(c in CONTR, m in MONTHS) COST(c)*rent(c,m)

! Fulfill the monthly requirements
 forall(m in MONTHS) 
  if(m<=2, NINIT, 0) + 
   sum(c in CONTR, n in maxlist(1,m-c+1)..minlist(m,NM-c+1)) rent(c,n) >= 
    REQ(m)

! Solve the problem
 minimize(Cost)
 
! Solution printing
 declarations
  NAMES: array(MONTHS) of string
 end-declarations

 initializations from 'e6vanrent.dat'
  NAMES
 end-initializations
 
 writeln("Total cost: ", getobjval)
 setparam("realfmt","%5g")   ! Reserve 5 char.s for display of real numbers
 write("new rents  ")
 forall(m in MONTHS) write(NAMES(m), "  ")
 writeln
 forall(c in CONTR) do
  write(c, " months ")
  forall(m in MONTHS) write(getsol(rent(c,m)))
  writeln
 end-do
 write("Total    ")
 forall(m in MONTHS) write(getsol(if(m<=2, NINIT, 0) + 
  sum(c in CONTR, n in maxlist(1,m-c+1)..minlist(m,NM-c+1)) rent(c,n)))
 writeln   

end-model

© 2001-2025 Fair Isaac Corporation. All rights reserved. This documentation is the property of Fair Isaac Corporation (“FICO”). Receipt or possession of this documentation does not convey rights to disclose, reproduce, make derivative works, use, or allow others to use it except solely for internal evaluation purposes to determine whether to purchase a license to the software described in this documentation, or as otherwise set forth in a written software license agreement between you and FICO (or a FICO affiliate). Use of this documentation and the software described in it must conform strictly to the foregoing permitted uses, and no other use is permitted.