Packages
fixpoint
0.21.2
0.22.1
0.21.5
0.21.4
0.21.3
0.21.2
0.21.1
0.21.0
0.20.6
0.20.5
0.20.4
0.20.3
0.20.2
0.20.1
0.19.5
0.19.4
0.19.3
0.19.2
0.19.1
0.18.2
0.18.1
0.17.6
0.17.5
0.17.4
0.17.3
0.17.2
0.17.1
0.16.5
0.16.4
0.16.3
0.16.2
0.16.1
0.16.0
0.15.6
0.15.5
0.15.4
0.15.3
0.15.2
0.15.1
0.15.0
0.14.9
0.14.8
0.14.7
0.14.6
0.14.5
0.14.4
0.14.3
0.14.2
0.14.1
0.13.5
0.13.4
0.13.2
0.13.1
0.12.9
0.12.8
0.12.7
0.12.6
0.12.5
0.12.4
0.12.2
0.12.1
0.11.8
0.11.7
0.11.6
0.11.5
0.11.4
0.11.3
0.11.2
0.11.1
0.10.7
0.10.6
0.10.5
0.10.4
0.10.3
0.10.2
0.10.1
0.9.12
0.9.11
0.9.10
0.9.9
0.9.8
0.9.7
0.9.6
0.9.5
0.9.4
0.9.3
0.9.2
0.9.1
0.9.0
0.8.52
0.8.51
0.8.50
0.8.49
0.8.48
0.8.46
0.8.44
0.8.43
0.8.42
0.8.41
0.8.40
0.8.39
0.8.38
0.8.37
0.8.36
0.8.35
0.8.34
0.8.33
0.8.32
0.8.31
0.8.30
0.8.29
0.8.28
0.8.27
0.8.26
0.8.25
0.8.24
0.8.23
0.8.22
0.8.21
0.8.20
0.8.19
0.8.18
0.8.17
0.8.16
0.8.15
0.8.14
0.8.13
0.8.12
0.8.11
0.8.10
0.8.9
0.8.8
0.8.7
0.8.6
0.8.5
0.8.4
0.8.3
0.8.2
0.8.1
0.8.0
0.7.10
0.7.9
0.7.8
0.7.7
0.7.6
0.7.5
0.7.4
0.7.3
0.7.2
0.7.1
0.7.0
0.6.5
0.6.4
0.6.3
0.6.2
0.6.1
0.6.0
0.5.12
0.5.11
0.5.10
0.5.9
0.5.8
0.5.7
0.5.6
0.5.5
0.5.4
0.5.3
0.5.2
0.5.1
0.5.0
0.4.3
0.4.2
0.4.1
0.4.0
0.3.6
0.3.5
0.3.4
0.3.3
0.3.2
0.3.1
0.3.0
0.2.3
0.2.2
0.2.1
0.1.3
0.1.2
0.1.1
0.1.0
Constraint Programming Solver
Current section
Files
Jump to
Current section
Files
lib/solver/search/strategy/variable/variable_selector.ex
defmodule CPSolver.Search.VariableSelector do
@callback initialize(map(), any()) :: :ok
@callback update(map(), Keyword.t()) :: :ok
@callback select(map(), Keyword.t()) :: Variable.t() | nil
@callback select([Variable.t()], map(), Keyword.t()) :: Variable.t() | nil
alias CPSolver.Search.VariableSelector.{
FirstFail,
InputOrder,
MostConstrained,
MostCompleted,
DomDeg,
MaxRegret,
AFC,
Action,
CHB
}
alias CPSolver.Variable.UnfixedTracker, as: Tracker
defmacro __using__(_) do
quote do
alias CPSolver.Search.VariableSelector
alias CPSolver.Variable.Interface
alias CPSolver.DefaultDomain, as: Domain
alias CPSolver.Variable.UnfixedTracker, as: Tracker
@behaviour VariableSelector
def initialize(_data, _opts) do
:ok
end
def update(_data, _opts) do
:ok
end
def select(data, opts) do
Tracker.iterate(data)
|> then(fn
[] -> VariableSelector.all_vars_fixed_exception()
unfixed_vars -> select(unfixed_vars, data, opts)
end)
end
def select(unfixed_variables, _data, _opts) do
List.first(unfixed_variables)
end
defoverridable initialize: 2, update: 2, select: 2, select: 3
end
end
def initialize(selector, _space_data) do
selector
end
def select_variable(data, variable_choice) when is_atom(variable_choice) do
select_variable(data, strategy(variable_choice))
end
def select_variable(
data,
variable_choice
)
when is_function(variable_choice) do
normalize_choice_fun(variable_choice).(data)
end
def all_vars_fixed_exception() do
throw(:all_vars_fixed)
end
def failed_variables_in_search_exception() do
:failed_variables_in_search
end
defp normalize_choice_fun(variable_choice)
when is_function(variable_choice, 1) do
fn data -> variable_choice.(data) end
end
defp normalize_choice_fun(variable_choice)
when is_function(variable_choice, 2) do
variable_choice
end
######################################
## Variable choice (shortcuts) ##
######################################
defp strategy({afc_mode, decay})
when afc_mode in [:afc_min, :afc_max, :afc_size_min, :afc_size_max] do
afc({afc_mode, decay}, &Enum.random/1)
end
defp strategy({action_mode, decay})
when action_mode in [:action_min, :action_max, :action_size_min, :action_size_max] do
action({action_mode, decay}, &Enum.random/1)
end
defp strategy(chb_mode)
when chb_mode in [:chb_min, :chb_max, :chb_size_min, :chb_size_max] do
chb(chb_mode, &Enum.random/1)
end
defp strategy(:first_fail) do
first_fail(&List.first/1)
end
defp strategy(:input_order) do
input_order()
end
defp strategy(:most_constrained) do
most_constrained(&Enum.random/1)
end
defp strategy(:most_completed) do
most_completed(&Enum.random/1)
end
defp strategy(:dom_deg) do
dom_deg(&Enum.random/1)
end
defp strategy(:max_regret) do
max_regret(&Enum.random/1)
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
###################################
## Implementations (top-level) ##
###################################
def most_constrained(break_even_fun \\ &Enum.random/1)
def most_constrained(break_even_fun) when is_function(break_even_fun) do
variable_choice(MostConstrained, break_even_fun)
end
def most_completed(break_even_fun \\ &Enum.random/1)
def most_completed(break_even_fun) do
variable_choice(MostCompleted, extract_strategy(break_even_fun))
end
def max_regret(break_even_fun \\ &Enum.random/1)
def max_regret(break_even_fun) when is_function(break_even_fun) do
variable_choice(MaxRegret, break_even_fun)
end
def first_fail(break_even_fun \\ &Enum.random/1)
def first_fail(break_even_fun) when is_function(break_even_fun) do
variable_choice(FirstFail, break_even_fun)
end
def input_order() do
variable_choice(InputOrder, nil)
end
def dom_deg(break_even_fun \\ &Enum.random/1)
def dom_deg(break_even_fun) when is_function(break_even_fun) do
variable_choice(DomDeg, break_even_fun)
end
def afc({afc_mode, decay}, break_even_fun \\ FirstFail)
when afc_mode in [:afc_min, :afc_max, :afc_size_min, :afc_size_max] do
variable_choice({AFC, mode: afc_mode, decay: decay}, break_even_fun)
end
def action({action_mode, decay}, break_even_fun \\ FirstFail)
when action_mode in [:action_min, :action_max, :action_size_min, :action_size_max] do
variable_choice({Action, mode: action_mode, decay: decay}, break_even_fun)
end
def chb(chb_mode, break_even_fun \\ FirstFail)
def chb({chb_mode, q_score}, break_even_fun)
when chb_mode in [:chb_min, :chb_max, :chb_size_min, :chb_size_max] do
variable_choice(
{CHB, mode: chb_mode, q_score: q_score},
break_even_fun
)
end
def chb(chb_mode, break_even_fun) do
chb({chb_mode, CHB.default_q_score()}, break_even_fun)
end
defp extract_strategy(shortcut) when is_atom(shortcut) do
strategy(shortcut)
end
defp extract_strategy(strategy) when is_function(strategy) do
strategy
end
def mixed(strategies) do
Enum.random(strategies)
|> extract_strategy()
end
defp execute_break_even(selection, _data, nil) do
selection
end
defp execute_break_even(selection, _data, break_even_fun) when is_function(break_even_fun, 1) do
break_even_fun.(selection)
end
defp execute_break_even(selection, data, break_even_fun) when is_function(break_even_fun, 2) do
break_even_fun.(selection, data)
end
defp variable_choice(strategy_fun, break_even_fun) when is_function(strategy_fun) do
fn data ->
data
|> strategy_fun.()
|> execute_break_even(data, break_even_fun)
end
end
defp variable_choice({strategy_impl, args}, break_even_fun) when is_atom(strategy_impl) do
impl = strategy(strategy_impl)
initialize? = function_exported?(impl, :initialize, 2)
strategy_fun = fn data ->
args = args || []
initialize? && impl.initialize(data, args)
impl.select(data, args)
|> tap(fn selection -> Enum.empty?(List.wrap(selection)) && all_vars_fixed_exception() end)
end
variable_choice(strategy_fun, break_even_fun)
end
defp variable_choice(strategy_impl, break_even_fun) when is_atom(strategy_impl) do
variable_choice({strategy_impl, nil}, break_even_fun)
end
end