Packages
fixpoint
0.4.0
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/propagators/propagator_thread_test.exs
defmodule CPSolverTest.Propagator.Thread do
use ExUnit.Case
describe "Propagator thread" do
alias CPSolver.Propagator.Thread, as: PropagatorThread
alias CPSolver.ConstraintStore
alias CPSolver.IntVariable
alias CPSolver.Variable
alias CPSolver.Propagator.NotEqual
test "create propagator thread" do
x = 1..1
y = -5..5
z = 0..0
variables = Enum.map([x, y, z], fn d -> IntVariable.new(d) end)
{:ok, [x_var, y_var, z_var] = _bound_vars, store} =
ConstraintStore.create_store(variables, space: nil)
{:ok, _propagator_thread} =
PropagatorThread.create_thread(self(), {NotEqual, x_var, y_var}, store: store)
## ...filters its variables upon start (happens in handle_continue, so needs a small timeout here)
Process.sleep(10)
refute Variable.contains?(y_var, 1)
## Note: we start propagator thread, but don't filter on a startup
{:ok, _propagator_thread} =
PropagatorThread.create_thread(self(), {NotEqual, y_var, z_var},
filter_on_startup: false,
store: store
)
## Fix 'y' to 0 so the propagator triggers a failure, as 'z' is also fixed to 0
assert :fixed = Variable.fix(y_var, 0)
Process.sleep(10)
# assert :fail == Variable.domain(z_var)
end
test "entailment with initially unfixed variables" do
x = 0..2
y = -5..5
variables = Enum.map([x, y], fn d -> IntVariable.new(d) end)
## space = nil results in Store notifying propagators directly
{:ok, [x_var, y_var] = bound_vars, store} =
ConstraintStore.create_store(variables, space: nil)
{:ok, propagator_thread} =
PropagatorThread.create_thread(self(), {NotEqual, bound_vars},
store: store,
subscribe_to_events: true
)
ConstraintStore.update(store, x_var, :fix, [1])
Process.sleep(10)
refute_received {:entailed, _}
ConstraintStore.update(store, y_var, :fix, [2])
Process.sleep(10)
assert_received {:entailed, _}
## Propagator thread discards itself on entailment
Process.sleep(10)
refute Process.alive?(propagator_thread)
end
test "entailment with initially fixed variables" do
x = 0..0
y = 1..1
variables = Enum.map([x, y], fn d -> IntVariable.new(d) end)
{:ok, bound_vars, store} = ConstraintStore.create_store(variables)
{:ok, propagator_thread} =
PropagatorThread.create_thread(self(), {NotEqual, bound_vars}, store: store)
## Propagator thread discards itself on entailment
Process.sleep(10)
assert_received {:entailed, _}
refute Process.alive?(propagator_thread)
end
test "Starting/stopping propagator subscribes it to/unsubscribes it from its variables" do
x = 0..2
y = -5..5
variables = Enum.map([x, y], fn d -> IntVariable.new(d) end)
{:ok, vars, store} = ConstraintStore.create_store(variables)
{:ok, propagator_thread} =
PropagatorThread.create_thread(self(), {NotEqual, vars}, store: store)
PropagatorThread.dispose(propagator_thread)
Process.sleep(10)
refute Process.alive?(propagator_thread)
end
test "stability" do
x = 0..5
y = 1..3
variables = Enum.map([x, y], fn d -> IntVariable.new(d) end)
{:ok, [x_var, y_var] = vars, store} = ConstraintStore.create_store(variables, space: nil)
## Detects stability on a startup
{:ok, propagator_thread} =
PropagatorThread.create_thread(self(), {NotEqual, vars},
store: store,
subscribe_to_events: true
)
Process.sleep(10)
assert_received {:stable, _}
## Filtering that leaves unfixed variable(s) (x_var in this case) should
## (eventually) put propagator into 'stable' state
ConstraintStore.update(store, y_var, :fix, [1])
Process.sleep(10)
assert_received {:stable, _}
## The propagator is stable, and so has to live..
assert Process.alive?(propagator_thread)
## Fixing all variables (i.e., entailment)
## does not result in stability.
ConstraintStore.update(store, x_var, :fix, [0])
Process.sleep(10)
assert_received {:entailed, _}
## The propagator has gone (entailnment had stopped it)
refute Process.alive?(propagator_thread)
end
test "propagator failure" do
x = 1..1
y = 1..2
z = 2..2
variables = Enum.map([x, y, z], fn d -> IntVariable.new(d) end)
{:ok, [x_var, y_var, z_var] = _vars, store} =
ConstraintStore.create_store(variables)
{:ok, _threadXY} =
PropagatorThread.create_thread(self(), {NotEqual, [x_var, y_var]},
id: "X != Y",
store: store
)
{:ok, _threadYZ} =
PropagatorThread.create_thread(self(), {NotEqual, [y_var, z_var]},
id: "Y != Z",
store: store
)
Process.sleep(5)
assert 1 == Variable.min(x_var)
## Non-deterministic failure - fails on either 'y' or 'z', depending on which propagator fixes first.
assert :fail == Variable.min(z_var) || :fail == Variable.min(y_var)
end
end
end