Skip to content

Commit

Permalink
Minor changes to propagator code; 'reduce' fun for subsets of damain …
Browse files Browse the repository at this point in the history
…values
  • Loading branch information
bokner committed Dec 16, 2024
1 parent 6ee47a3 commit 25b0fb0
Show file tree
Hide file tree
Showing 4 changed files with 43 additions and 21 deletions.
22 changes: 16 additions & 6 deletions lib/solver/core/constraint.ex
Original file line number Diff line number Diff line change
Expand Up @@ -29,18 +29,28 @@ defmodule CPSolver.Constraint do
{constraint_impl, args}
end

def constraint_to_propagators({constraint_mod, args}) when is_list(args) do
constraint_mod.propagators(args)
def constraint_to_propagators(constraint, reducer_fun \\ &Function.identity/1)

def constraint_to_propagators({constraint_mod, args}, reducer_fun) when is_list(args) do
List.foldr(constraint_mod.propagators(args), [], fn p, plist_acc ->
[reducer_fun.(p) | plist_acc]
end)
end

def constraint_to_propagators(constraint) when is_tuple(constraint) do
def constraint_to_propagators(constraint, reducer_fun) when is_tuple(constraint) do
[constraint_mod | args] = Tuple.to_list(constraint)
constraint_to_propagators({constraint_mod, args})
constraint_to_propagators({constraint_mod, args}, reducer_fun)
end

def post(constraint) when is_tuple(constraint) do
propagators = constraint_to_propagators(constraint)
Enum.map(propagators, fn p -> Propagator.filter(p) end)
constraint_to_propagators(constraint,
fn p ->
case Propagator.filter(p) do
:fail -> throw({:fail, p.id})
%{state: state} -> Propagator.update_state(p, state)
_ -> p
end
end)
end

def extract_variables(constraint) do
Expand Down
6 changes: 5 additions & 1 deletion lib/solver/core/propagator/propagator.ex
Original file line number Diff line number Diff line change
Expand Up @@ -108,7 +108,11 @@ defmodule CPSolver.Propagator do
end

def reset(%{mod: mod, args: args} = propagator, opts \\ []) do
Map.put(propagator, :state, mod.reset(args, Map.get(propagator, :state), opts))
update_state(propagator, mod.reset(args, Map.get(propagator, :state), opts))
end

def update_state(propagator, state) do
Map.put(propagator, :state, state)
end

def bind(%{mod: mod} = propagator, source, var_field \\ :domain) do
Expand Down
27 changes: 14 additions & 13 deletions lib/solver/domain/bitvector_domain.ex
Original file line number Diff line number Diff line change
Expand Up @@ -59,38 +59,39 @@ defmodule CPSolver.BitVectorDomain do
to_list(domain, mapper_fun)
end

def to_list(
{{:bit_vector, ref} = bit_vector, offset} = domain,
mapper_fun \\ &Function.identity/1
) do
## Reduce over domain values
def reduce( {{:bit_vector, ref} = bit_vector, offset} = domain, value_mapper_fun, reduce_fun \\ &MapSet.union/2, acc_init \\ MapSet.new()) do
%{
min_addr: %{block: current_min_block, offset: _min_offset},
max_addr: %{block: current_max_block, offset: _max_offset}
} = get_bound_addrs(bit_vector)

mapped_lb = mapper_fun.(min(domain))
mapped_ub = mapper_fun.(max(domain))
mapped_lb = value_mapper_fun.(min(domain))
mapped_ub = value_mapper_fun.(max(domain))

## Note: this will only work for monotonic mapper functions.
## We don't have non-monotonic mappers for the moment.
##
## Adjust bounds
{lb, ub} = (mapped_lb <= mapped_ub && {mapped_lb, mapped_ub}) || {mapped_ub, mapped_lb}

Enum.reduce(current_min_block..current_max_block, MapSet.new(), fn idx, acc ->
Enum.reduce(current_min_block..current_max_block, acc_init, fn idx, acc ->
n = :atomics.get(ref, idx)

if n == 0 do
acc
else
MapSet.union(
reduce_fun.(
acc,
bit_positions(n, fn val -> {lb, ub, mapper_fun.(val + 64 * (idx - 1) - offset)} end)
bit_positions(n, fn val -> {lb, ub, value_mapper_fun.(val + 64 * (idx - 1) - offset)} end)
)
end
end)
end

def to_list(
{{:bit_vector, ref} = bit_vector, offset} = domain,
value_mapper_fun \\ &Function.identity/1
) do
reduce(domain, value_mapper_fun, &MapSet.union/2, MapSet.new())
end

def fixed?({bit_vector, _offset} = _domain) do
{current_min_max, _min_max_idx, current_min, current_max} = get_min_max(bit_vector)
current_max == current_min && current_min_max != @failure_value
Expand Down
9 changes: 8 additions & 1 deletion lib/solver/model/model.ex
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,14 @@ defmodule CPSolver.Model do
}

def new(variables, constraints, opts \\ []) do
constraints = normalize_constraints(constraints)
constraints =
normalize_constraints(constraints)
# TODO:
# consider posting constraints and/or building constraint graph/list of propagators here
## For instance:
# tap(fn constraints -> Enum.each(constraints, fn c -> Constraint.post(c) end) end)
#

{all_variables, objective} = init_model(variables, constraints, opts[:objective])

%__MODULE__{
Expand Down

0 comments on commit 25b0fb0

Please sign in to comment.