Current section

Files

Jump to
fixpoint lib solver search strategy value partition.ex
Raw

lib/solver/search/strategy/value/partition.ex

defmodule CPSolver.Search.Partition do
alias CPSolver.DefaultDomain, as: Domain
alias CPSolver.Variable.Interface
alias CPSolver.Search.ValueSelector.{Min, Max, Random, Split}
import CPSolver.Utils
require Logger
def initialize(partition, _space_data) do
## TODO:
# strategy(partition).initialize(space_data)
partition
end
def partition(variable, value_choice) do
{:ok, partition_impl(variable, value_choice)}
end
defp partition_impl(variable, value) when is_integer(value) do
partition_by_fix(value, variable)
end
defp partition_impl(variable, value_choice) when is_function(value_choice) do
partition_impl(variable, value_choice.(variable))
end
defp partition_impl(variable, value_choice) when is_atom(value_choice) do
domain = Interface.domain(variable)
impl = strategy(value_choice)
selected_value = impl.select_value(variable)
impl.partition(selected_value)
|> Enum.map(fn partition_fun ->
d_copy = Domain.copy(domain)
domain_changes = partition_fun.(d_copy) |> normalize_domain_changes()
{
d_copy,
%{variable.id => domain_changes}
}
end)
end
defp normalize_domain_changes({changes, _domain}), do: changes
defp normalize_domain_changes(changes) when is_atom(changes), do: changes
defp strategy(:indomain_min) do
Min
end
defp strategy(:indomain_max) do
Max
end
defp strategy(:indomain_random) do
Random
end
defp strategy(:indomain_split) do
Split
end
defp strategy(impl) when is_atom(impl) do
if Code.ensure_loaded(impl) == {:module, impl} && function_exported?(impl, :select, 2) do
impl
else
throw({:unknown_strategy, impl})
end
end
## Default partitioning
def partition_by_fix(value, variable) do
try do
remove_changes = Interface.remove(variable, value)
[
fixed_partition(value, variable), # Equal.new(variable, value)
domain_partition(Interface.domain(variable), %{variable.id => remove_changes}), # NotEqual.new(variable, value)
]
catch
:fail ->
Logger.error(
"Failure on partitioning with value #{inspect(value)}, domain: #{domain_values(variable)}}"
)
throw(:fail)
end
end
def fixed_partition(value, variable) do
domain_partition(Domain.new(value), %{variable.id => :fixed})
end
def domain_partition(domain, constraint) do
{domain, constraint}
end
end