Packages
fixpoint
0.3.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/store/local_store.ex
defmodule CPSolver.Store.Local do
alias CPSolver.ConstraintStore
alias CPSolver.DefaultDomain, as: Domain
use ConstraintStore
use GenServer
## Store callbacks
@impl true
def create(variables, opts \\ []) do
variable_map =
Map.new(
variables,
fn var ->
{var.id, %{domain: Domain.new(var.domain), subscriptions: []}}
end
)
{:ok, _store} = GenServer.start_link(__MODULE__, [variable_map, opts])
end
@impl true
def dispose(store, _variables) do
GenServer.cast(store, :stop)
end
@impl true
def domain(store, var) do
GenServer.call(store, {:domain, var.id})
end
@impl true
def get(store, var, operation, args \\ []) do
GenServer.call(store, {:get, var.id, operation, args})
end
@impl true
def update_domain(store, var, operation, args \\ []) do
GenServer.call(store, {:update, var.id, operation, args})
end
@impl true
def on_change(_store, _variable, _change) do
:ok
end
@impl true
def on_fail(_store, _variable) do
:ok
end
@impl true
def on_no_change(_store, _variable) do
:ok
end
@impl true
def get_variables(store) do
GenServer.call(store, :get_variables)
end
@impl true
def subscribe(store, subscriptions) do
GenServer.cast(
store,
{:subscribe, Enum.map(subscriptions, &ConstraintStore.normalize_subscription/1)}
)
end
## GenServer callbacks
@impl true
def init([variables, _opts]) do
{:ok, %{variables: variables}}
end
@impl true
def handle_call({:domain, var}, _from, data) do
{:reply, get_domain(var, data), data}
end
def handle_call({request_kind, var, operation, args}, _from, data)
when request_kind in [:update, :get] do
var
|> get_domain(data)
|> handle_request(request_kind, var, operation, args, data)
end
def handle_call(:get_variables, _from, %{variables: variables} = data) do
var_ids = Map.keys(variables)
{:reply, var_ids, data}
end
@impl true
def handle_cast({:subscribe, subscriptions}, %{variables: variables} = _data) do
subscriptions_by_var = Enum.group_by(subscriptions, fn s -> s.variable end)
updated_variables =
Enum.reduce(subscriptions_by_var, variables, fn {var, subscrs}, acc ->
Map.update(acc, var, nil, fn rec ->
%{
rec
| subscriptions: (rec.subscriptions ++ subscrs) |> Enum.uniq_by(fn rec -> rec.pid end)
}
end)
end)
{:noreply, Map.put(variables, :variables, updated_variables)}
end
def handle_cast(:stop, data) do
{:stop, :normal, data}
end
defp handle_request(nil, _, _, _, _, data) do
{:reply, :not_found, data}
end
defp handle_request(:fail, _, _, _, _, data) do
{:reply, :fail, data}
end
defp handle_request(domain, :get, _variable, operation, args, data) do
{:reply, apply(Domain, operation, [domain | args]), data}
end
defp handle_request(domain, :update, variable, operation, args, data) do
{result, new_data} =
case apply(Domain, operation, [domain | args]) do
:fail ->
{:fail, update_variable_domain(variable, :fail, :fail, data)}
:no_change ->
{:no_change, data}
{domain_change, new_domain} ->
{domain_change, update_variable_domain(variable, new_domain, domain_change, data)}
end
{:reply, result, new_data}
end
defp get_domain(var_id, %{variables: variables} = _data) do
case Map.get(variables, var_id) do
nil -> nil
%{domain: domain} -> domain
end
end
defp update_variable_domain(var_id, domain, event, %{variables: variables} = data) do
variable_rec = Map.get(variables, var_id)
variable_rec
|> Map.put(:domain, domain)
|> then(fn updated_var ->
updated_vars = Map.put(variables, var_id, updated_var)
Map.put(data, :variables, updated_vars)
end)
|> tap(fn _ ->
ConstraintStore.notify_subscribers(var_id, event, variable_rec.subscriptions)
end)
end
end