NUCS 4.4__tar.gz → 4.4.4__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 (155) hide show
  1. {nucs-4.4 → nucs-4.4.4/NuCS.egg-info}/PKG-INFO +9 -4
  2. {nucs-4.4/NUCS.egg-info → nucs-4.4.4/NuCS.egg-info}/SOURCES.txt +5 -5
  3. nucs-4.4.4/NuCS.egg-info/requires.txt +3 -0
  4. {nucs-4.4/NUCS.egg-info → nucs-4.4.4}/PKG-INFO +9 -4
  5. {nucs-4.4 → nucs-4.4.4}/docs/source/conf.py +3 -3
  6. {nucs-4.4 → nucs-4.4.4}/nucs/examples/quasigroup/__main__.py +10 -4
  7. nucs-4.4.4/nucs/examples/quasigroup/quasigroup_problem.py +116 -0
  8. {nucs-4.4 → nucs-4.4.4}/nucs/propagators/element_iv_propagator.py +8 -9
  9. {nucs-4.4 → nucs-4.4.4}/nucs/propagators/element_lic_propagator.py +9 -10
  10. {nucs-4.4 → nucs-4.4.4}/nucs/propagators/element_liv_propagator.py +8 -9
  11. {nucs-4.4 → nucs-4.4.4}/pyproject.toml +9 -4
  12. {nucs-4.4 → nucs-4.4.4}/tests/examples/test_bibd.py +8 -15
  13. nucs-4.4.4/tests/examples/test_quasigroup.py +62 -0
  14. {nucs-4.4 → nucs-4.4.4}/tests/examples/test_sudokus.py +13 -12
  15. {nucs-4.4 → nucs-4.4.4}/tests/propagators/test_element_liv.py +1 -0
  16. nucs-4.4/NUCS.egg-info/requires.txt +0 -2
  17. nucs-4.4/nucs/examples/quasigroup/quasigroup_problem.py +0 -63
  18. nucs-4.4/tests/examples/test_quasigroup.py +0 -39
  19. {nucs-4.4 → nucs-4.4.4}/LICENSE.md +0 -0
  20. {nucs-4.4/NUCS.egg-info → nucs-4.4.4/NuCS.egg-info}/dependency_links.txt +0 -0
  21. {nucs-4.4/NUCS.egg-info → nucs-4.4.4/NuCS.egg-info}/top_level.txt +0 -0
  22. {nucs-4.4 → nucs-4.4.4}/README.md +0 -0
  23. {nucs-4.4 → nucs-4.4.4}/nucs/__init__.py +0 -0
  24. {nucs-4.4 → nucs-4.4.4}/nucs/constants.py +0 -0
  25. {nucs-4.4 → nucs-4.4.4}/nucs/examples/__init__.py +0 -0
  26. {nucs-4.4 → nucs-4.4.4}/nucs/examples/alpha/__init__.py +0 -0
  27. {nucs-4.4 → nucs-4.4.4}/nucs/examples/alpha/__main__.py +0 -0
  28. {nucs-4.4 → nucs-4.4.4}/nucs/examples/alpha/alpha_problem.py +0 -0
  29. {nucs-4.4 → nucs-4.4.4}/nucs/examples/bibd/__init__.py +0 -0
  30. {nucs-4.4 → nucs-4.4.4}/nucs/examples/bibd/__main__.py +0 -0
  31. {nucs-4.4 → nucs-4.4.4}/nucs/examples/bibd/bibd_problem.py +0 -0
  32. {nucs-4.4 → nucs-4.4.4}/nucs/examples/donald/__init__.py +0 -0
  33. {nucs-4.4 → nucs-4.4.4}/nucs/examples/donald/__main__.py +0 -0
  34. {nucs-4.4 → nucs-4.4.4}/nucs/examples/donald/donald_problem.py +0 -0
  35. {nucs-4.4 → nucs-4.4.4}/nucs/examples/golomb/__init__.py +0 -0
  36. {nucs-4.4 → nucs-4.4.4}/nucs/examples/golomb/__main__.py +0 -0
  37. {nucs-4.4 → nucs-4.4.4}/nucs/examples/golomb/golomb_problem.py +0 -0
  38. {nucs-4.4 → nucs-4.4.4}/nucs/examples/knapsack/__init__.py +0 -0
  39. {nucs-4.4 → nucs-4.4.4}/nucs/examples/knapsack/__main__.py +0 -0
  40. {nucs-4.4 → nucs-4.4.4}/nucs/examples/knapsack/knapsack_problem.py +0 -0
  41. {nucs-4.4 → nucs-4.4.4}/nucs/examples/magic_sequence/__init__.py +0 -0
  42. {nucs-4.4 → nucs-4.4.4}/nucs/examples/magic_sequence/__main__.py +0 -0
  43. {nucs-4.4 → nucs-4.4.4}/nucs/examples/magic_sequence/magic_sequence_problem.py +0 -0
  44. {nucs-4.4 → nucs-4.4.4}/nucs/examples/magic_square/__init__.py +0 -0
  45. {nucs-4.4 → nucs-4.4.4}/nucs/examples/magic_square/__main__.py +0 -0
  46. {nucs-4.4 → nucs-4.4.4}/nucs/examples/magic_square/magic_square_problem.py +0 -0
  47. {nucs-4.4 → nucs-4.4.4}/nucs/examples/quasigroup/__init__.py +0 -0
  48. {nucs-4.4 → nucs-4.4.4}/nucs/examples/queens/__init__.py +0 -0
  49. {nucs-4.4 → nucs-4.4.4}/nucs/examples/queens/__main__.py +0 -0
  50. {nucs-4.4 → nucs-4.4.4}/nucs/examples/queens/queens_problem.py +0 -0
  51. {nucs-4.4 → nucs-4.4.4}/nucs/examples/schur_lemma/__init__.py +0 -0
  52. {nucs-4.4 → nucs-4.4.4}/nucs/examples/schur_lemma/__main__.py +0 -0
  53. {nucs-4.4 → nucs-4.4.4}/nucs/examples/schur_lemma/schur_lemma_problem.py +0 -0
  54. {nucs-4.4 → nucs-4.4.4}/nucs/examples/sports_tournament_scheduling/__init__.py +0 -0
  55. {nucs-4.4 → nucs-4.4.4}/nucs/examples/sports_tournament_scheduling/__main__.py +0 -0
  56. {nucs-4.4 → nucs-4.4.4}/nucs/examples/sports_tournament_scheduling/sports_tournament_scheduling_problem.py +0 -0
  57. {nucs-4.4 → nucs-4.4.4}/nucs/examples/sudoku/__init__.py +0 -0
  58. {nucs-4.4 → nucs-4.4.4}/nucs/examples/sudoku/sudoku_problem.py +0 -0
  59. {nucs-4.4 → nucs-4.4.4}/nucs/examples/tsp/__init__.py +0 -0
  60. {nucs-4.4 → nucs-4.4.4}/nucs/examples/tsp/__main__.py +0 -0
  61. {nucs-4.4 → nucs-4.4.4}/nucs/examples/tsp/total_cost_propagator.py +0 -0
  62. {nucs-4.4 → nucs-4.4.4}/nucs/examples/tsp/tsp_instances.py +0 -0
  63. {nucs-4.4 → nucs-4.4.4}/nucs/examples/tsp/tsp_problem.py +0 -0
  64. {nucs-4.4 → nucs-4.4.4}/nucs/examples/tsp/tsp_var_heuristic.py +0 -0
  65. {nucs-4.4 → nucs-4.4.4}/nucs/heuristics/__init__.py +0 -0
  66. {nucs-4.4 → nucs-4.4.4}/nucs/heuristics/first_not_instantiated_var_heuristic.py +0 -0
  67. {nucs-4.4 → nucs-4.4.4}/nucs/heuristics/greatest_domain_var_heuristic.py +0 -0
  68. {nucs-4.4 → nucs-4.4.4}/nucs/heuristics/heuristics.py +0 -0
  69. {nucs-4.4 → nucs-4.4.4}/nucs/heuristics/max_regret_var_heuristic.py +0 -0
  70. {nucs-4.4 → nucs-4.4.4}/nucs/heuristics/max_value_dom_heuristic.py +0 -0
  71. {nucs-4.4 → nucs-4.4.4}/nucs/heuristics/mid_value_dom_heuristic.py +0 -0
  72. {nucs-4.4 → nucs-4.4.4}/nucs/heuristics/min_cost_dom_heuristic.py +0 -0
  73. {nucs-4.4 → nucs-4.4.4}/nucs/heuristics/min_value_dom_heuristic.py +0 -0
  74. {nucs-4.4 → nucs-4.4.4}/nucs/heuristics/smallest_domain_var_heuristic.py +0 -0
  75. {nucs-4.4 → nucs-4.4.4}/nucs/heuristics/split_high_dom_heuristic.py +0 -0
  76. {nucs-4.4 → nucs-4.4.4}/nucs/heuristics/split_low_dom_heuristic.py +0 -0
  77. {nucs-4.4 → nucs-4.4.4}/nucs/heuristics/value_dom_heuristic.py +0 -0
  78. {nucs-4.4 → nucs-4.4.4}/nucs/numba_helper.py +0 -0
  79. {nucs-4.4 → nucs-4.4.4}/nucs/numpy_helper.py +0 -0
  80. {nucs-4.4 → nucs-4.4.4}/nucs/problems/__init__.py +0 -0
  81. {nucs-4.4 → nucs-4.4.4}/nucs/problems/circuit_problem.py +0 -0
  82. {nucs-4.4 → nucs-4.4.4}/nucs/problems/latin_square_problem.py +0 -0
  83. {nucs-4.4 → nucs-4.4.4}/nucs/problems/permutation_problem.py +0 -0
  84. {nucs-4.4 → nucs-4.4.4}/nucs/problems/problem.py +0 -0
  85. {nucs-4.4 → nucs-4.4.4}/nucs/propagators/__init__.py +0 -0
  86. {nucs-4.4 → nucs-4.4.4}/nucs/propagators/affine_eq_propagator.py +0 -0
  87. {nucs-4.4 → nucs-4.4.4}/nucs/propagators/affine_geq_propagator.py +0 -0
  88. {nucs-4.4 → nucs-4.4.4}/nucs/propagators/affine_leq_propagator.py +0 -0
  89. {nucs-4.4 → nucs-4.4.4}/nucs/propagators/alldifferent_propagator.py +0 -0
  90. {nucs-4.4 → nucs-4.4.4}/nucs/propagators/and_propagator.py +0 -0
  91. {nucs-4.4 → nucs-4.4.4}/nucs/propagators/count_eq_propagator.py +0 -0
  92. {nucs-4.4 → nucs-4.4.4}/nucs/propagators/dummy_propagator.py +0 -0
  93. {nucs-4.4 → nucs-4.4.4}/nucs/propagators/exactly_eq_propagator.py +0 -0
  94. {nucs-4.4 → nucs-4.4.4}/nucs/propagators/exactly_true_propagator.py +0 -0
  95. {nucs-4.4 → nucs-4.4.4}/nucs/propagators/gcc_propagator.py +0 -0
  96. {nucs-4.4 → nucs-4.4.4}/nucs/propagators/lexicographic_leq_propagator.py +0 -0
  97. {nucs-4.4 → nucs-4.4.4}/nucs/propagators/max_eq_propagator.py +0 -0
  98. {nucs-4.4 → nucs-4.4.4}/nucs/propagators/max_leq_propagator.py +0 -0
  99. {nucs-4.4 → nucs-4.4.4}/nucs/propagators/min_eq_propagator.py +0 -0
  100. {nucs-4.4 → nucs-4.4.4}/nucs/propagators/min_geq_propagator.py +0 -0
  101. {nucs-4.4 → nucs-4.4.4}/nucs/propagators/no_sub_cycle_propagator.py +0 -0
  102. {nucs-4.4 → nucs-4.4.4}/nucs/propagators/permutation_aux_propagator.py +0 -0
  103. {nucs-4.4 → nucs-4.4.4}/nucs/propagators/propagators.py +0 -0
  104. {nucs-4.4 → nucs-4.4.4}/nucs/propagators/relation_propagator.py +0 -0
  105. {nucs-4.4 → nucs-4.4.4}/nucs/propagators/scc_propagator.py +0 -0
  106. {nucs-4.4 → nucs-4.4.4}/nucs/solvers/__init__.py +0 -0
  107. {nucs-4.4 → nucs-4.4.4}/nucs/solvers/backtrack_solver.py +0 -0
  108. {nucs-4.4 → nucs-4.4.4}/nucs/solvers/bound_consistency_algorithm.py +0 -0
  109. {nucs-4.4 → nucs-4.4.4}/nucs/solvers/choice_points.py +0 -0
  110. {nucs-4.4 → nucs-4.4.4}/nucs/solvers/consistency_algorithms.py +0 -0
  111. {nucs-4.4 → nucs-4.4.4}/nucs/solvers/multiprocessing_solver.py +0 -0
  112. {nucs-4.4 → nucs-4.4.4}/nucs/solvers/shaving_consistency_algorithm.py +0 -0
  113. {nucs-4.4 → nucs-4.4.4}/nucs/solvers/solver.py +0 -0
  114. {nucs-4.4 → nucs-4.4.4}/setup.cfg +0 -0
  115. {nucs-4.4 → nucs-4.4.4}/tests/__init__.py +0 -0
  116. {nucs-4.4 → nucs-4.4.4}/tests/examples/test_alpha.py +0 -0
  117. {nucs-4.4 → nucs-4.4.4}/tests/examples/test_donald.py +0 -0
  118. {nucs-4.4 → nucs-4.4.4}/tests/examples/test_golomb.py +0 -0
  119. {nucs-4.4 → nucs-4.4.4}/tests/examples/test_knapsack.py +0 -0
  120. {nucs-4.4 → nucs-4.4.4}/tests/examples/test_latin_square.py +0 -0
  121. {nucs-4.4 → nucs-4.4.4}/tests/examples/test_magic_sequence.py +0 -0
  122. {nucs-4.4 → nucs-4.4.4}/tests/examples/test_magic_square.py +0 -0
  123. {nucs-4.4 → nucs-4.4.4}/tests/examples/test_queens.py +0 -0
  124. {nucs-4.4 → nucs-4.4.4}/tests/examples/test_schur_lemma.py +0 -0
  125. {nucs-4.4 → nucs-4.4.4}/tests/examples/test_sports_tournament_scheduling.py +0 -0
  126. {nucs-4.4 → nucs-4.4.4}/tests/examples/test_tsp.py +0 -0
  127. {nucs-4.4 → nucs-4.4.4}/tests/heuristics/__init__.py +0 -0
  128. {nucs-4.4 → nucs-4.4.4}/tests/heuristics/test_max_value_dom_heuristic.py +0 -0
  129. {nucs-4.4 → nucs-4.4.4}/tests/heuristics/test_mid_value_dom_heuristic.py +0 -0
  130. {nucs-4.4 → nucs-4.4.4}/tests/heuristics/test_min_value_dom_heuristic.py +0 -0
  131. {nucs-4.4 → nucs-4.4.4}/tests/problems/__init__.py +0 -0
  132. {nucs-4.4 → nucs-4.4.4}/tests/problems/test_circuit_problem.py +0 -0
  133. {nucs-4.4 → nucs-4.4.4}/tests/problems/test_permutation_problem.py +0 -0
  134. {nucs-4.4 → nucs-4.4.4}/tests/problems/test_problem.py +0 -0
  135. {nucs-4.4 → nucs-4.4.4}/tests/propagators/__init__.py +0 -0
  136. {nucs-4.4 → nucs-4.4.4}/tests/propagators/test_affine_eq.py +0 -0
  137. {nucs-4.4 → nucs-4.4.4}/tests/propagators/test_affine_geq.py +0 -0
  138. {nucs-4.4 → nucs-4.4.4}/tests/propagators/test_affine_leq.py +0 -0
  139. {nucs-4.4 → nucs-4.4.4}/tests/propagators/test_alldifferent.py +0 -0
  140. {nucs-4.4 → nucs-4.4.4}/tests/propagators/test_count_eq.py +0 -0
  141. {nucs-4.4 → nucs-4.4.4}/tests/propagators/test_element_iv.py +0 -0
  142. {nucs-4.4 → nucs-4.4.4}/tests/propagators/test_element_lic.py +0 -0
  143. {nucs-4.4 → nucs-4.4.4}/tests/propagators/test_exactly_eq.py +0 -0
  144. {nucs-4.4 → nucs-4.4.4}/tests/propagators/test_gcc.py +0 -0
  145. {nucs-4.4 → nucs-4.4.4}/tests/propagators/test_lexicographic_leq.py +0 -0
  146. {nucs-4.4 → nucs-4.4.4}/tests/propagators/test_max_eq.py +0 -0
  147. {nucs-4.4 → nucs-4.4.4}/tests/propagators/test_max_leq.py +0 -0
  148. {nucs-4.4 → nucs-4.4.4}/tests/propagators/test_min_eq.py +0 -0
  149. {nucs-4.4 → nucs-4.4.4}/tests/propagators/test_min_geq.py +0 -0
  150. {nucs-4.4 → nucs-4.4.4}/tests/propagators/test_no_sub_cycle.py +0 -0
  151. {nucs-4.4 → nucs-4.4.4}/tests/propagators/test_relation.py +0 -0
  152. {nucs-4.4 → nucs-4.4.4}/tests/propagators/test_scc.py +0 -0
  153. {nucs-4.4 → nucs-4.4.4}/tests/solvers/__init__.py +0 -0
  154. {nucs-4.4 → nucs-4.4.4}/tests/solvers/test_backtrack_solver.py +0 -0
  155. {nucs-4.4 → nucs-4.4.4}/tests/solvers/test_multiprocessing_solver.py +0 -0
@@ -1,16 +1,20 @@
1
1
  Metadata-Version: 2.1
2
- Name: NUCS
3
- Version: 4.4
2
+ Name: NuCS
3
+ Version: 4.4.4
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
7
7
  Project-URL: Issues, https://github.com/yangeorget/nucs/issues
8
- Classifier: Development Status :: 4 - Beta
8
+ Classifier: Development Status :: 5 - Production/Stable
9
9
  Classifier: Intended Audience :: Developers
10
10
  Classifier: Intended Audience :: Science/Research
11
11
  Classifier: License :: OSI Approved :: MIT License
12
12
  Classifier: Operating System :: OS Independent
13
13
  Classifier: Programming Language :: Python :: 3
14
+ Classifier: Programming Language :: Python :: 3.9
15
+ Classifier: Programming Language :: Python :: 3.10
16
+ Classifier: Programming Language :: Python :: 3.11
17
+ Classifier: Programming Language :: Python :: 3.12
14
18
  Classifier: Topic :: Scientific/Engineering :: Artificial Intelligence
15
19
  Classifier: Topic :: Scientific/Engineering :: Mathematics
16
20
  Classifier: Topic :: Software Development :: Libraries :: Python Modules
@@ -18,7 +22,8 @@ Requires-Python: >=3.9
18
22
  Description-Content-Type: text/markdown
19
23
  License-File: LICENSE.md
20
24
  Requires-Dist: numba==0.60.0
21
- Requires-Dist: numpy==2.0.1
25
+ Requires-Dist: numpy<2.1
26
+ Requires-Dist: rich
22
27
 
23
28
  ![NucS logo](https://github.com/yangeorget/nucs/blob/main/assets/nucs.png?raw=true)
24
29
 
@@ -1,11 +1,11 @@
1
1
  LICENSE.md
2
2
  README.md
3
3
  pyproject.toml
4
- NUCS.egg-info/PKG-INFO
5
- NUCS.egg-info/SOURCES.txt
6
- NUCS.egg-info/dependency_links.txt
7
- NUCS.egg-info/requires.txt
8
- NUCS.egg-info/top_level.txt
4
+ NuCS.egg-info/PKG-INFO
5
+ NuCS.egg-info/SOURCES.txt
6
+ NuCS.egg-info/dependency_links.txt
7
+ NuCS.egg-info/requires.txt
8
+ NuCS.egg-info/top_level.txt
9
9
  docs/source/conf.py
10
10
  nucs/__init__.py
11
11
  nucs/constants.py
@@ -0,0 +1,3 @@
1
+ numba==0.60.0
2
+ numpy<2.1
3
+ rich
@@ -1,16 +1,20 @@
1
1
  Metadata-Version: 2.1
2
- Name: NUCS
3
- Version: 4.4
2
+ Name: NuCS
3
+ Version: 4.4.4
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
7
7
  Project-URL: Issues, https://github.com/yangeorget/nucs/issues
8
- Classifier: Development Status :: 4 - Beta
8
+ Classifier: Development Status :: 5 - Production/Stable
9
9
  Classifier: Intended Audience :: Developers
10
10
  Classifier: Intended Audience :: Science/Research
11
11
  Classifier: License :: OSI Approved :: MIT License
12
12
  Classifier: Operating System :: OS Independent
13
13
  Classifier: Programming Language :: Python :: 3
14
+ Classifier: Programming Language :: Python :: 3.9
15
+ Classifier: Programming Language :: Python :: 3.10
16
+ Classifier: Programming Language :: Python :: 3.11
17
+ Classifier: Programming Language :: Python :: 3.12
14
18
  Classifier: Topic :: Scientific/Engineering :: Artificial Intelligence
15
19
  Classifier: Topic :: Scientific/Engineering :: Mathematics
16
20
  Classifier: Topic :: Software Development :: Libraries :: Python Modules
@@ -18,7 +22,8 @@ Requires-Python: >=3.9
18
22
  Description-Content-Type: text/markdown
19
23
  License-File: LICENSE.md
20
24
  Requires-Dist: numba==0.60.0
21
- Requires-Dist: numpy==2.0.1
25
+ Requires-Dist: numpy<2.1
26
+ Requires-Dist: rich
22
27
 
23
28
  ![NucS logo](https://github.com/yangeorget/nucs/blob/main/assets/nucs.png?raw=true)
24
29
 
@@ -2,12 +2,12 @@
2
2
 
3
3
  # -- Project information
4
4
 
5
- project = 'NUCS'
5
+ project = 'NuCS'
6
6
  copyright = '2024, Yan Georget'
7
7
  author = 'Yan Georget'
8
8
 
9
- release = '4.4'
10
- version = '4.4'
9
+ release = '4.4.4'
10
+ version = '4.4.4'
11
11
 
12
12
  # -- General configuration
13
13
 
@@ -15,9 +15,10 @@ import argparse
15
15
  from rich import print
16
16
 
17
17
  from nucs.constants import LOG_LEVEL_INFO, LOG_LEVELS
18
- from nucs.examples.quasigroup.quasigroup_problem import Quasigroup5Problem
19
- from nucs.heuristics.heuristics import DOM_HEURISTIC_MIN_VALUE, VAR_HEURISTIC_SMALLEST_DOMAIN
18
+ from nucs.examples.quasigroup.quasigroup_problem import QuasigroupProblem
19
+ from nucs.heuristics.heuristics import DOM_HEURISTIC_SPLIT_LOW, VAR_HEURISTIC_SMALLEST_DOMAIN
20
20
  from nucs.solvers.backtrack_solver import BacktrackSolver
21
+ from nucs.solvers.consistency_algorithms import CONSISTENCY_ALG_BC, CONSISTENCY_ALG_SHAVING
21
22
 
22
23
  # Run with the following command (the second run is much faster because the code has been compiled):
23
24
  # NUMBA_CACHE_DIR=.numba/cache python -m nucs.examples.quasigroup -n 10 --symmetry_breaking
@@ -25,13 +26,18 @@ if __name__ == "__main__":
25
26
  parser = argparse.ArgumentParser()
26
27
  parser.add_argument("--log_level", choices=LOG_LEVELS, default=LOG_LEVEL_INFO)
27
28
  parser.add_argument("-n", type=int, default=10)
29
+ parser.add_argument("--idempotent", action=argparse.BooleanOptionalAction, default=True)
30
+ parser.add_argument("--shaving", type=bool, action=argparse.BooleanOptionalAction, default=False)
28
31
  parser.add_argument("--symmetry_breaking", action=argparse.BooleanOptionalAction, default=True)
32
+ parser.add_argument("--kind", type=int, choices=[3, 4, 5, 6, 7], default=5)
29
33
  args = parser.parse_args()
30
- problem = Quasigroup5Problem(args.n, args.symmetry_breaking)
34
+ problem = QuasigroupProblem(args.kind, args.n, args.idempotent, args.symmetry_breaking)
31
35
  solver = BacktrackSolver(
32
36
  problem,
37
+ decision_domains=list(range(0, args.n * args.n)),
38
+ consistency_alg_idx=CONSISTENCY_ALG_SHAVING if args.shaving else CONSISTENCY_ALG_BC,
33
39
  var_heuristic_idx=VAR_HEURISTIC_SMALLEST_DOMAIN,
34
- dom_heuristic_idx=DOM_HEURISTIC_MIN_VALUE,
40
+ dom_heuristic_idx=DOM_HEURISTIC_SPLIT_LOW,
35
41
  log_level=args.log_level,
36
42
  )
37
43
  solver.solve_all()
@@ -0,0 +1,116 @@
1
+ ###############################################################################
2
+ # __ _ _____ _____
3
+ # | \ | | / ____| / ____|
4
+ # | \| | _ _ | | | (___
5
+ # | . ` | | | | | | | \___ \
6
+ # | |\ | | |_| | | |____ ____) |
7
+ # |_| \_| \__,_| \_____| |_____/
8
+ #
9
+ # Fast constraint solving in Python - https://github.com/yangeorget/nucs
10
+ #
11
+ # Copyright 2024 - Yan Georget
12
+ ###############################################################################
13
+ from nucs.problems.latin_square_problem import M_COLOR, M_COLUMN, M_ROW, LatinSquareRCProblem
14
+ from nucs.propagators.propagators import ALG_ELEMENT_LIV
15
+
16
+
17
+ class QuasigroupProblem(LatinSquareRCProblem):
18
+ """
19
+ CSPLIB problem #3 - https://www.csplib.org/Problems/prob003/
20
+ """
21
+
22
+ def __init__(self, kind: int, n: int, idempotent: bool, symmetry_breaking: bool = True):
23
+ """
24
+ Inits the problem.
25
+ :param n: the size of the quasigroup
26
+ :param idempotent: a boolean indicating if the quasigroup is idempotent
27
+ :param symmetry_breaking: a boolean indicating if symmetry constraints should be added to the model
28
+ """
29
+ super().__init__(n)
30
+ if kind == 3: # (a∗b)∗(b*a)=a
31
+ # Equivalent to: color[color[i, j], color[j, i]] = i
32
+ # Equivalent to: column[color[i, j], i] = color[j, i] which avoids the creation of additional variables
33
+ self.add_propagators(
34
+ [
35
+ (
36
+ [*self.column(i, M_COLUMN), self.cell(i, j, M_COLOR), self.cell(j, i, M_COLOR)],
37
+ ALG_ELEMENT_LIV,
38
+ [],
39
+ )
40
+ for i in range(n)
41
+ for j in range(n)
42
+ ]
43
+ )
44
+ elif kind == 4: # (b∗a)∗(a*b) = a
45
+ # Equivalent to: color[color[j, i], color[i, j]] = i
46
+ # Equivalent to: column[color[j, i], i] = color[i, j] which avoids the creation of additional variables
47
+ self.add_propagators(
48
+ [
49
+ (
50
+ [*self.column(i, M_COLUMN), self.cell(j, i, M_COLOR), self.cell(i, j, M_COLOR)],
51
+ ALG_ELEMENT_LIV,
52
+ [],
53
+ )
54
+ for i in range(n)
55
+ for j in range(n)
56
+ ]
57
+ )
58
+ elif kind == 5: # ((b∗a)∗b)∗b = a
59
+ # Equivalent to: color[color[color[j, i], j], j] = i
60
+ # Equivalent to: row[i, j] = color[color[j, i], j] which avoids the creation of additional variables
61
+ self.add_propagators(
62
+ [
63
+ (
64
+ [*self.column(j, M_COLOR), self.cell(j, i, M_COLOR), self.cell(i, j, M_ROW)],
65
+ ALG_ELEMENT_LIV,
66
+ [],
67
+ )
68
+ for i in range(n)
69
+ for j in range(n)
70
+ ]
71
+ )
72
+ elif kind == 6: # (a∗b)∗b = a*(a*b)
73
+ # Equivalent to: color[color[i, j], j] = color[i, color[i, j]]
74
+ additional_vars_idx = self.add_variables([(0, n - 1)] * n**2) # additional variables
75
+ for i in range(n):
76
+ for j in range(n):
77
+ self.add_propagator(
78
+ (
79
+ [*self.column(j, M_COLOR), self.cell(i, j, M_COLOR), additional_vars_idx + i * n + j],
80
+ ALG_ELEMENT_LIV,
81
+ [],
82
+ )
83
+ )
84
+ self.add_propagator(
85
+ (
86
+ [*self.row(i, M_COLOR), self.cell(i, j, M_COLOR), additional_vars_idx + i * n + j],
87
+ ALG_ELEMENT_LIV,
88
+ [],
89
+ )
90
+ )
91
+ elif kind == 7: # (b∗a)∗b = a*(b*a)
92
+ # Equivalent to: color[color[j, i], j] = color[i, color[j, i]]
93
+ additional_vars_idx = self.add_variables([(0, n - 1)] * n**2) # additional variables
94
+ for i in range(n):
95
+ for j in range(n):
96
+ self.add_propagator(
97
+ (
98
+ [*self.column(j, M_COLOR), self.cell(j, i, M_COLOR), additional_vars_idx + i * n + j],
99
+ ALG_ELEMENT_LIV,
100
+ [],
101
+ )
102
+ )
103
+ self.add_propagator(
104
+ (
105
+ [*self.row(i, M_COLOR), self.cell(j, i, M_COLOR), additional_vars_idx + i * n + j],
106
+ ALG_ELEMENT_LIV,
107
+ [],
108
+ )
109
+ )
110
+ if idempotent:
111
+ for model in [M_COLOR, M_ROW, M_COLUMN]:
112
+ for i in range(n):
113
+ self.shr_domains_lst[self.cell(i, i, model)] = [i, i]
114
+ if symmetry_breaking:
115
+ for i in range(1, n):
116
+ self.shr_domains_lst[self.cell(i, n - 1)] = [i - 1, n - 1]
@@ -11,7 +11,6 @@
11
11
  # Copyright 2024 - Yan Georget
12
12
  ###############################################################################
13
13
  import sys
14
- from typing import List
15
14
 
16
15
  import numpy as np
17
16
  from numba import njit # type: ignore
@@ -58,23 +57,23 @@ def compute_domains_element_iv(domains: NDArray, parameters: NDArray) -> int:
58
57
  i[MAX] = min(i[MAX], len(l) - 1)
59
58
  v_min = sys.maxsize
60
59
  v_max = -sys.maxsize
61
- indices: List[int] = []
60
+ start = -1
62
61
  for idx in range(i[MIN], i[MAX] + 1):
63
62
  if v[MAX] < l[idx] or v[MIN] > l[idx]: # no intersection
64
- indices.append(idx)
63
+ if start == -1:
64
+ start = idx
65
65
  if idx == i[MIN]:
66
66
  i[MIN] += 1
67
67
  else: # intersection
68
+ start = -1
68
69
  if l[idx] < v_min:
69
70
  v_min = l[idx]
70
71
  if l[idx] > v_max:
71
72
  v_max = l[idx]
72
- for ix in range(len(indices) - 1, -1, -1):
73
- if indices[ix] != i[MAX]:
74
- break
75
- i[MAX] -= 1
76
- if i[MAX] < i[MIN]:
77
- return PROP_INCONSISTENCY
73
+ if start >= 0:
74
+ i[MAX] = start - 1
75
+ if i[MAX] < i[MIN]:
76
+ return PROP_INCONSISTENCY
78
77
  v[MIN] = max(v[MIN], v_min)
79
78
  v[MAX] = min(v[MAX], v_max)
80
79
  if i[MIN] == i[MAX]:
@@ -10,8 +10,6 @@
10
10
  #
11
11
  # Copyright 2024 - Yan Georget
12
12
  ###############################################################################
13
- from typing import List
14
-
15
13
  import numpy as np
16
14
  from numba import njit # type: ignore
17
15
  from numpy.typing import NDArray
@@ -53,18 +51,19 @@ def compute_domains_element_lic(domains: NDArray, parameters: NDArray) -> int:
53
51
  # i could be updated only once
54
52
  i[MIN] = max(i[MIN], 0)
55
53
  i[MAX] = min(i[MAX], len(l) - 1)
56
- indices: List[int] = []
54
+ start = -1
57
55
  for idx in range(i[MIN], i[MAX] + 1):
58
56
  if c < l[idx, MIN] or c > l[idx, MAX]: # no intersection
59
- indices.insert(0, idx)
57
+ if start == -1:
58
+ start = idx
60
59
  if idx == i[MIN]:
61
60
  i[MIN] += 1
62
- for idx in indices:
63
- if idx != i[MAX]:
64
- break
65
- i[MAX] -= 1
66
- if i[MAX] < i[MIN]:
67
- return PROP_INCONSISTENCY
61
+ else: # intersection
62
+ start = -1
63
+ if start >= 0:
64
+ i[MAX] = start - 1
65
+ if i[MAX] < i[MIN]:
66
+ return PROP_INCONSISTENCY
68
67
  if i[MIN] == i[MAX]:
69
68
  l[i[MIN]] = c
70
69
  return PROP_ENTAILMENT
@@ -11,7 +11,6 @@
11
11
  # Copyright 2024 - Yan Georget
12
12
  ###############################################################################
13
13
  import sys
14
- from typing import List
15
14
 
16
15
  import numpy as np
17
16
  from numba import njit # type: ignore
@@ -59,23 +58,23 @@ def compute_domains_element_liv(domains: NDArray, parameters: NDArray) -> int:
59
58
  i[MAX] = min(i[MAX], len(l) - 1)
60
59
  v_min = sys.maxsize
61
60
  v_max = -sys.maxsize
62
- indices: List[int] = []
61
+ start = -1
63
62
  for idx in range(i[MIN], i[MAX] + 1):
64
63
  if v[MAX] < l[idx, MIN] or v[MIN] > l[idx, MAX]: # no intersection
65
- indices.insert(0, idx)
64
+ if start == -1:
65
+ start = idx
66
66
  if idx == i[MIN]:
67
67
  i[MIN] += 1
68
68
  else: # intersection
69
+ start = -1
69
70
  if l[idx, MIN] < v_min:
70
71
  v_min = l[idx, MIN]
71
72
  if l[idx, MAX] > v_max:
72
73
  v_max = l[idx, MAX]
73
- for idx in indices:
74
- if idx != i[MAX]:
75
- break
76
- i[MAX] -= 1
77
- if i[MAX] < i[MIN]:
78
- return PROP_INCONSISTENCY
74
+ if start >= 0:
75
+ i[MAX] = start - 1
76
+ if i[MAX] < i[MIN]:
77
+ return PROP_INCONSISTENCY
79
78
  v[MIN] = max(v[MIN], v_min)
80
79
  v[MAX] = min(v[MAX], v_max)
81
80
  if i[MIN] == i[MAX]:
@@ -1,6 +1,6 @@
1
1
  [project]
2
- name="NUCS"
3
- version="4.4"
2
+ name="NuCS"
3
+ version="4.4.4"
4
4
  authors = [
5
5
  { name="Yan Georget", email="yan.georget@gmail.com" },
6
6
  ]
@@ -8,19 +8,24 @@ description="A Numpy and Numba based Python library for solving Constraint Satis
8
8
  readme = "README.md"
9
9
  requires-python = ">=3.9"
10
10
  classifiers = [
11
- "Development Status :: 4 - Beta",
11
+ "Development Status :: 5 - Production/Stable",
12
12
  "Intended Audience :: Developers",
13
13
  "Intended Audience :: Science/Research",
14
14
  "License :: OSI Approved :: MIT License",
15
15
  "Operating System :: OS Independent",
16
16
  "Programming Language :: Python :: 3",
17
+ "Programming Language :: Python :: 3.9",
18
+ "Programming Language :: Python :: 3.10",
19
+ "Programming Language :: Python :: 3.11",
20
+ "Programming Language :: Python :: 3.12",
17
21
  "Topic :: Scientific/Engineering :: Artificial Intelligence",
18
22
  "Topic :: Scientific/Engineering :: Mathematics",
19
23
  "Topic :: Software Development :: Libraries :: Python Modules"
20
24
  ]
21
25
  dependencies = [
22
26
  "numba==0.60.0",
23
- "numpy==2.0.1",
27
+ "numpy<2.1",
28
+ "rich"
24
29
  ]
25
30
  [project.urls]
26
31
  Homepage = "https://github.com/yangeorget/nucs"
@@ -10,26 +10,19 @@
10
10
  #
11
11
  # Copyright 2024 - Yan Georget
12
12
  ###############################################################################
13
+ import pytest
14
+
13
15
  from nucs.constants import STATS_IDX_SOLVER_SOLUTION_NB
14
16
  from nucs.examples.bibd.bibd_problem import BIBDProblem
15
17
  from nucs.solvers.backtrack_solver import BacktrackSolver
16
18
 
17
19
 
18
20
  class TestBIBD:
19
- def test_6_10_5_3_2(self) -> None:
20
- problem = BIBDProblem(6, 10, 5, 3, 2)
21
- solver = BacktrackSolver(problem, stacks_max_height=128)
22
- solver.solve_all()
23
- assert solver.statistics[STATS_IDX_SOLVER_SOLUTION_NB] == 1
24
-
25
- def test_7_7_3_3_1(self) -> None:
26
- problem = BIBDProblem(7, 7, 3, 3, 1)
27
- solver = BacktrackSolver(problem, stacks_max_height=128)
28
- solver.solve_all()
29
- assert solver.statistics[STATS_IDX_SOLVER_SOLUTION_NB] == 1
30
-
31
- def test_8_14_7_4_3(self) -> None:
32
- problem = BIBDProblem(8, 14, 7, 4, 3)
21
+ @pytest.mark.parametrize(
22
+ "v, b, r, k, l, solution_nb", [(6, 10, 5, 3, 2, 1), (7, 7, 3, 3, 1, 1), (8, 14, 7, 4, 3, 92)]
23
+ )
24
+ def test_bibd(self, v: int, b: int, r: int, k: int, l: int, solution_nb: int) -> None:
25
+ problem = BIBDProblem(v, b, r, k, l)
33
26
  solver = BacktrackSolver(problem, stacks_max_height=128)
34
27
  solver.solve_all()
35
- assert solver.statistics[STATS_IDX_SOLVER_SOLUTION_NB] == 92
28
+ assert solver.statistics[STATS_IDX_SOLVER_SOLUTION_NB] == solution_nb
@@ -0,0 +1,62 @@
1
+ ###############################################################################
2
+ # __ _ _____ _____
3
+ # | \ | | / ____| / ____|
4
+ # | \| | _ _ | | | (___
5
+ # | . ` | | | | | | | \___ \
6
+ # | |\ | | |_| | | |____ ____) |
7
+ # |_| \_| \__,_| \_____| |_____/
8
+ #
9
+ # Fast constraint solving in Python - https://github.com/yangeorget/nucs
10
+ #
11
+ # Copyright 2024 - Yan Georget
12
+ ###############################################################################
13
+ import pytest
14
+
15
+ from nucs.constants import STATS_IDX_SOLVER_SOLUTION_NB
16
+ from nucs.examples.quasigroup.quasigroup_problem import QuasigroupProblem
17
+ from nucs.heuristics.heuristics import DOM_HEURISTIC_SPLIT_LOW, VAR_HEURISTIC_SMALLEST_DOMAIN
18
+ from nucs.solvers.backtrack_solver import BacktrackSolver
19
+
20
+
21
+ class TestQuasigroup:
22
+ @pytest.mark.parametrize(
23
+ "kind, size, idempotent, solution_nb",
24
+ [
25
+ (3, 5, True, 0),
26
+ (3, 6, True, 0),
27
+ (3, 7, True, 0),
28
+ (3, 8, True, 18),
29
+ (4, 5, True, 3),
30
+ (4, 6, True, 0),
31
+ (4, 7, True, 0),
32
+ (4, 8, True, 0),
33
+ (5, 5, True, 1),
34
+ (5, 6, True, 0),
35
+ (5, 7, True, 3),
36
+ (5, 8, True, 1),
37
+ (5, 9, True, 0),
38
+ (5, 10, True, 0),
39
+ # (5, 11, True, 5),
40
+ # (5, 12, True, 0),
41
+ (6, 5, True, 0),
42
+ (6, 6, True, 0),
43
+ (6, 7, True, 0),
44
+ (6, 8, True, 2),
45
+ (6, 9, True, 4),
46
+ (7, 5, True, 3),
47
+ (7, 6, True, 0),
48
+ (7, 7, True, 0),
49
+ (7, 8, True, 0),
50
+ # (7, 9, True, 1),
51
+ ],
52
+ )
53
+ def test_qg(self, kind: int, size: int, idempotent: bool, solution_nb: int) -> None:
54
+ problem = QuasigroupProblem(kind, size, idempotent, True)
55
+ solver = BacktrackSolver(
56
+ problem,
57
+ decision_domains=list(range(0, size * size)),
58
+ var_heuristic_idx=VAR_HEURISTIC_SMALLEST_DOMAIN,
59
+ dom_heuristic_idx=DOM_HEURISTIC_SPLIT_LOW,
60
+ )
61
+ solver.solve_all()
62
+ assert solver.statistics[STATS_IDX_SOLVER_SOLUTION_NB] == solution_nb
@@ -10,14 +10,19 @@
10
10
  #
11
11
  # Copyright 2024 - Yan Georget
12
12
  ###############################################################################
13
+ from typing import List
14
+
15
+ import pytest
16
+
13
17
  from nucs.constants import STATS_IDX_SOLVER_SOLUTION_NB
14
18
  from nucs.examples.sudoku.sudoku_problem import SudokuProblem
15
19
  from nucs.solvers.backtrack_solver import BacktrackSolver
16
20
 
17
21
 
18
22
  class TestSudokus:
19
- def test_sudokus_1(self) -> None:
20
- problem = SudokuProblem(
23
+ @pytest.mark.parametrize(
24
+ "givens",
25
+ [
21
26
  [
22
27
  [0, 0, 0, 0, 3, 0, 0, 0, 0],
23
28
  [2, 8, 9, 0, 0, 0, 0, 0, 0],
@@ -28,14 +33,7 @@ class TestSudokus:
28
33
  [0, 6, 3, 0, 0, 0, 0, 0, 0],
29
34
  [0, 0, 0, 0, 4, 0, 2, 0, 0],
30
35
  [0, 0, 1, 0, 5, 0, 6, 0, 0],
31
- ]
32
- )
33
- solver = BacktrackSolver(problem)
34
- solver.solve_all()
35
- assert solver.statistics[STATS_IDX_SOLVER_SOLUTION_NB] == 1
36
-
37
- def test_sudokus_2(self) -> None:
38
- problem = SudokuProblem(
36
+ ],
39
37
  [
40
38
  [6, 0, 0, 0, 1, 0, 0, 8, 0],
41
39
  [5, 1, 7, 4, 0, 0, 0, 0, 0],
@@ -46,8 +44,11 @@ class TestSudokus:
46
44
  [2, 5, 9, 6, 0, 0, 0, 0, 0],
47
45
  [0, 0, 0, 0, 7, 0, 0, 0, 0],
48
46
  [0, 0, 0, 0, 5, 0, 4, 0, 0],
49
- ]
50
- )
47
+ ],
48
+ ],
49
+ )
50
+ def test_sudokus(self, givens: List[List[int]]) -> None:
51
+ problem = SudokuProblem(givens)
51
52
  solver = BacktrackSolver(problem)
52
53
  solver.solve_all()
53
54
  assert solver.statistics[STATS_IDX_SOLVER_SOLUTION_NB] == 1
@@ -34,6 +34,7 @@ class TestElementLIV:
34
34
  domains = new_shr_domains_by_values([3, 0, 1, 2, 4, (0, 4), (-2, 0)])
35
35
  data = new_parameters_by_values([])
36
36
  assert compute_domains_element_liv(domains, data) == PROP_ENTAILMENT
37
+ assert np.all(domains == np.array([[3, 3], [0, 0], [1, 1], [2, 2], [4, 4], [1, 1], [0, 0]]))
37
38
 
38
39
  def test_compute_domains_4(self) -> None:
39
40
  domains = new_shr_domains_by_values([(-4, -2), (1, 2), (0, 1), (0, 0)])
@@ -1,2 +0,0 @@
1
- numba==0.60.0
2
- numpy==2.0.1
@@ -1,63 +0,0 @@
1
- ###############################################################################
2
- # __ _ _____ _____
3
- # | \ | | / ____| / ____|
4
- # | \| | _ _ | | | (___
5
- # | . ` | | | | | | | \___ \
6
- # | |\ | | |_| | | |____ ____) |
7
- # |_| \_| \__,_| \_____| |_____/
8
- #
9
- # Fast constraint solving in Python - https://github.com/yangeorget/nucs
10
- #
11
- # Copyright 2024 - Yan Georget
12
- ###############################################################################
13
- from nucs.problems.latin_square_problem import M_COLOR, M_COLUMN, M_ROW, LatinSquareRCProblem
14
- from nucs.propagators.propagators import ALG_ELEMENT_LIV
15
-
16
-
17
- class QuasigroupProblem(LatinSquareRCProblem):
18
- """
19
- CSPLIB problem #3 - https://www.csplib.org/Problems/prob003/
20
- """
21
-
22
- def __init__(self, n: int, symmetry_breaking: bool = True):
23
- """
24
- Inits the problem.
25
- :param n: the size of the quasigroup
26
- :param symmetry_breaking: a boolean indicating if symmetry constraints should be added to the model
27
- """
28
- super().__init__(n)
29
- # idempotence
30
- for model in [M_COLOR, M_ROW, M_COLUMN]:
31
- for i in range(n):
32
- self.shr_domains_lst[self.cell(i, i, model)] = [i, i]
33
- if symmetry_breaking:
34
- for i in range(1, n):
35
- self.shr_domains_lst[self.cell(i, n - 1)] = [i - 1, n - 1]
36
-
37
-
38
- class Quasigroup5Problem(QuasigroupProblem):
39
- """
40
- Defined by:
41
- ((b∗a)∗b)∗b=a
42
- Can be enforced by:
43
- color[color[j, i] ,j] = row[i, j]
44
- which avoids the creation of additional variables
45
- """
46
-
47
- def __init__(self, n: int, symmetry_breaking: bool = True):
48
- """
49
- Inits the problem
50
- :param n: the size of the quasigroup
51
- :param symmetry_breaking: a boolean indicating if symmetry constraints should be added to the model
52
- """
53
- super().__init__(n, symmetry_breaking)
54
- for j in range(n):
55
- for i in range(n):
56
- if i != j:
57
- self.add_propagator(
58
- (
59
- [*self.column(j, M_COLOR), self.cell(j, i, M_COLOR), self.cell(i, j, M_ROW)],
60
- ALG_ELEMENT_LIV,
61
- [],
62
- )
63
- )