(!******************************************************
Mosel Example Problems
======================
file contract.mos
`````````````````
TYPE: Contract allocation problem
DIFFICULTY: 2
FEATURES: simple MIP problem, semi-continuous variables,
graphical representation of results
DESCRIPTION: A public utility, which is divided into six regional
districts, wishes to allocate ten power generation
contracts to its regions as cheaply as possible. The cost
per unit of power generated by each region for each
contract is known. If part of a contract is allocated to
a region than it must be at least as big as a certain
minimum size (5 units). For reliability reasons, no
contract may be placed exclusively with only one district.
Each district has a limited power generation capacity.
FURTHER INFO: `Applications of optimization with Xpress-MP teaching
material', Section 2.2 `Semi-continuous variables:
contract allocation';
`Applications of optimization with Xpress-MP',
Section 3.4.3 `Semi-continuous variables'
(c) 2008 Fair Isaac Corporation
author: S. Heipcke, Jan. 2001, rev. Sep. 2017
*******************************************************!)
model "Contract allocation"
uses "mmxprs", "mmsvg"
declarations
DISTRICT = 1..6 ! Districts
CONTRACT = 1..10 ! Contracts
OUTPUT: array(DISTRICT) of integer ! Maximum output per district
COST : array(DISTRICT) of integer ! Cost per district
VOLUME: array(CONTRACT) of integer ! Volume of contracts
alloc: array(DISTRICT,CONTRACT) of mpvar ! 1 if a bid is chosen, 0 otherwise
quant: array(DISTRICT,CONTRACT) of mpvar ! Quantities allocated to contractors
end-declarations
initializations from 'contract.dat'
OUTPUT COST VOLUME
end-initializations
! Objective function: total cost
Cost:= sum(d in DISTRICT, c in CONTRACT) COST(d)*quant(d,c)
forall(c in CONTRACT) do
sum(d in DISTRICT) quant(d,c) >= VOLUME(c) ! Cover the req. contract volume
sum(d in DISTRICT) alloc(d,c) >= 2 ! At least 2 districts per contract
end-do
! Do not exceed maximum output of any district
forall(d in DISTRICT) Output(d):= sum(c in CONTRACT) quant(d,c) <= OUTPUT(d)
! If a contract is allocated to a district, then at least 1 unit is
! allocated to it
forall(d in DISTRICT, c in CONTRACT) MinAlloc(d,c):= alloc(d,c) <= quant(d,c)
forall(d in DISTRICT, c in CONTRACT) do
alloc(d,c) is_binary
quant(d,c) is_semcont 5
quant(d,c) <= OUTPUT(d)
end-do
! Solve the problem
minimize(Cost)
! Solution printing
writeln("Total cost: ", getobjval)
writeln("Contract Districts")
forall(c in CONTRACT) do
write(strfmt(c,3), " (", VOLUME(c), "):")
forall(d in DISTRICT)
write(if(getsol(quant(d,c))>0, " "+d+"("+getsol(quant(d,c))+")", ""))
writeln
end-do
! Solution drawing
declarations
DistrGraph: array(DISTRICT) of string
end-declarations
forall(d in DISTRICT) do
DistrGraph(d):= "D"+d
svgaddgroup(DistrGraph(d), "District "+d)
svgsetstyle(SVG_STROKEWIDTH, "0.3")
end-do
forall(c in CONTRACT) do
ct:=0.0
forall(d in DISTRICT)
if getsol(quant(d,c))>0 then
! svgaddrectangle(DistrGraph(d), 2*c-0.2, ct, 0.4, getsol(quant(d,c)))
svgaddrectangle(DistrGraph(d), c-0.1, ct, 0.2, getsol(quant(d,c))/2)
ct+=getsol(quant(d,c))/2
end-if
end-do
svgsetgraphlabels("Contracts", "Contract volume")
svgsetgraphviewbox(0, 0, CONTRACT.size+1, 0.5*max(c in CONTRACT) VOLUME(c))
svgsave("contract.svg")
svgrefresh
svgwaitclose("Close browser window to terminate model execution.", 1)
end-model
|