-
Notifications
You must be signed in to change notification settings - Fork 72
Expand file tree
/
Copy pathtest_solvers.py
More file actions
134 lines (110 loc) · 5.1 KB
/
test_solvers.py
File metadata and controls
134 lines (110 loc) · 5.1 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
import pytest
from constraint import Problem, MinConflictsSolver, BacktrackingSolver, OptimizedBacktrackingSolver, RecursiveBacktrackingSolver, ParallelSolver
from constraint import MaxProdConstraint, MinProdConstraint, MinSumConstraint, FunctionConstraint
def test_min_conflicts_solver():
problem = Problem(MinConflictsSolver())
problem.addVariable("x", [0, 1])
problem.addVariable("y", [0, 1])
possible_solutions = [
{"x": 0, "y": 0},
{"x": 0, "y": 1},
{"x": 1, "y": 0},
{"x": 1, "y": 1},
]
# test if all solutions are eventually found by iteration and adding the last solutions as a constraint
for _ in possible_solutions:
solution = problem.getSolution()
assert solution in possible_solutions
problem.addConstraint(FunctionConstraint(lambda x, y: (lambda x, y, xs, ys: x != xs or y != ys)(x, y, solution['x'], solution['y'])))
def test_optimized_backtracking_solver():
# setup the solvers
problem_bt = Problem(BacktrackingSolver())
problem_opt = Problem(OptimizedBacktrackingSolver())
problem_opt_nfwd = Problem(OptimizedBacktrackingSolver(forwardcheck=False))
problems = [problem_bt, problem_opt, problem_opt_nfwd]
# define the problem for all solvers
for problem in problems:
problem.addVariable("x", [-1, 0, 1, 2])
problem.addVariable("y", [1, 2])
problem.addConstraint(MaxProdConstraint(2), ["x", "y"])
problem.addConstraint(MinProdConstraint(1), ["x", "y"])
problem.addConstraint(MinSumConstraint(0), ["x"])
# get the solutions
true_solutions = [(2, 1), (1, 2), (1, 1)]
order = ["x", "y"]
solution = problem_bt.getSolution()
solution_tuple = tuple(solution[key] for key in order)
# validate a single solution
solution_opt = problem_opt.getSolution()
assert tuple(solution_opt[key] for key in order) in true_solutions
# validate all solutions
def validate(solutions_list, solutions_dict, size):
assert size == len(true_solutions)
assert solution_tuple in solutions_list
assert solution_tuple in solutions_dict
assert all(sol in solutions_list for sol in true_solutions)
validate(*problem_opt.getSolutionsAsListDict(order=order))
validate(*problem_opt_nfwd.getSolutionsAsListDict(order=order))
def test_recursive_backtracking_solver():
problem = Problem(RecursiveBacktrackingSolver())
problem.addVariable("x", [0, 1])
problem.addVariable("y", [0, 1])
solution = problem.getSolution()
solutions = problem.getSolutions()
possible_solutions = [
{"x": 0, "y": 0},
{"x": 0, "y": 1},
{"x": 1, "y": 0},
{"x": 1, "y": 1},
]
assert solution in possible_solutions
assert all(sol in possible_solutions for sol in solutions)
def test_parallel_solver():
# setup the solvers
problem = Problem(ParallelSolver(process_mode=False))
problem.addVariable("x", [-1, 0, 1, 2])
problem.addVariable("y", [1, 2])
problem.addConstraint(MaxProdConstraint(2), ["x", "y"])
problem.addConstraint(MinProdConstraint(1), ["x", "y"])
problem.addConstraint(FunctionConstraint(lambda x, y: 1 <= x * y <= 2))
problem.addConstraint(MinSumConstraint(0), ["x"])
# assert that a single solution results in an error
with pytest.raises(NotImplementedError):
solution_opt = problem.getSolution()
assert tuple(solution_opt[key] for key in order) in true_solutions
# set the true solutions
true_solutions = [(2, 1), (1, 2), (1, 1)]
order = ["x", "y"]
# get all solutions
solutions_list, solutions_dict, size = problem.getSolutionsAsListDict(order=order)
# validate all solutions
assert size == len(true_solutions)
assert all(sol in solutions_list for sol in true_solutions)
def test_parallel_solver_process_mode():
# setup the solvers
problem = Problem(ParallelSolver(process_mode=True))
problem.addVariable("x", [-1, 0, 1, 2])
problem.addVariable("y", [1, 2])
problem.addConstraint(MaxProdConstraint(2), ["x", "y"])
problem.addConstraint(MinProdConstraint(1), ["x", "y"])
problem.addConstraint(["1 <= x * y <= 2"])
problem.addConstraint(MinSumConstraint(0), ["x"])
# assert that a single solution results in an error
with pytest.raises(NotImplementedError):
solution_opt = problem.getSolution()
assert tuple(solution_opt[key] for key in order) in true_solutions
# set the true solutions
true_solutions = [(2, 1), (1, 2), (1, 1)]
order = ["x", "y"]
# get all solutions
solutions_list, solutions_dict, size = problem.getSolutionsAsListDict(order=order)
# validate all solutions
assert size == len(true_solutions)
assert all(sol in solutions_list for sol in true_solutions)
# assert that using ProcessPool mode with FunctionConstraint results in an understandable error
problem = Problem(ParallelSolver(process_mode=True))
problem.addVariable("x", [-1, 0, 1, 2])
problem.addVariable("y", [1, 2])
problem.addConstraint(FunctionConstraint(lambda x, y: 1 <= x * y <= 2))
with pytest.raises(AssertionError):
problem.getSolutions()