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.
Files changed (47) hide show
  1. {nucs-0.1.2 → nucs-0.2.0/NUCS.egg-info}/PKG-INFO +39 -32
  2. {nucs-0.1.2/NUCS.egg-info → nucs-0.2.0}/PKG-INFO +39 -32
  3. {nucs-0.1.2 → nucs-0.2.0}/README.md +38 -31
  4. {nucs-0.1.2 → nucs-0.2.0}/nucs/heuristics/variable_heuristic.py +35 -0
  5. {nucs-0.1.2 → nucs-0.2.0}/nucs/memory.py +15 -11
  6. {nucs-0.1.2 → nucs-0.2.0}/nucs/problems/alpha_problem.py +5 -29
  7. {nucs-0.1.2 → nucs-0.2.0}/nucs/problems/bibd_problem.py +9 -19
  8. nucs-0.2.0/nucs/problems/golomb_problem.py +118 -0
  9. nucs-0.2.0/nucs/problems/problem.py +347 -0
  10. nucs-0.2.0/nucs/problems/queens_problem.py +20 -0
  11. {nucs-0.1.2 → nucs-0.2.0}/nucs/problems/schur_lemma_problem.py +5 -11
  12. {nucs-0.1.2 → nucs-0.2.0}/nucs/problems/sudoku_problem.py +5 -18
  13. nucs-0.2.0/nucs/propagators/affine_eq_propagator.py +53 -0
  14. nucs-0.2.0/nucs/propagators/affine_geq_propagator.py +44 -0
  15. nucs-0.2.0/nucs/propagators/affine_leq_propagator.py +44 -0
  16. {nucs-0.1.2 → nucs-0.2.0}/nucs/propagators/alldifferent_propagator.py +4 -6
  17. {nucs-0.1.2 → nucs-0.2.0}/nucs/propagators/count_eq_propagator.py +3 -10
  18. {nucs-0.1.2 → nucs-0.2.0}/nucs/propagators/dummy_propagator.py +2 -2
  19. {nucs-0.1.2 → nucs-0.2.0}/nucs/propagators/exactly_eq_propagator.py +3 -10
  20. {nucs-0.1.2 → nucs-0.2.0}/nucs/propagators/lexicographic_leq_propagator.py +3 -10
  21. {nucs-0.1.2 → nucs-0.2.0}/nucs/propagators/max_eq_propagator.py +2 -2
  22. {nucs-0.1.2 → nucs-0.2.0}/nucs/propagators/max_leq_propagator.py +3 -10
  23. {nucs-0.1.2 → nucs-0.2.0}/nucs/propagators/min_eq_propagator.py +2 -2
  24. {nucs-0.1.2 → nucs-0.2.0}/nucs/propagators/min_geq_propagator.py +3 -10
  25. nucs-0.2.0/nucs/propagators/propagators.py +128 -0
  26. {nucs-0.1.2 → nucs-0.2.0}/nucs/solvers/backtrack_solver.py +20 -14
  27. {nucs-0.1.2 → nucs-0.2.0}/nucs/statistics.py +20 -14
  28. {nucs-0.1.2 → nucs-0.2.0}/pyproject.toml +4 -1
  29. nucs-0.1.2/nucs/problems/golomb_problem.py +0 -77
  30. nucs-0.1.2/nucs/problems/problem.py +0 -271
  31. nucs-0.1.2/nucs/problems/queens_problem.py +0 -24
  32. nucs-0.1.2/nucs/propagators/affine_eq_propagator.py +0 -55
  33. nucs-0.1.2/nucs/propagators/affine_geq_propagator.py +0 -52
  34. nucs-0.1.2/nucs/propagators/affine_leq_propagator.py +0 -52
  35. nucs-0.1.2/nucs/propagators/propagators.py +0 -135
  36. {nucs-0.1.2 → nucs-0.2.0}/LICENSE.md +0 -0
  37. {nucs-0.1.2 → nucs-0.2.0}/NUCS.egg-info/SOURCES.txt +0 -0
  38. {nucs-0.1.2 → nucs-0.2.0}/NUCS.egg-info/dependency_links.txt +0 -0
  39. {nucs-0.1.2 → nucs-0.2.0}/NUCS.egg-info/requires.txt +0 -0
  40. {nucs-0.1.2 → nucs-0.2.0}/NUCS.egg-info/top_level.txt +0 -0
  41. {nucs-0.1.2 → nucs-0.2.0}/nucs/__init__.py +0 -0
  42. {nucs-0.1.2 → nucs-0.2.0}/nucs/heuristics/heuristic.py +0 -0
  43. {nucs-0.1.2 → nucs-0.2.0}/nucs/problems/__init__.py +0 -0
  44. {nucs-0.1.2 → nucs-0.2.0}/nucs/propagators/__init__.py +0 -0
  45. {nucs-0.1.2 → nucs-0.2.0}/nucs/solvers/__init__.py +0 -0
  46. {nucs-0.1.2 → nucs-0.2.0}/nucs/solvers/solver.py +0 -0
  47. {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.1.2
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
- 'PROBLEM_FILTERS_NB': 2797,
29
+ 'PROBLEM_FILTER_NB': 2797,
30
+ 'PROBLEM_PROPAGATOR_NB': 462,
31
+ 'PROBLEM_VARIABLE_NB': 504,
30
32
  'PROPAGATOR_ENTAILMENT_NB': 36977,
31
- 'PROPAGATOR_FILTERS_NB': 564122,
32
- 'PROPAGATOR_FILTERS_NO_CHANGE_NB': 534436,
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
- 'PROBLEM_FILTERS_NB': 49623,
45
- 'PROPAGATOR_ENTAILMENT_NB': 855996,
46
- 'PROPAGATOR_FILTERS_NB': 5160649,
47
- 'PROPAGATOR_FILTERS_NO_CHANGE_NB': 2893864,
48
- 'PROPAGATOR_INCONSISTENCY_NB': 24773,
49
- 'SOLVER_BACKTRACK_NB': 24772,
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': 24840,
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
- 'PROBLEM_FILTERS_NB': 262011,
63
+ 'PROBLEM_FILTER_NB': 262011,
64
+ 'PROBLEM_PROPAGATOR_NB': 3,
65
+ 'PROBLEM_VARIABLE_NB': 36,
60
66
  'PROPAGATOR_ENTAILMENT_NB': 0,
61
- 'PROPAGATOR_FILTERS_NB': 1910609,
62
- 'PROPAGATOR_FILTERS_NO_CHANGE_NB': 631079,
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
- refer to [the technical documentation](DOCUMENTATION.md) to better understand how NUCS works under the hood:
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
- shr_domains=[(0, n - 1)] * n, # these n domains are shared between 3n variables with different offsets
90
- dom_indices=list(range(n)) * 3, # for each variable, its domain
91
- dom_offsets=[0] * n + list(range(n)) + list(range(0, -n, -1)) # for each variable, its offset
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.set_propagators([
94
- (list(range(n)), ALG_ALLDIFFERENT, []),
95
- (list(range(n, 2 * n)), ALG_ALLDIFFERENT, []),
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.1.2
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
- 'PROBLEM_FILTERS_NB': 2797,
29
+ 'PROBLEM_FILTER_NB': 2797,
30
+ 'PROBLEM_PROPAGATOR_NB': 462,
31
+ 'PROBLEM_VARIABLE_NB': 504,
30
32
  'PROPAGATOR_ENTAILMENT_NB': 36977,
31
- 'PROPAGATOR_FILTERS_NB': 564122,
32
- 'PROPAGATOR_FILTERS_NO_CHANGE_NB': 534436,
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
- 'PROBLEM_FILTERS_NB': 49623,
45
- 'PROPAGATOR_ENTAILMENT_NB': 855996,
46
- 'PROPAGATOR_FILTERS_NB': 5160649,
47
- 'PROPAGATOR_FILTERS_NO_CHANGE_NB': 2893864,
48
- 'PROPAGATOR_INCONSISTENCY_NB': 24773,
49
- 'SOLVER_BACKTRACK_NB': 24772,
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': 24840,
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
- 'PROBLEM_FILTERS_NB': 262011,
63
+ 'PROBLEM_FILTER_NB': 262011,
64
+ 'PROBLEM_PROPAGATOR_NB': 3,
65
+ 'PROBLEM_VARIABLE_NB': 36,
60
66
  'PROPAGATOR_ENTAILMENT_NB': 0,
61
- 'PROPAGATOR_FILTERS_NB': 1910609,
62
- 'PROPAGATOR_FILTERS_NO_CHANGE_NB': 631079,
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
- refer to [the technical documentation](DOCUMENTATION.md) to better understand how NUCS works under the hood:
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
- shr_domains=[(0, n - 1)] * n, # these n domains are shared between 3n variables with different offsets
90
- dom_indices=list(range(n)) * 3, # for each variable, its domain
91
- dom_offsets=[0] * n + list(range(n)) + list(range(0, -n, -1)) # for each variable, its offset
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.set_propagators([
94
- (list(range(n)), ALG_ALLDIFFERENT, []),
95
- (list(range(n, 2 * n)), ALG_ALLDIFFERENT, []),
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
- 'PROBLEM_FILTERS_NB': 2797,
14
+ 'PROBLEM_FILTER_NB': 2797,
15
+ 'PROBLEM_PROPAGATOR_NB': 462,
16
+ 'PROBLEM_VARIABLE_NB': 504,
15
17
  'PROPAGATOR_ENTAILMENT_NB': 36977,
16
- 'PROPAGATOR_FILTERS_NB': 564122,
17
- 'PROPAGATOR_FILTERS_NO_CHANGE_NB': 534436,
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
- 'PROBLEM_FILTERS_NB': 49623,
30
- 'PROPAGATOR_ENTAILMENT_NB': 855996,
31
- 'PROPAGATOR_FILTERS_NB': 5160649,
32
- 'PROPAGATOR_FILTERS_NO_CHANGE_NB': 2893864,
33
- 'PROPAGATOR_INCONSISTENCY_NB': 24773,
34
- 'SOLVER_BACKTRACK_NB': 24772,
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': 24840,
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
- 'PROBLEM_FILTERS_NB': 262011,
48
+ 'PROBLEM_FILTER_NB': 262011,
49
+ 'PROBLEM_PROPAGATOR_NB': 3,
50
+ 'PROBLEM_VARIABLE_NB': 36,
45
51
  'PROPAGATOR_ENTAILMENT_NB': 0,
46
- 'PROPAGATOR_FILTERS_NB': 1910609,
47
- 'PROPAGATOR_FILTERS_NO_CHANGE_NB': 631079,
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
- refer to [the technical documentation](DOCUMENTATION.md) to better understand how NUCS works under the hood:
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
- shr_domains=[(0, n - 1)] * n, # these n domains are shared between 3n variables with different offsets
75
- dom_indices=list(range(n)) * 3, # for each variable, its domain
76
- dom_offsets=[0] * n + list(range(n)) + list(range(0, -n, -1)) # for each variable, its offset
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.set_propagators([
79
- (list(range(n)), ALG_ALLDIFFERENT, []),
80
- (list(range(n, 2 * n)), ALG_ALLDIFFERENT, []),
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 new_domains_by_values(domains: List[Union[int, Tuple[int, int]]]) -> NDArray:
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 new_indices_by_values(dom_indices: List[int]) -> NDArray:
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 new_indices(n: int) -> NDArray:
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 new_domain_offsets_by_values(dom_offsets: List[int]) -> NDArray:
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 new_offsets(n: int) -> NDArray:
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 new_domain_changes(n: int) -> NDArray:
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="F")
55
+ return np.ones((n, 2), dtype=bool, order="C")
56
56
  else:
57
- return np.zeros((n, 2), dtype=bool, order="F")
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 new_entailed_propagators(n: int) -> NDArray:
65
- return np.zeros(n, dtype=bool, order="C")
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 = 0
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__(shr_domains=[(1, 26)] * 26, dom_indices=list(range(26)), dom_offsets=[0] * 26)
51
- self.set_propagators(
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
- propagators.append((list(range(i * b, (i + 1) * b)), ALG_EXACTLY_EQ, [1, r]))
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
- propagators.append((list(range(j, v * b, b)), ALG_EXACTLY_EQ, [1, k]))
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
- propagators.append(
26
+ self.add_propagator(
36
27
  ([(i1 * b + j), (i2 * b + j), conj_idx], ALG_MIN_EQ, [])
37
- ) # TODO: replace by AND ?
28
+ ) # TODO:replace by AND ?
38
29
  conj_vars.append(conj_idx)
39
30
  conj_idx += 1
40
- propagators.append((conj_vars, ALG_EXACTLY_EQ, [1, l]))
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
- propagators.append((list(range(i * b, (i + 2) * b)), ALG_LEXICOGRAPHIC_LEQ, []))
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
- propagators.append((list(range(j, v * b, b)) + list(range(j + 1, v * b, b)), ALG_LEXICOGRAPHIC_LEQ, []))
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, []))