j1water.mos |
(!******************************************************
Mosel Example Problems
======================
file j1water.mos
````````````````
Water conveyance/water supply management
A water transport network is provided. Nodes correspond
to cities, reservoirs, and pumping stations. Arcs
correspond to pipes. Capacities for each reservoir,
demand for each city, and capacities for the pipe
connections are given. How much water should flow through
each pipe to maximize the flow in the network?
A network transformation is presented to introduce fictitious
source and sink nodes. A LP model based on the transport
network representation is presented.
(c) 2008 Fair Isaac Corporation
author: S. Heipcke, Mar. 2002
*******************************************************!)
model "J-1 Water supply"
uses "mmxprs"
declarations
ARCS: range ! Set of arcs
NODES=1..12
PIPE: array(ARCS,1..2) of integer ! Definition of arcs (= pipes)
CAP: array(ARCS) of integer ! Capacity of arcs
SOURCE,SINK: integer ! Number of source and sink nodes
end-declarations
initializations from 'j1water.dat'
PIPE CAP SOURCE SINK
end-initializations
declarations
flow: array(ARCS) of mpvar ! Flow on arcs
end-declarations
! Objective: total flow
TotalFlow:= sum(a in ARCS | PIPE(a,2)=SINK) flow(a)
! Flow balances in nodes
forall(n in NODES | n<>SOURCE and n<>SINK)
sum(a in ARCS | PIPE(a,1)=n) flow(a) = sum(a in ARCS | PIPE(a,2)=n) flow(a)
! Capacity limits
forall(a in ARCS) flow(a) <= CAP(a)
! Solve the problem
maximize(TotalFlow)
! Solution printing
writeln("Total flow: ", getobjval)
forall(a in ARCS) writeln(PIPE(a,1), " -> ", PIPE(a,2), ": ", getsol(flow(a)))
end-model
|
|
j1water2.mos |
(!******************************************************
Mosel Example Problems
======================
file j1water2.mos
`````````````````
Water conveyance/water supply management
- Record version -
A water transport network is provided. Nodes correspond
to cities, reservoirs, and pumping stations. Arcs
correspond to pipes. Capacities for each reservoir,
demand for each city, and capacities for the pipe
connections are given. How much water should flow through
each pipe to maximize the flow in the network?
A network transformation is presented to introduce fictitious
source and sink nodes. A LP model based on the transport
network representation is presented. All data and decision
variables are grouped in a single record data struture.
(c) 2008-2022 Fair Isaac Corporation
author: S. Heipcke, July 2006
*******************************************************!)
model "J-1 Water supply (2)"
uses "mmxprs"
declarations
ARCS: range ! Set of arcs
NODES=1..12
PIPE: array(ARCS) of record ! Definition of arcs (= pipes)
Source,Sink: integer ! start/end point of arc
Capacity: integer ! arc capacity
flow: mpvar ! flow on arc
end-record
SOURCE,SINK: integer ! Number of source and sink nodes
end-declarations
initializations from 'j1water2.dat'
PIPE(Source,Sink,Capacity) SOURCE SINK
end-initializations
! Objective: total flow
TotalFlow:= sum(a in ARCS | PIPE(a).Sink=SINK) PIPE(a).flow
! Flow balances in nodes
forall(n in NODES | n<>SOURCE and n<>SINK)
sum(a in ARCS | PIPE(a).Source=n) PIPE(a).flow =
sum(a in ARCS | PIPE(a).Sink=n) PIPE(a).flow
! Capacity limits
forall(a in ARCS) PIPE(a).flow <= PIPE(a).Capacity
! Solve the problem
maximize(TotalFlow)
! Solution printing
writeln("Total flow: ", getobjval)
forall(a in ARCS)
writeln(PIPE(a).Source, " -> ", PIPE(a).Sink, ": ", getsol(PIPE(a).flow))
end-model
|
|
j1water_graph.mos |
(!******************************************************
Mosel Example Problems
======================
file j1water_graph.mos
````````````````
Water conveyance/water supply management
A water transport network is provided. Nodes correspond
to cities, reservoirs, and pumping stations. Arcs
correspond to pipes. Capacities for each reservoir,
demand for each city, and capacities for the pipe
connections are given. How much water should flow through
each pipe to maximize the flow in the network?
A network transformation is presented to introduce fictitious
source and sink nodes. A LP model based on the transport
network representation is presented.
(c) 2008-2023 Fair Isaac Corporation
author: S. Heipcke, Mar. 2002, rev. Jun. 2023
*******************************************************!)
model "J-1 Water supply"
uses "mmxprs", "mmsvg"
declarations
ARCS: range ! Set of arcs
NODES=1..12
PIPE: array(ARCS,1..2) of integer ! Definition of arcs (= pipes)
CAP: array(ARCS) of integer ! Capacity of arcs
SOURCE,SINK: integer ! Number of source and sink nodes
end-declarations
initializations from 'j1water.dat'
PIPE CAP SOURCE SINK
end-initializations
declarations
flow: array(ARCS) of mpvar ! Flow on arcs
end-declarations
! Objective: total flow
TotalFlow:= sum(a in ARCS | PIPE(a,2)=SINK) flow(a)
! Flow balances in nodes
forall(n in NODES | n<>SOURCE and n<>SINK)
sum(a in ARCS | PIPE(a,1)=n) flow(a) = sum(a in ARCS | PIPE(a,2)=n) flow(a)
! Capacity limits
forall(a in ARCS) flow(a) <= CAP(a)
! Solve the problem
maximize(TotalFlow)
! Solution printing
writeln("Total flow: ", getobjval)
forall(a in ARCS) writeln(PIPE(a,1), " -> ", PIPE(a,2), ": ", getsol(flow(a)))
! Solution drawing
declarations
XN,YN: array(NODES) of real ! x-y-coordinates of all nodes
end-declarations
initializations from 'j1water.dat'
[XN,YN] as 'POS'
end-initializations
! Define settings of global picture
svgsetgraphviewbox(0,0,125,100) ! set dimensions of generated image (start x, start y, dim x, dim y)
svgsetgraphscale(3) ! scale of points/arrows and text
! Add arrows for flow values
svgaddgroup("ActArcs", "Active pipes and optimal flow values", SVG_GREEN)
svgaddgroup("InactArcs", "Inactive pipes", SVG_BLACK)
forall(a in ARCS) do
if(getsol(flow(a)) > 0) then
svgaddarrow("ActArcs", XN(PIPE(a,1)), YN(PIPE(a,1)), XN(PIPE(a,1)) + (XN(PIPE(a,2))-XN(PIPE(a,1)))*0.93, YN(PIPE(a,1)) + (YN(PIPE(a,2)) - YN(PIPE(a,1)))*0.93)
svgsetstyle(svggetlastobj, SVG_STROKEWIDTH, 1.5)
! Add flow value in the center of the arrow
svgaddtext("ActArcs", (XN(PIPE(a,1))+XN(PIPE(a,2)))/2-1.5, (YN(PIPE(a,1))+YN(PIPE(a,2)))/2-3, text(getsol(flow(a))))
svgsetstyle(svggetlastobj, SVG_FONTSTYLE, 'italic')
svgsetstyle(svggetlastobj, SVG_FONTSIZE, 'xx-small')
svgsetstyle(svggetlastobj, SVG_FONTWEIGHT, 'bold')
else
svgaddarrow("InactArcs", XN(PIPE(a,1)), YN(PIPE(a,1)), XN(PIPE(a,1)) + (XN(PIPE(a,2))-XN(PIPE(a,1)))*0.93, YN(PIPE(a,1)) + (YN(PIPE(a,2)) - YN(PIPE(a,1)))*0.93)
svgsetstyle(svggetlastobj, SVG_STROKEDASH, 1.5)
svgsetstyle(svggetlastobj, SVG_STROKEWIDTH, 1.5)
svgsetstyle(svggetlastobj, SVG_STROKEOPACITY, 0.5)
end-if
end-do
! Add reservoir nodes
svgaddgroup("Nodes", "Nodes", SVG_GRAY) ! declare groups to add color
forall(n in NODES) do
svgaddcircle("Nodes", XN(n), YN(n), 1.25)
svgsetstyle(svggetlastobj, SVG_FILL, SVG_GRAY)
svgaddtext("Nodes", XN(n)+1, YN(n)+1, text(n))
svgsetstyle(svggetlastobj, SVG_FONTSIZE, 'x-small')
svgsetstyle(svggetlastobj, SVG_FONTWEIGHT, 'bold')
svgsetstyle(svggetlastobj, SVG_TEXTANCHOR, 'start')
end-do
svgsave("j1water.svg")
svgrefresh
svgwaitclose("Close browser window to terminate model execution.", 1)
end-model
|
|
j2bigbro.mos |
(!******************************************************
Mosel Example Problems
======================
file j2bigbro.mos
`````````````````
CCTV surveillance
A town council has determined candidate street intersections
where cameras can be installed. A map providing the possible
locations is given. Where should the cameras be located
to monitor all the streets to minimize the total number
of installed cameras?
This problem is modeled as a graph-based IP model. Nodes
in the graph correspond to street intersections where
cameras can be installed, and links correspond to the
streets connecting nodes. The undirected graph is
encoded by a symmetric adjacency matrix. The unique set
of constraints guarantees that every street needs
to be surveyed by at least one camera.
(c) 2008-2022 Fair Isaac Corporation
author: S. Heipcke, Mar. 2002, rev. Mar. 2022
*******************************************************!)
model "J-2 CCTV surveillance"
uses "mmxprs"
declarations
NODES=1..49
STREET: dynamic array(NODES,NODES) of integer ! 1 if a street connects
! two nodes, 0 otherwise
place: array(NODES) of mpvar ! 1 if camera at node, 0 otherwise
end-declarations
initializations from 'j2bigbro.dat'
STREET
end-initializations
forall(n,m in NODES | exists(STREET(n,m)) and n<m )
STREET(m,n):= STREET(n,m)
! Objective: number of cameras to install
Total:= sum(n in NODES) place(n)
! Flow balances in nodes
forall(n,m in NODES | exists(STREET(n,m)) ) place(n)+place(m) >= 1
forall(n in NODES) place(n) is_binary
! Solve the problem
minimize(Total)
! Solution printing
writeln("Total number of cameras: ", getobjval)
forall(n in NODES | getsol(place(n))>0) write(" ", n)
writeln
end-model
|
|
j2bigbro_graph.mos |
(!******************************************************
Mosel Example Problems
======================
file j2bigbro_graph.mos
`````````````````
CCTV surveillance
A town council has determined candidate street intersections
where cameras can be installed. A map providing the possible
locations is given. Where should the cameras be located
to monitor all the streets to minimize the total number
of installed cameras?
This problem is modeled as a graph-based IP model. Nodes
in the graph correspond to street intersections where
cameras can be installed, and links correspond to the
streets connecting nodes. The undirected graph is
encoded by a symmetric adjacency matrix. The unique set
of constraints guarantees that every street needs
to be surveyed by at least one camera.
The resulting street map is displayed graphically.
(c) 2008-2023 Fair Isaac Corporation
author: S. Heipcke, Mar. 2002, rev. Jun. 2023
*******************************************************!)
model "J-2 CCTV surveillance"
uses "mmxprs", "mmsvg"
declarations
NODES=1..49
STREET: dynamic array(NODES,NODES) of integer ! 1 if a street connects two nodes, 0 otherwise
place: array(NODES) of mpvar ! 1 if camera at node, 0 otherwise
end-declarations
initializations from 'j2bigbro.dat'
STREET
end-initializations
! Connections are recyprocal
forall(n,m in NODES | exists(STREET(n,m)))
STREET(m,n):= STREET(n,m)
! Objective: number of cameras to install
Total:= sum(n in NODES) place(n)
! Flow balances in nodes - ensure all streets are covered
forall(n,m in NODES | exists(STREET(n,m)) ) place(n)+place(m) >= 1
forall(n in NODES) place(n) is_binary
! Solve the problem
minimize(Total)
! Solution printing
writeln("Total number of cameras: ", getobjval)
forall(n in NODES | getsol(place(n))>0) write(" ", n)
writeln
! Solution drawing
declarations
XN,YN: array(NODES) of integer ! x-y-coordinates of nodes (potential camera locations)
end-declarations
initializations from 'j2bigbro.dat'
[XN,YN] as 'POS'
end-initializations
! Define settings of global picture
svgsetgraphviewbox(2,3,110,110) ! set dimensions of generated image (start x, start y, dim x, dim y)
svgsetgraphscale(3) ! scale of points/arrows and text
! Add points related to nodes, highlighting the nodes chosen for a camera
svgaddgroup("CovNodes", "Optimal camera locations", SVG_GREEN) ! declare groups to add color
svgaddgroup("UncNodes", "Other possible locations", SVG_BLACK)
forall(n in NODES) do
if(getsol(place(n))>0) then ! if location is chosen depict a different color
svgaddcircle("CovNodes", XN(n), YN(n), 0.3)
svgsetstyle(svggetlastobj, SVG_FILL, SVG_GREEN)
svgaddcircle("CovNodes", XN(n), YN(n), 1.2)
svgaddtext("CovNodes", XN(n)+1, YN(n)+1, text(n))
else
svgaddcircle("UncNodes", XN(n), YN(n), 0.4)
svgsetstyle(svggetlastobj, SVG_FILL, SVG_BLACK)
svgaddtext("UncNodes", XN(n)+1, YN(n)+1, text(n))
end-if
svgsetstyle(svggetlastobj, SVG_FONTSIZE, 'xx-small')
svgsetstyle(svggetlastobj, SVG_FONTWEIGHT, 'bold')
end-do
! Add lines between nodes representing streets
svgaddgroup("BuildStreets", "Streets", SVG_GRAY)
forall(n,m in NODES | exists(STREET(n,m))) do
svgaddline("BuildStreets", XN(n), YN(n), XN(m), YN(m))
svgsetstyle(svggetlastobj, SVG_COLOR, SVG_GRAY)
svgsetstyle(svggetlastobj, SVG_STROKEWIDTH, 4)
svgsetstyle(svggetlastobj, SVG_STROKEOPACITY, 0.3)
end-do
svgsave("j2bigbro.svg")
svgrefresh
svgwaitclose("Close browser window to terminate model execution.", 1)
end-model |
|
j3elect.mos |
(!******************************************************
Mosel Example Problems
======================
file j3elect.mos
````````````````
Grouping quarters to election districts
For elections, a capital is divided into zones called
quarters. For each quarter, we know the forecasted number
of favorable votes for a particular candidate and the total
number of electors. An electoral district is formed by
several adjacent quarters that must have between a minimum
and a maximum number of voters. Determine a partitioning
into five electoral districts that maximizes the number
of seats for the candidate.
This partitioning problem asks for a subset of electoral
districts such that every quarter appears in a single chosen
electoral district. The Mosel implementation is divided into
the data preprocessing and the model itself. After data arrays
declaration, the included file j3elect_calc.mos generates the data
in the form required for the model. Function 'getprobstat'
is used to test the optimization status.
(c) 2008-2022 Fair Isaac Corporation
author: S. Heipcke, Apr. 2002, rev. Mar. 2022
*******************************************************!)
model "J-3 Rigging elections"
uses "mmxprs"
parameters
REQD = 6 ! Required number of districts
end-parameters
declarations
QUARTERS = 1..14 ! Number of quarters
RDIST: range ! Set of election districts
MAJ: array(RDIST) of integer ! 1 if majority of votes, 0 otherwise
DISTR: array(RDIST,QUARTERS) of integer ! 1 if quarter is in district,
! 0 otherwise
end-declarations
include "j3elect_calc.mos"
declarations
choose: array(RDIST) of mpvar ! 1 if district chosen, 0 otherwise
end-declarations
! Objective: number of votes
Votes:= sum(d in RDIST) MAJ(d)*choose(d)
! Partitioning
forall(q in QUARTERS) sum(d in RDIST) DISTR(d,q)*choose(d) = 1
! Desired number of districts
sum(d in RDIST) choose(d) = REQD
forall(d in RDIST) choose(d) is_binary
! Solve the problem
maximize(Votes)
! Solution printing
if(getprobstat<>XPRS_OPT) then
writeln("Problem is infeasible")
else
writeln("Total number of votes: ", getobjval)
forall(r in RDIST | getsol(choose(r))>0) do
write(r, ": ")
forall(q in QUARTERS | DISTR(r,q)>0) write(" ", q)
writeln(" (", MAJ(r), ")")
end-do
end-if
end-model
|
|
j3elect_calc.mos |
(!******************************************************
Mosel Example Problems
======================
file j3elect_calc.mos
````````````````''''`
Include file for data pre-processing
(c) 2008 Fair Isaac Corporation
author: S. Heipcke, Apr. 2002
*******************************************************!)
declarations
NUMD: integer ! Number of possible districts
RN: range ! Neighboring quarters
NEIGHB: dynamic array(QUARTERS,RN) of integer ! Set of neighboring quarters
POP: array(QUARTERS) of integer ! Number of electors (in 1000)
VOTES: array(QUARTERS) of real ! Number of favorable votes (in 1000)
MINPOP,MAXPOP,MINSINGLE: integer ! Limits on electors per district
end-declarations
initializations from 'j3elect.dat'
NEIGHB POP VOTES MINPOP MAXPOP MINSINGLE
end-initializations
!**** Save a new entry in the list of districts ****
procedure savedistr(sQ: set of integer)
NUMD+=1
forall(q in sQ) DISTR(NUMD,q):=1
end-procedure
!**** Add a neighboring quarter to the current set of quarters ****
procedure addneighb(toadd:integer, sQ:set of integer)
declarations
nQ: set of integer
end-declarations
nQ:=sQ+{toadd}
if(sum(q in nQ) POP(q) >= MINPOP) then ! Large enough to form distr.
savedistr(nQ)
end-if
forall(p in RN | exists(NEIGHB(toadd,p))) ! Try adding every neighbor
if(sum(q in nQ) POP(q)+POP(NEIGHB(toadd,p))<=MAXPOP) then
addneighb(NEIGHB(toadd,p), nQ)
end-if
end-procedure
!**** Calculate the list of possible districts ****
procedure calculatedistr
NUMD:=0
forall(q in QUARTERS) do
if (POP(q) >= MINSINGLE and q<>10) then ! Single quarter districts
savedistr({q})
end-if
forall(p in RN | exists(NEIGHB(q,p))) ! Try adding every neighbor
if(POP(q)+POP(NEIGHB(q,p))<=MAXPOP) then
addneighb(NEIGHB(q,p),{q})
end-if
end-do
forall(d in 1..NUMD) do ! Print the resulting list
write(d,":")
forall(q in QUARTERS| DISTR(d,q)>0) write(" ", q)
writeln(" ", (sum(q in QUARTERS | DISTR(d,q)>0) VOTES(q)) *100 /
(sum(q in QUARTERS | DISTR(d,q)>0) POP(q)), "%")
end-do
writeln("Number of possible districts: ",NUMD)
forall(d in 1..NUMD) ! Calculate majorities
MAJ(d):= if(((sum(q in QUARTERS | DISTR(d,q)>0) VOTES(q)) /
(sum(q in QUARTERS | DISTR(d,q)>0) POP(q)) >= 0.5), 1, 0)
finalize(RDIST)
end-procedure
!**** Start the calculation of the list of possible districts ****
calculatedistr
|
|
j3elect_calc2.mos |
(!******************************************************
Mosel Example Problems
======================
file j3elect_calc2.mos
`````````````````````````
Include file for data pre-processing
- Set version -
(c) 2008 Fair Isaac Corporation
author: S. Heipcke, Jan. 2006
*******************************************************!)
declarations
NUMD: integer ! Number of possible districts
NEIGHB: array(QUARTERS) of set of integer ! Set of neighboring quarters
POP: array(QUARTERS) of integer ! Number of electors (in 1000)
VOTES: array(QUARTERS) of real ! Number of favorable votes (in 1000)
MINPOP,MAXPOP,MINSINGLE: integer ! Limits on electors per district
end-declarations
initializations from 'j3elect2.dat'
NEIGHB POP VOTES MINPOP MAXPOP MINSINGLE
end-initializations
!**** Save a new entry in the list of districts ****
procedure save_distr(sQ: set of integer)
NUMD+=1
forall(q in sQ) DISTR(NUMD,q):=1
end-procedure
!**** Add a neighboring quarter to the current set of quarters ****
procedure add_neighb(toadd:integer, sQ:set of integer)
declarations
nQ: set of integer
end-declarations
nQ:=sQ+{toadd}
if(sum(q in nQ) POP(q) >= MINPOP) then ! Large enough to form distr.
save_distr(nQ)
end-if
forall(p in NEIGHB(toadd)) ! Try adding every neighbor
if(sum(q in nQ) POP(q)+POP(p)<=MAXPOP) then
add_neighb(p, nQ)
end-if
end-procedure
!**** Calculate the list of possible districts ****
procedure calculate_distr
NUMD:=0
forall(q in QUARTERS) do
if (POP(q) >= MINSINGLE and q<>10) then ! Single quarter districts
save_distr({q})
end-if
forall(p in NEIGHB(q)) ! Try adding every neighbor
if(POP(q)+POP(p)<=MAXPOP) then
add_neighb(p,{q})
end-if
end-do
forall(d in 1..NUMD) do ! Print the resulting list
write(d,":")
forall(q in QUARTERS) write(if(DISTR(d,q)>0, " "+q, ""))
writeln(" ", (sum(q in QUARTERS | DISTR(d,q)>0) VOTES(q)) *100 /
(sum(q in QUARTERS | DISTR(d,q)>0) POP(q)), "%")
end-do
writeln("Number of possible districts: ",NUMD)
forall(d in 1..NUMD) ! Calculate majorities
MAJ(d):= if(((sum(q in QUARTERS | DISTR(d,q)>0) VOTES(q)) /
(sum(q in QUARTERS | DISTR(d,q)>0) POP(q)) >= 0.5), 1, 0)
finalize(RDIST)
end-procedure
!**** Start the calculation of the list of possible districts ****
calculate_distr
|
|
j3elect_graph.mos |
(!******************************************************
Mosel Example Problems
======================
file j3elect_graph.mos
````````````````
Grouping quarters to election districts
For elections, a capital is divided into zones called
quarters. For each quarter, we know the forecasted number
of favorable votes for a particular candidate and the total
number of electors. An electoral district is formed by
several adjacent quarters that must have between a minimum
and a maximum number of voters. Determine a partitioning
into five electoral districts that maximizes the number
of seats for the candidate.
This partitioning problem asks for a subset of electoral
districts such that every quarter appears in a single chosen
electoral district. The Mosel implementation is divided into
the data preprocessing and the model itself. After data arrays
declaration, the included file j3elect_calc.mos generates the data
in the form required for the model. Function 'getprobstat'
is used to test the optimization status.
The resulting district map is displayed graphically.
(c) 2008-2023 Fair Isaac Corporation
author: S. Heipcke, Apr. 2002, rev. Jun. 2023
*******************************************************!)
model "J-3 Rigging elections"
uses "mmxprs", "mmsvg"
parameters
REQD = 6 ! Required number of districts
end-parameters
declarations
QUARTERS = 1..14 ! Number of quarters
RDIST: range ! Set of election districts
MAJ: array(RDIST) of integer ! 1 if majority of votes, 0 otherwise
DISTR: array(RDIST,QUARTERS) of integer ! 1 if quarter is in district,
! 0 otherwise
end-declarations
include "j3elect_calc.mos"
declarations
choose: array(RDIST) of mpvar ! 1 if district chosen, 0 otherwise
end-declarations
! Objective: number of votes
Votes:= sum(d in RDIST) MAJ(d)*choose(d)
! Partitioning
forall(q in QUARTERS) sum(d in RDIST) DISTR(d,q)*choose(d) = 1
! Desired number of districts
sum(d in RDIST) choose(d) = REQD
forall(d in RDIST) choose(d) is_binary
! Solve the problem
maximize(Votes)
! Solution printing
if(getprobstat<>XPRS_OPT) then
writeln("Problem is infeasible")
else
writeln("Total number of votes: ", getobjval)
forall(r in RDIST | getsol(choose(r))>0) do
write(r, ": ")
forall(q in QUARTERS | DISTR(r,q)>0) write(" ", q)
writeln(" (", MAJ(r), ")")
end-do
end-if
! Solution drawing
declarations
XQ,YQ,WQ,HQ: array(QUARTERS) of integer ! x-y-coordinates, wight and height of rectangles (quarters)
end-declarations
initializations from 'j3elect.dat'
[XQ,YQ,WQ,HQ] as 'REC'
end-initializations
! Define settings of global picture
svgsetgraphviewbox(0,0,130,130) ! set dimensions of generated image (start x, start y, dim x, dim y)
svgsetgraphscale(3) ! scale of points/arrows and text
! Iterate over districts and create a group with random colors for each
setrandseed(7)
forall(r in RDIST | getsol(choose(r))>0) do
red := integer(255*random)
green := integer(255*random)
blue := integer(255*random)
svgaddgroup("d"+r,"District "+r, svgcolor(red,green,blue)) ! declare groups to add randomly generated colors
forall(q in QUARTERS | DISTR(r,q)>0) do
svgaddrectangle("d"+r, XQ(q), YQ(q),WQ(q),HQ(q))
svgsetstyle(svggetlastobj, SVG_FILL, svgcolor(red,green,blue))
svgsetstyle(svggetlastobj, SVG_OPACITY, 0.4)
! Add district label in the center of the rectangle
svgaddtext((2*XQ(q)+WQ(q))/2-2, (2*YQ(q)+HQ(q))/2-2, text(q))
svgsetstyle(svggetlastobj, SVG_FONTSIZE, 'small')
svgsetstyle(svggetlastobj, SVG_FONTWEIGHT, 'bold')
end-do
end-do
svgsave("j3elect.svg")
svgrefresh
svgwaitclose("Close browser window to terminate model execution.", 1)
end-model |
|
j4grit.mos |
(!******************************************************
Mosel Example Problems
======================
file j4grit.mos
```````````````
Gritting roads in a village
A directed graph representing street intersections (nodes)
and streets required to be gritted (arcs) is provided.
Street lengths are arc attributes, and the initial location
of a gritting truck is also known. Determine a tour for the
gritting truck of minimum total length that passes through
all streets.
The graph is implemented as an adjacency matrix. Decision
variables represent the frequency of use of an arc (streets).
Since a Eulerian circuit is asked, the function 'addpath'
is implemented to obtain the Eulerian circuit post optimization
from the decision variables solution.
(c) 2008-2022 Fair Isaac Corporation
author: S. Heipcke, Mar. 2002, rev. Mar. 2022
*******************************************************!)
model "J-4 Gritting circuit"
uses "mmxprs"
forward function findunused(J: array(range) of integer):integer
forward function addpath(node:integer, J: array(range) of integer):integer
declarations
ISEC = 1..12 ! Set of street intersections
LEN: dynamic array(ISEC,ISEC) of integer ! Length of streets
use: dynamic array(ISEC,ISEC) of mpvar ! Frequency of use of streets
end-declarations
initializations from 'j4grit.dat'
LEN
end-initializations
forall(i,j in ISEC | exists(LEN(i,j))) create(use(i,j))
! Objective: length of circuit
Length:= sum(i,j in ISEC | exists(LEN(i,j))) LEN(i,j)*use(i,j)
! Balance traffic flow through intersections
forall(i in ISEC) sum(j in ISEC) use(i,j) = sum(j in ISEC) use(j,i)
! Grit every street
forall(i,j in ISEC | exists(LEN(i,j))) use(i,j) >= 1
! Solve the problem
minimize(Length)
! Solution printing
writeln("Total length: ", getobjval)
ct:=round(getsol(sum(i,j in ISEC) use(i,j)))
declarations
TOUR: array(1..ct+1) of integer
TCOUNT: array(ISEC,ISEC) of integer
end-declarations
! Main loop of the Eulerian circuit algorithm
forall(i,j in ISEC | exists(LEN(i,j))) TCOUNT(i,j):=round(getsol(use(i,j)))
TOUR(1):=1
ct-=addpath(1,TOUR)
while(ct>0)
ct-=addpath(findunused(TOUR),TOUR)
writeln("Tour: ", TOUR)
!-----------------------------------------------------------------
! Find first node in list with free path(s)
function findunused(J: array(range) of integer):integer
i:=1
returned:=1
while(J(i)>0 and i<getsize(J))
if (sum(j in ISEC) TCOUNT(J(i),j) > 0) then
returned:=J(i)
break
else
i+=1
end-if
end-function
!-----------------------------------------------------------------
! Add a subtour to the current tour
function addpath(node:integer, J: array(range) of integer):integer
declarations
NEWJ: array(1..getsize(J)) of integer
end-declarations
! Insertion position
pos:=1
while(J(pos)<>node and pos<getsize(J)) pos+=1
! Find a new path
cur:=node; newct:=0
while(sum(j in ISEC) TCOUNT(cur,j) > 0) do
forall(j in ISEC) if(TCOUNT(cur,j) > 0) then
TCOUNT(cur,j)-=1
newct+=1; NEWJ(newct):=j
cur:=j
break
end-if
end-do
! Add the new path to main journey
i:=getsize(J)-newct
while(i>pos) do
J(i+newct):=J(i)
i-=1
end-do
forall(j in 1..newct) J(pos+j):=NEWJ(j)
returned:=newct
end-function
end-model
|
|
j4grit2.mos |
(!******************************************************
Mosel Example Problems
======================
file j4grit_list.mos
````````````````````
Gritting roads in a village
- List version -
(c) 2009 Fair Isaac Corporation
author: S. Heipcke, July 2006
*******************************************************!)
model "J-4 Gritting circuit"
uses "mmxprs"
forward function find_unused(J: list of integer):integer
forward function add_path(node:integer, J: list of integer):integer
declarations
ISEC = 1..12 ! Set of street intersections
LEN: dynamic array(ISEC,ISEC) of integer ! Length of streets
use: dynamic array(ISEC,ISEC) of mpvar ! Frequency of use of streets
end-declarations
initializations from 'j4grit.dat'
LEN
end-initializations
forall(i,j in ISEC | exists(LEN(i,j))) create(use(i,j))
! Objective: length of circuit
Length:= sum(i,j in ISEC | exists(LEN(i,j))) LEN(i,j)*use(i,j)
! Balance traffic flow through intersections
forall(i in ISEC) sum(j in ISEC) use(i,j) = sum(j in ISEC) use(j,i)
! Grit every street
forall(i,j in ISEC | exists(LEN(i,j))) use(i,j) >= 1
! Solve the problem
minimize(Length)
! Solution printing
writeln("Total length: ", getobjval)
ct:=round(getsol(sum(i,j in ISEC) use(i,j)))
declarations
TOUR: list of integer
UNUSED: array(ISEC) of list of integer
end-declarations
! Main loop of the Eulerian circuit algorithm
forall(i,j in ISEC | exists(LEN(i,j)), k in 1..round(getsol(use(i,j))))
UNUSED(i)+=[j]
TOUR:=[1]
ct-=add_path(1,TOUR)
while(ct>0)
ct-=add_path(find_unused(TOUR),TOUR)
writeln("Tour: ", TOUR)
!-----------------------------------------------------------------
! Find first node in list with free path(s)
function find_unused(J: list of integer):integer
returned:=0
forall(i in J)
if UNUSED(i) <> [] then
returned:=i
break
end-if
end-function
!-----------------------------------------------------------------
! Add a subtour to the current tour
function add_path(node:integer, J: list of integer):integer
declarations
NEWJ, TAIL: list of integer
end-declarations
! Insertion position
pos:= findfirst(J, node)
! Find a new path
cur:=node
while(UNUSED(cur) <> []) do
NEWJ+=splithead(UNUSED(cur),1)
cur:=getlast(NEWJ)
end-do
! Add the new path to main journey
TAIL:=splittail(J, -pos)
J += NEWJ + TAIL
returned:=getsize(NEWJ)
end-function
end-model
|
|
j4grit_graph.mos |
(!******************************************************
Mosel Example Problems
======================
file j4grit_graph.mos
`````````````````````
Gritting roads in a village
A directed graph representing street intersections (nodes)
and streets required to be gritted (arcs) is provided.
Street lengths are arc attributes, and the initial location
of a gritting truck is also known. Determine a tour for the
gritting truck of minimum total length that passes through
all streets.
The graph is implemented as an adjacency matrix. Decision
variables represent the frequency of use of an arc (streets).
Since a Eulerian circuit is asked, the function 'addpath'
is implemented to obtain the Eulerian circuit post optimization
from the decision variables solution.
The resulting circuit is displayed graphically.
(c) 2008-2022 Fair Isaac Corporation
author: S. Heipcke, Mar. 2002, rev. Mar. 2022
*******************************************************!)
model "J-4 Gritting circuit"
uses "mmxprs", "mmsvg"
forward function findunused(J: array(range) of integer):integer
forward function addpath(node:integer, J: array(range) of integer):integer
forward procedure drawtour
declarations
ISEC = 1..12 ! Set of street intersections
LEN: dynamic array(ISEC,ISEC) of integer ! Length of streets
use: dynamic array(ISEC,ISEC) of mpvar ! Frequency of use of streets
end-declarations
initializations from 'j4grit.dat'
LEN
end-initializations
forall(i,j in ISEC | exists(LEN(i,j))) create(use(i,j))
! Objective: length of circuit
Length:= sum(i,j in ISEC | exists(LEN(i,j))) LEN(i,j)*use(i,j)
! Balance traffic flow through intersections
forall(i in ISEC) sum(j in ISEC) use(i,j) = sum(j in ISEC) use(j,i)
! Grit every street
forall(i,j in ISEC | exists(LEN(i,j))) use(i,j) >= 1
! Solve the problem
minimize(Length)
! Solution printing
writeln("Total length: ", getobjval)
ct:=round(getsol(sum(i,j in ISEC) use(i,j)))
declarations
TOUR: array(1..ct+1) of integer
TCOUNT: array(ISEC,ISEC) of integer
end-declarations
! Main loop of the Eulerian circuit algorithm
forall(i,j in ISEC | exists(LEN(i,j))) TCOUNT(i,j):=round(getsol(use(i,j)))
TOUR(1):=1
ct-=addpath(1,TOUR)
while(ct>0)
ct-=addpath(findunused(TOUR),TOUR)
writeln("Tour: ", TOUR)
drawtour
!-----------------------------------------------------------------
! Find first node in list with free path(s)
function findunused(J: array(range) of integer):integer
i:=1
returned:=1
while(J(i)>0 and i<getsize(J))
if (sum(j in ISEC) TCOUNT(J(i),j) > 0) then
returned:=J(i)
break
else
i+=1
end-if
end-function
!-----------------------------------------------------------------
! Add a subtour to the current tour
function addpath(node:integer, J: array(range) of integer):integer
declarations
NEWJ: array(1..getsize(J)) of integer
end-declarations
! Insertion position
pos:=1
while(J(pos)<>node and pos<getsize(J)) pos+=1
! Find a new path
cur:=node; newct:=0
while(sum(j in ISEC) TCOUNT(cur,j) > 0) do
forall(j in ISEC) if(TCOUNT(cur,j) > 0) then
TCOUNT(cur,j)-=1
newct+=1; NEWJ(newct):=j
cur:=j
break
end-if
end-do
! Add the new path to main journey
i:=getsize(J)-newct
while(i>pos) do
J(i+newct):=J(i)
i-=1
end-do
forall(j in 1..newct) J(pos+j):=NEWJ(j)
returned:=newct
end-function
!-----------------------------------------------------------------
procedure drawtour
declarations
XPOS,YPOS: array(ISEC) of integer
ARC:dynamic array(ISEC,ISEC) of integer
end-declarations
forall(i in ISEC) do
XPOS(i):= (i-1) mod 4
YPOS(i):= 3 - ((i-1) div 4)
end-do
writeln(XPOS,YPOS)
svgaddgroup("Tour", "Eulerian Graph")
forall(i in 2..TOUR.size) ARC(TOUR(i-1),TOUR(i))+=1
forall(i,j in ISEC | exists(ARC(i,j))) do
svgaddarrow(XPOS(i),YPOS(i),XPOS(j),YPOS(j))
svgsetstyle(svggetlastobj, SVG_STROKEWIDTH, 0.25*ARC(i,j))
end-do
svgaddgroup("Node", "Intersections")
svgsetstyle(SVG_FONTSIZE, "3px")
forall(i in ISEC)
svgaddtext(XPOS(i)-0.3,YPOS(i)+0.15, text(i))
svgsetgraphviewbox(-1,-1,5,5)
svgsetgraphscale(10)
svgsave("grit.svg")
svgrefresh
svgwaitclose("Close browser window to terminate model execution.", 1)
end-procedure
end-model
|
|
j5tax.mos |
(!******************************************************
Mosel Example Problems
======================
file j5tax.mos
``````````````
Choice of locations for income tax offices
A graph representing the cities and major roads connecting
them is provided. The population of each city and the
distance between two cities directly connected are also
known from the graph. Where should tax offices be located
to minimize the average distance per inhabitant to the
closest tax office?
Given the graph, the distance matrix is calculated using a
specialized algorithm (Floyd-Warshall), implemented by the
procedure 'calculatedist'. These distances are used
in the MIP model where two families of decision variables
are defined.
(c) 2008-2022 Fair Isaac Corporation
author: S. Heipcke, Mar. 2002, rev. Mar. 2022
*******************************************************!)
model "J-5 Tax office location"
uses "mmxprs"
forward procedure calculatedist
declarations
CITIES = 1..12 ! Set of cities
DIST: array(CITIES,CITIES) of integer ! Distance matrix
POP: array(CITIES) of integer ! Population of cities
LEN: dynamic array(CITIES,CITIES) of integer ! Road lengths
NUMLOC: integer ! Desired number of tax offices
build: array(CITIES) of mpvar ! 1 if office in city, 0 otherwise
depend: array(CITIES,CITIES) of mpvar ! (c,d) 1 if city c depends on office
! in city d, 0 otherwise
end-declarations
initializations from 'j5tax.dat'
LEN POP NUMLOC
end-initializations
! Calculate the distance matrix
calculatedist
! Objective: weighted total distance
TotDist:= sum(c,d in CITIES) POP(c)*DIST(c,d)*depend(c,d)
! Assign cities to offices
forall(c in CITIES) sum(d in CITIES) depend(c,d) = 1
! Limit total number of offices
sum(c in CITIES) build(c) <= NUMLOC
! Relations between dependencies and offices built
forall(c,d in CITIES) depend(c,d) <= build(d)
forall(c in CITIES) build(c) is_binary
! Solve the problem
minimize(TotDist)
! Solution printing
writeln("Total weighted distance: ", getobjval,
" (average per inhabitant: ", getobjval/sum(c in CITIES) POP(c), ")")
forall(c in CITIES | getsol(build(c))>0) do
write("Office in ", c, ": ")
forall(d in CITIES | getsol(depend(d,c))>0) write(" ", d)
writeln
end-do
!-----------------------------------------------------------------
! Calculate the distance matrix using Floyd-Warshall algorithm
procedure calculatedist
! Initialize all distance labels with a sufficiently large value
BIGM:=sum(c,d in CITIES | exists(LEN(c,d))) LEN(c,d)
forall(c,d in CITIES) DIST(c,d):=BIGM
forall(c in CITIES) DIST(c,c):=0 ! Set values on the diagonal to 0
! Length of existing road connections
forall(c,d in CITIES | exists(LEN(c,d))) do
DIST(c,d):=LEN(c,d)
DIST(d,c):=LEN(c,d)
end-do
! Update shortest distance for every node triple
forall(b,c,d in CITIES | c<d )
if DIST(c,d) > DIST(c,b)+DIST(b,d) then
DIST(c,d):= DIST(c,b)+DIST(b,d)
DIST(d,c):= DIST(c,b)+DIST(b,d)
end-if
end-procedure
end-model
|
|
j6hospit.mos |
(!******************************************************
Mosel Example Problems
======================
file j6hospit.mos
`````````````````
Compare the efficiency of hospitals (DEA method)
A city aims to measure the efficiency of four major
hospitals to improve the service to the public. The method
suggested to measure the efficiency is DEA (Data Envelopment
Analysis) where a mathematical model is solved to find the
efficiency for each hospital. Three initial indicators
(resources) are considered as well as four final indicators
(services). Use the DEA method to assess how hospital H2
performs in comparison with the others.
The DEA method is implemented. The mathematical model that
calculates the efficiency is solved for every hospital by
using a loop. The constraints need to be named in order
to be able to overwrite their definition in every loop
iteration (an explicit declaration as 'linctr' is optional,
but it is recommended for efficiency reasons in this example).
(c) 2008-2022 Fair Isaac Corporation
author: S. Heipcke, Mar. 2002, rev. Mar. 2022
*******************************************************!)
model "J-6 Hospital efficiency"
uses "mmxprs"
declarations
HOSP = 1..4 ! Set of hospitals
SERV: set of string ! Service indicators
RES: set of string ! Resource indicators
INDSERV: array(SERV,HOSP) of real ! Service indicator values
INDRES: array(RES,HOSP) of real ! Resource indicator values
end-declarations
initializations from 'j6hospit.dat'
INDSERV INDRES
end-initializations
declarations
eff: mpvar ! Efficiency value
coef: array(HOSP) of mpvar ! Coefficients for DEA method
fserv: array(SERV) of mpvar ! Service indicator of fict. hospital
fres: array(RES) of mpvar ! Resource indicator of fict. hospit.
LimServ: array(SERV) of linctr ! Hospital-specific service constr.
LimRes: array(RES) of linctr ! Hospital-specific resource constr.
end-declarations
! DEA coefficients
sum(h in HOSP) coef(h) = 1
! Relations between service and resource indicators
forall(s in SERV) fserv(s) = sum(h in HOSP) INDSERV(s,h)*coef(h)
forall(r in RES) fres(r) = sum(h in HOSP) INDRES(r,h)*coef(h)
! Solve the problem for every hospital
forall(h in HOSP) do
! Limits on services and resources for the hospital currently looked at
forall(s in SERV) LimServ(s):= fserv(s) >= INDSERV(s,h)
forall(r in RES) LimRes(r):= fres(r) <= INDRES(r,h)*eff
! Minimize efficiency index
minimize(eff)
writeln("Evaluation of hospital ", h, ": ", getobjval)
end-do
end-model
|
|