NUCS 0.1.2__tar.gz → 0.2.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-0.1.2 → nucs-0.2.0/NUCS.egg-info}/PKG-INFO +39 -32
- {nucs-0.1.2/NUCS.egg-info → nucs-0.2.0}/PKG-INFO +39 -32
- {nucs-0.1.2 → nucs-0.2.0}/README.md +38 -31
- {nucs-0.1.2 → nucs-0.2.0}/nucs/heuristics/variable_heuristic.py +35 -0
- {nucs-0.1.2 → nucs-0.2.0}/nucs/memory.py +15 -11
- {nucs-0.1.2 → nucs-0.2.0}/nucs/problems/alpha_problem.py +5 -29
- {nucs-0.1.2 → nucs-0.2.0}/nucs/problems/bibd_problem.py +9 -19
- nucs-0.2.0/nucs/problems/golomb_problem.py +118 -0
- nucs-0.2.0/nucs/problems/problem.py +347 -0
- nucs-0.2.0/nucs/problems/queens_problem.py +20 -0
- {nucs-0.1.2 → nucs-0.2.0}/nucs/problems/schur_lemma_problem.py +5 -11
- {nucs-0.1.2 → nucs-0.2.0}/nucs/problems/sudoku_problem.py +5 -18
- nucs-0.2.0/nucs/propagators/affine_eq_propagator.py +53 -0
- nucs-0.2.0/nucs/propagators/affine_geq_propagator.py +44 -0
- nucs-0.2.0/nucs/propagators/affine_leq_propagator.py +44 -0
- {nucs-0.1.2 → nucs-0.2.0}/nucs/propagators/alldifferent_propagator.py +4 -6
- {nucs-0.1.2 → nucs-0.2.0}/nucs/propagators/count_eq_propagator.py +3 -10
- {nucs-0.1.2 → nucs-0.2.0}/nucs/propagators/dummy_propagator.py +2 -2
- {nucs-0.1.2 → nucs-0.2.0}/nucs/propagators/exactly_eq_propagator.py +3 -10
- {nucs-0.1.2 → nucs-0.2.0}/nucs/propagators/lexicographic_leq_propagator.py +3 -10
- {nucs-0.1.2 → nucs-0.2.0}/nucs/propagators/max_eq_propagator.py +2 -2
- {nucs-0.1.2 → nucs-0.2.0}/nucs/propagators/max_leq_propagator.py +3 -10
- {nucs-0.1.2 → nucs-0.2.0}/nucs/propagators/min_eq_propagator.py +2 -2
- {nucs-0.1.2 → nucs-0.2.0}/nucs/propagators/min_geq_propagator.py +3 -10
- nucs-0.2.0/nucs/propagators/propagators.py +128 -0
- {nucs-0.1.2 → nucs-0.2.0}/nucs/solvers/backtrack_solver.py +20 -14
- {nucs-0.1.2 → nucs-0.2.0}/nucs/statistics.py +20 -14
- {nucs-0.1.2 → nucs-0.2.0}/pyproject.toml +4 -1
- nucs-0.1.2/nucs/problems/golomb_problem.py +0 -77
- nucs-0.1.2/nucs/problems/problem.py +0 -271
- nucs-0.1.2/nucs/problems/queens_problem.py +0 -24
- nucs-0.1.2/nucs/propagators/affine_eq_propagator.py +0 -55
- nucs-0.1.2/nucs/propagators/affine_geq_propagator.py +0 -52
- nucs-0.1.2/nucs/propagators/affine_leq_propagator.py +0 -52
- nucs-0.1.2/nucs/propagators/propagators.py +0 -135
- {nucs-0.1.2 → nucs-0.2.0}/LICENSE.md +0 -0
- {nucs-0.1.2 → nucs-0.2.0}/NUCS.egg-info/SOURCES.txt +0 -0
- {nucs-0.1.2 → nucs-0.2.0}/NUCS.egg-info/dependency_links.txt +0 -0
- {nucs-0.1.2 → nucs-0.2.0}/NUCS.egg-info/requires.txt +0 -0
- {nucs-0.1.2 → nucs-0.2.0}/NUCS.egg-info/top_level.txt +0 -0
- {nucs-0.1.2 → nucs-0.2.0}/nucs/__init__.py +0 -0
- {nucs-0.1.2 → nucs-0.2.0}/nucs/heuristics/heuristic.py +0 -0
- {nucs-0.1.2 → nucs-0.2.0}/nucs/problems/__init__.py +0 -0
- {nucs-0.1.2 → nucs-0.2.0}/nucs/propagators/__init__.py +0 -0
- {nucs-0.1.2 → nucs-0.2.0}/nucs/solvers/__init__.py +0 -0
- {nucs-0.1.2 → nucs-0.2.0}/nucs/solvers/solver.py +0 -0
- {nucs-0.1.2 → nucs-0.2.0}/setup.cfg +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: NUCS
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.2.0
|
|
4
4
|
Summary: A Numpy and Numba based Python library for solving Constraint Satifaction Problems
|
|
5
5
|
Author-email: Yan Georget <yan.georget@gmail.com>
|
|
6
6
|
Project-URL: Homepage, https://github.com/yangeorget/nucs
|
|
@@ -22,14 +22,16 @@ NUCS is also very fast because it is powered by [Numpy](https://numpy.org/) and
|
|
|
22
22
|
|
|
23
23
|
With NUCS, in a few seconds you can ...
|
|
24
24
|
|
|
25
|
-
Compute the 92 solutions to the BIBD(8,14,7,4,3) problem:
|
|
25
|
+
Compute the 92 solutions to the [BIBD(8,14,7,4,3) problem](https://www.csplib.org/Problems/prob028/):
|
|
26
26
|
```python
|
|
27
27
|
{
|
|
28
28
|
'OPTIMIZER_SOLUTION_NB': 0,
|
|
29
|
-
'
|
|
29
|
+
'PROBLEM_FILTER_NB': 2797,
|
|
30
|
+
'PROBLEM_PROPAGATOR_NB': 462,
|
|
31
|
+
'PROBLEM_VARIABLE_NB': 504,
|
|
30
32
|
'PROPAGATOR_ENTAILMENT_NB': 36977,
|
|
31
|
-
'
|
|
32
|
-
'
|
|
33
|
+
'PROPAGATOR_FILTER_NB': 564122,
|
|
34
|
+
'PROPAGATOR_FILTER_NO_CHANGE_NB': 534436,
|
|
33
35
|
'PROPAGATOR_INCONSISTENCY_NB': 1307,
|
|
34
36
|
'SOLVER_BACKTRACK_NB': 1398,
|
|
35
37
|
'SOLVER_CHOICE_DEPTH': 41,
|
|
@@ -37,29 +39,33 @@ Compute the 92 solutions to the BIBD(8,14,7,4,3) problem:
|
|
|
37
39
|
'SOLVER_SOLUTION_NB': 92
|
|
38
40
|
}
|
|
39
41
|
```
|
|
40
|
-
Demonstrate that the optimal 10-marks Golomb ruler length is 55:
|
|
42
|
+
Demonstrate that the optimal [10-marks Golomb ruler](https://www.csplib.org/Problems/prob006/) length is 55:
|
|
41
43
|
```python
|
|
42
44
|
{
|
|
43
45
|
'OPTIMIZER_SOLUTION_NB': 10,
|
|
44
|
-
'
|
|
45
|
-
'
|
|
46
|
-
'
|
|
47
|
-
'
|
|
48
|
-
'
|
|
49
|
-
'
|
|
46
|
+
'PROBLEM_FILTER_NB': 22204,
|
|
47
|
+
'PROBLEM_PROPAGATOR_NB': 82,
|
|
48
|
+
'PROBLEM_VARIABLE_NB': 45,
|
|
49
|
+
'PROPAGATOR_ENTAILMENT_NB': 416934,
|
|
50
|
+
'PROPAGATOR_FILTER_NB': 2145268,
|
|
51
|
+
'PROPAGATOR_FILTER_NO_CHANGE_NB': 1129818,
|
|
52
|
+
'PROPAGATOR_INCONSISTENCY_NB': 11065,
|
|
53
|
+
'SOLVER_BACKTRACK_NB': 11064,
|
|
50
54
|
'SOLVER_CHOICE_DEPTH': 9,
|
|
51
|
-
'SOLVER_CHOICE_NB':
|
|
55
|
+
'SOLVER_CHOICE_NB': 11129,
|
|
52
56
|
'SOLVER_SOLUTION_NB': 10
|
|
53
|
-
}
|
|
57
|
+
}
|
|
54
58
|
```
|
|
55
|
-
Find all 14200 solutions to the 12-queens problem:
|
|
59
|
+
Find all 14200 solutions to the [12-queens problem](https://www.csplib.org/Problems/prob054/):
|
|
56
60
|
```python
|
|
57
61
|
{
|
|
58
62
|
'OPTIMIZER_SOLUTION_NB': 0,
|
|
59
|
-
'
|
|
63
|
+
'PROBLEM_FILTER_NB': 262011,
|
|
64
|
+
'PROBLEM_PROPAGATOR_NB': 3,
|
|
65
|
+
'PROBLEM_VARIABLE_NB': 36,
|
|
60
66
|
'PROPAGATOR_ENTAILMENT_NB': 0,
|
|
61
|
-
'
|
|
62
|
-
'
|
|
67
|
+
'PROPAGATOR_FILTER_NB': 1910609,
|
|
68
|
+
'PROPAGATOR_FILTER_NO_CHANGE_NB': 631079,
|
|
63
69
|
'PROPAGATOR_INCONSISTENCY_NB': 116806,
|
|
64
70
|
'SOLVER_BACKTRACK_NB': 131005,
|
|
65
71
|
'SOLVER_CHOICE_DEPTH': 10,
|
|
@@ -77,8 +83,8 @@ Let's install the Pip package for NUCS:
|
|
|
77
83
|
```bash
|
|
78
84
|
pip install nucs
|
|
79
85
|
````
|
|
80
|
-
Now we can write the following `queens.py` program
|
|
81
|
-
|
|
86
|
+
Now we can write the following `queens.py` program (please refer to [the technical documentation](DOCUMENTATION.md)
|
|
87
|
+
to better understand how NUCS works under the hood):
|
|
82
88
|
```python
|
|
83
89
|
from nucs.problems.problem import Problem
|
|
84
90
|
from nucs.solvers.backtrack_solver import BacktrackSolver
|
|
@@ -86,20 +92,18 @@ from nucs.propagators.propagators import ALG_ALLDIFFERENT
|
|
|
86
92
|
|
|
87
93
|
n = 8 # the number of queens
|
|
88
94
|
problem = Problem(
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
95
|
+
[(0, n - 1)] * n, # these n domains are shared between 3n variables with different offsets
|
|
96
|
+
list(range(n)) * 3, # for each variable, its domain
|
|
97
|
+
[0] * n + list(range(n)) + list(range(0, -n, -1)) # for each variable, its offset
|
|
92
98
|
)
|
|
93
|
-
problem.
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
(list(range(2 * n, 3 * n)), ALG_ALLDIFFERENT, [])
|
|
97
|
-
])
|
|
99
|
+
problem.add_propagator((list(range(n)), ALG_ALLDIFFERENT, []))
|
|
100
|
+
problem.add_propagator((list(range(n, 2 * n)), ALG_ALLDIFFERENT, []))
|
|
101
|
+
problem.add_propagator((list(range(2 * n, 3 * n)), ALG_ALLDIFFERENT, []))
|
|
98
102
|
print(BacktrackSolver(problem).solve_one()[:n])
|
|
99
103
|
```
|
|
100
104
|
Let's run this model with the following command:
|
|
101
105
|
```bash
|
|
102
|
-
PYTHONPATH=. python queens.py
|
|
106
|
+
NUMBA_CACHE_DIR=.numba/cache PYTHONPATH=. python queens.py
|
|
103
107
|
```
|
|
104
108
|
The first solution found is:
|
|
105
109
|
```bash
|
|
@@ -130,11 +134,14 @@ NUMBA_CACHE_DIR=.numba/cache PYTHONPATH=. python tests/examples/test_golomb.py -
|
|
|
130
134
|
```
|
|
131
135
|
|
|
132
136
|
## Other constraint solvers in Python
|
|
133
|
-
### python-constraint
|
|
134
|
-
_The Python constraint module offers solvers for Constraint Solving Problems (CSPs) over finite domains in simple and pure Python._
|
|
135
|
-
|
|
136
137
|
### CCPMpy
|
|
137
138
|
_CPMpy is a Constraint Programming and Modeling library in Python, based on numpy, with direct solver access._
|
|
138
139
|
|
|
140
|
+
### Numberjack
|
|
141
|
+
_Numberjack is a modelling package written in Python for combinatorial optimisation._
|
|
142
|
+
|
|
143
|
+
### python-constraint
|
|
144
|
+
_The Python constraint module offers solvers for Constraint Solving Problems (CSPs) over finite domains in simple and pure Python._
|
|
145
|
+
|
|
139
146
|
### PyCSP
|
|
140
147
|
_PyCSP3 is a Python library for developping models of combinatorial constrained problems in a declarative manner; you can write models of constraint satisfaction (CSP) and constraint optimization (COP) problems._
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: NUCS
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.2.0
|
|
4
4
|
Summary: A Numpy and Numba based Python library for solving Constraint Satifaction Problems
|
|
5
5
|
Author-email: Yan Georget <yan.georget@gmail.com>
|
|
6
6
|
Project-URL: Homepage, https://github.com/yangeorget/nucs
|
|
@@ -22,14 +22,16 @@ NUCS is also very fast because it is powered by [Numpy](https://numpy.org/) and
|
|
|
22
22
|
|
|
23
23
|
With NUCS, in a few seconds you can ...
|
|
24
24
|
|
|
25
|
-
Compute the 92 solutions to the BIBD(8,14,7,4,3) problem:
|
|
25
|
+
Compute the 92 solutions to the [BIBD(8,14,7,4,3) problem](https://www.csplib.org/Problems/prob028/):
|
|
26
26
|
```python
|
|
27
27
|
{
|
|
28
28
|
'OPTIMIZER_SOLUTION_NB': 0,
|
|
29
|
-
'
|
|
29
|
+
'PROBLEM_FILTER_NB': 2797,
|
|
30
|
+
'PROBLEM_PROPAGATOR_NB': 462,
|
|
31
|
+
'PROBLEM_VARIABLE_NB': 504,
|
|
30
32
|
'PROPAGATOR_ENTAILMENT_NB': 36977,
|
|
31
|
-
'
|
|
32
|
-
'
|
|
33
|
+
'PROPAGATOR_FILTER_NB': 564122,
|
|
34
|
+
'PROPAGATOR_FILTER_NO_CHANGE_NB': 534436,
|
|
33
35
|
'PROPAGATOR_INCONSISTENCY_NB': 1307,
|
|
34
36
|
'SOLVER_BACKTRACK_NB': 1398,
|
|
35
37
|
'SOLVER_CHOICE_DEPTH': 41,
|
|
@@ -37,29 +39,33 @@ Compute the 92 solutions to the BIBD(8,14,7,4,3) problem:
|
|
|
37
39
|
'SOLVER_SOLUTION_NB': 92
|
|
38
40
|
}
|
|
39
41
|
```
|
|
40
|
-
Demonstrate that the optimal 10-marks Golomb ruler length is 55:
|
|
42
|
+
Demonstrate that the optimal [10-marks Golomb ruler](https://www.csplib.org/Problems/prob006/) length is 55:
|
|
41
43
|
```python
|
|
42
44
|
{
|
|
43
45
|
'OPTIMIZER_SOLUTION_NB': 10,
|
|
44
|
-
'
|
|
45
|
-
'
|
|
46
|
-
'
|
|
47
|
-
'
|
|
48
|
-
'
|
|
49
|
-
'
|
|
46
|
+
'PROBLEM_FILTER_NB': 22204,
|
|
47
|
+
'PROBLEM_PROPAGATOR_NB': 82,
|
|
48
|
+
'PROBLEM_VARIABLE_NB': 45,
|
|
49
|
+
'PROPAGATOR_ENTAILMENT_NB': 416934,
|
|
50
|
+
'PROPAGATOR_FILTER_NB': 2145268,
|
|
51
|
+
'PROPAGATOR_FILTER_NO_CHANGE_NB': 1129818,
|
|
52
|
+
'PROPAGATOR_INCONSISTENCY_NB': 11065,
|
|
53
|
+
'SOLVER_BACKTRACK_NB': 11064,
|
|
50
54
|
'SOLVER_CHOICE_DEPTH': 9,
|
|
51
|
-
'SOLVER_CHOICE_NB':
|
|
55
|
+
'SOLVER_CHOICE_NB': 11129,
|
|
52
56
|
'SOLVER_SOLUTION_NB': 10
|
|
53
|
-
}
|
|
57
|
+
}
|
|
54
58
|
```
|
|
55
|
-
Find all 14200 solutions to the 12-queens problem:
|
|
59
|
+
Find all 14200 solutions to the [12-queens problem](https://www.csplib.org/Problems/prob054/):
|
|
56
60
|
```python
|
|
57
61
|
{
|
|
58
62
|
'OPTIMIZER_SOLUTION_NB': 0,
|
|
59
|
-
'
|
|
63
|
+
'PROBLEM_FILTER_NB': 262011,
|
|
64
|
+
'PROBLEM_PROPAGATOR_NB': 3,
|
|
65
|
+
'PROBLEM_VARIABLE_NB': 36,
|
|
60
66
|
'PROPAGATOR_ENTAILMENT_NB': 0,
|
|
61
|
-
'
|
|
62
|
-
'
|
|
67
|
+
'PROPAGATOR_FILTER_NB': 1910609,
|
|
68
|
+
'PROPAGATOR_FILTER_NO_CHANGE_NB': 631079,
|
|
63
69
|
'PROPAGATOR_INCONSISTENCY_NB': 116806,
|
|
64
70
|
'SOLVER_BACKTRACK_NB': 131005,
|
|
65
71
|
'SOLVER_CHOICE_DEPTH': 10,
|
|
@@ -77,8 +83,8 @@ Let's install the Pip package for NUCS:
|
|
|
77
83
|
```bash
|
|
78
84
|
pip install nucs
|
|
79
85
|
````
|
|
80
|
-
Now we can write the following `queens.py` program
|
|
81
|
-
|
|
86
|
+
Now we can write the following `queens.py` program (please refer to [the technical documentation](DOCUMENTATION.md)
|
|
87
|
+
to better understand how NUCS works under the hood):
|
|
82
88
|
```python
|
|
83
89
|
from nucs.problems.problem import Problem
|
|
84
90
|
from nucs.solvers.backtrack_solver import BacktrackSolver
|
|
@@ -86,20 +92,18 @@ from nucs.propagators.propagators import ALG_ALLDIFFERENT
|
|
|
86
92
|
|
|
87
93
|
n = 8 # the number of queens
|
|
88
94
|
problem = Problem(
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
95
|
+
[(0, n - 1)] * n, # these n domains are shared between 3n variables with different offsets
|
|
96
|
+
list(range(n)) * 3, # for each variable, its domain
|
|
97
|
+
[0] * n + list(range(n)) + list(range(0, -n, -1)) # for each variable, its offset
|
|
92
98
|
)
|
|
93
|
-
problem.
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
(list(range(2 * n, 3 * n)), ALG_ALLDIFFERENT, [])
|
|
97
|
-
])
|
|
99
|
+
problem.add_propagator((list(range(n)), ALG_ALLDIFFERENT, []))
|
|
100
|
+
problem.add_propagator((list(range(n, 2 * n)), ALG_ALLDIFFERENT, []))
|
|
101
|
+
problem.add_propagator((list(range(2 * n, 3 * n)), ALG_ALLDIFFERENT, []))
|
|
98
102
|
print(BacktrackSolver(problem).solve_one()[:n])
|
|
99
103
|
```
|
|
100
104
|
Let's run this model with the following command:
|
|
101
105
|
```bash
|
|
102
|
-
PYTHONPATH=. python queens.py
|
|
106
|
+
NUMBA_CACHE_DIR=.numba/cache PYTHONPATH=. python queens.py
|
|
103
107
|
```
|
|
104
108
|
The first solution found is:
|
|
105
109
|
```bash
|
|
@@ -130,11 +134,14 @@ NUMBA_CACHE_DIR=.numba/cache PYTHONPATH=. python tests/examples/test_golomb.py -
|
|
|
130
134
|
```
|
|
131
135
|
|
|
132
136
|
## Other constraint solvers in Python
|
|
133
|
-
### python-constraint
|
|
134
|
-
_The Python constraint module offers solvers for Constraint Solving Problems (CSPs) over finite domains in simple and pure Python._
|
|
135
|
-
|
|
136
137
|
### CCPMpy
|
|
137
138
|
_CPMpy is a Constraint Programming and Modeling library in Python, based on numpy, with direct solver access._
|
|
138
139
|
|
|
140
|
+
### Numberjack
|
|
141
|
+
_Numberjack is a modelling package written in Python for combinatorial optimisation._
|
|
142
|
+
|
|
143
|
+
### python-constraint
|
|
144
|
+
_The Python constraint module offers solvers for Constraint Solving Problems (CSPs) over finite domains in simple and pure Python._
|
|
145
|
+
|
|
139
146
|
### PyCSP
|
|
140
147
|
_PyCSP3 is a Python library for developping models of combinatorial constrained problems in a declarative manner; you can write models of constraint satisfaction (CSP) and constraint optimization (COP) problems._
|
|
@@ -7,14 +7,16 @@ NUCS is also very fast because it is powered by [Numpy](https://numpy.org/) and
|
|
|
7
7
|
|
|
8
8
|
With NUCS, in a few seconds you can ...
|
|
9
9
|
|
|
10
|
-
Compute the 92 solutions to the BIBD(8,14,7,4,3) problem:
|
|
10
|
+
Compute the 92 solutions to the [BIBD(8,14,7,4,3) problem](https://www.csplib.org/Problems/prob028/):
|
|
11
11
|
```python
|
|
12
12
|
{
|
|
13
13
|
'OPTIMIZER_SOLUTION_NB': 0,
|
|
14
|
-
'
|
|
14
|
+
'PROBLEM_FILTER_NB': 2797,
|
|
15
|
+
'PROBLEM_PROPAGATOR_NB': 462,
|
|
16
|
+
'PROBLEM_VARIABLE_NB': 504,
|
|
15
17
|
'PROPAGATOR_ENTAILMENT_NB': 36977,
|
|
16
|
-
'
|
|
17
|
-
'
|
|
18
|
+
'PROPAGATOR_FILTER_NB': 564122,
|
|
19
|
+
'PROPAGATOR_FILTER_NO_CHANGE_NB': 534436,
|
|
18
20
|
'PROPAGATOR_INCONSISTENCY_NB': 1307,
|
|
19
21
|
'SOLVER_BACKTRACK_NB': 1398,
|
|
20
22
|
'SOLVER_CHOICE_DEPTH': 41,
|
|
@@ -22,29 +24,33 @@ Compute the 92 solutions to the BIBD(8,14,7,4,3) problem:
|
|
|
22
24
|
'SOLVER_SOLUTION_NB': 92
|
|
23
25
|
}
|
|
24
26
|
```
|
|
25
|
-
Demonstrate that the optimal 10-marks Golomb ruler length is 55:
|
|
27
|
+
Demonstrate that the optimal [10-marks Golomb ruler](https://www.csplib.org/Problems/prob006/) length is 55:
|
|
26
28
|
```python
|
|
27
29
|
{
|
|
28
30
|
'OPTIMIZER_SOLUTION_NB': 10,
|
|
29
|
-
'
|
|
30
|
-
'
|
|
31
|
-
'
|
|
32
|
-
'
|
|
33
|
-
'
|
|
34
|
-
'
|
|
31
|
+
'PROBLEM_FILTER_NB': 22204,
|
|
32
|
+
'PROBLEM_PROPAGATOR_NB': 82,
|
|
33
|
+
'PROBLEM_VARIABLE_NB': 45,
|
|
34
|
+
'PROPAGATOR_ENTAILMENT_NB': 416934,
|
|
35
|
+
'PROPAGATOR_FILTER_NB': 2145268,
|
|
36
|
+
'PROPAGATOR_FILTER_NO_CHANGE_NB': 1129818,
|
|
37
|
+
'PROPAGATOR_INCONSISTENCY_NB': 11065,
|
|
38
|
+
'SOLVER_BACKTRACK_NB': 11064,
|
|
35
39
|
'SOLVER_CHOICE_DEPTH': 9,
|
|
36
|
-
'SOLVER_CHOICE_NB':
|
|
40
|
+
'SOLVER_CHOICE_NB': 11129,
|
|
37
41
|
'SOLVER_SOLUTION_NB': 10
|
|
38
|
-
}
|
|
42
|
+
}
|
|
39
43
|
```
|
|
40
|
-
Find all 14200 solutions to the 12-queens problem:
|
|
44
|
+
Find all 14200 solutions to the [12-queens problem](https://www.csplib.org/Problems/prob054/):
|
|
41
45
|
```python
|
|
42
46
|
{
|
|
43
47
|
'OPTIMIZER_SOLUTION_NB': 0,
|
|
44
|
-
'
|
|
48
|
+
'PROBLEM_FILTER_NB': 262011,
|
|
49
|
+
'PROBLEM_PROPAGATOR_NB': 3,
|
|
50
|
+
'PROBLEM_VARIABLE_NB': 36,
|
|
45
51
|
'PROPAGATOR_ENTAILMENT_NB': 0,
|
|
46
|
-
'
|
|
47
|
-
'
|
|
52
|
+
'PROPAGATOR_FILTER_NB': 1910609,
|
|
53
|
+
'PROPAGATOR_FILTER_NO_CHANGE_NB': 631079,
|
|
48
54
|
'PROPAGATOR_INCONSISTENCY_NB': 116806,
|
|
49
55
|
'SOLVER_BACKTRACK_NB': 131005,
|
|
50
56
|
'SOLVER_CHOICE_DEPTH': 10,
|
|
@@ -62,8 +68,8 @@ Let's install the Pip package for NUCS:
|
|
|
62
68
|
```bash
|
|
63
69
|
pip install nucs
|
|
64
70
|
````
|
|
65
|
-
Now we can write the following `queens.py` program
|
|
66
|
-
|
|
71
|
+
Now we can write the following `queens.py` program (please refer to [the technical documentation](DOCUMENTATION.md)
|
|
72
|
+
to better understand how NUCS works under the hood):
|
|
67
73
|
```python
|
|
68
74
|
from nucs.problems.problem import Problem
|
|
69
75
|
from nucs.solvers.backtrack_solver import BacktrackSolver
|
|
@@ -71,20 +77,18 @@ from nucs.propagators.propagators import ALG_ALLDIFFERENT
|
|
|
71
77
|
|
|
72
78
|
n = 8 # the number of queens
|
|
73
79
|
problem = Problem(
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
80
|
+
[(0, n - 1)] * n, # these n domains are shared between 3n variables with different offsets
|
|
81
|
+
list(range(n)) * 3, # for each variable, its domain
|
|
82
|
+
[0] * n + list(range(n)) + list(range(0, -n, -1)) # for each variable, its offset
|
|
77
83
|
)
|
|
78
|
-
problem.
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
(list(range(2 * n, 3 * n)), ALG_ALLDIFFERENT, [])
|
|
82
|
-
])
|
|
84
|
+
problem.add_propagator((list(range(n)), ALG_ALLDIFFERENT, []))
|
|
85
|
+
problem.add_propagator((list(range(n, 2 * n)), ALG_ALLDIFFERENT, []))
|
|
86
|
+
problem.add_propagator((list(range(2 * n, 3 * n)), ALG_ALLDIFFERENT, []))
|
|
83
87
|
print(BacktrackSolver(problem).solve_one()[:n])
|
|
84
88
|
```
|
|
85
89
|
Let's run this model with the following command:
|
|
86
90
|
```bash
|
|
87
|
-
PYTHONPATH=. python queens.py
|
|
91
|
+
NUMBA_CACHE_DIR=.numba/cache PYTHONPATH=. python queens.py
|
|
88
92
|
```
|
|
89
93
|
The first solution found is:
|
|
90
94
|
```bash
|
|
@@ -115,11 +119,14 @@ NUMBA_CACHE_DIR=.numba/cache PYTHONPATH=. python tests/examples/test_golomb.py -
|
|
|
115
119
|
```
|
|
116
120
|
|
|
117
121
|
## Other constraint solvers in Python
|
|
118
|
-
### python-constraint
|
|
119
|
-
_The Python constraint module offers solvers for Constraint Solving Problems (CSPs) over finite domains in simple and pure Python._
|
|
120
|
-
|
|
121
122
|
### CCPMpy
|
|
122
123
|
_CPMpy is a Constraint Programming and Modeling library in Python, based on numpy, with direct solver access._
|
|
123
124
|
|
|
125
|
+
### Numberjack
|
|
126
|
+
_Numberjack is a modelling package written in Python for combinatorial optimisation._
|
|
127
|
+
|
|
128
|
+
### python-constraint
|
|
129
|
+
_The Python constraint module offers solvers for Constraint Solving Problems (CSPs) over finite domains in simple and pure Python._
|
|
130
|
+
|
|
124
131
|
### PyCSP
|
|
125
132
|
_PyCSP3 is a Python library for developping models of combinatorial constrained problems in a declarative manner; you can write models of constraint satisfaction (CSP) and constraint optimization (COP) problems._
|
|
@@ -63,6 +63,24 @@ def smallest_domain_var_heuristic(shr_domains: NDArray, dom_indices: NDArray) ->
|
|
|
63
63
|
return min_idx
|
|
64
64
|
|
|
65
65
|
|
|
66
|
+
@njit("int16(int32[::1, :], uint16[:])", cache=True)
|
|
67
|
+
def greatest_domain_var_heuristic(shr_domains: NDArray, dom_indices: NDArray) -> int:
|
|
68
|
+
"""
|
|
69
|
+
Chooses the variable with the greatest domain and which is not instantiated.
|
|
70
|
+
:param shr_domains: the shared domains of the problem
|
|
71
|
+
:param dom_indices: the domain indices of the problem variables
|
|
72
|
+
:return: the index of the variable
|
|
73
|
+
"""
|
|
74
|
+
max_size = 0
|
|
75
|
+
max_idx = -1
|
|
76
|
+
for var_idx, dom_index in enumerate(dom_indices):
|
|
77
|
+
size = shr_domains[dom_index, MAX] - shr_domains[dom_index, MIN] # actually this is size - 1
|
|
78
|
+
if max_size < size:
|
|
79
|
+
max_idx = var_idx
|
|
80
|
+
max_size = size
|
|
81
|
+
return max_idx
|
|
82
|
+
|
|
83
|
+
|
|
66
84
|
@njit("(int32[::1, :], boolean[::1, :], int32[::1, :], uint16)", cache=True)
|
|
67
85
|
def min_value_dom_heuristic(
|
|
68
86
|
shr_domains: NDArray, shr_domain_changes: NDArray, shr_domains_copy: NDArray, domain_idx: int
|
|
@@ -80,6 +98,23 @@ def min_value_dom_heuristic(
|
|
|
80
98
|
shr_domain_changes[domain_idx, MAX] = True
|
|
81
99
|
|
|
82
100
|
|
|
101
|
+
@njit("(int32[::1, :], boolean[::1, :], int32[::1, :], uint16)", cache=True)
|
|
102
|
+
def max_value_dom_heuristic(
|
|
103
|
+
shr_domains: NDArray, shr_domain_changes: NDArray, shr_domains_copy: NDArray, domain_idx: int
|
|
104
|
+
) -> None:
|
|
105
|
+
"""
|
|
106
|
+
Chooses the last value of the domain
|
|
107
|
+
:param shr_domains: the shared domains of the problem
|
|
108
|
+
:param: shr_domain_changes: the changes to the shared domains
|
|
109
|
+
:param: shr_domains_copy: the shared domains to be added to the choice point
|
|
110
|
+
:param domain_idx: the index of the domain
|
|
111
|
+
"""
|
|
112
|
+
value = shr_domains[domain_idx, MAX]
|
|
113
|
+
shr_domains_copy[domain_idx, MAX] = value - 1
|
|
114
|
+
shr_domains[domain_idx, MIN] = value
|
|
115
|
+
shr_domain_changes[domain_idx, MIN] = True
|
|
116
|
+
|
|
117
|
+
|
|
83
118
|
@njit("(int32[::1, :], boolean[::1, :], int32[::1, :], uint16)", cache=True)
|
|
84
119
|
def split_low_dom_heuristic(
|
|
85
120
|
shr_domains: NDArray, shr_domain_changes: NDArray, shr_domains_copy: NDArray, domain_idx: int
|
|
@@ -14,7 +14,7 @@ PROP_CONSISTENCY = 1
|
|
|
14
14
|
PROP_ENTAILMENT = 2
|
|
15
15
|
|
|
16
16
|
|
|
17
|
-
def
|
|
17
|
+
def new_shr_domains_by_values(domains: List[Union[int, Tuple[int, int]]]) -> NDArray:
|
|
18
18
|
return np.array(
|
|
19
19
|
[(domain, domain) if isinstance(domain, int) else domain for domain in domains],
|
|
20
20
|
dtype=np.int32,
|
|
@@ -22,19 +22,19 @@ def new_domains_by_values(domains: List[Union[int, Tuple[int, int]]]) -> NDArray
|
|
|
22
22
|
)
|
|
23
23
|
|
|
24
24
|
|
|
25
|
-
def
|
|
25
|
+
def new_dom_indices_by_values(dom_indices: List[int]) -> NDArray:
|
|
26
26
|
return np.array(dom_indices, dtype=np.uint16, order="C")
|
|
27
27
|
|
|
28
28
|
|
|
29
|
-
def
|
|
29
|
+
def new_dom_indices(n: int) -> NDArray:
|
|
30
30
|
return np.empty(n, dtype=np.uint16, order="C")
|
|
31
31
|
|
|
32
32
|
|
|
33
|
-
def
|
|
33
|
+
def new_dom_offsets_by_values(dom_offsets: List[int]) -> NDArray:
|
|
34
34
|
return np.array(dom_offsets, dtype=np.int32, order="C")
|
|
35
35
|
|
|
36
36
|
|
|
37
|
-
def
|
|
37
|
+
def new_dom_offsets(n: int) -> NDArray:
|
|
38
38
|
return np.empty(n, dtype=np.int32, order="C")
|
|
39
39
|
|
|
40
40
|
|
|
@@ -46,23 +46,23 @@ def new_data(n: int) -> NDArray:
|
|
|
46
46
|
return np.empty(n, dtype=np.int32, order="C")
|
|
47
47
|
|
|
48
48
|
|
|
49
|
-
def
|
|
49
|
+
def new_shr_domain_changes(n: int) -> NDArray:
|
|
50
50
|
return np.ones((n, 2), dtype=bool, order="F")
|
|
51
51
|
|
|
52
52
|
|
|
53
53
|
def new_triggers(n: int, init_value: bool) -> NDArray:
|
|
54
54
|
if init_value:
|
|
55
|
-
return np.ones((n, 2), dtype=bool, order="
|
|
55
|
+
return np.ones((n, 2), dtype=bool, order="C")
|
|
56
56
|
else:
|
|
57
|
-
return np.zeros((n, 2), dtype=bool, order="
|
|
57
|
+
return np.zeros((n, 2), dtype=bool, order="C")
|
|
58
58
|
|
|
59
59
|
|
|
60
60
|
def new_triggered_propagators(n: int) -> NDArray:
|
|
61
61
|
return np.empty(n, dtype=bool, order="C")
|
|
62
62
|
|
|
63
63
|
|
|
64
|
-
def
|
|
65
|
-
return np.
|
|
64
|
+
def new_not_entailed_propagators(n: int) -> NDArray:
|
|
65
|
+
return np.ones(n, dtype=bool, order="C")
|
|
66
66
|
|
|
67
67
|
|
|
68
68
|
def new_algorithms(n: int) -> NDArray:
|
|
@@ -70,4 +70,8 @@ def new_algorithms(n: int) -> NDArray:
|
|
|
70
70
|
|
|
71
71
|
|
|
72
72
|
def new_bounds(n: int) -> NDArray:
|
|
73
|
-
return np.empty((n, 2), dtype=np.uint16)
|
|
73
|
+
return np.empty((n, 2), dtype=np.uint16, order="C")
|
|
74
|
+
|
|
75
|
+
|
|
76
|
+
def new_shr_domains_propagators(n: int, m: int) -> NDArray:
|
|
77
|
+
return np.zeros((n, 2, m), dtype=bool, order="C")
|
|
@@ -3,37 +3,11 @@ from typing import List
|
|
|
3
3
|
from nucs.problems.problem import Problem
|
|
4
4
|
from nucs.propagators.propagators import ALG_AFFINE_EQ, ALG_ALLDIFFERENT
|
|
5
5
|
|
|
6
|
-
A =
|
|
7
|
-
B = 1
|
|
8
|
-
C = 2
|
|
9
|
-
D = 3
|
|
10
|
-
E = 4
|
|
11
|
-
F = 5
|
|
12
|
-
G = 6
|
|
13
|
-
H = 7
|
|
14
|
-
I = 8
|
|
15
|
-
J = 9
|
|
16
|
-
K = 10
|
|
17
|
-
L = 11
|
|
18
|
-
M = 12
|
|
19
|
-
N = 13
|
|
20
|
-
O = 14
|
|
21
|
-
P = 15
|
|
22
|
-
Q = 16
|
|
23
|
-
R = 17
|
|
24
|
-
S = 18
|
|
25
|
-
T = 19
|
|
26
|
-
U = 20
|
|
27
|
-
V = 21
|
|
28
|
-
W = 22
|
|
29
|
-
X = 23
|
|
30
|
-
Y = 24
|
|
31
|
-
Z = 25
|
|
6
|
+
A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q, R, S, T, U, V, W, X, Y, Z = tuple(range(26))
|
|
32
7
|
|
|
33
8
|
|
|
34
9
|
class AlphaProblem(Problem):
|
|
35
10
|
"""
|
|
36
|
-
This problem comes from the newsgroup rec.puzzle.
|
|
37
11
|
The numbers from 1 to 26 are assigned to the letters of the alphabet.
|
|
38
12
|
The numbers beside each word are the total of the values assigned to the letters in the word
|
|
39
13
|
(e.g for LYRE: L,Y,R,E might be to equal 5,9,20 and 13 or any other combination that add up to 47).
|
|
@@ -44,11 +18,13 @@ class AlphaProblem(Problem):
|
|
|
44
18
|
CONCERT 74 LYRE 47 SAXOPHONE 134 THEME 72
|
|
45
19
|
FLUTE 30 OBOE 53 SCALE 51 VIOLIN 100
|
|
46
20
|
FUGUE 50 OPERA 65 SOLO 37 WALTZ 34
|
|
21
|
+
|
|
22
|
+
This problem comes from the newsgroup rec.puzzle.
|
|
47
23
|
"""
|
|
48
24
|
|
|
49
25
|
def __init__(self) -> None:
|
|
50
|
-
super().__init__(
|
|
51
|
-
self.
|
|
26
|
+
super().__init__([(1, 26)] * 26)
|
|
27
|
+
self.add_propagators(
|
|
52
28
|
[
|
|
53
29
|
([A, B, E, T, L], ALG_AFFINE_EQ, [1, 1, 1, 1, 2, 45]),
|
|
54
30
|
([C, E, O, L], ALG_AFFINE_EQ, [1, 1, 1, 2, 43]),
|
|
@@ -1,9 +1,5 @@
|
|
|
1
1
|
from nucs.problems.problem import Problem
|
|
2
|
-
from nucs.propagators.propagators import
|
|
3
|
-
ALG_EXACTLY_EQ,
|
|
4
|
-
ALG_LEXICOGRAPHIC_LEQ,
|
|
5
|
-
ALG_MIN_EQ,
|
|
6
|
-
)
|
|
2
|
+
from nucs.propagators.propagators import ALG_EXACTLY_EQ, ALG_LEXICOGRAPHIC_LEQ, ALG_MIN_EQ
|
|
7
3
|
|
|
8
4
|
|
|
9
5
|
class BIBDProblem(Problem):
|
|
@@ -14,35 +10,29 @@ class BIBDProblem(Problem):
|
|
|
14
10
|
def __init__(self, v: int, b: int, r: int, k: int, l: int):
|
|
15
11
|
s = (v * (v - 1)) // 2
|
|
16
12
|
n = (v + s) * b
|
|
17
|
-
super().__init__(
|
|
18
|
-
shr_domains=[(0, 1)] * n,
|
|
19
|
-
dom_indices=list(range(n)),
|
|
20
|
-
dom_offsets=[0] * n,
|
|
21
|
-
)
|
|
22
|
-
propagators = []
|
|
13
|
+
super().__init__([(0, 1)] * n)
|
|
23
14
|
# rows: counts
|
|
24
15
|
for i in range(0, v):
|
|
25
|
-
|
|
16
|
+
self.add_propagator((list(range(i * b, (i + 1) * b)), ALG_EXACTLY_EQ, [1, r]))
|
|
26
17
|
# columns: counts
|
|
27
18
|
for j in range(0, b):
|
|
28
|
-
|
|
19
|
+
self.add_propagator((list(range(j, v * b, b)), ALG_EXACTLY_EQ, [1, k]))
|
|
29
20
|
# scalar products: conjunctions and counts
|
|
30
21
|
conj_idx = v * b
|
|
31
22
|
for i1 in range(0, v - 1):
|
|
32
23
|
for i2 in range(i1 + 1, v):
|
|
33
24
|
conj_vars = []
|
|
34
25
|
for j in range(0, b):
|
|
35
|
-
|
|
26
|
+
self.add_propagator(
|
|
36
27
|
([(i1 * b + j), (i2 * b + j), conj_idx], ALG_MIN_EQ, [])
|
|
37
|
-
) # TODO:
|
|
28
|
+
) # TODO:replace by AND ?
|
|
38
29
|
conj_vars.append(conj_idx)
|
|
39
30
|
conj_idx += 1
|
|
40
|
-
|
|
31
|
+
self.add_propagator((conj_vars, ALG_EXACTLY_EQ, [1, l]))
|
|
41
32
|
# remove symmetries
|
|
42
33
|
# lexleq on rows
|
|
43
34
|
for i in range(0, v - 1):
|
|
44
|
-
|
|
35
|
+
self.add_propagator((list(range(i * b, (i + 2) * b)), ALG_LEXICOGRAPHIC_LEQ, []))
|
|
45
36
|
# lexleq on columns
|
|
46
37
|
for j in range(0, b - 1):
|
|
47
|
-
|
|
48
|
-
self.set_propagators(propagators)
|
|
38
|
+
self.add_propagator((list(range(j, v * b, b)) + list(range(j + 1, v * b, b)), ALG_LEXICOGRAPHIC_LEQ, []))
|