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
|
|