Packages
fixpoint
0.7.0
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/propagators/sum_test.exs
defmodule CPSolverTest.Propagator.Sum do
use ExUnit.Case
describe "Propagator filtering" do
alias CPSolver.ConstraintStore
alias CPSolver.IntVariable, as: Variable
alias CPSolver.Variable.Interface
alias CPSolver.Propagator
alias CPSolver.Propagator.Sum
import CPSolver.Variable.Interface
import CPSolver.Variable.View.Factory
test "The domain bounds of 'sum' variable are reduced to the sum of bounds of the summands" do
y = Variable.new(-100..100, name: "y")
x =
Enum.map([{"x1", 0..5}, {"x2", 1..5}, {"x3", 0..5}], fn {name, d} ->
Variable.new(d, name: name)
end)
{:ok, [y_var | x_vars] = _bound_vars, store} = ConstraintStore.create_store([y | x])
Propagator.filter(Sum.new(y_var, x_vars), store: store)
assert 1 == min(y_var)
assert 15 == max(y_var)
end
test "Test 2" do
y = Variable.new(0..100, name: "y")
x =
Enum.map([{-5..5, "x1"}, {[1, 2], "x2"}, {[0, 1], "x3"}], fn {d, name} ->
Variable.new(d, name: name)
end)
{:ok, [y_var | x_vars] = _bound_vars, store} = ConstraintStore.create_store([y | x])
[x1_var, _x2_var, _x3_var] = x_vars
sum_propagator = Sum.new(y_var, x_vars)
Propagator.filter(sum_propagator, store: store)
assert -3 == min(x1_var)
assert 0 == min(y_var)
assert 8 == max(y_var)
end
test "when 'y' variable is fixed" do
y = Variable.new([5], name: "y")
x =
Enum.map([{1..5, "x1"}, {[1], "x2"}, {[0, 1], "x3"}], fn {d, name} ->
Variable.new(d, name: name)
end)
{:ok, [y_var | x_vars] = _bound_vars, store} = ConstraintStore.create_store([y | x])
[x1_var, _x2_var, x3_var] = x_vars
sum_propagator = Sum.new(y_var, x_vars)
Propagator.filter(sum_propagator, store: store)
assert 4 == max(x1_var)
assert 3 == min(x1_var)
assert 1 == max(x3_var)
assert 0 == min(x3_var)
end
test "fails on inconsistency" do
y = Variable.new(10, name: "y")
x1 = Variable.new(0..4, name: "x1")
x2 = Variable.new(0..5, name: "x2")
{:ok, [y_var, x1_var, x2_var] = _bound_vars, store} =
ConstraintStore.create_store([y, x1, x2])
assert :fail == Propagator.filter(Sum.new(y_var, [x1_var, x2_var]), store: store)
end
test "when summands are views" do
y = Variable.new(50, name: "y")
x1 = Variable.new(0..2, name: "x1")
x2 = Variable.new(1..2, name: "x2")
{:ok, [y_var, x1_var, x2_var] = _bound_vars, store} =
ConstraintStore.create_store([y, x1, x2])
refute :fail ==
Propagator.filter(Sum.new(y_var, [mul(x1_var, 10), mul(x2_var, 20)]), store: store)
assert 1 == Variable.min(x1_var)
assert 1 == Variable.max(x1_var)
end
test "maintains sum of fixed values and the list of unfixed variables" do
y = Variable.new(-100..100, name: "y")
x =
Enum.map([{"x1", 0..5}, {"x2", 1..5}, {"x3", 0..5}, {"x4", 4}, {"x5", 5}], fn {name, d} ->
Variable.new(d, name: name)
end)
{:ok, [y_var | x_vars] = _bound_vars, _store} = ConstraintStore.create_store([y | x])
[x1_var, x2_var, x3_var, _x4_var, _x5_var] = x_vars
sum_propagator = Sum.new(y_var, x_vars)
%{sum_fixed: sum_fixed, unfixed_vars: unfixed_vars} = sum_propagator.state
## There are 2 fixed variables with total 4+5 = 9
assert sum_fixed == 9
unfixed_num = length([y | x]) - 2
assert MapSet.size(unfixed_vars) == unfixed_num
:fixed = Interface.fix(x1_var, 1)
updated_sum_propagator = Propagator.update(sum_propagator, %{x1_var.id => :fixed})
%{sum_fixed: sum_fixed_new, unfixed_vars: unfixed_vars} = updated_sum_propagator.state
assert sum_fixed_new == 10
assert MapSet.size(unfixed_vars) == unfixed_num - 1
## Update with the variable that has already been fixed doesn't change the propagator
updated_sum_propagator2 = Propagator.update(updated_sum_propagator, %{x1_var.id => :fixed})
assert updated_sum_propagator2 == updated_sum_propagator
## If the change is not ':fixed', there is no effect
updated_sum_propagator3 =
Propagator.update(updated_sum_propagator, %{x2_var.id => :domain_change})
assert updated_sum_propagator3 == updated_sum_propagator
## 2 fixed vars in a single update
:fixed = Interface.fix(x2_var, 5)
:fixed = Interface.fix(x3_var, 5)
updated_sum_propagator4 =
Propagator.update(updated_sum_propagator, %{x2_var.id => :fixed, x3_var.id => :fixed})
assert updated_sum_propagator4.state.sum_fixed == 20
assert MapSet.size(updated_sum_propagator4.state.unfixed_vars) == 1
## Filter
refute Interface.fixed?(y_var)
Propagator.filter(updated_sum_propagator4)
assert Interface.fixed?(y_var)
assert Interface.min(y_var) == Enum.map(x_vars, fn x -> Interface.min(x) end) |> Enum.sum()
end
end
end