Packages
fixpoint
0.19.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
test/solver/cpsolver_test.exs
defmodule CPSolverTest do
use ExUnit.Case
alias CPSolver.IntVariable
alias CPSolver.Model
alias CPSolver.Constraint.NotEqual
alias CPSolver.Examples.Queens
alias CPSolver.Examples.Knapsack
@solution_handler_test_file "solution_handler_test.tmp"
setup do
File.touch(@solution_handler_test_file)
on_exit(fn -> File.rm(@solution_handler_test_file) end)
:ok
end
test "Solves CSP with 2 variables and a single constraint" do
x = IntVariable.new([1, 2])
y = IntVariable.new([0, 1])
model =
Model.new(
[x, y],
[NotEqual.new(x, y)]
)
{:ok, res} = CPSolver.solve(model)
assert res.statistics.failure_count == 0
## Note: there are 2 "first fail" distributions:
## 1. Choice of variable 'x' triggers distribution into 2 spaces - (x: 1, y: [0, 1]) and (x: 2, y: [0, 1])).
## 2. First space produces solution (x: 1, y: 0)
## 3. Second space triggers distribution into 2 spaces - (x: 2, y: 0) and (x: 2, y: 1)
## 4. These 2 spaces produce remaining solutions.
#
## Note 2: for the second space, the child spaces are not being created anymore,
## as NotEqual is passive in that space (x: 2, y: [0, 1]).
## So the solutions here are deducted by cartesian product of domains, which gives
## solutions (x: 2, y: 0) and (x: 2, y: 1).
## Finally, we have only 3 nodes: top one, and two child spaces (p.2, p.3).
##
assert res.statistics.node_count == 3
assert res.statistics.solution_count == 3
solutions =
res.solutions
|> Enum.sort_by(fn [x, y] -> x + y end)
assert solutions == [[1, 0], [2, 0], [2, 1]]
end
test "Stops on max_solutions reached" do
max_solutions = 2
{:ok, solver} = Queens.solve(5, stop_on: {:max_solutions, max_solutions})
Process.sleep(100)
assert CPSolver.complete?(solver)
end
test "Synchronous solver" do
{:ok, result} = CPSolver.solve(Queens.model(8))
assert result.statistics.solution_count == 92
## No active nodes - solving is done
assert result.statistics.active_node_count == 0
end
test "Solver status" do
## N-Queens for n = 3 is unatisfiable
{:ok, res} = CPSolver.solve(Queens.model(3))
assert res.status == :unsatisfiable
## N-Queens for n = 4
{:ok, res} = CPSolver.solve(Queens.model(4))
assert res.status == :all_solutions
## N-Queens for n = 8, async solving
{:ok, solver} = CPSolver.solve_async(Queens.model(8))
Process.sleep(10)
{:running, _} = CPSolver.status(solver)
Process.sleep(100)
assert :all_solutions = CPSolver.status(solver)
## Status for optimization problem
{:ok, solver} = CPSolver.solve_async(Knapsack.model("data/knapsack/ks_4_0"))
Process.sleep(100)
assert {:optimal, [objective: 19]} == CPSolver.status(solver)
end
test "Solution handler" do
x = IntVariable.new([1, 2], name: "x")
y = IntVariable.new([0, 1], name: "y")
model =
Model.new(
[x, y],
[NotEqual.new(x, y)]
)
{:ok, res} =
CPSolver.solve(model,
solution_handler: fn solution ->
File.write!(@solution_handler_test_file, :erlang.term_to_binary(solution) <> "\n", [
:append
])
end
)
File.close(@solution_handler_test_file)
solutions_from_file =
@solution_handler_test_file
|> File.read!()
|> String.trim()
|> String.split("\n")
|> Enum.map(fn binary -> :erlang.binary_to_term(binary) end)
## Make {ref, value} list off the solver solutions
## to be able to compare with the output of solutuon handler
solver_solutions =
Enum.map(res.solutions, fn sol -> Enum.zip(res.variables, sol) end)
|> List.flatten()
|> Enum.sort()
handler_solutions = List.flatten(solutions_from_file) |> Enum.sort()
assert solver_solutions == handler_solutions
end
end