# # # defmodule CPUtils do # alias CPSolver.IntVariable # alias CPSolver.Constraint.Sum # alias CPSolver.Constraint.Equal alias CPSolver.Constraint.AllDifferent.FWC, as: AllDifferent # alias CPSolver.Model # # "System" / General functions. # @doc """ timeit(fun) From https://stackoverflow.com/questions/29668635/how-can-we-easily-time-function-calls-in-elixir A more elaborate timing function. Prints * Name of the function * Result * Time in seconds ##Examples## > timeit(&test1/0) """ def timeit(fun) do # Convert the function (e.g. &Euler1.euler1a/0 to a string fun_s = Kernel.inspect(fun) {time0, res} = :timer.tc(fun, []) time = (time0 / 1_000_000) |> :erlang.float_to_binary([:compact, decimals: 5]) IO.puts("#{fun_s} res:#{res} time:#{time}s") end @doc """ timeit_simple(fun) A simple timing function, returns the time in seconds (as a string). ##Examples## > Util.timeit_simple(&Test1.main/0) > Util.timeit_simple(fn () -> Test1.main() end) """ def timeit_simple(fun) do {time0, res} = :timer.tc(fun, []) IO.inspect(res) (time0 / 1_000_000) |> :erlang.float_to_binary([:compact, decimals: 5]) end @doc """ mat_at(m,i,j) Returns the value (`i`,`j`) of the 2d matrix `mat`. ##Examples## iex> [[1,2,3],[4,5,6],[7,8,9]] |> mat_at(1,2) 6 """ def mat_at(m, i, j) do m |> Enum.at(i) |> Enum.at(j) end @doc """ transpose(m) Returns a transposed version of `m`. ##Example## iex> [[1,2,3],[4,5,6],[7,8,9]] |> transpose [[1, 4, 7], [2, 5, 8], [3, 6, 9]] """ def transpose(m) do Enum.zip_with(m, &Function.identity/1) end @doc """ print_matrix(x,rows,cols, format \\ "~2w") Pretty print `x` as a matrix. Note: `x` is assumed to be a list of rows*cols elements. `format` is the spacing of the values, defaults to "~2w". """ def print_matrix(x, rows, cols, format \\ "~2w") do for i <- 0..(rows - 1) do for j <- 0..(cols - 1) do :io.format(format, [Enum.at(x, i * cols + j)]) end IO.puts("") end IO.puts("\n") end # # Decomposition of constraints # @doc """ latin_square(x) Ensures that an n x n matrix `x` is a Latin Square. ##Examples## > latin_square(x) """ def latin_square(x) do row_constraints = Enum.map(x, fn row -> AllDifferent.new(row) end) col_constraints = Enum.map(x |> transpose, fn row -> AllDifferent.new(row) end) row_constraints ++ col_constraints end end