Initializing help system before first use

J. Local authorities and public services


Description:

Problem name and type, features Difficulty Related examples
J‑1 Water conveyance / water supply management: Maximum flow problem ** j1water_graph.mos, g1rely.mos
encoding of arcs, selection with `|', record data structure
J‑2 CCTV surveillance: Maximum vertex cover problem ** j2bigbro_graph.mos, g6transmit.mos, d5cutsh.mos
encoding of network, exists
J‑3 Rigging elections: Partitioning problem **** j3elect_graph.mos, partitioning_graph.mos
algorithm for data preprocessing; file inclusion, 3 nested/recursive procedures, working with sets, if-then, forall-do, exists, finalize
J‑4 Gritting roads: Directed Chinese postman problem **** j4grit_graph.mos
algorithm for finding Eulerian path/graph for printing; encoding of arcs, dynamic array, exists, 2 functions implementing Eulerian circuit algorithm, round, getsize, break, while-do, if-then-else, list handling
J‑5 Location of income tax offices: p-median problem ****
modeling an implication, all-pairs shortest path algorithm (Floyd-Warshall); dynamic array, exists, procedure for shortest path algorithm, forall-do, if-then, selection with `|'
J‑6 Efficiency of hospitals: Data Envelopment Analysis (DEA) ***
description of DEA method; loop over problem solving with complete re-definition of problem every time, naming and declaring constraints


File(s): j1water.mos (Mar. 2002), j1water2.mos (Jan. 2006), j1water_graph.mos (Jun. 2023), j2bigbro.mos (Mar. 2002), j2bigbro_graph.mos (Jun. 2023), j3elect.mos (Apr. 2002), j3elect_calc.mos (Apr. 2002), j3elect_calc2.mos (Jan. 2006), j3elect_graph.mos (Jun. 2023), j4grit.mos (Mar. 2002), j4grit2.mos (Jan. 2006), j4grit_graph.mos (Mar. 2002), j5tax.mos (Mar. 2002), j6hospit.mos (Mar. 2002)
Data file(s): j1water.dat, j1water2.dat, j2bigbro.dat, j3elect.dat, j3elect2.dat, j4grit.dat, j5tax.dat, j6hospit.dat

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

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