Current section

Files

Jump to
fixpoint lib solver search variable_value most_completed.ex
Raw

lib/solver/search/variable_value/most_completed.ex

defmodule CPSolver.Search.VariableSelector.MostCompleted do
alias CPSolver.Propagator.ConstraintGraph
alias CPSolver.Search.VariableSelector.FirstFail
def candidates(_variables, space_data) do
most_completed_propagators_selection(space_data[:constraint_graph])
end
## Choose variables connected to "most completed" propagators.
## 1) Choose propagators with smallest number of still unfixed variables
## (this corresponds to propagators with smallest degree in constraint graph).
## 2) Choose variables most constrained by the propagators above.
def most_completed_propagators_selection(constraint_graph) do
## Make p => (unfixed variables) map
constraint_graph
|> Graph.edges()
|> Enum.group_by(
fn edge -> edge.v2 end,
fn edge -> edge.v1 end
)
## Pick out the propagators with minimal number of unfixed variables.
## Build the list of variable ids constrained by those propagators.
|> Enum.reduce({[], nil},
fn {_propagator_id, var_ids}, {var_ids_acc, current_min} = acc ->
var_count = length(var_ids)
cond do
is_nil(current_min) || var_count < current_min -> {var_ids, var_count}
var_count > current_min -> acc
var_count == current_min -> {var_ids ++ var_ids_acc, var_count}
end
end)
|> elem(0)
## Choose variables with the largest counts of constraints (i.e., attached propagators)
|> Enum.frequencies()
|> Enum.reduce({[], nil}, fn {var_id, var_count}, {vars_acc, current_max} = acc ->
graph_var = ConstraintGraph.get_variable(constraint_graph, var_id)
cond do
is_nil(current_max) || var_count > current_max -> {[graph_var], var_count}
var_count < current_max -> acc
var_count == current_max -> {[graph_var | vars_acc], var_count}
end
end)
|> elem(0)
end
def select_variable(variables, space_data, break_even_fun \\ &FirstFail.select_variable/1) do
## Pick out all variables with maximal degrees
candidates(variables, space_data)
|> break_even_fun.()
end
end