Packages
fixpoint
0.7.5
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/variables/view_test.exs
defmodule CPSolverTest.Variable.View do
use ExUnit.Case
alias CPSolver.DefaultDomain, as: Domain
describe "Views" do
alias CPSolver.ConstraintStore
alias CPSolver.IntVariable, as: Variable
alias CPSolver.Variable.View
alias CPSolver.Variable.Interface
import CPSolver.Variable.View.Factory
test "'minus' view" do
v1_values = 1..10
v2_values = -5..5
v3_values = 0..0
v4_values = 1..1
values = [v1_values, v2_values, v3_values, v4_values]
variables = Enum.map(values, fn d -> Variable.new(d) end)
{:ok, [source_var, var2, _var3, _var4] = bound_vars, _store} =
ConstraintStore.create_store(variables)
views = [view1, view2, view3, view4] = Enum.map(bound_vars, fn var -> minus(var) end)
## Domains of variables that back up views do not change
assert Variable.min(source_var) == 1
assert Variable.max(source_var) == 10
## :min and :max
assert View.min(view1) == -10
assert View.max(view1) == -1
assert View.min(view2) == -5
assert View.max(view2) == 5
assert View.min(view3) == 0 && View.max(view3) == 0
assert View.min(view4) == -1 && View.max(view4) == -1
## Size
assert Enum.all?(Enum.zip(bound_vars, views), fn {var, view} ->
Variable.size(var) == View.size(view)
end)
## Fixed?
refute View.fixed?(view1) || View.fixed?(view2)
assert View.fixed?(view3) && View.fixed?(view4)
## Domain
assert Enum.all?(Enum.zip(bound_vars, views), fn {var, view} ->
compare_domains(View.domain(view), Variable.domain(var), fn x -> -x end)
end)
## :contains?
refute Enum.any?(v1_values, fn v -> View.contains?(view1, v) end)
assert Enum.all?(v1_values, fn v -> View.contains?(view1, -v) end)
## Remove
assert View.contains?(view1, -5)
assert :domain_change == View.remove(view1, -5)
refute View.contains?(view1, -5)
assert :no_change == View.remove(view1, 1)
## Remove above
assert :no_change == View.removeAbove(view1, 4)
## removeAbove/removeBelow report domain changes for source variables,
## not for views, hence :min_change for removeAbove
assert :min_change == View.removeAbove(view1, -4)
assert -4 == View.max(view1)
assert -10 == View.min(view1)
## Remove below
assert Domain.to_list(View.domain(view1)) == [-10, -9, -8, -7, -6, -4]
## Same as for removeAbove, :max_change reflects the domain change for the variable,
## and not the view.
assert :max_change == View.removeBelow(view1, -7)
assert Domain.to_list(View.domain(view1)) == [-7, -6, -4]
assert :fixed == View.removeBelow(view1, -4)
assert -4 == View.min(view1)
## Fix
assert :fixed == View.fix(view2, -1)
assert View.fixed?(view2) && Variable.fixed?(var2)
assert View.min(view2) == -1 && Variable.min(var2) == 1
assert :fail == View.fix(view3, 1)
end
test "'mul' view" do
domain = 1..10
{:ok, [source_var] = _bound_vars, _store} =
ConstraintStore.create_store([Variable.new(domain)])
view1 = mul(source_var, 1)
view2 = mul(source_var, 10)
view3 = mul(source_var, -90)
assert 1 == View.min(view1)
assert 10 == View.max(view1)
assert 10 == View.min(view2)
assert 100 == View.max(view2)
assert -900 == View.min(view3)
assert -90 == View.max(view3)
assert Variable.contains?(source_var, 1)
assert View.contains?(view1, 1)
refute View.contains?(view2, 1)
assert :no_change == View.remove(view1, 100)
assert View.domain(view2) |> Domain.to_list() == Enum.map(1..10, fn val -> 10 * val end)
assert :max_change == View.remove(view2, 100)
## After removing from view2, other views will be affected
assert 9 == View.max(view1)
assert -810 == View.min(view3)
## ...as will the source variable
assert 9 == Variable.max(source_var)
assert :min_change == View.removeAbove(view3, -450)
assert 5 == Variable.min(source_var)
assert 5 == View.min(view1)
assert 50 == View.min(view2)
assert -450 == View.max(view3)
assert :fixed == View.fix(view2, 50)
assert View.fixed?(view1) && View.fixed?(view3) && Variable.fixed?(source_var)
end
test "remove value that falls in the hole" do
{:ok, [x] = _bound_vars, _store} =
ConstraintStore.create_store([Variable.new(0..5, name: "x")])
y_plus = mul(x, 20)
y_minus = mul(x, -20)
## View with positive coefficient
assert 0 == View.min(y_plus)
## 10 is in the domain hole for the view
assert :min_change == View.removeBelow(y_plus, 10)
assert 20 == View.min(y_plus)
## 30 is in the domain hole as well
assert :max_change == View.removeAbove(y_plus, 70)
assert 1 == Variable.min(x)
assert 3 == Variable.max(x)
## View with negative coefficient
assert -60 == View.min(y_minus)
assert :min_change == View.removeAbove(y_minus, -30)
assert -40 == View.max(y_minus)
assert :fixed == View.removeBelow(y_minus, -50)
## All views and the source variable are fixed
assert Enum.all?([x, y_plus, y_minus], fn v -> Interface.fixed?(v) end)
## Views are fixed to the values that correspond their coefficients
assert 2 == Interface.min(x)
assert 2 * 20 == Interface.min(y_plus)
assert 2 * -20 == Interface.min(y_minus)
end
end
defp compare_domains(d1, d2, map_fun) do
Enum.zip(Domain.to_list(d1) |> Enum.sort(:desc), Domain.to_list(d2) |> Enum.sort(:asc))
|> Enum.all?(fn {val1, val2} -> val2 == map_fun.(val1) end)
end
end