(!****************************************************** Mosel Example Problems ====================== file partitioning.mos ````````````````````` TYPE: Partitioning problem DIFFICULTY: 4 FEATURES: MIP problem, algorithm for data preprocessing; file inclusion, 3 nested/recursive procedures, working with sets, `if-then', `forall-do', `exists', `finalize', graphical representation of results DESCRIPTION: In a country far away, the party of the duke Sark Mevo has finally beaten the ruling coalition headed by the princess Reguel Tekris. Mevo wishes to consolidate his position in the capital, the fourteen quarters of which need to be grouped to electoral districts. The forecast number of favorable votes for Mevo and the total number of electors per quarter are known. All electors must vote and the winner needs to have the absolute majority. A valid electoral district is formed by several adjacent quarters and must have between 30,000 and 100,000 voters. Electoral districts consisting of a single quarter are permitted if it has at least 50,000 voters. Nevertheless, Mevo may not decently define an electoral district solely with quarter 10, since this contains his residence. Determine a partitioning into five electoral districts that maximizes the number of seats for Mevo. Should this cause any difficulties, try a partitioning into six districts. FURTHER INFO: `Applications of optimization with Xpress-MP', Section 15.3 `Rigging elections' (c) 2008 Fair Isaac Corporation author: S. Heipcke, 2002, rev. Sep. 2017 *******************************************************!) model "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 "partition_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) Partition(q):= sum(d in RDIST) DISTR(d,q)*choose(d) = 1 ! Desired number of districts NumDist:= 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) if getsol(choose(r))>0 then write(r, ": ") forall(q in QUARTERS) write(if(DISTR(r,q)>0, " "+q, "")) writeln(" (", MAJ(r), ")") end-if end-if ! Solution drawing declarations X,Y: array(QUARTERS) of integer ! x-y-coordinates of quarters end-declarations initializations from 'partitioning.dat' [X,Y] as 'POS' end-initializations svgsetgraphviewbox(0, 0, max(q in QUARTERS) X(q)+10, max(q in QUARTERS) Y(q)+10) svgsetgraphscale(2) svgaddgroup("Neighbor", "Neighboring quarters", SVG_BLACK) svgaddgroup("Fav", "Favorable votes", SVG_GREEN) svgaddgroup("Unfav", "Unfavorable votes", SVG_RED) forall(q in QUARTERS) do svgaddpoint("Neighbor", X(q), Y(q)) forall(p in QUARTERS | exists(NEIGHB(q,p))) svgaddline("Neighbor", X(q), Y(q), X(NEIGHB(q,p)), Y(NEIGHB(q,p))) svgaddtext(if(VOTES(q)/POP(q)>0.5, "Fav", "Unfav"), X(q)+1, Y(q)+1, string(q)) end-do if(getprobstat=XPRS_OPT) then forall(r in RDIST) if getsol(choose(r))>0 then first:= min(q in QUARTERS | DISTR(r,q)>0) q forall(q in QUARTERS | q>first and DISTR(r,q)>0) do svgaddline(if(MAJ(r)=1, "Fav", "Unfav"), X(first), Y(first), X(q), Y(q)) first:=q end-do end-if end-if svgsave("partitioning.svg") svgrefresh svgwaitclose("Close browser window to terminate model execution.", 1) end-model