Packages
fixpoint
0.9.1
0.22.1
0.21.5
0.21.4
0.21.3
0.21.2
0.21.1
0.21.0
0.20.6
0.20.5
0.20.4
0.20.3
0.20.2
0.20.1
0.19.5
0.19.4
0.19.3
0.19.2
0.19.1
0.18.2
0.18.1
0.17.6
0.17.5
0.17.4
0.17.3
0.17.2
0.17.1
0.16.5
0.16.4
0.16.3
0.16.2
0.16.1
0.16.0
0.15.6
0.15.5
0.15.4
0.15.3
0.15.2
0.15.1
0.15.0
0.14.9
0.14.8
0.14.7
0.14.6
0.14.5
0.14.4
0.14.3
0.14.2
0.14.1
0.13.5
0.13.4
0.13.2
0.13.1
0.12.9
0.12.8
0.12.7
0.12.6
0.12.5
0.12.4
0.12.2
0.12.1
0.11.8
0.11.7
0.11.6
0.11.5
0.11.4
0.11.3
0.11.2
0.11.1
0.10.7
0.10.6
0.10.5
0.10.4
0.10.3
0.10.2
0.10.1
0.9.12
0.9.11
0.9.10
0.9.9
0.9.8
0.9.7
0.9.6
0.9.5
0.9.4
0.9.3
0.9.2
0.9.1
0.9.0
0.8.52
0.8.51
0.8.50
0.8.49
0.8.48
0.8.46
0.8.44
0.8.43
0.8.42
0.8.41
0.8.40
0.8.39
0.8.38
0.8.37
0.8.36
0.8.35
0.8.34
0.8.33
0.8.32
0.8.31
0.8.30
0.8.29
0.8.28
0.8.27
0.8.26
0.8.25
0.8.24
0.8.23
0.8.22
0.8.21
0.8.20
0.8.19
0.8.18
0.8.17
0.8.16
0.8.15
0.8.14
0.8.13
0.8.12
0.8.11
0.8.10
0.8.9
0.8.8
0.8.7
0.8.6
0.8.5
0.8.4
0.8.3
0.8.2
0.8.1
0.8.0
0.7.10
0.7.9
0.7.8
0.7.7
0.7.6
0.7.5
0.7.4
0.7.3
0.7.2
0.7.1
0.7.0
0.6.5
0.6.4
0.6.3
0.6.2
0.6.1
0.6.0
0.5.12
0.5.11
0.5.10
0.5.9
0.5.8
0.5.7
0.5.6
0.5.5
0.5.4
0.5.3
0.5.2
0.5.1
0.5.0
0.4.3
0.4.2
0.4.1
0.4.0
0.3.6
0.3.5
0.3.4
0.3.3
0.3.2
0.3.1
0.3.0
0.2.3
0.2.2
0.2.1
0.1.3
0.1.2
0.1.1
0.1.0
Constraint Programming Solver
Current section
Files
Jump to
Current section
Files
test/constraints/element_test.exs
defmodule CPSolverTest.Constraint.Element do
use ExUnit.Case, async: false
alias CPSolver.IntVariable, as: Variable
alias CPSolver.DefaultDomain, as: Domain
alias CPSolver.Model
alias CPSolver.Constraint.Factory, as: ConstraintFactory
describe "Element (constant array)" do
alias CPSolver.Constraint.{Element, Element2D}
test "`element` functionality" do
y = Variable.new(-3..10)
z = Variable.new(-20..40)
t = [9, 8, 7, 5, 6]
model = Model.new([y, z], [Element.new(t, y, z)])
{:ok, result} = CPSolver.solve(model)
assert result.statistics.solution_count == 5
assert_element(result.solutions, t)
end
test "`element2d functionality" do
x = Variable.new(-2..40, name: "x")
y = Variable.new(-3..10, name: "y")
z = Variable.new(2..40, name: "z")
t = [
[9, 8, 7, 5, 6],
[9, 1, 5, 2, 8],
[8, 3, 1, 4, 9],
[9, 1, 2, 8, 6]
]
model = Model.new([x, y, z], [Element2D.new(t, x, y, z)])
{:ok, result} = CPSolver.solve(model)
refute Enum.empty?(result.solutions)
assert_element2d(result.solutions, t)
end
test "`element` factory function" do
x_var = Variable.new(-20..40)
t = [9, 8, 7, 5, 6]
{y_var, element_constraint} = ConstraintFactory.element(t, x_var)
## domain of generated variable corresponds to content of t
assert Domain.to_list(y_var.domain) |> Enum.sort() == Enum.sort(t)
## Create and run model with generated constraint
model = Model.new([x_var, y_var], [element_constraint])
{:ok, result} = CPSolver.solve(model)
assert_element(result.solutions, t)
end
test "`element2d` factory function" do
x_var = Variable.new(-2..40, name: "x")
y_var = Variable.new(-3..10, name: "y")
t = [
[9, 8, 7, 5, 6],
[9, 1, 5, 2, 8],
[8, 3, 1, 4, 9],
[9, 1, 2, 8, 6]
]
{z_var, element2d_constraint} = ConstraintFactory.element2d(t, x_var, y_var)
## domain of generated variable corresponds to content of t (all unique values)
assert Domain.to_list(z_var.domain) |> Enum.sort() ==
t |> List.flatten() |> Enum.uniq() |> Enum.sort()
model = Model.new([x_var, y_var, z_var], [element2d_constraint])
{:ok, result} = CPSolver.solve(model)
assert_element2d(result.solutions, t)
end
## Constraint check: t[y] = z
## Note: last variable is a placeholder (0)
## This is to maintain compatibility with element2D
## Placeholder will be eliminated in upcoming versions.
##
defp assert_element(solutions, t) do
assert Enum.all?(solutions, fn [y_value, z_value | _placeholder] ->
Enum.at(t, y_value) == z_value
end)
end
defp assert_element2d(solutions, t) do
assert Enum.all?(solutions, fn [x, y, z | _rest] ->
Enum.at(t, x) |> Enum.at(y) == z
end)
end
end
describe "Element (variable array)" do
alias CPSolver.Constraint.ElementVar
test "inconsistency (index domain outside of index set of the array)" do
index_var = Variable.new(6..10, name: "index")
value_var = Variable.new(-20..40, name: "value")
array_var =
Enum.map(Enum.with_index([9, 8, 7, 5, 6], 1), fn {val, idx} ->
Variable.new(val, name: "T#{idx}")
end)
element_constraint = ElementVar.new(array_var, index_var, value_var)
model = Model.new([index_var, value_var | array_var], [element_constraint])
{:ok, res} = CPSolver.solve(model)
assert res.status == :unsatisfiable
end
test "`element with fixed values in variable array" do
index_var = Variable.new(-3..10, name: "index")
value_var = Variable.new(-20..40, name: "value")
array_values = [9, 8, 7, 5, 6]
# Enum.map(Enum.with_index([9, 8, 7, 5, 6], 1), fn {val, idx} ->
# Variable.new(val, name: "T#{idx}")
# end)
element_constraint = ElementVar.new(array_values, index_var, value_var)
model = Model.new([index_var, value_var | array_values], [element_constraint])
{:ok, res} = CPSolver.solve(model)
assert res.statistics.solution_count == 5
assert Enum.all?(res.solutions, fn [idx, val | array_vals] ->
Enum.at(array_vals, idx) == val
end)
end
test "element with non-fixed domains in the array" do
index_var = Variable.new(-5..2, name: "idx")
value_var = Variable.new(-2..2, name: "value")
array_var = Enum.map(0..4, fn idx -> Variable.new(-1..1, name: "A#{idx}") end)
element_constraint = ElementVar.new(array_var, index_var, value_var)
model = Model.new([index_var, value_var | array_var], [element_constraint])
{:ok, res} = CPSolver.solve(model)
~S"""
Verified by MiniZinc model:
var -5..2: idx;
var -2..2: value;
array[0..4] of var -1..1: arr;
constraint arr[idx] = value;
"""
assert res.statistics.solution_count == 729
assert Enum.all?(res.solutions, fn [idx, val | array_vals] ->
Enum.at(array_vals, idx) == val
end)
end
test "enumerated index" do
index_var = Variable.new([-5, 0, 2], name: "idx")
value_var = Variable.new(-2..2, name: "value")
array_var = Enum.map(0..4, fn idx -> Variable.new(-1..1, name: "A#{idx}") end)
element_constraint = ElementVar.new(array_var, index_var, value_var)
model = Model.new([index_var, value_var | array_var], [element_constraint])
{:ok, res} = CPSolver.solve(model)
~S"""
Verified by MiniZinc model:
var {-5, 0, 2}: idx;
var -10..10: value;
array[0..4] of var -1..1: arr;
constraint arr[idx] = value;
"""
assert res.statistics.solution_count == 486
assert Enum.all?(res.solutions, fn [idx, val | array_vals] ->
Enum.at(array_vals, idx) == val
end)
end
end
test "variable 2d array" do
~S"""
MiniZinc:
array[1..2, 1..2] of var 0..3: arr2d;
var 0..4: x;
var 0..2: y;
var 1..10: z;
constraint arr2d[x, y] = z;
"""
arr2d =
for i <- 1..2 do
for j <- 1..2 do
Variable.new(0..3, name: "arr(#{i},#{j})")
end
end
x = Variable.new(0..4, name: "x")
y = Variable.new(0..2, name: "y")
z = Variable.new(1..10, name: "z")
model =
Model.new(
[x, y, z, arr2d] |> List.flatten(),
ConstraintFactory.element2d_var(arr2d, x, y, z)
)
{:ok, res} = CPSolver.solve(model)
assert res.statistics.solution_count == 768
assert_element2d_var(res.solutions, length(arr2d), length(hd(arr2d)))
end
defp assert_element2d_var(solutions, row_num, col_num) do
assert Enum.all?(
solutions,
fn solution ->
[x, y, z | rest] = solution
arr_solution = Enum.take(rest, row_num * col_num)
Enum.at(arr_solution, x * col_num + y) == z
end
)
end
end