Current section

Files

Jump to
fixpoint test propagators propagator_test.exs
Raw

test/propagators/propagator_test.exs

defmodule CPSolverTest.Propagator do
use ExUnit.Case
describe "Propagator general" do
alias CPSolver.IntVariable, as: Variable
alias CPSolver.Variable.Interface
alias CPSolver.Propagator.{NotEqual, LessOrEqual}
alias CPSolver.Propagator
import CPSolver.Variable.View.Factory
test "filtering with variables bound to a store" do
%{variables: variables} =
setup_store([1..1, 1..2])
[x_var, y_var] = variables
refute Variable.fixed?(y_var)
assert Variable.fixed?(x_var)
propagator = NotEqual.new(variables)
assert %{changes: %{y_var.id => :fixed}, active?: false, state: nil} ==
Propagator.filter(propagator)
assert Interface.fixed?(y_var)
end
test "Using views" do
x = 1..10
y = 0..10
variables = Enum.map([x, y], fn d -> Variable.new(d) end)
[x_var, y_var] = variables
## Make 'minus' view
minus_y_view = minus(y_var)
## Inconsistency: no solution to x <= -y
##
## The propagator will fail on one of the variables
assert :fail = Propagator.filter(LessOrEqual.new(x_var, minus_y_view))
end
test "dry run (reduction)" do
# `dry_run` option tests the result of the propagator filtering,
# but does not change space variables
%{variables: variables} =
setup_store([1..1, 1..2])
[x_var, y_var] = variables
assert Variable.fixed?(x_var)
refute Variable.fixed?(y_var)
propagator = NotEqual.new(variables)
## Dry-run first
{_p_copy, dry_run_result} = Propagator.dry_run(propagator)
assert dry_run_result == %{changes: %{y_var.id => :fixed}, active?: false, state: nil}
# Store variables didn't change
assert Variable.fixed?(x_var)
refute Variable.fixed?(y_var)
## Real run now
real_run_result = Propagator.filter(propagator)
## The results of dry run vs. real run
assert dry_run_result == real_run_result
## Variables are fixed, as expected
assert Variable.fixed?(x_var)
assert Variable.fixed?(y_var)
end
test "dry run (inconsistency, view)" do
x = 1..10
y = 0..10
variables = Enum.map([x, y], fn d -> Variable.new(d) end)
[x_var, y_var] = variables
minus_y_view = minus(y_var)
{_p_copy, res} = Propagator.dry_run(LessOrEqual.new(x_var, minus_y_view))
## Should fail, because `minus` view turns `y` domain to -10..0
assert res == :fail
## ...but the domains of variables stay intact
assert 10 == Interface.size(x_var) && (11 = Interface.size(y_var))
## Now, filter for real
assert :fail == Propagator.filter(LessOrEqual.new(x_var, minus_y_view))
## At least one variable is now in :fail state
assert catch_throw(10 == Interface.size(x_var) && (11 = Interface.size(y_var))) == :fail
end
defp setup_store(domains) do
variables = Enum.map(domains, fn d -> Variable.new(d) end)
%{variables: variables}
end
end
end