NUCS 4.0.0__tar.gz → 4.3.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 (154) hide show
  1. {nucs-4.0.0 → nucs-4.3.0/NUCS.egg-info}/PKG-INFO +1 -1
  2. {nucs-4.0.0 → nucs-4.3.0}/NUCS.egg-info/SOURCES.txt +5 -0
  3. {nucs-4.0.0/NUCS.egg-info → nucs-4.3.0}/PKG-INFO +1 -1
  4. {nucs-4.0.0 → nucs-4.3.0}/docs/source/conf.py +2 -2
  5. {nucs-4.0.0 → nucs-4.3.0}/nucs/constants.py +6 -2
  6. {nucs-4.0.0 → nucs-4.3.0}/nucs/examples/alpha/alpha_problem.py +3 -2
  7. {nucs-4.0.0 → nucs-4.3.0}/nucs/examples/bibd/__main__.py +4 -2
  8. {nucs-4.0.0 → nucs-4.3.0}/nucs/examples/donald/donald_problem.py +4 -3
  9. {nucs-4.0.0 → nucs-4.3.0}/nucs/examples/golomb/__main__.py +20 -4
  10. {nucs-4.0.0 → nucs-4.3.0}/nucs/examples/golomb/golomb_problem.py +14 -22
  11. {nucs-4.0.0 → nucs-4.3.0}/nucs/examples/knapsack/__main__.py +3 -2
  12. {nucs-4.0.0 → nucs-4.3.0}/nucs/examples/magic_sequence/__main__.py +2 -1
  13. {nucs-4.0.0 → nucs-4.3.0}/nucs/examples/magic_square/__main__.py +2 -2
  14. {nucs-4.0.0 → nucs-4.3.0}/nucs/examples/queens/queens_problem.py +2 -1
  15. {nucs-4.0.0 → nucs-4.3.0}/nucs/examples/schur_lemma/__main__.py +2 -2
  16. {nucs-4.0.0 → nucs-4.3.0}/nucs/examples/sports_tournament_scheduling/sports_tournament_scheduling_problem.py +1 -1
  17. nucs-4.3.0/nucs/examples/tsp/__main__.py +69 -0
  18. {nucs-4.0.0 → nucs-4.3.0}/nucs/examples/tsp/total_cost_propagator.py +17 -6
  19. {nucs-4.0.0 → nucs-4.3.0}/nucs/examples/tsp/tsp_problem.py +14 -11
  20. nucs-4.3.0/nucs/examples/tsp/tsp_var_heuristic.py +52 -0
  21. {nucs-4.0.0 → nucs-4.3.0}/nucs/heuristics/first_not_instantiated_var_heuristic.py +4 -4
  22. {nucs-4.0.0 → nucs-4.3.0}/nucs/heuristics/greatest_domain_var_heuristic.py +11 -11
  23. {nucs-4.0.0 → nucs-4.3.0}/nucs/heuristics/heuristics.py +5 -3
  24. {nucs-4.0.0 → nucs-4.3.0}/nucs/heuristics/max_regret_var_heuristic.py +23 -20
  25. {nucs-4.0.0 → nucs-4.3.0}/nucs/heuristics/max_value_dom_heuristic.py +9 -9
  26. {nucs-4.0.0 → nucs-4.3.0}/nucs/heuristics/min_cost_dom_heuristic.py +5 -5
  27. {nucs-4.0.0 → nucs-4.3.0}/nucs/heuristics/min_value_dom_heuristic.py +9 -9
  28. {nucs-4.0.0 → nucs-4.3.0}/nucs/heuristics/smallest_domain_var_heuristic.py +11 -11
  29. nucs-4.3.0/nucs/heuristics/split_high_dom_heuristic.py +58 -0
  30. {nucs-4.0.0 → nucs-4.3.0}/nucs/heuristics/split_low_dom_heuristic.py +9 -9
  31. {nucs-4.0.0 → nucs-4.3.0}/nucs/heuristics/value_dom_heuristic.py +15 -15
  32. {nucs-4.0.0 → nucs-4.3.0}/nucs/numba_helper.py +2 -2
  33. nucs-4.3.0/nucs/problems/circuit_problem.py +36 -0
  34. nucs-4.0.0/nucs/problems/circuit_problem.py → nucs-4.3.0/nucs/problems/permutation_problem.py +11 -10
  35. {nucs-4.0.0 → nucs-4.3.0}/nucs/problems/problem.py +1 -0
  36. {nucs-4.0.0 → nucs-4.3.0}/nucs/propagators/affine_eq_propagator.py +1 -1
  37. {nucs-4.0.0 → nucs-4.3.0}/nucs/propagators/affine_geq_propagator.py +1 -1
  38. {nucs-4.0.0 → nucs-4.3.0}/nucs/propagators/affine_leq_propagator.py +1 -1
  39. {nucs-4.0.0 → nucs-4.3.0}/nucs/propagators/element_iv_propagator.py +3 -3
  40. {nucs-4.0.0 → nucs-4.3.0}/nucs/propagators/gcc_propagator.py +9 -9
  41. {nucs-4.0.0 → nucs-4.3.0}/nucs/propagators/no_sub_cycle_propagator.py +21 -18
  42. nucs-4.3.0/nucs/propagators/permutation_aux_propagator.py +65 -0
  43. {nucs-4.0.0 → nucs-4.3.0}/nucs/propagators/propagators.py +11 -4
  44. {nucs-4.0.0 → nucs-4.3.0}/nucs/propagators/scc_propagator.py +1 -1
  45. {nucs-4.0.0 → nucs-4.3.0}/nucs/solvers/backtrack_solver.py +101 -86
  46. {nucs-4.0.0 → nucs-4.3.0}/nucs/solvers/bound_consistency_algorithm.py +3 -3
  47. {nucs-4.0.0 → nucs-4.3.0}/nucs/solvers/choice_points.py +61 -3
  48. {nucs-4.0.0 → nucs-4.3.0}/nucs/solvers/multiprocessing_solver.py +12 -9
  49. {nucs-4.0.0 → nucs-4.3.0}/nucs/solvers/shaving_consistency_algorithm.py +5 -5
  50. {nucs-4.0.0 → nucs-4.3.0}/nucs/solvers/solver.py +3 -45
  51. {nucs-4.0.0 → nucs-4.3.0}/pyproject.toml +1 -1
  52. {nucs-4.0.0 → nucs-4.3.0}/tests/examples/test_bibd.py +3 -3
  53. {nucs-4.0.0 → nucs-4.3.0}/tests/examples/test_golomb.py +2 -7
  54. {nucs-4.0.0 → nucs-4.3.0}/tests/examples/test_magic_sequence.py +1 -0
  55. nucs-4.3.0/tests/examples/test_tsp.py +59 -0
  56. nucs-4.3.0/tests/problems/test_permutation_problem.py +35 -0
  57. {nucs-4.0.0 → nucs-4.3.0}/tests/propagators/test_no_sub_cycle.py +7 -2
  58. {nucs-4.0.0 → nucs-4.3.0}/tests/solvers/test_backtrack_solver.py +31 -1
  59. {nucs-4.0.0 → nucs-4.3.0}/tests/solvers/test_multiprocessing_solver.py +28 -23
  60. nucs-4.0.0/nucs/examples/tsp/__main__.py +0 -43
  61. nucs-4.0.0/tests/examples/test_tsp.py +0 -47
  62. {nucs-4.0.0 → nucs-4.3.0}/LICENSE.md +0 -0
  63. {nucs-4.0.0 → nucs-4.3.0}/NUCS.egg-info/dependency_links.txt +0 -0
  64. {nucs-4.0.0 → nucs-4.3.0}/NUCS.egg-info/requires.txt +0 -0
  65. {nucs-4.0.0 → nucs-4.3.0}/NUCS.egg-info/top_level.txt +0 -0
  66. {nucs-4.0.0 → nucs-4.3.0}/README.md +0 -0
  67. {nucs-4.0.0 → nucs-4.3.0}/nucs/__init__.py +0 -0
  68. {nucs-4.0.0 → nucs-4.3.0}/nucs/examples/__init__.py +0 -0
  69. {nucs-4.0.0 → nucs-4.3.0}/nucs/examples/alpha/__init__.py +0 -0
  70. {nucs-4.0.0 → nucs-4.3.0}/nucs/examples/alpha/__main__.py +0 -0
  71. {nucs-4.0.0 → nucs-4.3.0}/nucs/examples/bibd/__init__.py +0 -0
  72. {nucs-4.0.0 → nucs-4.3.0}/nucs/examples/bibd/bibd_problem.py +0 -0
  73. {nucs-4.0.0 → nucs-4.3.0}/nucs/examples/donald/__init__.py +0 -0
  74. {nucs-4.0.0 → nucs-4.3.0}/nucs/examples/donald/__main__.py +0 -0
  75. {nucs-4.0.0 → nucs-4.3.0}/nucs/examples/golomb/__init__.py +0 -0
  76. {nucs-4.0.0 → nucs-4.3.0}/nucs/examples/knapsack/__init__.py +0 -0
  77. {nucs-4.0.0 → nucs-4.3.0}/nucs/examples/knapsack/knapsack_problem.py +0 -0
  78. {nucs-4.0.0 → nucs-4.3.0}/nucs/examples/magic_sequence/__init__.py +0 -0
  79. {nucs-4.0.0 → nucs-4.3.0}/nucs/examples/magic_sequence/magic_sequence_problem.py +0 -0
  80. {nucs-4.0.0 → nucs-4.3.0}/nucs/examples/magic_square/__init__.py +0 -0
  81. {nucs-4.0.0 → nucs-4.3.0}/nucs/examples/magic_square/magic_square_problem.py +0 -0
  82. {nucs-4.0.0 → nucs-4.3.0}/nucs/examples/quasigroup/__init__.py +0 -0
  83. {nucs-4.0.0 → nucs-4.3.0}/nucs/examples/quasigroup/__main__.py +1 -1
  84. {nucs-4.0.0 → nucs-4.3.0}/nucs/examples/quasigroup/quasigroup_problem.py +0 -0
  85. {nucs-4.0.0 → nucs-4.3.0}/nucs/examples/queens/__init__.py +0 -0
  86. {nucs-4.0.0 → nucs-4.3.0}/nucs/examples/queens/__main__.py +2 -2
  87. {nucs-4.0.0 → nucs-4.3.0}/nucs/examples/schur_lemma/__init__.py +0 -0
  88. {nucs-4.0.0 → nucs-4.3.0}/nucs/examples/schur_lemma/schur_lemma_problem.py +0 -0
  89. {nucs-4.0.0 → nucs-4.3.0}/nucs/examples/sports_tournament_scheduling/__init__.py +0 -0
  90. {nucs-4.0.0 → nucs-4.3.0}/nucs/examples/sports_tournament_scheduling/__main__.py +1 -1
  91. {nucs-4.0.0 → nucs-4.3.0}/nucs/examples/sudoku/__init__.py +0 -0
  92. {nucs-4.0.0 → nucs-4.3.0}/nucs/examples/sudoku/sudoku_problem.py +0 -0
  93. {nucs-4.0.0 → nucs-4.3.0}/nucs/examples/tsp/__init__.py +0 -0
  94. {nucs-4.0.0 → nucs-4.3.0}/nucs/examples/tsp/tsp_instances.py +0 -0
  95. {nucs-4.0.0 → nucs-4.3.0}/nucs/heuristics/__init__.py +0 -0
  96. {nucs-4.0.0 → nucs-4.3.0}/nucs/heuristics/mid_value_dom_heuristic.py +3 -3
  97. {nucs-4.0.0 → nucs-4.3.0}/nucs/numpy_helper.py +0 -0
  98. {nucs-4.0.0 → nucs-4.3.0}/nucs/problems/__init__.py +0 -0
  99. {nucs-4.0.0 → nucs-4.3.0}/nucs/problems/latin_square_problem.py +0 -0
  100. {nucs-4.0.0 → nucs-4.3.0}/nucs/propagators/__init__.py +0 -0
  101. {nucs-4.0.0 → nucs-4.3.0}/nucs/propagators/alldifferent_propagator.py +0 -0
  102. {nucs-4.0.0 → nucs-4.3.0}/nucs/propagators/and_propagator.py +0 -0
  103. {nucs-4.0.0 → nucs-4.3.0}/nucs/propagators/count_eq_propagator.py +0 -0
  104. {nucs-4.0.0 → nucs-4.3.0}/nucs/propagators/dummy_propagator.py +0 -0
  105. {nucs-4.0.0 → nucs-4.3.0}/nucs/propagators/element_lic_propagator.py +0 -0
  106. {nucs-4.0.0 → nucs-4.3.0}/nucs/propagators/element_liv_propagator.py +0 -0
  107. {nucs-4.0.0 → nucs-4.3.0}/nucs/propagators/exactly_eq_propagator.py +0 -0
  108. {nucs-4.0.0 → nucs-4.3.0}/nucs/propagators/exactly_true_propagator.py +0 -0
  109. {nucs-4.0.0 → nucs-4.3.0}/nucs/propagators/lexicographic_leq_propagator.py +0 -0
  110. {nucs-4.0.0 → nucs-4.3.0}/nucs/propagators/max_eq_propagator.py +0 -0
  111. {nucs-4.0.0 → nucs-4.3.0}/nucs/propagators/max_leq_propagator.py +0 -0
  112. {nucs-4.0.0 → nucs-4.3.0}/nucs/propagators/min_eq_propagator.py +0 -0
  113. {nucs-4.0.0 → nucs-4.3.0}/nucs/propagators/min_geq_propagator.py +0 -0
  114. {nucs-4.0.0 → nucs-4.3.0}/nucs/propagators/relation_propagator.py +0 -0
  115. {nucs-4.0.0 → nucs-4.3.0}/nucs/solvers/__init__.py +0 -0
  116. {nucs-4.0.0 → nucs-4.3.0}/nucs/solvers/consistency_algorithms.py +0 -0
  117. {nucs-4.0.0 → nucs-4.3.0}/setup.cfg +0 -0
  118. {nucs-4.0.0 → nucs-4.3.0}/tests/__init__.py +0 -0
  119. {nucs-4.0.0 → nucs-4.3.0}/tests/examples/test_alpha.py +0 -0
  120. {nucs-4.0.0 → nucs-4.3.0}/tests/examples/test_donald.py +0 -0
  121. {nucs-4.0.0 → nucs-4.3.0}/tests/examples/test_knapsack.py +0 -0
  122. {nucs-4.0.0 → nucs-4.3.0}/tests/examples/test_latin_square.py +0 -0
  123. {nucs-4.0.0 → nucs-4.3.0}/tests/examples/test_magic_square.py +0 -0
  124. {nucs-4.0.0 → nucs-4.3.0}/tests/examples/test_quasigroup.py +0 -0
  125. {nucs-4.0.0 → nucs-4.3.0}/tests/examples/test_queens.py +0 -0
  126. {nucs-4.0.0 → nucs-4.3.0}/tests/examples/test_schur_lemma.py +0 -0
  127. {nucs-4.0.0 → nucs-4.3.0}/tests/examples/test_sports_tournament_scheduling.py +0 -0
  128. {nucs-4.0.0 → nucs-4.3.0}/tests/examples/test_sudokus.py +0 -0
  129. {nucs-4.0.0 → nucs-4.3.0}/tests/heuristics/__init__.py +0 -0
  130. {nucs-4.0.0 → nucs-4.3.0}/tests/heuristics/test_max_value_dom_heuristic.py +0 -0
  131. {nucs-4.0.0 → nucs-4.3.0}/tests/heuristics/test_mid_value_dom_heuristic.py +0 -0
  132. {nucs-4.0.0 → nucs-4.3.0}/tests/heuristics/test_min_value_dom_heuristic.py +0 -0
  133. {nucs-4.0.0 → nucs-4.3.0}/tests/problems/__init__.py +0 -0
  134. {nucs-4.0.0 → nucs-4.3.0}/tests/problems/test_circuit_problem.py +0 -0
  135. {nucs-4.0.0 → nucs-4.3.0}/tests/problems/test_problem.py +0 -0
  136. {nucs-4.0.0 → nucs-4.3.0}/tests/propagators/__init__.py +0 -0
  137. {nucs-4.0.0 → nucs-4.3.0}/tests/propagators/test_affine_eq.py +0 -0
  138. {nucs-4.0.0 → nucs-4.3.0}/tests/propagators/test_affine_geq.py +0 -0
  139. {nucs-4.0.0 → nucs-4.3.0}/tests/propagators/test_affine_leq.py +0 -0
  140. {nucs-4.0.0 → nucs-4.3.0}/tests/propagators/test_alldifferent.py +0 -0
  141. {nucs-4.0.0 → nucs-4.3.0}/tests/propagators/test_count_eq.py +0 -0
  142. {nucs-4.0.0 → nucs-4.3.0}/tests/propagators/test_element_iv.py +0 -0
  143. {nucs-4.0.0 → nucs-4.3.0}/tests/propagators/test_element_lic.py +0 -0
  144. {nucs-4.0.0 → nucs-4.3.0}/tests/propagators/test_element_liv.py +0 -0
  145. {nucs-4.0.0 → nucs-4.3.0}/tests/propagators/test_exactly_eq.py +0 -0
  146. {nucs-4.0.0 → nucs-4.3.0}/tests/propagators/test_gcc.py +0 -0
  147. {nucs-4.0.0 → nucs-4.3.0}/tests/propagators/test_lexicographic_leq.py +0 -0
  148. {nucs-4.0.0 → nucs-4.3.0}/tests/propagators/test_max_eq.py +0 -0
  149. {nucs-4.0.0 → nucs-4.3.0}/tests/propagators/test_max_leq.py +0 -0
  150. {nucs-4.0.0 → nucs-4.3.0}/tests/propagators/test_min_eq.py +0 -0
  151. {nucs-4.0.0 → nucs-4.3.0}/tests/propagators/test_min_geq.py +0 -0
  152. {nucs-4.0.0 → nucs-4.3.0}/tests/propagators/test_relation.py +0 -0
  153. {nucs-4.0.0 → nucs-4.3.0}/tests/propagators/test_scc.py +0 -0
  154. {nucs-4.0.0 → nucs-4.3.0}/tests/solvers/__init__.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: NUCS
3
- Version: 4.0.0
3
+ Version: 4.3.0
4
4
  Summary: A Numpy and Numba based Python library for solving Constraint Satisfaction Problems over finite domains
5
5
  Author-email: Yan Georget <yan.georget@gmail.com>
6
6
  Project-URL: Homepage, https://github.com/yangeorget/nucs
@@ -52,6 +52,7 @@ nucs/examples/tsp/__main__.py
52
52
  nucs/examples/tsp/total_cost_propagator.py
53
53
  nucs/examples/tsp/tsp_instances.py
54
54
  nucs/examples/tsp/tsp_problem.py
55
+ nucs/examples/tsp/tsp_var_heuristic.py
55
56
  nucs/heuristics/__init__.py
56
57
  nucs/heuristics/first_not_instantiated_var_heuristic.py
57
58
  nucs/heuristics/greatest_domain_var_heuristic.py
@@ -62,11 +63,13 @@ nucs/heuristics/mid_value_dom_heuristic.py
62
63
  nucs/heuristics/min_cost_dom_heuristic.py
63
64
  nucs/heuristics/min_value_dom_heuristic.py
64
65
  nucs/heuristics/smallest_domain_var_heuristic.py
66
+ nucs/heuristics/split_high_dom_heuristic.py
65
67
  nucs/heuristics/split_low_dom_heuristic.py
66
68
  nucs/heuristics/value_dom_heuristic.py
67
69
  nucs/problems/__init__.py
68
70
  nucs/problems/circuit_problem.py
69
71
  nucs/problems/latin_square_problem.py
72
+ nucs/problems/permutation_problem.py
70
73
  nucs/problems/problem.py
71
74
  nucs/propagators/__init__.py
72
75
  nucs/propagators/affine_eq_propagator.py
@@ -88,6 +91,7 @@ nucs/propagators/max_leq_propagator.py
88
91
  nucs/propagators/min_eq_propagator.py
89
92
  nucs/propagators/min_geq_propagator.py
90
93
  nucs/propagators/no_sub_cycle_propagator.py
94
+ nucs/propagators/permutation_aux_propagator.py
91
95
  nucs/propagators/propagators.py
92
96
  nucs/propagators/relation_propagator.py
93
97
  nucs/propagators/scc_propagator.py
@@ -120,6 +124,7 @@ tests/heuristics/test_mid_value_dom_heuristic.py
120
124
  tests/heuristics/test_min_value_dom_heuristic.py
121
125
  tests/problems/__init__.py
122
126
  tests/problems/test_circuit_problem.py
127
+ tests/problems/test_permutation_problem.py
123
128
  tests/problems/test_problem.py
124
129
  tests/propagators/__init__.py
125
130
  tests/propagators/test_affine_eq.py
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: NUCS
3
- Version: 4.0.0
3
+ Version: 4.3.0
4
4
  Summary: A Numpy and Numba based Python library for solving Constraint Satisfaction Problems over finite domains
5
5
  Author-email: Yan Georget <yan.georget@gmail.com>
6
6
  Project-URL: Homepage, https://github.com/yangeorget/nucs
@@ -6,8 +6,8 @@ project = 'NUCS'
6
6
  copyright = '2024, Yan Georget'
7
7
  author = 'Yan Georget'
8
8
 
9
- release = '4.0.0'
10
- version = '4.0.0'
9
+ release = '4.3.0'
10
+ version = '4.3.0'
11
11
 
12
12
  # -- General configuration
13
13
 
@@ -14,6 +14,10 @@ import os
14
14
 
15
15
  from numba import bool, int32, int64, types, uint8, uint16 # type: ignore
16
16
 
17
+ OPT_RESET = "RESET"
18
+ OPT_PRUNE = "PRUNE"
19
+ OPT_MODES = [OPT_RESET, OPT_PRUNE]
20
+
17
21
  RG_START = 0 # index corresponding the start of a values range
18
22
  RG_END = 1 # index corresponding the end of a values range
19
23
 
@@ -61,18 +65,18 @@ SIGNATURE_CONSISTENCY_ALG = int64(
61
65
  uint16[:], # decision_domains
62
66
  )
63
67
  SIGNATURE_DOM_HEURISTIC = int64(
64
- int64[:, :], # dom_heuristic_params
65
68
  int32[:, :, :], # shr_domains_stack
66
69
  bool[:, :], # not_entailed_propagators_stack
67
70
  uint16[:, :], # dom_update_stack
68
71
  uint8[:], # stacks_top
69
72
  int64, # dom_idx
73
+ int64[:, :], # dom_heuristic_params
70
74
  )
71
75
  SIGNATURE_VAR_HEURISTIC = int64(
72
- int64[:, :], # var_heuristic_params
73
76
  uint16[:], # decision_variables
74
77
  int32[:, :, :], # shr_domains_stack
75
78
  uint8[:], # stacks_top
79
+ int64[:, :], # var_heuristic_params
76
80
  )
77
81
 
78
82
 
@@ -24,7 +24,7 @@ class AlphaProblem(Problem):
24
24
  """
25
25
  The numbers from 1 to 26 are assigned to the letters of the alphabet.
26
26
  The numbers beside each word are the total of the values assigned to the letters in the word
27
- (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).
27
+ (eg for LYRE: L,Y,R,E might be to equal 5,9,20 and 13 or any other combination that add up to 47).
28
28
 
29
29
  Find the value of each letter under the equations:
30
30
  BALLET 45 GLEE 66 POLKA 59 SONG 61
@@ -67,7 +67,8 @@ class AlphaProblem(Problem):
67
67
  ]
68
68
  )
69
69
 
70
- def solution_as_dict(self, solution: NDArray) -> Dict[str, int]:
70
+ @staticmethod
71
+ def solution_as_dict(solution: NDArray) -> Dict[str, int]:
71
72
  """
72
73
  Returns the solution as a dict.
73
74
  :param solution: the solution as a list of ints
@@ -28,10 +28,12 @@ if __name__ == "__main__":
28
28
  parser.add_argument("-r", type=int)
29
29
  parser.add_argument("-k", type=int)
30
30
  parser.add_argument("-l", type=int)
31
- parser.add_argument("--symmetry_breaking", action=argparse.BooleanOptionalAction, default=True)
32
31
  parser.add_argument("--log_level", choices=LOG_LEVELS, default=LOG_LEVEL_INFO)
32
+ parser.add_argument("--symmetry_breaking", action=argparse.BooleanOptionalAction, default=True)
33
33
  args = parser.parse_args()
34
34
  problem = BIBDProblem(args.v, args.b, args.r, args.k, args.l, args.symmetry_breaking)
35
- solver = BacktrackSolver(problem, dom_heuristic_idx=DOM_HEURISTIC_MAX_VALUE, log_level=args.log_level)
35
+ solver = BacktrackSolver(
36
+ problem, dom_heuristic_idx=DOM_HEURISTIC_MAX_VALUE, log_level=args.log_level, stack_max_height=128
37
+ )
36
38
  solver.solve_all()
37
39
  print(solver.get_statistics())
@@ -10,9 +10,9 @@
10
10
  #
11
11
  # Copyright 2024 - Yan Georget
12
12
  ###############################################################################
13
- from typing import Dict
13
+ from typing import Any, Dict
14
14
 
15
- from numpy._typing import NDArray
15
+ from numpy.typing import NDArray
16
16
 
17
17
  from nucs.problems.problem import Problem
18
18
  from nucs.propagators.propagators import ALG_AFFINE_EQ, ALG_ALLDIFFERENT
@@ -40,7 +40,8 @@ class DonaldProblem(Problem):
40
40
  )
41
41
  self.add_propagator(([A, B, D, E, G, L, N, O, R, T], ALG_ALLDIFFERENT, []))
42
42
 
43
- def solution_as_dict(self, solution: NDArray) -> Dict[str, int]:
43
+ @staticmethod
44
+ def solution_as_dict(solution: NDArray) -> Dict[str, Any]:
44
45
  """
45
46
  Returns the solution as a dict.
46
47
  :param solution: the solution as a list of ints
@@ -14,23 +14,39 @@ import argparse
14
14
 
15
15
  from rich import print
16
16
 
17
- from nucs.constants import LOG_LEVEL_INFO, LOG_LEVELS
17
+ from nucs.constants import LOG_LEVEL_INFO, LOG_LEVELS, OPT_MODES, OPT_PRUNE
18
18
  from nucs.examples.golomb.golomb_problem import GolombProblem, golomb_consistency_algorithm
19
19
  from nucs.solvers.backtrack_solver import BacktrackSolver
20
20
  from nucs.solvers.consistency_algorithms import register_consistency_algorithm
21
+ from nucs.solvers.multiprocessing_solver import MultiprocessingSolver
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.golomb -n 10 --symmetry_breaking
24
25
  if __name__ == "__main__":
25
26
  parser = argparse.ArgumentParser()
26
27
  parser.add_argument("-n", type=int, default=10)
27
- parser.add_argument("--symmetry_breaking", action=argparse.BooleanOptionalAction, default=True)
28
28
  parser.add_argument("--log_level", choices=LOG_LEVELS, default=LOG_LEVEL_INFO)
29
+ parser.add_argument("--opt_mode", choices=OPT_MODES, default=OPT_PRUNE)
30
+ parser.add_argument("--processors", type=int, default=1)
31
+ parser.add_argument("--symmetry_breaking", action=argparse.BooleanOptionalAction, default=True)
29
32
  args = parser.parse_args()
30
33
  problem = GolombProblem(args.n, args.symmetry_breaking)
31
34
  consistency_alg_golomb = register_consistency_algorithm(golomb_consistency_algorithm)
32
- solver = BacktrackSolver(problem, consistency_alg_idx=consistency_alg_golomb, log_level=args.log_level)
33
- solution = solver.minimize(problem.length_idx)
35
+ solver = (
36
+ MultiprocessingSolver(
37
+ [
38
+ BacktrackSolver(
39
+ prob, consistency_alg_idx=consistency_alg_golomb, log_level=args.log_level, stack_max_height=128
40
+ )
41
+ for prob in problem.split(args.processors, 0)
42
+ ]
43
+ )
44
+ if args.processors > 1
45
+ else BacktrackSolver(
46
+ problem, consistency_alg_idx=consistency_alg_golomb, log_level=args.log_level, stack_max_height=128
47
+ )
48
+ )
49
+ solution = solver.minimize(problem.length_idx, mode=args.opt_mode)
34
50
  print(solver.get_statistics())
35
51
  if solution is not None:
36
52
  print(solution[: (args.n - 1)])
@@ -19,14 +19,14 @@ from numpy.typing import NDArray
19
19
  from nucs.constants import EVENT_MASK_GROUND, EVENT_MASK_MIN, MAX, MIN
20
20
  from nucs.heuristics.heuristics import first_not_instantiated_var_heuristic
21
21
  from nucs.problems.problem import Problem
22
- from nucs.propagators.propagators import ALG_AFFINE_EQ, ALG_AFFINE_LEQ, ALG_ALLDIFFERENT, add_propagators
22
+ from nucs.propagators.propagators import ALG_AFFINE_EQ, ALG_AFFINE_LEQ, ALG_ALLDIFFERENT, update_propagators
23
23
  from nucs.solvers.bound_consistency_algorithm import bound_consistency_algorithm
24
24
 
25
25
  GOLOMB_LENGTHS = np.array([0, 0, 1, 3, 6, 11, 17, 25, 34, 44, 55, 72, 85, 106, 127])
26
26
 
27
27
 
28
28
  @njit(cache=True)
29
- def sum_first(n: np.uint32) -> np.uint32:
29
+ def sum_first(n: int) -> int:
30
30
  """
31
31
  Returns the sum of the first n integers.
32
32
  :param n: an integer
@@ -36,7 +36,7 @@ def sum_first(n: np.uint32) -> np.uint32:
36
36
 
37
37
 
38
38
  @njit(cache=True)
39
- def index(mark_nb: np.uint32, i: np.uint32, j: np.uint32) -> np.uint32:
39
+ def index(mark_nb: int, i: int, j: int) -> int:
40
40
  """
41
41
  Returns the index of the distance variable between two marks.
42
42
  :param mark_nb: the total number of marks
@@ -47,22 +47,6 @@ def index(mark_nb: np.uint32, i: np.uint32, j: np.uint32) -> np.uint32:
47
47
  return i * mark_nb - sum_first(i) + j - i - 1
48
48
 
49
49
 
50
- @njit(cache=True)
51
- def init_domains(dist_nb: int, mark_nb: int) -> NDArray:
52
- """
53
- Returns the domains.
54
- :param dist_nb: the number of distances
55
- :param mark_nb: the number of marks
56
- :return: a Numpy array of domains
57
- """
58
- domains = np.empty((dist_nb, 2), dtype=np.int32)
59
- for i in range(0, mark_nb - 1):
60
- for j in range(i + 1, mark_nb):
61
- domains[index(mark_nb, i, j), MIN] = GOLOMB_LENGTHS[j - i + 1] if j - i + 1 < mark_nb else sum_first(j - i)
62
- domains[:, MAX] = sum_first(dist_nb)
63
- return domains
64
-
65
-
66
50
  class GolombProblem(Problem):
67
51
  """
68
52
  This is the famous Golomb ruler problem.
@@ -77,7 +61,15 @@ class GolombProblem(Problem):
77
61
  """
78
62
 
79
63
  def __init__(self, mark_nb: int, symmetry_breaking: bool = True) -> None:
80
- super().__init__(init_domains(sum_first(mark_nb - 1), mark_nb))
64
+ dist_nb = sum_first(mark_nb - 1)
65
+ domains = np.empty((dist_nb, 2), dtype=np.int32)
66
+ for i in range(0, mark_nb - 1):
67
+ for j in range(i + 1, mark_nb):
68
+ domains[index(mark_nb, i, j), MIN] = (
69
+ GOLOMB_LENGTHS[j - i + 1] if j - i + 1 < mark_nb else sum_first(j - i)
70
+ )
71
+ domains[:, MAX] = sum_first(dist_nb) - sum_first(dist_nb - mark_nb)
72
+ super().__init__(domains)
81
73
  self.length_idx = index(mark_nb, 0, mark_nb - 1) # we want to minimize this
82
74
  # dist_ij = mark_j - mark_i for j > i
83
75
  # mark_j = dist_0j for j > 0
@@ -142,7 +134,7 @@ def golomb_consistency_algorithm(
142
134
  # first prune the search space
143
135
  mark_nb = (1 + int(math.sqrt(8 * len(dom_indices_arr) + 1))) // 2
144
136
  ni_var_idx = first_not_instantiated_var_heuristic(
145
- None, decision_domains, shr_domains_stack, stacks_top
137
+ decision_domains, shr_domains_stack, stacks_top, None
146
138
  ) # no domains shared between vars
147
139
  if 1 < ni_var_idx < mark_nb - 1: # otherwise useless
148
140
  used_distance = np.zeros(sum_first(mark_nb - 2) + 1, dtype=np.bool)
@@ -169,7 +161,7 @@ def golomb_consistency_algorithm(
169
161
  events = EVENT_MASK_MIN
170
162
  if shr_domains_stack[top, dom_idx, MIN] == shr_domains_stack[top, dom_idx, MAX]:
171
163
  events |= EVENT_MASK_GROUND
172
- add_propagators(
164
+ update_propagators(
173
165
  triggered_propagators,
174
166
  not_entailed_propagators_stack[top],
175
167
  shr_domains_propagators,
@@ -14,7 +14,7 @@ import argparse
14
14
 
15
15
  from rich import print
16
16
 
17
- from nucs.constants import LOG_LEVEL_INFO, LOG_LEVELS
17
+ from nucs.constants import LOG_LEVEL_INFO, LOG_LEVELS, OPT_MODES, OPT_RESET
18
18
  from nucs.examples.knapsack.knapsack_problem import KnapsackProblem
19
19
  from nucs.heuristics.heuristics import DOM_HEURISTIC_MAX_VALUE, VAR_HEURISTIC_FIRST_NOT_INSTANTIATED
20
20
  from nucs.solvers.backtrack_solver import BacktrackSolver
@@ -24,6 +24,7 @@ from nucs.solvers.backtrack_solver import BacktrackSolver
24
24
  if __name__ == "__main__":
25
25
  parser = argparse.ArgumentParser()
26
26
  parser.add_argument("--log_level", choices=LOG_LEVELS, default=LOG_LEVEL_INFO)
27
+ parser.add_argument("--opt_mode", choices=OPT_MODES, default=OPT_RESET)
27
28
  args = parser.parse_args()
28
29
  problem = KnapsackProblem(
29
30
  [40, 40, 38, 38, 36, 36, 34, 34, 32, 32, 30, 30, 28, 28, 26, 26, 24, 24, 22, 22],
@@ -36,6 +37,6 @@ if __name__ == "__main__":
36
37
  dom_heuristic_idx=DOM_HEURISTIC_MAX_VALUE,
37
38
  log_level=args.log_level,
38
39
  )
39
- solution = solver.maximize(problem.weight)
40
+ solution = solver.maximize(problem.weight, mode=args.opt_mode)
40
41
  print(solver.get_statistics())
41
42
  print(solution)
@@ -23,8 +23,8 @@ from nucs.solvers.backtrack_solver import BacktrackSolver
23
23
  # NUMBA_CACHE_DIR=.numba/cache python -m nucs.examples.magic_sequence -n 100
24
24
  if __name__ == "__main__":
25
25
  parser = argparse.ArgumentParser()
26
- parser.add_argument("-n", type=int, default=100)
27
26
  parser.add_argument("--log_level", choices=LOG_LEVELS, default=LOG_LEVEL_INFO)
27
+ parser.add_argument("-n", type=int, default=100)
28
28
  args = parser.parse_args()
29
29
  problem = MagicSequenceProblem(args.n)
30
30
  solver = BacktrackSolver(
@@ -33,6 +33,7 @@ if __name__ == "__main__":
33
33
  var_heuristic_idx=VAR_HEURISTIC_FIRST_NOT_INSTANTIATED,
34
34
  dom_heuristic_idx=DOM_HEURISTIC_MIN_VALUE,
35
35
  log_level=args.log_level,
36
+ stack_max_height=128,
36
37
  )
37
38
  solver.solve_all()
38
39
  print(solver.get_statistics())
@@ -23,9 +23,9 @@ from nucs.solvers.backtrack_solver import BacktrackSolver
23
23
  # NUMBA_CACHE_DIR=.numba/cache python -m nucs.examples.magic_square -n 4 --symmetry_breaking
24
24
  if __name__ == "__main__":
25
25
  parser = argparse.ArgumentParser()
26
- parser.add_argument("-n", type=int)
27
- parser.add_argument("--symmetry_breaking", action=argparse.BooleanOptionalAction, default=True)
28
26
  parser.add_argument("--log_level", choices=LOG_LEVELS, default=LOG_LEVEL_INFO)
27
+ parser.add_argument("-n", type=int, default=4)
28
+ parser.add_argument("--symmetry_breaking", action=argparse.BooleanOptionalAction, default=True)
29
29
  args = parser.parse_args()
30
30
  problem = MagicSquareProblem(args.n, args.symmetry_breaking)
31
31
  solver = BacktrackSolver(
@@ -37,6 +37,7 @@ class QueensProblem(Problem):
37
37
  self.add_propagator((list(range(n, 2 * n)), ALG_ALLDIFFERENT, []))
38
38
  self.add_propagator((list(range(2 * n, 3 * n)), ALG_ALLDIFFERENT, []))
39
39
 
40
- def solution_as_matrix(self, solution: List[int]) -> List[List[str]]:
40
+ @staticmethod
41
+ def solution_as_matrix(solution: List[int]) -> List[List[str]]:
41
42
  n = len(solution)
42
43
  return [([" "] * i + ["X"] + [" "] * (n - i - 1)) for i in range(n)]
@@ -22,11 +22,11 @@ from nucs.solvers.backtrack_solver import BacktrackSolver
22
22
  # NUMBA_CACHE_DIR=.numba/cache python -m nucs.examples.schur_lemma -n 20 --symmetry_breaking
23
23
  if __name__ == "__main__":
24
24
  parser = argparse.ArgumentParser()
25
- parser.add_argument("-n", type=int, default=20)
26
25
  parser.add_argument("--log_level", choices=LOG_LEVELS, default=LOG_LEVEL_INFO)
26
+ parser.add_argument("-n", type=int, default=20)
27
27
  parser.add_argument("--symmetry_breaking", action=argparse.BooleanOptionalAction, default=True)
28
28
  args = parser.parse_args()
29
29
  problem = SchurLemmaProblem(args.n, args.symmetry_breaking)
30
- solver = BacktrackSolver(problem, log_level=args.log_level)
30
+ solver = BacktrackSolver(problem, log_level=args.log_level, stack_max_height=128)
31
31
  solver.solve_all()
32
32
  print(solver.get_statistics())
@@ -12,7 +12,7 @@
12
12
  ###############################################################################
13
13
  from typing import List
14
14
 
15
- from numpy._typing import NDArray
15
+ from numpy.typing import NDArray
16
16
 
17
17
  from nucs.problems.problem import Problem
18
18
  from nucs.propagators.propagators import ALG_ALLDIFFERENT, ALG_EXACTLY_EQ, ALG_GCC, ALG_RELATION
@@ -0,0 +1,69 @@
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 argparse
14
+
15
+ from nucs.constants import LOG_LEVEL_INFO, LOG_LEVELS, OPT_MODES, OPT_PRUNE
16
+ from nucs.examples.tsp.tsp_instances import TSP_INSTANCES
17
+ from nucs.examples.tsp.tsp_problem import TSPProblem
18
+ from nucs.examples.tsp.tsp_var_heuristic import tsp_var_heuristic
19
+ from nucs.heuristics.heuristics import DOM_HEURISTIC_MIN_COST, register_var_heuristic
20
+ from nucs.solvers.backtrack_solver import BacktrackSolver
21
+ from nucs.solvers.consistency_algorithms import CONSISTENCY_ALG_BC, CONSISTENCY_ALG_SHAVING
22
+ from nucs.solvers.multiprocessing_solver import MultiprocessingSolver
23
+
24
+ # Run with the following command (the second run is much faster because the code has been compiled):
25
+ # NUMBA_CACHE_DIR=.numba/cache python -m nucs.examples.alpha
26
+ if __name__ == "__main__":
27
+ parser = argparse.ArgumentParser()
28
+ parser.add_argument("--log_level", choices=LOG_LEVELS, default=LOG_LEVEL_INFO)
29
+ parser.add_argument("--name", choices=["GR17", "GR21", "GR24"], default="GR17")
30
+ parser.add_argument("--opt_mode", choices=OPT_MODES, default=OPT_PRUNE)
31
+ parser.add_argument("--processors", type=int, default=1)
32
+ parser.add_argument("--shaving", type=bool, action=argparse.BooleanOptionalAction, default=False)
33
+ args = parser.parse_args()
34
+ tsp_instance = TSP_INSTANCES[args.name]
35
+ n = len(tsp_instance)
36
+ decision_domains = list(range(0, 2 * n))
37
+ problem = TSPProblem(tsp_instance)
38
+ costs = tsp_instance + tsp_instance # symmetry of costs
39
+ tsp_var_heuristic_idx = register_var_heuristic(tsp_var_heuristic)
40
+ solver = (
41
+ MultiprocessingSolver(
42
+ [
43
+ BacktrackSolver(
44
+ prob,
45
+ consistency_alg_idx=CONSISTENCY_ALG_SHAVING if args.shaving else CONSISTENCY_ALG_BC,
46
+ decision_domains=decision_domains,
47
+ var_heuristic_idx=tsp_var_heuristic_idx,
48
+ var_heuristic_params=costs,
49
+ dom_heuristic_idx=DOM_HEURISTIC_MIN_COST,
50
+ dom_heuristic_params=costs,
51
+ log_level=args.log_level,
52
+ )
53
+ for prob in problem.split(args.processors, 0)
54
+ ]
55
+ )
56
+ if args.processors > 1
57
+ else BacktrackSolver(
58
+ problem,
59
+ consistency_alg_idx=CONSISTENCY_ALG_SHAVING if args.shaving else CONSISTENCY_ALG_BC,
60
+ decision_domains=decision_domains,
61
+ var_heuristic_idx=tsp_var_heuristic_idx,
62
+ var_heuristic_params=costs,
63
+ dom_heuristic_idx=DOM_HEURISTIC_MIN_COST,
64
+ dom_heuristic_params=costs,
65
+ log_level=args.log_level,
66
+ )
67
+ )
68
+ solution = solver.minimize(problem.total_cost, mode=args.opt_mode)
69
+ print(solver.get_statistics())
@@ -26,7 +26,7 @@ def get_complexity_total_cost(n: int, parameters: NDArray) -> float:
26
26
  :param parameters: the parameters, unused here
27
27
  :return: a float
28
28
  """
29
- return 2 * n
29
+ return n * n
30
30
 
31
31
 
32
32
  def get_triggers_total_cost(n: int, parameters: NDArray) -> NDArray:
@@ -53,13 +53,24 @@ def compute_domains_total_cost(domains: NDArray, parameters: NDArray) -> int:
53
53
  for i in range(n):
54
54
  if domains[i, MIN] == domains[i, MAX]:
55
55
  used[domains[i, MIN]] = True
56
- global_min = global_max = 0
56
+ global_min = 0
57
+ # for j in range(n):
58
+ # max_regret = 0
59
+ # min_cost = min([costs[i, j] for i in range(n) if costs[i,j] > 0])
60
+ # for i in range(n):
61
+ # if costs[i, j] == min_cost:
62
+ # regret = compute_regret(domains[i], costs[i])
63
+ # if regret > max_regret:
64
+ # max_regret = regret
65
+ # global_min += regret
66
+ # global_min -= max_regret
67
+ global_max = 0
57
68
  for i in range(n):
58
- local_min = sys.maxsize
59
- local_max = 0
60
69
  if domains[i, MIN] == domains[i, MAX]:
61
70
  local_min = local_max = parameters[i * n + domains[i, MIN]]
62
71
  else:
72
+ local_min = sys.maxsize
73
+ local_max = 0
63
74
  for value in range(domains[i, MIN], domains[i, MAX] + 1):
64
75
  if not used[value]:
65
76
  cost = parameters[i * n + value]
@@ -68,8 +79,8 @@ def compute_domains_total_cost(domains: NDArray, parameters: NDArray) -> int:
68
79
  local_min = cost
69
80
  if cost > local_max:
70
81
  local_max = cost
71
- if local_min > local_max:
72
- return PROP_INCONSISTENCY
82
+ # if local_min > local_max:
83
+ # return PROP_INCONSISTENCY
73
84
  global_min += local_min
74
85
  global_max += local_max
75
86
  domains[-1, MIN] = max(domains[-1, MIN], global_min)
@@ -33,18 +33,21 @@ class TSPProblem(CircuitProblem):
33
33
  super().__init__(n)
34
34
  max_costs = [max(cost_row) for cost_row in cost_rows]
35
35
  min_costs = [min([cost for cost in cost_row if cost > 0]) for cost_row in cost_rows]
36
- cost_vars = self.add_variables([(min_costs[i], max_costs[i]) for i in range(n)]) # the costs
37
- total_cost_var = self.add_variable((sum(min_costs), sum(max_costs))) # the total cost
36
+ self.next_costs = self.add_variables([(min_costs[i], max_costs[i]) for i in range(n)])
37
+ self.prev_costs = self.add_variables([(min_costs[i], max_costs[i]) for i in range(n)])
38
+ self.total_cost = self.add_variable((sum(min_costs), sum(max_costs))) # the total cost
38
39
  for i in range(n):
39
- self.add_propagator(([i, cost_vars + i], ALG_ELEMENT_IV, cost_rows[i]))
40
- self.add_propagator((list(range(cost_vars, cost_vars + n + 1)), ALG_AFFINE_EQ, [1] * n + [-1, 0]))
41
- alg_total_cost = register_propagator(
42
- get_triggers_total_cost, get_complexity_total_cost, compute_domains_total_cost
40
+ self.add_propagator(([i, self.next_costs + i], ALG_ELEMENT_IV, cost_rows[i]))
41
+ self.add_propagator(([n + i, self.prev_costs + i], ALG_ELEMENT_IV, cost_rows[i]))
42
+ self.add_propagator(
43
+ (list(range(self.next_costs, self.next_costs + n)) + [self.total_cost], ALG_AFFINE_EQ, [1] * n + [-1, 0])
43
44
  )
44
45
  self.add_propagator(
45
- (
46
- list(range(0, n)) + [total_cost_var],
47
- alg_total_cost,
48
- [cost for cost_row in cost_rows for cost in cost_row],
49
- )
46
+ (list(range(self.prev_costs, self.prev_costs + n)) + [self.total_cost], ALG_AFFINE_EQ, [1] * n + [-1, 0])
47
+ )
48
+ total_cost_prop_idx = register_propagator(
49
+ get_triggers_total_cost, get_complexity_total_cost, compute_domains_total_cost
50
50
  )
51
+ costs = [cost for cost_row in cost_rows for cost in cost_row]
52
+ self.add_propagator((list(range(n)) + [self.total_cost], total_cost_prop_idx, costs))
53
+ self.add_propagator((list(range(n, 2 * n)) + [self.total_cost], total_cost_prop_idx, costs))
@@ -0,0 +1,52 @@
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 sys
14
+
15
+ from numba import njit # type: ignore
16
+ from numpy.typing import NDArray
17
+
18
+ from nucs.constants import MAX, MIN
19
+ from nucs.heuristics.max_regret_var_heuristic import regret
20
+
21
+
22
+ @njit(cache=True)
23
+ def tsp_var_heuristic(
24
+ decision_domains: NDArray, shr_domains_stack: NDArray, stacks_top: NDArray, params: NDArray
25
+ ) -> int:
26
+ """
27
+ :param decision_domains: the indices of a subset of the shared domains
28
+ :param shr_domains_stack: the stack of shared domains
29
+ :param stacks_top: the index of the top of the stacks as a Numpy array
30
+ :param params: a two-dimensional (first dimension correspond to variables, second to values) costs array
31
+ :return: the index of the shared domain
32
+ """
33
+ best_score = -sys.maxsize
34
+ best_idx = -1
35
+ top = stacks_top[0]
36
+ for dom_idx in decision_domains:
37
+ shr_domain = shr_domains_stack[top, dom_idx]
38
+ if 0 < shr_domain[MAX] - shr_domain[MIN]:
39
+ score = compute_score(shr_domain, dom_idx, params)
40
+ if best_score < score:
41
+ best_idx = dom_idx
42
+ best_score = score
43
+ return best_idx
44
+
45
+
46
+ @njit(cache=True)
47
+ def compute_score(shr_domain: NDArray, dom_idx: int, params: NDArray) -> int:
48
+ """
49
+ Minimize [min(5, size(X)), -regret(X)] for lexicographic order.
50
+ """
51
+ size = min(12, shr_domain[MAX] - shr_domain[MIN] + 1)
52
+ return -size * 1024 + regret(shr_domain, params[dom_idx])
@@ -18,18 +18,18 @@ from nucs.constants import MAX, MIN
18
18
 
19
19
  @njit(cache=True)
20
20
  def first_not_instantiated_var_heuristic(
21
- params: NDArray, decision_domains: NDArray, shr_domains_stack: NDArray, stacks_top: NDArray
21
+ decision_domains: NDArray, shr_domains_stack: NDArray, stacks_top: NDArray, params: NDArray
22
22
  ) -> int:
23
23
  """
24
24
  Chooses the first non-instantiated shared domain.
25
- :param params: a two-dimensional parameters array, unused here
26
25
  :param decision_domains: the indices of a subset of the shared domains
27
26
  :param shr_domains_stack: the stack of shared domains
28
27
  :param stacks_top: the index of the top of the stacks as a Numpy array
28
+ :param params: a two-dimensional parameters array, unused here
29
29
  :return: the index of the shared domain
30
30
  """
31
- cp_top_idx = stacks_top[0]
31
+ top = stacks_top[0]
32
32
  for dom_idx in decision_domains:
33
- if shr_domains_stack[cp_top_idx, dom_idx, MIN] < shr_domains_stack[cp_top_idx, dom_idx, MAX]:
33
+ if shr_domains_stack[top, dom_idx, MIN] < shr_domains_stack[top, dom_idx, MAX]:
34
34
  return dom_idx
35
35
  return -1 # cannot happen
@@ -18,23 +18,23 @@ from nucs.constants import MAX, MIN
18
18
 
19
19
  @njit(cache=True)
20
20
  def greatest_domain_var_heuristic(
21
- params: NDArray, decision_domains: NDArray, shr_domains_stack: NDArray, stacks_top: NDArray
21
+ decision_domains: NDArray, shr_domains_stack: NDArray, stacks_top: NDArray, params: NDArray
22
22
  ) -> int:
23
23
  """
24
24
  Chooses the greatest shared domain and which is not instantiated.
25
- :param params: a two-dimensional parameters array, unused here
26
25
  :param decision_domains: the indices of a subset of the shared domains
27
26
  :param shr_domains_stack: the stack of shared domains
28
27
  :param stacks_top: the index of the top of the stacks as a Numpy array
28
+ :param params: a two-dimensional parameters array, unused here
29
29
  :return: the index of the shared domain
30
30
  """
31
- max_size = 0
32
- max_idx = -1
33
- cp_top_idx = stacks_top[0]
31
+ best_score = 0
32
+ best_idx = -1
33
+ top = stacks_top[0]
34
34
  for dom_idx in decision_domains:
35
- shr_domain = shr_domains_stack[cp_top_idx, dom_idx]
36
- size = shr_domain[MAX] - shr_domain[MIN] # actually this is size - 1
37
- if max_size < size:
38
- max_idx = dom_idx
39
- max_size = size
40
- return max_idx
35
+ shr_domain = shr_domains_stack[top, dom_idx]
36
+ score = shr_domain[MAX] - shr_domain[MIN] # this is size - 1
37
+ if best_score < score:
38
+ best_idx = dom_idx
39
+ best_score = score
40
+ return best_idx