Current section

Files

Jump to
fixpoint lib solver constraints propagators abs.ex
Raw

lib/solver/constraints/propagators/abs.ex

defmodule CPSolver.Propagator.Absolute do
use CPSolver.Propagator
alias CPSolver.DefaultDomain, as: Domain
def new(x, y) do
new([x, y])
end
@impl true
def variables(args) do
args
|> Propagator.default_variables_impl()
|> Enum.map(fn var -> set_propagate_on(var, :bound_change) end)
end
@impl true
def filter(args) do
filter(args, nil)
end
@impl true
def filter([x, y], state, changes) do
(state && filter_impl(x, y, changes)) || initial_reduction(x, y)
{:state, %{}}
end
def filter_impl(x, y, changes) do
## x and y have 0 and 1 indices in the list of args
x_idx = 0
y_idx = 1
Enum.each(
changes,
fn
{idx, _change} when idx == x_idx ->
abs_min_x = abs(min(x))
abs_max_x = abs(max(x))
abs_x_lb = min(abs_min_x, abs_max_x)
abs_x_ub = max(abs_min_x, abs_max_x)
removeBelow(y, min(min(y), abs_x_lb))
removeAbove(y, max(max(y), abs_x_ub))
{idx, _change} when idx == y_idx ->
y_min = min(y)
y_max = max(y)
cond do
min(x) >= 0 ->
removeBelow(x, y_min)
removeAbove(x, y_max)
max(x) <= 0 ->
:ok
removeBelow(x, -y_max)
removeAbove(x, -y_min)
true ->
removeAbove(x, y_max)
removeBelow(x, -y_max)
end
end
)
fixed?(x) && fix(y, abs(min(x)))
fixed?(y) && fix_abs(x, min(y))
end
defp initial_reduction(x, y) do
## y is non-negative
removeBelow(y, 0)
filter_impl(x, y, %{0 => :domain_change, 1 => :domain_change})
end
defp fix_abs(x, value) do
Enum.each(domain(x) |> Domain.to_list(), fn val -> abs(val) != value && remove(x, val) end)
end
end