NUCS 2.0.0__tar.gz → 2.1.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {nucs-2.0.0 → nucs-2.1.0/NUCS.egg-info}/PKG-INFO +4 -3
- {nucs-2.0.0 → nucs-2.1.0}/NUCS.egg-info/SOURCES.txt +2 -0
- {nucs-2.0.0/NUCS.egg-info → nucs-2.1.0}/PKG-INFO +4 -3
- {nucs-2.0.0 → nucs-2.1.0}/README.md +3 -2
- {nucs-2.0.0 → nucs-2.1.0}/docs/source/conf.py +2 -2
- {nucs-2.0.0 → nucs-2.1.0}/nucs/constants.py +4 -2
- {nucs-2.0.0 → nucs-2.1.0}/nucs/examples/golomb/golomb_problem.py +16 -8
- {nucs-2.0.0 → nucs-2.1.0}/nucs/examples/queens/__main__.py +3 -0
- {nucs-2.0.0 → nucs-2.1.0}/nucs/propagators/propagators.py +18 -4
- {nucs-2.0.0 → nucs-2.1.0}/nucs/solvers/backtrack_solver.py +52 -42
- {nucs-2.0.0 → nucs-2.1.0}/nucs/solvers/bound_consistency_algorithm.py +23 -14
- nucs-2.1.0/nucs/solvers/choice_points.py +84 -0
- {nucs-2.0.0 → nucs-2.1.0}/nucs/solvers/consistency_algorithms.py +2 -0
- {nucs-2.0.0 → nucs-2.1.0}/nucs/solvers/heuristics.py +16 -4
- nucs-2.1.0/nucs/solvers/shaving_consistency_algorithm.py +269 -0
- {nucs-2.0.0 → nucs-2.1.0}/nucs/statistics.py +13 -1
- {nucs-2.0.0 → nucs-2.1.0}/pyproject.toml +1 -1
- {nucs-2.0.0 → nucs-2.1.0}/LICENSE.md +0 -0
- {nucs-2.0.0 → nucs-2.1.0}/NUCS.egg-info/dependency_links.txt +0 -0
- {nucs-2.0.0 → nucs-2.1.0}/NUCS.egg-info/requires.txt +0 -0
- {nucs-2.0.0 → nucs-2.1.0}/NUCS.egg-info/top_level.txt +0 -0
- {nucs-2.0.0 → nucs-2.1.0}/nucs/__init__.py +0 -0
- {nucs-2.0.0 → nucs-2.1.0}/nucs/examples/__init__.py +0 -0
- {nucs-2.0.0 → nucs-2.1.0}/nucs/examples/alpha/__init__.py +0 -0
- {nucs-2.0.0 → nucs-2.1.0}/nucs/examples/alpha/__main__.py +0 -0
- {nucs-2.0.0 → nucs-2.1.0}/nucs/examples/alpha/alpha_problem.py +0 -0
- {nucs-2.0.0 → nucs-2.1.0}/nucs/examples/bibd/__init__.py +0 -0
- {nucs-2.0.0 → nucs-2.1.0}/nucs/examples/bibd/__main__.py +0 -0
- {nucs-2.0.0 → nucs-2.1.0}/nucs/examples/bibd/bibd_problem.py +0 -0
- {nucs-2.0.0 → nucs-2.1.0}/nucs/examples/donald/__init__.py +0 -0
- {nucs-2.0.0 → nucs-2.1.0}/nucs/examples/donald/__main__.py +0 -0
- {nucs-2.0.0 → nucs-2.1.0}/nucs/examples/donald/donald_problem.py +0 -0
- {nucs-2.0.0 → nucs-2.1.0}/nucs/examples/golomb/__init__.py +0 -0
- {nucs-2.0.0 → nucs-2.1.0}/nucs/examples/golomb/__main__.py +0 -0
- {nucs-2.0.0 → nucs-2.1.0}/nucs/examples/knapsack/__init__.py +0 -0
- {nucs-2.0.0 → nucs-2.1.0}/nucs/examples/knapsack/__main__.py +0 -0
- {nucs-2.0.0 → nucs-2.1.0}/nucs/examples/knapsack/knapsack_problem.py +0 -0
- {nucs-2.0.0 → nucs-2.1.0}/nucs/examples/magic_sequence/__init__.py +0 -0
- {nucs-2.0.0 → nucs-2.1.0}/nucs/examples/magic_sequence/__main__.py +0 -0
- {nucs-2.0.0 → nucs-2.1.0}/nucs/examples/magic_sequence/magic_sequence_problem.py +0 -0
- {nucs-2.0.0 → nucs-2.1.0}/nucs/examples/magic_square/__init__.py +0 -0
- {nucs-2.0.0 → nucs-2.1.0}/nucs/examples/magic_square/__main__.py +0 -0
- {nucs-2.0.0 → nucs-2.1.0}/nucs/examples/magic_square/magic_square_problem.py +0 -0
- {nucs-2.0.0 → nucs-2.1.0}/nucs/examples/quasigroup/__init__.py +0 -0
- {nucs-2.0.0 → nucs-2.1.0}/nucs/examples/quasigroup/__main__.py +0 -0
- {nucs-2.0.0 → nucs-2.1.0}/nucs/examples/quasigroup/quasigroup_problem.py +0 -0
- {nucs-2.0.0 → nucs-2.1.0}/nucs/examples/queens/__init__.py +0 -0
- {nucs-2.0.0 → nucs-2.1.0}/nucs/examples/queens/queens_problem.py +0 -0
- {nucs-2.0.0 → nucs-2.1.0}/nucs/examples/schur_lemma/__init__.py +0 -0
- {nucs-2.0.0 → nucs-2.1.0}/nucs/examples/schur_lemma/__main__.py +0 -0
- {nucs-2.0.0 → nucs-2.1.0}/nucs/examples/schur_lemma/schur_lemma_problem.py +0 -0
- {nucs-2.0.0 → nucs-2.1.0}/nucs/examples/sports_tournament_scheduling/__init__.py +0 -0
- {nucs-2.0.0 → nucs-2.1.0}/nucs/examples/sports_tournament_scheduling/__main__.py +0 -0
- {nucs-2.0.0 → nucs-2.1.0}/nucs/examples/sports_tournament_scheduling/sports_tournament_scheduling_problem.py +0 -0
- {nucs-2.0.0 → nucs-2.1.0}/nucs/examples/sudoku/__init__.py +0 -0
- {nucs-2.0.0 → nucs-2.1.0}/nucs/examples/sudoku/sudoku_problem.py +0 -0
- {nucs-2.0.0 → nucs-2.1.0}/nucs/numba_helper.py +0 -0
- {nucs-2.0.0 → nucs-2.1.0}/nucs/numpy_helper.py +0 -0
- {nucs-2.0.0 → nucs-2.1.0}/nucs/problems/__init__.py +0 -0
- {nucs-2.0.0 → nucs-2.1.0}/nucs/problems/latin_square_problem.py +0 -0
- {nucs-2.0.0 → nucs-2.1.0}/nucs/problems/problem.py +0 -0
- {nucs-2.0.0 → nucs-2.1.0}/nucs/propagators/__init__.py +0 -0
- {nucs-2.0.0 → nucs-2.1.0}/nucs/propagators/affine_eq_propagator.py +0 -0
- {nucs-2.0.0 → nucs-2.1.0}/nucs/propagators/affine_geq_propagator.py +0 -0
- {nucs-2.0.0 → nucs-2.1.0}/nucs/propagators/affine_leq_propagator.py +0 -0
- {nucs-2.0.0 → nucs-2.1.0}/nucs/propagators/alldifferent_propagator.py +0 -0
- {nucs-2.0.0 → nucs-2.1.0}/nucs/propagators/and_propagator.py +0 -0
- {nucs-2.0.0 → nucs-2.1.0}/nucs/propagators/count_eq_propagator.py +0 -0
- {nucs-2.0.0 → nucs-2.1.0}/nucs/propagators/dummy_propagator.py +0 -0
- {nucs-2.0.0 → nucs-2.1.0}/nucs/propagators/element_lic_propagator.py +0 -0
- {nucs-2.0.0 → nucs-2.1.0}/nucs/propagators/element_liv_propagator.py +0 -0
- {nucs-2.0.0 → nucs-2.1.0}/nucs/propagators/exactly_eq_propagator.py +0 -0
- {nucs-2.0.0 → nucs-2.1.0}/nucs/propagators/exactly_true_propagator.py +0 -0
- {nucs-2.0.0 → nucs-2.1.0}/nucs/propagators/gcc_propagator.py +0 -0
- {nucs-2.0.0 → nucs-2.1.0}/nucs/propagators/lexicographic_leq_propagator.py +0 -0
- {nucs-2.0.0 → nucs-2.1.0}/nucs/propagators/max_eq_propagator.py +0 -0
- {nucs-2.0.0 → nucs-2.1.0}/nucs/propagators/max_leq_propagator.py +0 -0
- {nucs-2.0.0 → nucs-2.1.0}/nucs/propagators/min_eq_propagator.py +0 -0
- {nucs-2.0.0 → nucs-2.1.0}/nucs/propagators/min_geq_propagator.py +0 -0
- {nucs-2.0.0 → nucs-2.1.0}/nucs/propagators/relation_propagator.py +0 -0
- {nucs-2.0.0 → nucs-2.1.0}/nucs/solvers/__init__.py +0 -0
- {nucs-2.0.0 → nucs-2.1.0}/nucs/solvers/multiprocessing_solver.py +0 -0
- {nucs-2.0.0 → nucs-2.1.0}/nucs/solvers/solver.py +0 -0
- {nucs-2.0.0 → nucs-2.1.0}/setup.cfg +0 -0
- {nucs-2.0.0 → nucs-2.1.0}/tests/__init__.py +0 -0
- {nucs-2.0.0 → nucs-2.1.0}/tests/examples/test_alpha.py +0 -0
- {nucs-2.0.0 → nucs-2.1.0}/tests/examples/test_bibd.py +0 -0
- {nucs-2.0.0 → nucs-2.1.0}/tests/examples/test_donald.py +0 -0
- {nucs-2.0.0 → nucs-2.1.0}/tests/examples/test_golomb.py +0 -0
- {nucs-2.0.0 → nucs-2.1.0}/tests/examples/test_knapsack.py +0 -0
- {nucs-2.0.0 → nucs-2.1.0}/tests/examples/test_latin_square.py +0 -0
- {nucs-2.0.0 → nucs-2.1.0}/tests/examples/test_magic_sequence.py +0 -0
- {nucs-2.0.0 → nucs-2.1.0}/tests/examples/test_magic_square.py +0 -0
- {nucs-2.0.0 → nucs-2.1.0}/tests/examples/test_quasigroup.py +0 -0
- {nucs-2.0.0 → nucs-2.1.0}/tests/examples/test_queens.py +0 -0
- {nucs-2.0.0 → nucs-2.1.0}/tests/examples/test_schur_lemma.py +0 -0
- {nucs-2.0.0 → nucs-2.1.0}/tests/examples/test_sports_tournament_scheduling.py +0 -0
- {nucs-2.0.0 → nucs-2.1.0}/tests/examples/test_sudokus.py +0 -0
- {nucs-2.0.0 → nucs-2.1.0}/tests/problems/__init__.py +0 -0
- {nucs-2.0.0 → nucs-2.1.0}/tests/problems/test_problem.py +0 -0
- {nucs-2.0.0 → nucs-2.1.0}/tests/propagators/__init__.py +0 -0
- {nucs-2.0.0 → nucs-2.1.0}/tests/propagators/test_affine_eq.py +0 -0
- {nucs-2.0.0 → nucs-2.1.0}/tests/propagators/test_affine_geq.py +0 -0
- {nucs-2.0.0 → nucs-2.1.0}/tests/propagators/test_affine_leq.py +0 -0
- {nucs-2.0.0 → nucs-2.1.0}/tests/propagators/test_alldifferent.py +0 -0
- {nucs-2.0.0 → nucs-2.1.0}/tests/propagators/test_count_eq.py +0 -0
- {nucs-2.0.0 → nucs-2.1.0}/tests/propagators/test_element_lic.py +0 -0
- {nucs-2.0.0 → nucs-2.1.0}/tests/propagators/test_element_liv.py +0 -0
- {nucs-2.0.0 → nucs-2.1.0}/tests/propagators/test_exactly_eq.py +0 -0
- {nucs-2.0.0 → nucs-2.1.0}/tests/propagators/test_gcc.py +0 -0
- {nucs-2.0.0 → nucs-2.1.0}/tests/propagators/test_lexicographic_leq.py +0 -0
- {nucs-2.0.0 → nucs-2.1.0}/tests/propagators/test_max_eq.py +0 -0
- {nucs-2.0.0 → nucs-2.1.0}/tests/propagators/test_max_leq.py +0 -0
- {nucs-2.0.0 → nucs-2.1.0}/tests/propagators/test_min_eq.py +0 -0
- {nucs-2.0.0 → nucs-2.1.0}/tests/propagators/test_min_geq.py +0 -0
- {nucs-2.0.0 → nucs-2.1.0}/tests/propagators/test_relation.py +0 -0
- {nucs-2.0.0 → nucs-2.1.0}/tests/solvers/__init__.py +0 -0
- {nucs-2.0.0 → nucs-2.1.0}/tests/solvers/test_backtrack_solver.py +0 -0
- {nucs-2.0.0 → nucs-2.1.0}/tests/solvers/test_multiprocessing_solver.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: NUCS
|
|
3
|
-
Version: 2.
|
|
3
|
+
Version: 2.1.0
|
|
4
4
|
Summary: A Numpy and Numba based Python library for solving Constraint Satisfaction Problems over finite domains
|
|
5
5
|
Author-email: Yan Georget <yan.georget@gmail.com>
|
|
6
6
|
Project-URL: Homepage, https://github.com/yangeorget/nucs
|
|
@@ -35,8 +35,9 @@ Requires-Dist: numpy==2.0.1
|
|
|
35
35
|
|
|
36
36
|
## TLDR
|
|
37
37
|
NuCS is a Python library for solving Constraint Satisfaction and Optimization Problems.
|
|
38
|
-
Because it is 100% written in Python,
|
|
39
|
-
NuCS is
|
|
38
|
+
Because it is 100% written in Python,
|
|
39
|
+
NuCS is easy to install and allows to model complex problems in a few lines of code.
|
|
40
|
+
The NuCS solver is also very fast because it is powered by [Numpy](https://numpy.org/) and [Numba](https://numba.pydata.org/).
|
|
40
41
|
|
|
41
42
|
## Installation
|
|
42
43
|
```bash
|
|
@@ -74,9 +74,11 @@ nucs/propagators/relation_propagator.py
|
|
|
74
74
|
nucs/solvers/__init__.py
|
|
75
75
|
nucs/solvers/backtrack_solver.py
|
|
76
76
|
nucs/solvers/bound_consistency_algorithm.py
|
|
77
|
+
nucs/solvers/choice_points.py
|
|
77
78
|
nucs/solvers/consistency_algorithms.py
|
|
78
79
|
nucs/solvers/heuristics.py
|
|
79
80
|
nucs/solvers/multiprocessing_solver.py
|
|
81
|
+
nucs/solvers/shaving_consistency_algorithm.py
|
|
80
82
|
nucs/solvers/solver.py
|
|
81
83
|
tests/__init__.py
|
|
82
84
|
tests/examples/test_alpha.py
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: NUCS
|
|
3
|
-
Version: 2.
|
|
3
|
+
Version: 2.1.0
|
|
4
4
|
Summary: A Numpy and Numba based Python library for solving Constraint Satisfaction Problems over finite domains
|
|
5
5
|
Author-email: Yan Georget <yan.georget@gmail.com>
|
|
6
6
|
Project-URL: Homepage, https://github.com/yangeorget/nucs
|
|
@@ -35,8 +35,9 @@ Requires-Dist: numpy==2.0.1
|
|
|
35
35
|
|
|
36
36
|
## TLDR
|
|
37
37
|
NuCS is a Python library for solving Constraint Satisfaction and Optimization Problems.
|
|
38
|
-
Because it is 100% written in Python,
|
|
39
|
-
NuCS is
|
|
38
|
+
Because it is 100% written in Python,
|
|
39
|
+
NuCS is easy to install and allows to model complex problems in a few lines of code.
|
|
40
|
+
The NuCS solver is also very fast because it is powered by [Numpy](https://numpy.org/) and [Numba](https://numba.pydata.org/).
|
|
40
41
|
|
|
41
42
|
## Installation
|
|
42
43
|
```bash
|
|
@@ -13,8 +13,9 @@
|
|
|
13
13
|
|
|
14
14
|
## TLDR
|
|
15
15
|
NuCS is a Python library for solving Constraint Satisfaction and Optimization Problems.
|
|
16
|
-
Because it is 100% written in Python,
|
|
17
|
-
NuCS is
|
|
16
|
+
Because it is 100% written in Python,
|
|
17
|
+
NuCS is easy to install and allows to model complex problems in a few lines of code.
|
|
18
|
+
The NuCS solver is also very fast because it is powered by [Numpy](https://numpy.org/) and [Numba](https://numba.pydata.org/).
|
|
18
19
|
|
|
19
20
|
## Installation
|
|
20
21
|
```bash
|
|
@@ -42,8 +42,10 @@ SIGNATURE_CONSISTENCY_ALG = int64(
|
|
|
42
42
|
int32[:, :], # props_dom_offsets
|
|
43
43
|
int32[:], # props_parameters
|
|
44
44
|
bool[:, :, :], # shr_domains_propagators
|
|
45
|
-
int32[:, :], #
|
|
46
|
-
bool[:], #
|
|
45
|
+
int32[:, :, :], # shr_domains_stack
|
|
46
|
+
bool[:, :], # not_entailed_propagators_stack
|
|
47
|
+
uint16[:, :], # dom_update_stack
|
|
48
|
+
uint8[:], # stacks_height
|
|
47
49
|
bool[:], # triggered_propagators
|
|
48
50
|
int64[:], # compute_domains_addrs
|
|
49
51
|
)
|
|
@@ -18,7 +18,7 @@ from numpy.typing import NDArray
|
|
|
18
18
|
|
|
19
19
|
from nucs.constants import MAX, MIN
|
|
20
20
|
from nucs.problems.problem import Problem
|
|
21
|
-
from nucs.propagators.propagators import ALG_AFFINE_EQ, ALG_AFFINE_LEQ, ALG_ALLDIFFERENT
|
|
21
|
+
from nucs.propagators.propagators import ALG_AFFINE_EQ, ALG_AFFINE_LEQ, ALG_ALLDIFFERENT, add_propagators
|
|
22
22
|
from nucs.solvers.bound_consistency_algorithm import bound_consistency_algorithm
|
|
23
23
|
from nucs.solvers.heuristics import first_not_instantiated_var_heuristic
|
|
24
24
|
|
|
@@ -124,8 +124,10 @@ def golomb_consistency_algorithm(
|
|
|
124
124
|
props_dom_offsets: NDArray,
|
|
125
125
|
props_parameters: NDArray,
|
|
126
126
|
shr_domains_propagators: NDArray,
|
|
127
|
-
|
|
128
|
-
|
|
127
|
+
shr_domains_stack: NDArray,
|
|
128
|
+
not_entailed_propagators_stack: NDArray,
|
|
129
|
+
dom_update_stack: NDArray,
|
|
130
|
+
stacks_height: NDArray,
|
|
129
131
|
triggered_propagators: NDArray,
|
|
130
132
|
compute_domains_addrs: NDArray,
|
|
131
133
|
) -> int:
|
|
@@ -137,7 +139,7 @@ def golomb_consistency_algorithm(
|
|
|
137
139
|
"""
|
|
138
140
|
# first prune the search space
|
|
139
141
|
mark_nb = (1 + int(math.sqrt(8 * len(dom_indices_arr) + 1))) // 2
|
|
140
|
-
ni_var_idx = first_not_instantiated_var_heuristic(
|
|
142
|
+
ni_var_idx = first_not_instantiated_var_heuristic(shr_domains_stack[0]) # no domains shared between vars
|
|
141
143
|
if 1 < ni_var_idx < mark_nb - 1: # otherwise useless
|
|
142
144
|
used_distance = np.zeros(sum_first(mark_nb - 2) + 1, dtype=np.bool)
|
|
143
145
|
# a reusable array for storing the minimal sum of different integers:
|
|
@@ -146,7 +148,7 @@ def golomb_consistency_algorithm(
|
|
|
146
148
|
# the following will mark at most sum(n-3) numbers as used
|
|
147
149
|
# hence there will be at least n-2 unused numbers greater than 0
|
|
148
150
|
for var_idx in range(index(mark_nb, ni_var_idx - 2, ni_var_idx - 1) + 1):
|
|
149
|
-
dist =
|
|
151
|
+
dist = shr_domains_stack[0, dom_indices_arr[var_idx], MIN] # no offset
|
|
150
152
|
if dist < len(used_distance):
|
|
151
153
|
used_distance[dist] = True
|
|
152
154
|
# let's compute the sum of non-used numbers
|
|
@@ -158,7 +160,11 @@ def golomb_consistency_algorithm(
|
|
|
158
160
|
distance += 1
|
|
159
161
|
for i in range(ni_var_idx - 1, mark_nb - 1):
|
|
160
162
|
for j in range(i + 1, mark_nb):
|
|
161
|
-
|
|
163
|
+
dom_idx = dom_indices_arr[index(mark_nb, i, j)]
|
|
164
|
+
shr_domains_stack[0, dom_idx, MIN] = minimal_sum[j - i] # no offset
|
|
165
|
+
add_propagators(
|
|
166
|
+
triggered_propagators, not_entailed_propagators_stack[0], shr_domains_propagators, dom_idx, MIN
|
|
167
|
+
)
|
|
162
168
|
return bound_consistency_algorithm(
|
|
163
169
|
statistics,
|
|
164
170
|
algorithms,
|
|
@@ -170,8 +176,10 @@ def golomb_consistency_algorithm(
|
|
|
170
176
|
props_dom_offsets,
|
|
171
177
|
props_parameters,
|
|
172
178
|
shr_domains_propagators,
|
|
173
|
-
|
|
174
|
-
|
|
179
|
+
shr_domains_stack,
|
|
180
|
+
not_entailed_propagators_stack,
|
|
181
|
+
dom_update_stack,
|
|
182
|
+
stacks_height,
|
|
175
183
|
triggered_propagators,
|
|
176
184
|
compute_domains_addrs,
|
|
177
185
|
)
|
|
@@ -16,6 +16,7 @@ from rich import print
|
|
|
16
16
|
|
|
17
17
|
from nucs.examples.queens.queens_problem import QueensProblem
|
|
18
18
|
from nucs.solvers.backtrack_solver import BacktrackSolver
|
|
19
|
+
from nucs.solvers.consistency_algorithms import CONSISTENCY_ALG_BC, CONSISTENCY_ALG_SHAVING
|
|
19
20
|
from nucs.solvers.heuristics import VAR_HEURISTIC_FIRST_NOT_INSTANTIATED, VAR_HEURISTIC_SMALLEST_DOMAIN
|
|
20
21
|
from nucs.solvers.multiprocessing_solver import MultiprocessingSolver
|
|
21
22
|
from nucs.statistics import get_statistics
|
|
@@ -26,6 +27,7 @@ if __name__ == "__main__":
|
|
|
26
27
|
parser = argparse.ArgumentParser()
|
|
27
28
|
parser.add_argument("-n", type=int, default=10)
|
|
28
29
|
parser.add_argument("--processors", type=int, default=1)
|
|
30
|
+
parser.add_argument("--shaving", type=bool, action=argparse.BooleanOptionalAction, default=False)
|
|
29
31
|
parser.add_argument("--ff", type=bool, action=argparse.BooleanOptionalAction, default=False)
|
|
30
32
|
args = parser.parse_args()
|
|
31
33
|
problem = QueensProblem(args.n)
|
|
@@ -34,6 +36,7 @@ if __name__ == "__main__":
|
|
|
34
36
|
[
|
|
35
37
|
BacktrackSolver(
|
|
36
38
|
problem,
|
|
39
|
+
consistency_alg_idx=CONSISTENCY_ALG_SHAVING if args.shaving else CONSISTENCY_ALG_BC,
|
|
37
40
|
var_heuristic_idx=VAR_HEURISTIC_SMALLEST_DOMAIN if args.ff else VAR_HEURISTIC_FIRST_NOT_INSTANTIATED,
|
|
38
41
|
)
|
|
39
42
|
for problem in problems
|
|
@@ -124,16 +124,30 @@ ALG_RELATION = register_propagator(get_triggers_relation, get_complexity_relatio
|
|
|
124
124
|
|
|
125
125
|
|
|
126
126
|
@njit(cache=True)
|
|
127
|
-
def pop_propagator(triggered_propagators: NDArray,
|
|
127
|
+
def pop_propagator(triggered_propagators: NDArray, previous_prop_idx: int) -> int:
|
|
128
128
|
"""
|
|
129
129
|
Pops a propagator to be filtered.
|
|
130
130
|
:param triggered_propagators: the candidate propagators
|
|
131
|
-
:param not_entailed_propagators: the propagators that are not entailed yet
|
|
132
131
|
:param previous_prop_idx: the index of the previous propagator which has been selected
|
|
133
132
|
:return: an index
|
|
134
133
|
"""
|
|
135
|
-
for prop_idx
|
|
136
|
-
if
|
|
134
|
+
for prop_idx in range(len(triggered_propagators)):
|
|
135
|
+
if triggered_propagators[prop_idx] and prop_idx != previous_prop_idx:
|
|
137
136
|
triggered_propagators[prop_idx] = False
|
|
138
137
|
return prop_idx
|
|
139
138
|
return -1
|
|
139
|
+
|
|
140
|
+
|
|
141
|
+
@njit(cache=True)
|
|
142
|
+
def add_propagators(
|
|
143
|
+
triggered_propagators: NDArray,
|
|
144
|
+
not_entailed_propagators: NDArray,
|
|
145
|
+
shr_domains_propagators: NDArray,
|
|
146
|
+
dom_idx: int,
|
|
147
|
+
bound: int,
|
|
148
|
+
) -> None:
|
|
149
|
+
for prop_idx in range(len(triggered_propagators)):
|
|
150
|
+
if shr_domains_propagators[dom_idx, bound, prop_idx] and not_entailed_propagators[prop_idx]:
|
|
151
|
+
triggered_propagators[prop_idx] = True
|
|
152
|
+
# np.logical_or(triggered_propagators, shr_domains_propagators[dom_idx, bound], triggered_propagators)
|
|
153
|
+
# np.logical_and(triggered_propagators, not_entailed_propagators, triggered_propagators)
|
|
@@ -31,7 +31,8 @@ from nucs.constants import (
|
|
|
31
31
|
)
|
|
32
32
|
from nucs.numba_helper import build_function_address_list, function_from_address
|
|
33
33
|
from nucs.problems.problem import Problem
|
|
34
|
-
from nucs.propagators.propagators import COMPUTE_DOMAINS_FCTS
|
|
34
|
+
from nucs.propagators.propagators import COMPUTE_DOMAINS_FCTS, add_propagators
|
|
35
|
+
from nucs.solvers.choice_points import backtrack, cp_init, cp_put
|
|
35
36
|
from nucs.solvers.consistency_algorithms import CONSISTENCY_ALG_BC, CONSISTENCY_ALG_FCTS
|
|
36
37
|
from nucs.solvers.heuristics import (
|
|
37
38
|
DOM_HEURISTIC_FCTS,
|
|
@@ -44,7 +45,6 @@ from nucs.statistics import (
|
|
|
44
45
|
STATS_IDX_OPTIMIZER_SOLUTION_NB,
|
|
45
46
|
STATS_IDX_PROBLEM_PROPAGATOR_NB,
|
|
46
47
|
STATS_IDX_PROBLEM_VARIABLE_NB,
|
|
47
|
-
STATS_IDX_SOLVER_BACKTRACK_NB,
|
|
48
48
|
STATS_IDX_SOLVER_CHOICE_DEPTH,
|
|
49
49
|
STATS_IDX_SOLVER_CHOICE_NB,
|
|
50
50
|
STATS_IDX_SOLVER_SOLUTION_NB,
|
|
@@ -83,7 +83,7 @@ class BacktrackSolver(Solver):
|
|
|
83
83
|
):
|
|
84
84
|
"""
|
|
85
85
|
Inits the solver.
|
|
86
|
-
:param problem: the problem
|
|
86
|
+
:param problem: the problem to be solved
|
|
87
87
|
:param consistency_alg_idx: the index of the consistency algorithm
|
|
88
88
|
:param var_heuristic_idx: the index of the heuristic for selecting a variable/domain
|
|
89
89
|
:param dom_heuristic_idx: the index of the heuristic for reducing a domain
|
|
@@ -98,10 +98,16 @@ class BacktrackSolver(Solver):
|
|
|
98
98
|
self.problem = problem
|
|
99
99
|
# choice points
|
|
100
100
|
self.shr_domains_stack = np.empty((stack_max_height, self.problem.variable_nb, 2), dtype=np.int32)
|
|
101
|
-
self.shr_domains_stack[0] = problem.shr_domains_lst
|
|
102
101
|
self.not_entailed_propagators_stack = np.empty((stack_max_height, self.problem.propagator_nb), dtype=np.bool)
|
|
103
|
-
self.
|
|
102
|
+
self.dom_update_stack = np.empty((stack_max_height, 2), dtype=np.uint16)
|
|
104
103
|
self.stacks_height = np.ones((1,), dtype=np.uint8)
|
|
104
|
+
cp_init(
|
|
105
|
+
self.shr_domains_stack,
|
|
106
|
+
self.not_entailed_propagators_stack,
|
|
107
|
+
self.dom_update_stack,
|
|
108
|
+
self.stacks_height,
|
|
109
|
+
np.array(problem.shr_domains_lst),
|
|
110
|
+
)
|
|
105
111
|
# statistics
|
|
106
112
|
self.statistics = init_statistics()
|
|
107
113
|
self.statistics[STATS_IDX_PROBLEM_PROPAGATOR_NB] = self.problem.propagator_nb
|
|
@@ -148,6 +154,7 @@ class BacktrackSolver(Solver):
|
|
|
148
154
|
self.problem.shr_domains_propagators,
|
|
149
155
|
self.shr_domains_stack,
|
|
150
156
|
self.not_entailed_propagators_stack,
|
|
157
|
+
self.dom_update_stack,
|
|
151
158
|
self.stacks_height,
|
|
152
159
|
self.triggered_propagators,
|
|
153
160
|
self.consistency_alg_idx,
|
|
@@ -165,6 +172,7 @@ class BacktrackSolver(Solver):
|
|
|
165
172
|
self.problem,
|
|
166
173
|
self.shr_domains_stack,
|
|
167
174
|
self.not_entailed_propagators_stack,
|
|
175
|
+
self.dom_update_stack,
|
|
168
176
|
self.stacks_height,
|
|
169
177
|
self.triggered_propagators,
|
|
170
178
|
)
|
|
@@ -199,6 +207,7 @@ class BacktrackSolver(Solver):
|
|
|
199
207
|
self.problem.shr_domains_propagators,
|
|
200
208
|
self.shr_domains_stack,
|
|
201
209
|
self.not_entailed_propagators_stack,
|
|
210
|
+
self.dom_update_stack,
|
|
202
211
|
self.stacks_height,
|
|
203
212
|
self.triggered_propagators,
|
|
204
213
|
self.consistency_alg_idx,
|
|
@@ -216,8 +225,10 @@ class BacktrackSolver(Solver):
|
|
|
216
225
|
self.statistics,
|
|
217
226
|
self.shr_domains_stack,
|
|
218
227
|
self.not_entailed_propagators_stack,
|
|
228
|
+
self.dom_update_stack,
|
|
219
229
|
self.stacks_height,
|
|
220
230
|
self.triggered_propagators,
|
|
231
|
+
self.problem.shr_domains_propagators,
|
|
221
232
|
):
|
|
222
233
|
break
|
|
223
234
|
|
|
@@ -265,6 +276,7 @@ class BacktrackSolver(Solver):
|
|
|
265
276
|
self.problem.shr_domains_propagators,
|
|
266
277
|
self.shr_domains_stack,
|
|
267
278
|
self.not_entailed_propagators_stack,
|
|
279
|
+
self.dom_update_stack,
|
|
268
280
|
self.stacks_height,
|
|
269
281
|
self.triggered_propagators,
|
|
270
282
|
self.consistency_alg_idx,
|
|
@@ -283,6 +295,7 @@ class BacktrackSolver(Solver):
|
|
|
283
295
|
self.problem,
|
|
284
296
|
self.shr_domains_stack,
|
|
285
297
|
self.not_entailed_propagators_stack,
|
|
298
|
+
self.dom_update_stack,
|
|
286
299
|
self.stacks_height,
|
|
287
300
|
self.triggered_propagators,
|
|
288
301
|
)
|
|
@@ -318,6 +331,7 @@ class BacktrackSolver(Solver):
|
|
|
318
331
|
self.problem.shr_domains_propagators,
|
|
319
332
|
self.shr_domains_stack,
|
|
320
333
|
self.not_entailed_propagators_stack,
|
|
334
|
+
self.dom_update_stack,
|
|
321
335
|
self.stacks_height,
|
|
322
336
|
self.triggered_propagators,
|
|
323
337
|
self.consistency_alg_idx,
|
|
@@ -335,43 +349,20 @@ class BacktrackSolver(Solver):
|
|
|
335
349
|
self.statistics,
|
|
336
350
|
self.shr_domains_stack,
|
|
337
351
|
self.not_entailed_propagators_stack,
|
|
352
|
+
self.dom_update_stack,
|
|
338
353
|
self.stacks_height,
|
|
339
354
|
self.triggered_propagators,
|
|
355
|
+
self.problem.shr_domains_propagators,
|
|
340
356
|
):
|
|
341
357
|
break
|
|
342
358
|
solution_queue.put((processor_idx, None, self.statistics))
|
|
343
359
|
|
|
344
360
|
|
|
345
|
-
@njit(cache=True)
|
|
346
|
-
def backtrack(
|
|
347
|
-
statistics: NDArray,
|
|
348
|
-
shr_domains_stack: NDArray,
|
|
349
|
-
not_entailed_propagators_stack: NDArray,
|
|
350
|
-
stacks_height: NDArray,
|
|
351
|
-
triggered_propagators: NDArray,
|
|
352
|
-
) -> bool:
|
|
353
|
-
"""
|
|
354
|
-
Backtracks and updates the problem's domains.
|
|
355
|
-
:param statistics: the statistics array
|
|
356
|
-
:param shr_domains_stack: the stack of shared domains
|
|
357
|
-
:param not_entailed_propagators_stack: the stack of not entailed propagators
|
|
358
|
-
:param stacks_height: the height of both stacks
|
|
359
|
-
:return: true iff it is possible to backtrack
|
|
360
|
-
"""
|
|
361
|
-
if stacks_height[0] == 1:
|
|
362
|
-
return False
|
|
363
|
-
stacks_height[0] -= 1
|
|
364
|
-
shr_domains_stack[0, :, :] = shr_domains_stack[stacks_height[0], :, :]
|
|
365
|
-
not_entailed_propagators_stack[0, :] = not_entailed_propagators_stack[stacks_height[0], :]
|
|
366
|
-
statistics[STATS_IDX_SOLVER_BACKTRACK_NB] += 1
|
|
367
|
-
triggered_propagators[:] = not_entailed_propagators_stack[0, :] # numba does not support copyto
|
|
368
|
-
return True
|
|
369
|
-
|
|
370
|
-
|
|
371
361
|
def reset(
|
|
372
362
|
problem: Problem,
|
|
373
363
|
shr_domains_stack: NDArray,
|
|
374
364
|
not_entailed_propagators_stack: NDArray,
|
|
365
|
+
dom_update_stack: NDArray,
|
|
375
366
|
stacks_height: NDArray,
|
|
376
367
|
triggered_propagators: NDArray,
|
|
377
368
|
) -> None:
|
|
@@ -383,9 +374,13 @@ def reset(
|
|
|
383
374
|
:param stacks_height: the height of both stacks
|
|
384
375
|
:param triggered_propagators: the list of triggered propagators
|
|
385
376
|
"""
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
377
|
+
cp_init(
|
|
378
|
+
shr_domains_stack,
|
|
379
|
+
not_entailed_propagators_stack,
|
|
380
|
+
dom_update_stack,
|
|
381
|
+
stacks_height,
|
|
382
|
+
np.array(problem.shr_domains_lst),
|
|
383
|
+
)
|
|
389
384
|
triggered_propagators.fill(True)
|
|
390
385
|
|
|
391
386
|
|
|
@@ -403,6 +398,7 @@ def solve_one(
|
|
|
403
398
|
shr_domains_propagators: NDArray,
|
|
404
399
|
shr_domains_stack: NDArray,
|
|
405
400
|
not_entailed_propagators_stack: NDArray,
|
|
401
|
+
dom_update_stack: NDArray,
|
|
406
402
|
stacks_height: NDArray,
|
|
407
403
|
triggered_propagators: NDArray,
|
|
408
404
|
consistency_alg_idx: int,
|
|
@@ -462,8 +458,10 @@ def solve_one(
|
|
|
462
458
|
props_dom_offsets,
|
|
463
459
|
props_parameters,
|
|
464
460
|
shr_domains_propagators,
|
|
465
|
-
shr_domains_stack
|
|
466
|
-
not_entailed_propagators_stack
|
|
461
|
+
shr_domains_stack,
|
|
462
|
+
not_entailed_propagators_stack,
|
|
463
|
+
dom_update_stack,
|
|
464
|
+
stacks_height,
|
|
467
465
|
triggered_propagators,
|
|
468
466
|
compute_domains_addrs,
|
|
469
467
|
)
|
|
@@ -472,15 +470,27 @@ def solve_one(
|
|
|
472
470
|
return get_solution(shr_domains_stack[0], dom_indices_arr, dom_offsets_arr)
|
|
473
471
|
elif status == PROBLEM_UNBOUND:
|
|
474
472
|
dom_idx = var_heuristic_fct(shr_domains_stack[0])
|
|
475
|
-
shr_domains_stack
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
473
|
+
cp_put(shr_domains_stack, not_entailed_propagators_stack, dom_update_stack, stacks_height, dom_idx)
|
|
474
|
+
cp_idx = stacks_height[0] - 1
|
|
475
|
+
event = dom_heuristic_fct(shr_domains_stack[0, dom_idx], shr_domains_stack[cp_idx, dom_idx])
|
|
476
|
+
dom_update_stack[cp_idx, 1] = event
|
|
477
|
+
add_propagators(
|
|
478
|
+
triggered_propagators,
|
|
479
|
+
not_entailed_propagators_stack[0],
|
|
480
|
+
shr_domains_propagators,
|
|
481
|
+
dom_idx,
|
|
482
|
+
event,
|
|
483
|
+
)
|
|
480
484
|
statistics[STATS_IDX_SOLVER_CHOICE_NB] += 1
|
|
481
485
|
if stacks_height[0] - 1 > statistics[STATS_IDX_SOLVER_CHOICE_DEPTH]:
|
|
482
486
|
statistics[STATS_IDX_SOLVER_CHOICE_DEPTH] = stacks_height[0] - 1
|
|
483
487
|
elif not backtrack(
|
|
484
|
-
statistics,
|
|
488
|
+
statistics,
|
|
489
|
+
shr_domains_stack,
|
|
490
|
+
not_entailed_propagators_stack,
|
|
491
|
+
dom_update_stack,
|
|
492
|
+
stacks_height,
|
|
493
|
+
triggered_propagators,
|
|
494
|
+
shr_domains_propagators,
|
|
485
495
|
):
|
|
486
496
|
return None
|
|
@@ -28,7 +28,7 @@ from nucs.constants import (
|
|
|
28
28
|
TYPE_COMPUTE_DOMAINS,
|
|
29
29
|
)
|
|
30
30
|
from nucs.numba_helper import function_from_address
|
|
31
|
-
from nucs.propagators.propagators import COMPUTE_DOMAINS_FCTS, pop_propagator
|
|
31
|
+
from nucs.propagators.propagators import COMPUTE_DOMAINS_FCTS, add_propagators, pop_propagator
|
|
32
32
|
from nucs.solvers.solver import is_solved
|
|
33
33
|
from nucs.statistics import (
|
|
34
34
|
STATS_IDX_PROBLEM_FILTER_NB,
|
|
@@ -51,8 +51,10 @@ def bound_consistency_algorithm(
|
|
|
51
51
|
props_dom_offsets: NDArray,
|
|
52
52
|
props_parameters: NDArray,
|
|
53
53
|
shr_domains_propagators: NDArray,
|
|
54
|
-
|
|
55
|
-
|
|
54
|
+
shr_domains_stack: NDArray,
|
|
55
|
+
not_entailed_propagators_stack: NDArray,
|
|
56
|
+
dom_update_stack: NDArray,
|
|
57
|
+
stacks_height: NDArray,
|
|
56
58
|
triggered_propagators: NDArray,
|
|
57
59
|
compute_domains_addrs: NDArray,
|
|
58
60
|
) -> int:
|
|
@@ -70,8 +72,11 @@ def bound_consistency_algorithm(
|
|
|
70
72
|
:param shr_domains_propagators: a Numpy array of booleans indexed
|
|
71
73
|
by shared domain indices, MIN/MAX and propagators; true means that the propagator has to be triggered when the MIN
|
|
72
74
|
or MAX of the shared domain has changed
|
|
73
|
-
:param
|
|
74
|
-
|
|
75
|
+
:param shr_domains_stack: a stack of shared domains;
|
|
76
|
+
the first level correspond to the current shared domains, the rest correspond to the choice points
|
|
77
|
+
:param not_entailed_propagators_stack: a stack not entailed propagators;
|
|
78
|
+
the first level correspond to the propagators currently not entailed, the rest correspond to the choice points
|
|
79
|
+
:param stacks_height: the height of the stacks as a Numpy array
|
|
75
80
|
:param triggered_propagators: the Numpy array of triggered propagators
|
|
76
81
|
:param compute_domains_addrs: the addresses of the compute_domains functions
|
|
77
82
|
:return: a status (consistency, inconsistency or entailment) as an integer
|
|
@@ -79,9 +84,9 @@ def bound_consistency_algorithm(
|
|
|
79
84
|
statistics[STATS_IDX_PROBLEM_FILTER_NB] += 1
|
|
80
85
|
prop_idx = -1
|
|
81
86
|
while True:
|
|
82
|
-
prop_idx = pop_propagator(triggered_propagators,
|
|
87
|
+
prop_idx = pop_propagator(triggered_propagators, prop_idx)
|
|
83
88
|
if prop_idx == -1:
|
|
84
|
-
return PROBLEM_BOUND if is_solved(
|
|
89
|
+
return PROBLEM_BOUND if is_solved(shr_domains_stack[0]) else PROBLEM_UNBOUND
|
|
85
90
|
statistics[STATS_IDX_PROPAGATOR_FILTER_NB] += 1
|
|
86
91
|
prop_var_start = var_bounds[prop_idx, START]
|
|
87
92
|
prop_var_end = var_bounds[prop_idx, END]
|
|
@@ -89,7 +94,7 @@ def bound_consistency_algorithm(
|
|
|
89
94
|
prop_offsets = props_dom_offsets[prop_var_start:prop_var_end]
|
|
90
95
|
prop_var_nb = prop_var_end - prop_var_start
|
|
91
96
|
prop_domains = np.empty((prop_var_nb, 2), dtype=np.int32)
|
|
92
|
-
np.add(
|
|
97
|
+
np.add(shr_domains_stack[0, prop_indices], prop_offsets, prop_domains)
|
|
93
98
|
compute_domains_function = (
|
|
94
99
|
COMPUTE_DOMAINS_FCTS[algorithms[prop_idx]]
|
|
95
100
|
if NUMBA_DISABLE_JIT
|
|
@@ -102,19 +107,23 @@ def bound_consistency_algorithm(
|
|
|
102
107
|
statistics[STATS_IDX_PROPAGATOR_INCONSISTENCY_NB] += 1
|
|
103
108
|
return PROBLEM_INCONSISTENT
|
|
104
109
|
if status == PROP_ENTAILMENT:
|
|
105
|
-
|
|
110
|
+
not_entailed_propagators_stack[0, prop_idx] = False
|
|
106
111
|
statistics[STATS_IDX_PROPAGATOR_ENTAILMENT_NB] += 1
|
|
107
112
|
shr_domains_changes = False
|
|
108
113
|
for var_idx in range(prop_var_nb):
|
|
109
114
|
shr_domain_idx = prop_indices[var_idx]
|
|
110
|
-
prop_offset = prop_offsets[var_idx, 0]
|
|
115
|
+
prop_offset = prop_offsets[var_idx, 0] # because of vertical shape
|
|
111
116
|
for bound in [MIN, MAX]:
|
|
112
117
|
shr_domain_bound = prop_domains[var_idx, bound] - prop_offset
|
|
113
|
-
if
|
|
114
|
-
|
|
118
|
+
if shr_domains_stack[0, shr_domain_idx, bound] != shr_domain_bound:
|
|
119
|
+
shr_domains_stack[0, shr_domain_idx, bound] = shr_domain_bound
|
|
115
120
|
shr_domains_changes = True
|
|
116
|
-
|
|
117
|
-
triggered_propagators,
|
|
121
|
+
add_propagators(
|
|
122
|
+
triggered_propagators,
|
|
123
|
+
not_entailed_propagators_stack[0],
|
|
124
|
+
shr_domains_propagators,
|
|
125
|
+
shr_domain_idx,
|
|
126
|
+
bound,
|
|
118
127
|
)
|
|
119
128
|
if not shr_domains_changes:
|
|
120
129
|
statistics[STATS_IDX_PROPAGATOR_FILTER_NO_CHANGE_NB] += 1
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
from typing import Optional
|
|
2
|
+
|
|
3
|
+
from numba import njit # type: ignore
|
|
4
|
+
from numpy.typing import NDArray
|
|
5
|
+
|
|
6
|
+
from nucs.propagators.propagators import add_propagators
|
|
7
|
+
from nucs.statistics import STATS_IDX_SOLVER_BACKTRACK_NB
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
@njit(cache=True)
|
|
11
|
+
def cp_init(
|
|
12
|
+
shr_domains_stack: NDArray,
|
|
13
|
+
not_entailed_propagators_stack: NDArray,
|
|
14
|
+
dom_update_stack: NDArray,
|
|
15
|
+
stacks_height: NDArray,
|
|
16
|
+
shr_domains_arr: NDArray,
|
|
17
|
+
) -> None:
|
|
18
|
+
shr_domains_stack[0] = shr_domains_arr
|
|
19
|
+
not_entailed_propagators_stack[0] = True
|
|
20
|
+
dom_update_stack[0, :] = 0
|
|
21
|
+
stacks_height[0] = 1
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
@njit(cache=True)
|
|
25
|
+
def cp_put(
|
|
26
|
+
shr_domains_stack: NDArray,
|
|
27
|
+
not_entailed_propagators_stack: NDArray,
|
|
28
|
+
dom_update_stack: NDArray,
|
|
29
|
+
stacks_height: NDArray,
|
|
30
|
+
dom_index: int,
|
|
31
|
+
bound: Optional[int] = 0,
|
|
32
|
+
) -> None:
|
|
33
|
+
shr_domains_stack[stacks_height[0], :, :] = shr_domains_stack[0, :, :]
|
|
34
|
+
not_entailed_propagators_stack[stacks_height[0], :] = not_entailed_propagators_stack[0, :]
|
|
35
|
+
dom_update_stack[stacks_height[0], 0] = dom_index
|
|
36
|
+
dom_update_stack[stacks_height[0], 1] = bound
|
|
37
|
+
stacks_height[0] += 1
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
@njit(cache=True)
|
|
41
|
+
def cp_pop(
|
|
42
|
+
shr_domains_stack: NDArray,
|
|
43
|
+
not_entailed_propagators_stack: NDArray,
|
|
44
|
+
dom_update_stack: NDArray,
|
|
45
|
+
stacks_height: NDArray,
|
|
46
|
+
) -> bool:
|
|
47
|
+
if stacks_height[0] == 1:
|
|
48
|
+
return False
|
|
49
|
+
stacks_height[0] -= 1
|
|
50
|
+
shr_domains_stack[0, :, :] = shr_domains_stack[stacks_height[0], :, :]
|
|
51
|
+
not_entailed_propagators_stack[0, :] = not_entailed_propagators_stack[stacks_height[0], :]
|
|
52
|
+
dom_update_stack[0] = dom_update_stack[stacks_height[0]]
|
|
53
|
+
return True
|
|
54
|
+
|
|
55
|
+
|
|
56
|
+
@njit(cache=True)
|
|
57
|
+
def backtrack(
|
|
58
|
+
statistics: NDArray,
|
|
59
|
+
shr_domains_stack: NDArray,
|
|
60
|
+
not_entailed_propagators_stack: NDArray,
|
|
61
|
+
dom_update_stack: NDArray,
|
|
62
|
+
stacks_height: NDArray,
|
|
63
|
+
triggered_propagators: NDArray,
|
|
64
|
+
shr_domains_propagators: NDArray,
|
|
65
|
+
) -> bool:
|
|
66
|
+
"""
|
|
67
|
+
Backtracks and updates the problem's domains.
|
|
68
|
+
:param statistics: the statistics array
|
|
69
|
+
:param shr_domains_stack: the stack of shared domains
|
|
70
|
+
:param not_entailed_propagators_stack: the stack of not entailed propagators
|
|
71
|
+
:param stacks_height: the height of both stacks
|
|
72
|
+
:return: true iff it is possible to backtrack
|
|
73
|
+
"""
|
|
74
|
+
if not cp_pop(shr_domains_stack, not_entailed_propagators_stack, dom_update_stack, stacks_height):
|
|
75
|
+
return False
|
|
76
|
+
statistics[STATS_IDX_SOLVER_BACKTRACK_NB] += 1
|
|
77
|
+
add_propagators(
|
|
78
|
+
triggered_propagators,
|
|
79
|
+
not_entailed_propagators_stack[0],
|
|
80
|
+
shr_domains_propagators,
|
|
81
|
+
dom_update_stack[0, 0],
|
|
82
|
+
1 - dom_update_stack[0, 1],
|
|
83
|
+
)
|
|
84
|
+
return True
|
|
@@ -13,6 +13,7 @@
|
|
|
13
13
|
from typing import Callable
|
|
14
14
|
|
|
15
15
|
from nucs.solvers.bound_consistency_algorithm import bound_consistency_algorithm
|
|
16
|
+
from nucs.solvers.shaving_consistency_algorithm import shaving_consistency_algorithm
|
|
16
17
|
|
|
17
18
|
CONSISTENCY_ALG_FCTS = []
|
|
18
19
|
|
|
@@ -28,3 +29,4 @@ def register_consistency_algorithm(consistency_algorithm_fct: Callable) -> int:
|
|
|
28
29
|
|
|
29
30
|
|
|
30
31
|
CONSISTENCY_ALG_BC = register_consistency_algorithm(bound_consistency_algorithm)
|
|
32
|
+
CONSISTENCY_ALG_SHAVING = register_consistency_algorithm(shaving_consistency_algorithm)
|
|
@@ -26,8 +26,21 @@ def first_not_instantiated_var_heuristic(shr_domains: NDArray) -> int:
|
|
|
26
26
|
:param shr_domains: the shared domains of the problem
|
|
27
27
|
:return: the index of the shared domain
|
|
28
28
|
"""
|
|
29
|
-
for dom_idx
|
|
30
|
-
if
|
|
29
|
+
for dom_idx in range(len(shr_domains)):
|
|
30
|
+
if shr_domains[dom_idx, MIN] < shr_domains[dom_idx, MAX]:
|
|
31
|
+
return dom_idx
|
|
32
|
+
return -1 # cannot happen
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
@njit(cache=True)
|
|
36
|
+
def first_not_instantiated_var_heuristic_from_index(shr_domains: NDArray, start_idx: int) -> int:
|
|
37
|
+
"""
|
|
38
|
+
Chooses the first non-instantiated shared domain.
|
|
39
|
+
:param shr_domains: the shared domains of the problem
|
|
40
|
+
:return: the index of the shared domain
|
|
41
|
+
"""
|
|
42
|
+
for dom_idx in range(start_idx, len(shr_domains)):
|
|
43
|
+
if shr_domains[dom_idx, MIN] < shr_domains[dom_idx, MAX]:
|
|
31
44
|
return dom_idx
|
|
32
45
|
return -1 # cannot happen
|
|
33
46
|
|
|
@@ -40,8 +53,7 @@ def last_not_instantiated_var_heuristic(shr_domains: NDArray) -> int:
|
|
|
40
53
|
:return: the index of the shared domain
|
|
41
54
|
"""
|
|
42
55
|
for dom_idx in range(len(shr_domains) - 1, -1, -1):
|
|
43
|
-
|
|
44
|
-
if shr_domain[MIN] < shr_domain[MAX]:
|
|
56
|
+
if shr_domains[dom_idx, MIN] < shr_domains[dom_idx, MAX]:
|
|
45
57
|
return dom_idx
|
|
46
58
|
return -1 # cannot happen
|
|
47
59
|
|