Packages
fixpoint
0.9.6
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
test/domain/mutable_domain_test.exs
defmodule CPSolverTest.MutableDomain do
use ExUnit.Case
describe "Mutable domain" do
alias CPSolver.BitVectorDomain, as: Domain
test "creates domain from integer range and list" do
assert catch_throw(Domain.new([])) == :fail
assert Domain.size(Domain.new(1..10)) == 10
int_list = [-1, 2, 4, 8, 10]
assert Domain.size(Domain.new(int_list)) == length(int_list)
end
test "fixed?" do
assert Domain.new([1]) |> Domain.fixed?()
refute Domain.new([1, 2]) |> Domain.fixed?()
end
test "min, max" do
values = [0, 2, 3, -1, 4, 10]
domain = Domain.new(values)
assert Domain.min(domain) == Enum.min(values)
assert Domain.max(domain) == Enum.max(values)
end
test "contains?" do
values = [1, 3, 7, -1, 0, -2, 10]
domain = Domain.new(values)
Enum.all?(values, fn v -> Domain.contains?(domain, v) end)
refute Domain.contains?(domain, 9)
end
test "remove" do
values = [0, 2, 3, -1, 4, 10]
domain = Domain.new(values)
{:domain_change, domain} = Domain.remove(domain, 3)
refute Domain.contains?(domain, 3)
assert Domain.size(domain) == length(values) - 1
{:min_change, domain} = Domain.remove(domain, -1)
{:max_change, domain} = Domain.remove(domain, 10)
assert 0 == Domain.min(domain)
assert 4 == Domain.max(domain)
{:domain_change, domain} = Domain.remove(domain, 2)
{:fixed, _fixed} = Domain.remove(domain, 4)
assert 0 == Domain.min(domain)
end
test "removeBelow" do
values = [-1, 0, 2, 3, 4, 10]
domain = Domain.new(values)
{:min_change, cutBelow} = Domain.removeBelow(domain, 1)
assert Domain.min(cutBelow) == 2
assert Domain.size(domain) == 4
{:min_change, cutBelow} = Domain.removeBelow(domain, 3)
assert Domain.min(cutBelow) == 3
assert :no_change == Domain.removeBelow(domain, Enum.min(values))
{:fixed, _fixed} = Domain.removeBelow(domain, Enum.max(values))
assert Domain.fixed?(domain)
assert catch_throw(Domain.removeBelow(domain, Enum.max(values) + 1)) == :fail
end
test "removeAbove" do
values = [-1, 0, 2, 3, 4, 10]
domain = Domain.new(values)
{:max_change, cutAbove} = Domain.removeAbove(domain, 3)
assert Domain.max(cutAbove) == 3
assert Domain.size(domain) == 4
{:max_change, cutAbove} = Domain.removeAbove(domain, 1)
assert Domain.max(cutAbove) == 0
assert :no_change == Domain.removeAbove(domain, Enum.max(values))
{:fixed, _fixed} = Domain.removeAbove(domain, Enum.min(values))
assert Domain.fixed?(domain)
assert catch_throw(Domain.removeAbove(domain, Enum.min(values) - 1)) == :fail
end
test "fix" do
values = [0, -2, 4, 5, 6]
assert Enum.all?(values, fn val ->
domain = Domain.new(values)
:fixed = Domain.fix(domain, val)
Domain.fixed?(domain) &&
Domain.min(domain) == val &&
Domain.max(domain) == val
end)
## Fixing non-existing value leads to a failure
domain = Domain.new(values)
assert catch_throw(Domain.fix(domain, 1)) == :fail
end
test "to_list, map" do
values = [0, 2, 3, -1, 4, 10]
domain = Domain.new(values)
assert Enum.sort(Domain.to_list(domain)) == Enum.sort(values)
mapper_fun = fn x -> 2 * x end
assert Domain.map(domain, mapper_fun) |> Enum.sort() ==
Enum.map(values, mapper_fun) |> Enum.sort()
end
test "copy" do
values = 200..500
domain = Domain.new(values)
Domain.removeAbove(domain, 300)
domain_copy = Domain.copy(domain)
assert Domain.to_list(domain) == Domain.to_list(domain_copy)
assert Domain.size(domain) == Domain.size(domain_copy)
assert Domain.min(domain) == Domain.min(domain_copy)
assert Domain.max(domain) == Domain.max(domain_copy)
Domain.removeBelow(domain_copy, 250)
domain_copy2 = Domain.copy(domain_copy)
assert Domain.to_list(domain_copy2) == Domain.to_list(domain_copy)
assert Domain.size(domain_copy2) == Domain.size(domain_copy)
assert Domain.min(domain_copy2) == Domain.min(domain_copy)
assert Domain.max(domain_copy2) == Domain.max(domain_copy)
end
test "consistency" do
data = %{
max: 76,
min: 14,
raw: %{offset: -11, content: [4_503_599_644_147_720, 2, 279_172_874_243]},
size: 4,
remove: 76,
values: [76, 63, 35, 14],
failed?: false,
fixed?: false
}
domain = build_domain(data)
assert_domain(domain, data.values)
{:max_change, _} = Domain.remove(domain, Domain.max(domain))
values1 = List.delete(data.values, Enum.max(data.values))
assert_domain(domain, values1)
end
@tag :slow
test "Concurrent removal of values (threads remove distinct values)" do
##
values = 1..100_000
domain = Domain.new(values)
Task.async_stream(
values,
fn val ->
try do
Domain.remove(domain, val)
catch
_ ->
:ok
end
end,
max_concurrency: 8
)
|> Enum.to_list()
assert Domain.failed?(domain)
end
test "Concurrent removal of values (multiple threads remove shared values)" do
##
n_values = 3
values = 1..n_values
domain = Domain.new(values)
Task.async_stream(
1..2,
fn _thread_id ->
try do
## Keep one random value, remove the rest
Enum.each(Enum.take(values, n_values - 1), fn val ->
Domain.remove(domain, val)
end)
catch
_ ->
:failed
end
end,
max_concurrency: 8
)
|> Enum.to_list()
assert Domain.fixed?(domain)
end
defp build_domain(data) do
ref = :atomics.new(length(data.raw.content), [{:signed, false}])
Enum.each(Enum.with_index(data.raw.content, 1), fn {val, idx} ->
:atomics.put(ref, idx, val)
end)
bit_vector = {:bit_vector, ref}
_domain = {bit_vector, data.raw.offset}
end
defp assert_domain(domain, values) do
assert Domain.to_list(domain) |> Enum.sort() == values |> Enum.sort()
assert Domain.size(domain) == length(values)
assert Domain.min(domain) == Enum.min(values)
assert Domain.max(domain) == Enum.max(values)
refute Domain.fixed?(domain)
refute Domain.failed?(domain)
end
end
describe "Single-value domain" do
alias CPSolver.DefaultDomain, as: Domain
test "single-value domain" do
assert Domain.fixed?(1)
assert Domain.size(5) == 1
assert Domain.contains?(1, 1)
refute Domain.contains?(1, 2)
assert Domain.min(1) == 1
assert Domain.max(1) == 1
assert Domain.to_list(1) == MapSet.new([1])
assert Domain.map(3, fn x -> 2 * x end) == [6]
assert Domain.copy(1) == 1
assert Domain.remove(2, 1) == :no_change
assert catch_throw(Domain.remove(2, 2)) == :fail
assert Domain.removeAbove(2, 2) == :no_change
assert catch_throw(Domain.removeAbove(3, 2)) == :fail
assert Domain.removeBelow(2, 2) == :no_change
assert catch_throw(Domain.removeBelow(2, 3)) == :fail
assert Domain.fix(1, 1) == :no_change
assert catch_throw(Domain.fix(1, 2)) == :fail
end
end
end