Initializing help system before first use

Vehicle routing


Type: Vehicle routing (VRP)
Rating: 4 (medium-difficult)
Description: A transporter has to deliver heating oil from a refinery to a certain number of clients. The distances between the clients and the refinery and the demands in liters for the different sites are given. The transport company uses tankers with a capacity of 39000 liters for the deliveries. Determine the tours for delivering to all clients that minimize the total number of kilometers driven.
File(s): vrp_graph.mos
Data file(s): vrp.dat


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

   file vrp.mos
   ````````````
   TYPE:         Vehicle routing problem (VRP)
   DIFFICULTY:   4
   FEATURES:     MIP problem, formulation of constraints to eliminate
                 inadmissible subtours, definition of model cuts,
                 selection  with `|', algorithm for printing the tours, 
                 graphical solution representation
   DESCRIPTION:  A transporter has to deliver heating oil from a refinery 
                 to a certain number of clients. The distances between the
                 clients and the refinery and the demands in liters for 
                 the different sites are given. The transport company uses 
                 tankers with a capacity of 39000 liters for the deliveries. 
                 Determine the tours for delivering to all clients that 
                 minimize the total number of kilometers driven.
   FURTHER INFO: `Applications of optimization with Xpress-MP', 
                 Section 10.4 `Heating oil delivery'
   
   (c) 2008 Fair Isaac Corporation
       author: S. Heipcke, 2002, rev. Sep. 2017
*******************************************************!)

model "Heating oil delivery"
 uses "mmxprs", "mmsvg"

 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 'vrp.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) EnterOnce(j):= sum(i in SITES| i<>j) prec(i,j) = 1
 forall(i in CLIENTS) LeaveOnce(i):= 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) QuantFirst(i):= 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) 
  QuantSucc(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)
  if(getsol(prec(1,i))>0) then
   ct:=DEM(i)
   writeln(1, " -> ", i)
   p:=i
   while(p<>1) do
    n:= integer(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-if

! Solution drawing
 declarations
  X,Y: array(SITES) of integer        ! x-y-coordinates of sites
 end-declarations
 
 initializations from 'vrp.dat'
  [X,Y] as 'POS'
 end-initializations

 minx:=min(i in SITES)X(i)-15; miny:=min(i in SITES)Y(i)-15
 svgsetgraphviewbox(0, 0,
         max(i in SITES)X(i)+15, max(i in SITES)Y(i)+25)
 svgsetgraphscale(2)
 svgsetgraphpointsize(2)

 svgaddgroup("Sites", "Clients", SVG_BLACK)
 forall(i in CLIENTS) do
  svgaddpoint(X(i), Y(i))
  svgaddtext(X(i)+0.5, Y(i)+1, text(i-1))
 end-do
 svgaddgroup("Ref", "Refinery", SVG_BROWN)
 svgaddpoint(X(1), Y(1))
 svgaddtext(X(1)+0.5, Y(1)-5, "Refinery")

 svgaddgroup("Routes", "Delivery routes")
 forall(i in CLIENTS)
  if(getsol(prec(1,i))>0) then
   svgaddarrow(X(1), Y(1), X(i), Y(i))
   p:=i
   while(p<>1) do
    n:= integer(round(sum(j in SITES) j*getsol(prec(p,j))))
    svgaddarrow(X(p), Y(p), X(n), Y(n))
    p:=n
   end-do
  end-if

 svgsave("vrp.svg")
 svgrefresh
 svgwaitclose("Close browser window to terminate model execution.", 1)
end-model

© 2001-2026 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.