defmodule CPSolverTest.Propagator.LessOrEqual do use ExUnit.Case describe "Propagator filtering" do alias CPSolver.ConstraintStore alias CPSolver.IntVariable, as: Variable alias CPSolver.Propagator alias CPSolver.Propagator.LessOrEqual test "filtering" do ## Both vars are unfixed x = 0..10 y = -5..5 variables = Enum.map([x, y], fn d -> Variable.new(d) end) {:ok, [x_var, y_var] = bound_vars, _store} = ConstraintStore.create_store(variables) {:changed, changes} = Propagator.filter(LessOrEqual, bound_vars) assert Map.get(changes, x_var.id) == :max_change assert Map.get(changes, y_var.id) == :min_change assert 0 == Variable.min(x_var) assert 5 == Variable.max(x_var) ## Both domains are cut to 0..5 assert Variable.min(x_var) == Variable.min(y_var) assert Variable.max(x_var) == Variable.max(y_var) end test "inconsistency" do x = 1..10 y = -10..0 ## Inconsistency: no solution to x <= y [x_var, y_var] = variables = Enum.map([x, y], fn d -> Variable.new(d) end) {:ok, bound_vars, _store} = ConstraintStore.create_store(variables, space: nil) ## The propagator will fail on one of the variables assert catch_throw(LessOrEqual.filter(bound_vars)) in [{:fail, x_var.id}, {:fail, y_var.id}] ## One of variables (depending on filtering implementation) will fail assert Enum.any?( bound_vars, fn var -> :fail == Variable.fixed?(var) end ) end test "offset" do x = 0..10 y = -10..0 variables = Enum.map([x, y], fn d -> Variable.new(d) end) {:ok, [x_var, y_var], _store} = ConstraintStore.create_store(variables) # (x <= y + 5) offset = 5 LessOrEqual.filter(x_var, y_var, offset) ## The domain of (y+5) variable is -5..5 assert 0 == Variable.min(x_var) assert 5 == Variable.max(x_var) assert Variable.min(x_var) == Variable.min(y_var) + offset assert Variable.max(x_var) == Variable.max(y_var) + offset end end end