(!****************************************************** 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 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