Initializing help system before first use

equiv: Location of income tax offices

The example description in the following sections is taken from Section 15.5 `Location of income tax offices' of the book `Applications of optimization with Xpress-MP'.

The income tax administration is planning to restructure the network of income tax offices in a region. The number of inhabitants of every city and the distances between each pair of cities are known (Table Distance matrix and population of cities). The income tax administration has determined that offices should be established in three cities to provide sufficient coverage. Where should these offices be located to minimize the average distance per inhabitant to the closest income tax office?

Table 3.8: Distance matrix and population of cities
1 2 3 4 5 6 7 8 9 10 11 12
1 0 15 37 55 24 60 18 33 48 40 58 67
2 15 0 22 40 38 52 33 48 42 55 61 61
3 37 22 0 18 16 30 43 28 20 58 39 39
4 55 40 18 0 34 12 61 46 24 62 43 34
5 24 38 16 34 0 36 27 12 24 49 37 43
6 60 52 30 12 36 0 57 42 12 50 31 22
7 18 33 43 61 27 57 0 15 45 22 40 61
8 33 48 28 46 12 42 15 0 30 37 25 46
9 48 42 20 24 24 12 45 30 0 38 19 19
10 40 55 58 62 49 50 22 37 38 0 19 40
11 58 61 39 43 37 31 40 25 19 19 0 21
12 67 61 39 34 43 22 61 46 19 40 21 0
Pop. (in 1000) 15 10 12 18 5 24 11 16 13 22 19 20

Model formulation

Let CITIES be the set of cities. For the formulation of the problem, two groups of decision variables are necessary: a variable buildc that is one if and only if a tax office is established in city c, and a variable dependc that takes the number of the office on which city c depends. For the formulation of the constraints, we further introduce two sets of auxiliary variables: depdistc, the distance from city c to the office indicated by dependc, and numdepc, the number of cities depending on an office location.

The following relations are required to link the buildc with the dependc variables:
(1) numdepc counts the number of occurrences of office location c among the variables dependc.
(2) numdepc ≥ 1 if and only if the office in c is built (as a consequence, if the office in c is not built, then we must have numdepc = 0).

∀ c ∈ CITIES: numdepc = |dependd = c|d ∈CITIES
∀ c ∈ CITIES: numdepc ≥ 1 ⇒ buildc = 1

Since the number of offices built is limited by the given bound NUMLOC

c ∈ CITIES
buildc ≤ NUMLOC

it would actually be sufficient to formulate the second relation between the buildc and dependc variables as the implication `If numdepc ≥ 1 then the office in c must be built, and inversely, if the office in c is not built, then we must have numdepc = 0'.

The objective function to be minimized is the total distance weighted by the number of inhabitants of the cities. We need to divide the resulting value by the total population of the region to obtain the average distance per inhabitant to the closest income tax office. The distance depdistc from city c to the closest tax office location is obtained by a discrete function, namely the row c of the distance matrix DISTcd indexed by the value of dependc:

depdistc = DISTc,dependc

We now obtain the following CP model:

minimize
c ∈ CITIES
POPc·distc
∀ c ∈ CITIES: buildc ∈ {0,1}, dependc ∈ CITIES,
numdepc ∈ CITIES ∪ {0}, depdistc ∈ {mind∈CITIESDISTc,d,..., maxd∈CITIESDISTc,d}
∀ c ∈ CITIES: depdistc = DISTc,dependc
c ∈ CITIES
buildc ≤ NUMLOC
∀ c ∈ CITIES: numdepc = |dependd = c|d∈CITIES
∀ c ∈ CITIES: numdepc ≥ 1 ⇒ buildc = 1

Implementation

To solve this problem, we define a branching strategy with two parts, one for the buildc variables and a second strategy for the depdistc variables. The latter are enumerated using the split_domain branching scheme that divides the domain of the branching variable into several disjoint subsets (instead of assigning a value to the variable). We now pass an array of type cpbranching as the argument to procedure cp_set_branching. The different strategies will be applied in their order in this array. Since our enumeration strategy does not explicitly include all decision variables of the problem, Xpress Kalis will enumerate these using the default strategy if any unassigned variables remain after the application of our search strategy.

model "J-5 Tax office location (CP)"
 uses "kalis"

 forward procedure calculate_dist

 setparam("KALIS_DEFAULT_LB", 0)

 declarations
  NC = 12
  CITIES = 1..NC                        ! 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
  D: array(CITIES) of integer           ! Auxiliary array used in constr. def.

  build: array(CITIES) of cpvar         ! 1 if office in city, 0 otherwise
  depend: array(CITIES) of cpvar        ! Office on which city depends
  depdist: array(CITIES) of cpvar       ! Distance to tax office
  numdep: array(CITIES) of cpvar        ! Number of depending cities per off.
  totDist: cpvar                        ! Objective function variable
  Strategy: array(1..2) of cpbranching  ! Branching strategy
 end-declarations

 initializations from 'Data/j5tax.dat'
  LEN POP NUMLOC
 end-initializations

! Calculate the distance matrix
 calculate_dist

 forall(c in CITIES) do
  build(c) <= 1
  1 <= depend(c); depend(c) <= NC
  min(d in CITIES) DIST(c,d) <= depdist(c)
  depdist(c) <= max(d in CITIES) DIST(c,d)
  numdep(c) <= NC
 end-do

! Distance from cities to tax offices
 forall(c in CITIES) do
  forall(d in CITIES) D(d):=DIST(c,d)
  element(D, depend(c)) = depdist(c)
 end-do

! Number of cities depending on every office
 forall(c in CITIES) occurrence(c, depend) = numdep(c)

! Relations between dependencies and offices built
 forall(c in CITIES) equiv( build(c) = 1, numdep(c) >= 1 )

! Limit total number of offices
 sum(c in CITIES) build(c) <= NUMLOC

! Branching strategy
 Strategy(1):= assign_and_forbid(KALIS_MAX_DEGREE, KALIS_MAX_TO_MIN, build)
 Strategy(2):= split_domain(KALIS_SMALLEST_DOMAIN, KALIS_MIN_TO_MAX,
                            depdist, true, 5)
 cp_set_branching(Strategy)

! Objective: weighted total distance
 totDist = sum(c in CITIES) POP(c)*depdist(c)

! Solve the problem
 if not cp_minimize(totDist) then
  writeln("Problem is infeasible")
  exit(1)
 end-if

! Solution printing
 writeln("Total weighted distance: ", getsol(totDist),
        " (average per inhabitant: ",
	   getsol(totDist)/sum(c in CITIES) POP(c), ")")
 forall(c in CITIES) if(getsol(build(c))>0) then
  write("Office in ", c, ": ")
  forall(d in CITIES) write(if(getsol(depend(d))=c, " "+d, ""))
  writeln
 end-if

!-----------------------------------------------------------------

! Calculate the distance matrix using Floyd-Warshall algorithm
 procedure calculate_dist
 ! 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

This implementation contains another example of the use of a subroutine in Mosel: the calculation of the distance data is carried out in the procedure calculate_dist. We thus use a subroutine to structure our model, removing secondary tasks from the main model formulation.

Results

The optimal solution to this problem has a total weighted distance of 2438. Since the region has a total of 185,000 inhabitants, the average distance per inhabitant is 2438/185 ≈ 13.178 km. The three offices are established at nodes 1, 6, and 11. The first serves cities 1, 2, 5, 7, the office in node 6 cities 3, 4, 6, 9, and the office in node 11 cities 8, 10, 11, 12.

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