Current section

Files

Jump to
fixpoint lib examples hakank coin_puzzle.ex
Raw

lib/examples/hakank/coin_puzzle.ex

#
# Coins grid problem in Elixir.
#
# Problem from
# Tony Hurlimann: "A coin puzzle - SVOR-contest 2007"
# http://www.svor.ch/competitions/competition2007/AsroContestSolution.pdf
# """
# In a quadratic grid (or a larger chessboard) with 31x31 cells, one
# should place coins in such a way that the following conditions are
# fulfilled:
# 1. In each row exactly 14 coins must be placed.
# 2. In each column exactly 14 coins must be placed.
# 3. The sum of the quadratic horizontal distance from the main
# diagonal of all cells containing a coin must be as small as possible.
# 4. In each cell at most one coin can be placed.
#
# The description says to place 14x31 = 434 coins on the chessboard
# each row containing 14 coins and each column also containing 14 coins.
# """
#
# Note: This problem is quite/very hard for (plain) CP solvers. A MIP solver solves
# the 14,31 problem in millis.
#
#
# Cf the MiniZinc model http://hakank.org/minizinc/coins_grid.mzn
#
#
# This program was created by Hakan Kjellerstrand, hakank@gmail.com
# See also my Elixir page: http://www.hakank.org/elxir/
#
defmodule CoinsGrid do
# import CPUtils
alias CPSolver.IntVariable
alias CPSolver.Constraint.Sum
# alias CPSolver.Constraint.AllDifferent.FWC, as: AllDifferent
alias CPSolver.Model
alias CPSolver.Objective
import CPSolver.Variable.View.Factory
def main(n, c) do
# 31
#n = 4
# 2
# 14
#c = 2
rs = 0..(n - 1)
x =
for i <- rs do
for j <- rs do
IntVariable.new(0..1, name: "x[#{i},#{j}]")
end
end
x_flatten = List.flatten(x)
# To be minimized
z = IntVariable.new(0..(n * n * n), name: "z]")
# quadratic horizontal distance
# MiniZinc: z = sum(i,j in 1..n) ( x[i,j]*(abs(i-j))*(abs(i-j)) )
sum_constraint =
Sum.new(
z,
for i <- rs, j <- rs do
mul(CPUtils.mat_at(x, i, j), abs(i - j) ** 2)
end
|> List.flatten()
)
# MiniZinc: forall(i in 1..n) ( sum(j in 1..n) (x[i,j]) = c )
row_constraints =
for row <- x do
Sum.new(c, row)
end
# MiniZinc: forall(j in 1..n) ( sum(i in 1..n) (x[i,j]) = c )
col_constraints =
for col <- CPUtils.transpose(x) do
Sum.new(c, col)
end
# |> List.flatten
constraints = [sum_constraint | row_constraints ++ col_constraints]
# constraints = row_constraints ++ col_constraints
model =
Model.new(
x_flatten ++ [z],
constraints,
# minimize z
objective: Objective.minimize(z)
)
Logger.configure(level: :info)
opts = [
search: {:input_order, :indomain_random},
space_threads: 4,
timeout: :timer.seconds(300),
#stop_on: {:max_solutions, 2}
]
{:ok, res} =
CPSolver.solve_sync(
model,
opts
)
res.solutions
|> Enum.map(fn s ->
IO.puts("z: #{Enum.at(s, n * n)}")
Enum.take(s, n * n) |> CPUtils.print_matrix(n, n)
end)
IO.inspect(res.statistics)
IO.inspect(res.solutions)
IO.inspect(res)
end
end