Packages
fixpoint
0.7.3
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/core/propagator/propagator.ex
defmodule CPSolver.Propagator do
@type propagator_event :: :domain_change | :bound_change | :min_change | :max_change | :fixed
@callback new(args :: list()) :: Propagator.t()
@callback update(Propagator.t(), changes: any()) :: Propagator.t()
@callback filter(args :: list()) :: map() | :stable | :fail | propagator_event()
@callback filter(args :: list(), state :: map() | nil) ::
map() | :stable | :fail | propagator_event()
@callback variables(args :: list()) :: list()
alias CPSolver.Variable
alias CPSolver.Variable.View
alias CPSolver.Propagator.Variable, as: PropagatorVariable
alias CPSolver.DefaultDomain, as: Domain
alias CPSolver.Variable.Interface
alias CPSolver.ConstraintStore
defmacro __using__(_) do
quote do
alias CPSolver.Propagator
alias CPSolver.Variable.Interface
alias CPSolver.DefaultDomain, as: Domain
import CPSolver.Propagator.Variable
@behaviour Propagator
def new(args) do
Propagator.new(__MODULE__, args)
end
def update(propagator, _changes) do
propagator
end
def filter(args, _propagator_state) do
filter(args)
end
def variables(args) do
Propagator.default_variables_impl(args)
end
defoverridable variables: 1, update: 2, new: 1, filter: 2
end
end
def propagator_events() do
[:domain_change, :bound_change, :min_change, :max_change, :fixed]
end
def default_variables_impl(args) do
args
|> Enum.filter(fn
%Variable{} -> true
_ -> false
end)
end
def new(mod, args, opts \\ []) do
id = Keyword.get_lazy(opts, :id, fn -> make_ref() end)
name = Keyword.get(opts, :name, id)
%{
id: id,
name: name,
mod: mod,
args:
Enum.map(args, fn
%Variable{domain: domain} = arg ->
## We don't want propagator vars to keep domains, as propagator operates on store variables.
## Except when variables are fixed at the time propagator is created.
##
## Drop domain if variable is fixed, otherwise keep the fixed value
fixed? = Domain.fixed?(domain)
d = (fixed? && Domain.min(domain)) || nil
arg
|> Map.put(:fixed?, fixed?)
|> Map.put(:domain, d)
const ->
const
end)
}
end
def update(%{mod: mod} = propagator, changes) do
try do
mod.update(propagator, changes)
catch
{:fail, _var_id} ->
:fail
end
end
def filter(%{mod: mod, args: args} = propagator, opts \\ []) do
PropagatorVariable.reset_variable_ops()
store = Keyword.get(opts, :store)
state = propagator[:state]
ConstraintStore.set_store(store)
try do
mod.filter(args, state)
catch
{:fail, var_id} ->
{:fail, var_id}
else
:fail ->
:fail
:stable ->
:stable
result ->
## If propagator doesn't explicitly return 'stable',
## we retrieve the map of variable operation results created by PropagatorVariable wrapper
get_filter_changes(result != :passive)
end
end
def find_variable(args, var_id) do
Enum.find(args, fn arg -> Interface.id(arg) == var_id end)
end
## How propagator events map to domain events
def to_domain_events(:domain_change) do
[:domain_change, :min_change, :max_change, :fixed]
end
def to_domain_events(:bound_change) do
[:min_change, :max_change, :fixed]
end
def to_domain_events(:min_change) do
[:min_change, :fixed]
end
def to_domain_events(:max_change) do
[:max_change, :fixed]
end
def to_domain_events(:fixed) do
[:fixed]
end
@spec get_filter_changes(boolean()) ::
%{:changes => map(), active?: boolean()}
defp get_filter_changes(propagator_active?) do
%{
changes: PropagatorVariable.get_variable_ops(),
active?: propagator_active?
}
end
def bind_to_variables(propagator, indexed_variables) do
bound_args =
propagator.args
|> Enum.map(fn arg -> bind_to_variable(arg, indexed_variables) end)
Map.put(propagator, :args, bound_args)
end
defp bind_to_variable(%Variable{id: id} = var, indexed_variables) do
var_idx = Map.get(indexed_variables, id).index
Map.put(var, :index, var_idx)
end
defp bind_to_variable(%View{variable: variable} = view, indexed_variables) do
bound_var = bind_to_variable(variable, indexed_variables)
Map.put(view, :variable, bound_var)
end
defp bind_to_variable(const, _indexed_variables) do
const
end
end