# # Set covering problem in Elixir. # # Placing of firestations, from Winston "Operations Research", page 486 # # Cf http://hakank.org/minizinc/set_covering.mzn # # This program was created by Hakan Kjellerstrand, hakank@gmail.com # See also my Elixir page: http://www.hakank.org/elxir/ # ## Boris Okner: modified to sync with the latest API, ## change naming and result handling. ## defmodule CPSolver.Examples.Hakank.SetCovering do import Hakank.CPUtils alias CPSolver.IntVariable # alias CPSolver.Constraint.AllDifferent.FWC, as: AllDifferent alias CPSolver.Constraint.Sum alias CPSolver.Constraint.LessOrEqual # alias CPSolver.Constraint.NotEqual # alias CPSolver.Constraint.Equal alias CPSolver.Model alias CPSolver.Objective import CPSolver.Constraint.Factory # import CPSolver.Variable.View.Factory def problem(1) do min_distance = 15 # minimum distance distance = [[ 0,10,20,30,30,20], # distances between the cities [10, 0,25,35,20,10], [20,25, 0,15,30,20], [30,35,15, 0,15,25], [30,20,30,15, 0,14], [20,10,20,25,14, 0]] [min_distance,distance] end def run() do [min_distance, distance] = problem(1) num_cities = length(distance) # where to place the fire stations: 1 if placed in this city. x = for i <- 0..num_cities-1 do IntVariable.new(0..1, name: "x[#{i}]") end # number of fire stations, to minimize z = IntVariable.new(0..num_cities, name: "z") # calculate the number of covered fire stations constraints = for j <- 0..num_cities-1 do {d_var, d_constraint} = sum(for i <- 0..num_cities-1, mat_at(distance,i,j) <= min_distance do Enum.at(x,i) end) gt_constraint = LessOrEqual.new(1,d_var) # d >= 1 [gt_constraint,d_constraint] end model = Model.new(x ++ [z] , constraints ++ [ Sum.new(z, x) ] |> List.flatten, objective: Objective.minimize(z) ) Logger.configure(level: :info) opts = [ # search: {:first_fail, :indomain_min}, search: {:input_order, :indomain_min}, # search: {:first_fail, :indomain_random}, timeout: :infinity, # stop_on: {:max_solutions, 2}, ] {:ok, res} = CPSolver.solve(model, opts ) IO.inspect(res.statistics) sol = res.solutions |> List.last covering = Enum.take(sol,num_cities) z_val = Enum.at(sol,num_cities) IO.inspect(z_val, label: "z") IO.inspect(covering, label: "covering") end end