defmodule CPSolver.Constraint.Sum do use CPSolver.Constraint alias CPSolver.Propagator.Sum, as: SumPropagator alias CPSolver.Variable.View.Factory alias CPSolver.IntVariable, as: Variable @spec new(Variable.variable_or_view(), [Variable.variable_or_view()]) :: Constraint.t() def new(c, x) when is_integer(c) do new(Variable.new(c), x) end def new(y, x) do new([y | x]) end @impl true def propagators([y | x]) do # Separate constants and variables {constant, vars} = List.foldr(x, {0, []}, fn arg, {constant_acc, vars_acc} -> (is_integer(arg) && {constant_acc + arg, vars_acc}) || {constant_acc, [arg | vars_acc]} end) ## Adjust sum (variable or constant) y_arg = (is_integer(y) && Variable.new(y - constant)) || Factory.add(y, -constant) [SumPropagator.new(y_arg, vars)] end end