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.
- {nucs-4.4 → nucs-4.4.4/NuCS.egg-info}/PKG-INFO +9 -4
- {nucs-4.4/NUCS.egg-info → nucs-4.4.4/NuCS.egg-info}/SOURCES.txt +5 -5
- nucs-4.4.4/NuCS.egg-info/requires.txt +3 -0
- {nucs-4.4/NUCS.egg-info → nucs-4.4.4}/PKG-INFO +9 -4
- {nucs-4.4 → nucs-4.4.4}/docs/source/conf.py +3 -3
- {nucs-4.4 → nucs-4.4.4}/nucs/examples/quasigroup/__main__.py +10 -4
- nucs-4.4.4/nucs/examples/quasigroup/quasigroup_problem.py +116 -0
- {nucs-4.4 → nucs-4.4.4}/nucs/propagators/element_iv_propagator.py +8 -9
- {nucs-4.4 → nucs-4.4.4}/nucs/propagators/element_lic_propagator.py +9 -10
- {nucs-4.4 → nucs-4.4.4}/nucs/propagators/element_liv_propagator.py +8 -9
- {nucs-4.4 → nucs-4.4.4}/pyproject.toml +9 -4
- {nucs-4.4 → nucs-4.4.4}/tests/examples/test_bibd.py +8 -15
- nucs-4.4.4/tests/examples/test_quasigroup.py +62 -0
- {nucs-4.4 → nucs-4.4.4}/tests/examples/test_sudokus.py +13 -12
- {nucs-4.4 → nucs-4.4.4}/tests/propagators/test_element_liv.py +1 -0
- nucs-4.4/NUCS.egg-info/requires.txt +0 -2
- nucs-4.4/nucs/examples/quasigroup/quasigroup_problem.py +0 -63
- nucs-4.4/tests/examples/test_quasigroup.py +0 -39
- {nucs-4.4 → nucs-4.4.4}/LICENSE.md +0 -0
- {nucs-4.4/NUCS.egg-info → nucs-4.4.4/NuCS.egg-info}/dependency_links.txt +0 -0
- {nucs-4.4/NUCS.egg-info → nucs-4.4.4/NuCS.egg-info}/top_level.txt +0 -0
- {nucs-4.4 → nucs-4.4.4}/README.md +0 -0
- {nucs-4.4 → nucs-4.4.4}/nucs/__init__.py +0 -0
- {nucs-4.4 → nucs-4.4.4}/nucs/constants.py +0 -0
- {nucs-4.4 → nucs-4.4.4}/nucs/examples/__init__.py +0 -0
- {nucs-4.4 → nucs-4.4.4}/nucs/examples/alpha/__init__.py +0 -0
- {nucs-4.4 → nucs-4.4.4}/nucs/examples/alpha/__main__.py +0 -0
- {nucs-4.4 → nucs-4.4.4}/nucs/examples/alpha/alpha_problem.py +0 -0
- {nucs-4.4 → nucs-4.4.4}/nucs/examples/bibd/__init__.py +0 -0
- {nucs-4.4 → nucs-4.4.4}/nucs/examples/bibd/__main__.py +0 -0
- {nucs-4.4 → nucs-4.4.4}/nucs/examples/bibd/bibd_problem.py +0 -0
- {nucs-4.4 → nucs-4.4.4}/nucs/examples/donald/__init__.py +0 -0
- {nucs-4.4 → nucs-4.4.4}/nucs/examples/donald/__main__.py +0 -0
- {nucs-4.4 → nucs-4.4.4}/nucs/examples/donald/donald_problem.py +0 -0
- {nucs-4.4 → nucs-4.4.4}/nucs/examples/golomb/__init__.py +0 -0
- {nucs-4.4 → nucs-4.4.4}/nucs/examples/golomb/__main__.py +0 -0
- {nucs-4.4 → nucs-4.4.4}/nucs/examples/golomb/golomb_problem.py +0 -0
- {nucs-4.4 → nucs-4.4.4}/nucs/examples/knapsack/__init__.py +0 -0
- {nucs-4.4 → nucs-4.4.4}/nucs/examples/knapsack/__main__.py +0 -0
- {nucs-4.4 → nucs-4.4.4}/nucs/examples/knapsack/knapsack_problem.py +0 -0
- {nucs-4.4 → nucs-4.4.4}/nucs/examples/magic_sequence/__init__.py +0 -0
- {nucs-4.4 → nucs-4.4.4}/nucs/examples/magic_sequence/__main__.py +0 -0
- {nucs-4.4 → nucs-4.4.4}/nucs/examples/magic_sequence/magic_sequence_problem.py +0 -0
- {nucs-4.4 → nucs-4.4.4}/nucs/examples/magic_square/__init__.py +0 -0
- {nucs-4.4 → nucs-4.4.4}/nucs/examples/magic_square/__main__.py +0 -0
- {nucs-4.4 → nucs-4.4.4}/nucs/examples/magic_square/magic_square_problem.py +0 -0
- {nucs-4.4 → nucs-4.4.4}/nucs/examples/quasigroup/__init__.py +0 -0
- {nucs-4.4 → nucs-4.4.4}/nucs/examples/queens/__init__.py +0 -0
- {nucs-4.4 → nucs-4.4.4}/nucs/examples/queens/__main__.py +0 -0
- {nucs-4.4 → nucs-4.4.4}/nucs/examples/queens/queens_problem.py +0 -0
- {nucs-4.4 → nucs-4.4.4}/nucs/examples/schur_lemma/__init__.py +0 -0
- {nucs-4.4 → nucs-4.4.4}/nucs/examples/schur_lemma/__main__.py +0 -0
- {nucs-4.4 → nucs-4.4.4}/nucs/examples/schur_lemma/schur_lemma_problem.py +0 -0
- {nucs-4.4 → nucs-4.4.4}/nucs/examples/sports_tournament_scheduling/__init__.py +0 -0
- {nucs-4.4 → nucs-4.4.4}/nucs/examples/sports_tournament_scheduling/__main__.py +0 -0
- {nucs-4.4 → nucs-4.4.4}/nucs/examples/sports_tournament_scheduling/sports_tournament_scheduling_problem.py +0 -0
- {nucs-4.4 → nucs-4.4.4}/nucs/examples/sudoku/__init__.py +0 -0
- {nucs-4.4 → nucs-4.4.4}/nucs/examples/sudoku/sudoku_problem.py +0 -0
- {nucs-4.4 → nucs-4.4.4}/nucs/examples/tsp/__init__.py +0 -0
- {nucs-4.4 → nucs-4.4.4}/nucs/examples/tsp/__main__.py +0 -0
- {nucs-4.4 → nucs-4.4.4}/nucs/examples/tsp/total_cost_propagator.py +0 -0
- {nucs-4.4 → nucs-4.4.4}/nucs/examples/tsp/tsp_instances.py +0 -0
- {nucs-4.4 → nucs-4.4.4}/nucs/examples/tsp/tsp_problem.py +0 -0
- {nucs-4.4 → nucs-4.4.4}/nucs/examples/tsp/tsp_var_heuristic.py +0 -0
- {nucs-4.4 → nucs-4.4.4}/nucs/heuristics/__init__.py +0 -0
- {nucs-4.4 → nucs-4.4.4}/nucs/heuristics/first_not_instantiated_var_heuristic.py +0 -0
- {nucs-4.4 → nucs-4.4.4}/nucs/heuristics/greatest_domain_var_heuristic.py +0 -0
- {nucs-4.4 → nucs-4.4.4}/nucs/heuristics/heuristics.py +0 -0
- {nucs-4.4 → nucs-4.4.4}/nucs/heuristics/max_regret_var_heuristic.py +0 -0
- {nucs-4.4 → nucs-4.4.4}/nucs/heuristics/max_value_dom_heuristic.py +0 -0
- {nucs-4.4 → nucs-4.4.4}/nucs/heuristics/mid_value_dom_heuristic.py +0 -0
- {nucs-4.4 → nucs-4.4.4}/nucs/heuristics/min_cost_dom_heuristic.py +0 -0
- {nucs-4.4 → nucs-4.4.4}/nucs/heuristics/min_value_dom_heuristic.py +0 -0
- {nucs-4.4 → nucs-4.4.4}/nucs/heuristics/smallest_domain_var_heuristic.py +0 -0
- {nucs-4.4 → nucs-4.4.4}/nucs/heuristics/split_high_dom_heuristic.py +0 -0
- {nucs-4.4 → nucs-4.4.4}/nucs/heuristics/split_low_dom_heuristic.py +0 -0
- {nucs-4.4 → nucs-4.4.4}/nucs/heuristics/value_dom_heuristic.py +0 -0
- {nucs-4.4 → nucs-4.4.4}/nucs/numba_helper.py +0 -0
- {nucs-4.4 → nucs-4.4.4}/nucs/numpy_helper.py +0 -0
- {nucs-4.4 → nucs-4.4.4}/nucs/problems/__init__.py +0 -0
- {nucs-4.4 → nucs-4.4.4}/nucs/problems/circuit_problem.py +0 -0
- {nucs-4.4 → nucs-4.4.4}/nucs/problems/latin_square_problem.py +0 -0
- {nucs-4.4 → nucs-4.4.4}/nucs/problems/permutation_problem.py +0 -0
- {nucs-4.4 → nucs-4.4.4}/nucs/problems/problem.py +0 -0
- {nucs-4.4 → nucs-4.4.4}/nucs/propagators/__init__.py +0 -0
- {nucs-4.4 → nucs-4.4.4}/nucs/propagators/affine_eq_propagator.py +0 -0
- {nucs-4.4 → nucs-4.4.4}/nucs/propagators/affine_geq_propagator.py +0 -0
- {nucs-4.4 → nucs-4.4.4}/nucs/propagators/affine_leq_propagator.py +0 -0
- {nucs-4.4 → nucs-4.4.4}/nucs/propagators/alldifferent_propagator.py +0 -0
- {nucs-4.4 → nucs-4.4.4}/nucs/propagators/and_propagator.py +0 -0
- {nucs-4.4 → nucs-4.4.4}/nucs/propagators/count_eq_propagator.py +0 -0
- {nucs-4.4 → nucs-4.4.4}/nucs/propagators/dummy_propagator.py +0 -0
- {nucs-4.4 → nucs-4.4.4}/nucs/propagators/exactly_eq_propagator.py +0 -0
- {nucs-4.4 → nucs-4.4.4}/nucs/propagators/exactly_true_propagator.py +0 -0
- {nucs-4.4 → nucs-4.4.4}/nucs/propagators/gcc_propagator.py +0 -0
- {nucs-4.4 → nucs-4.4.4}/nucs/propagators/lexicographic_leq_propagator.py +0 -0
- {nucs-4.4 → nucs-4.4.4}/nucs/propagators/max_eq_propagator.py +0 -0
- {nucs-4.4 → nucs-4.4.4}/nucs/propagators/max_leq_propagator.py +0 -0
- {nucs-4.4 → nucs-4.4.4}/nucs/propagators/min_eq_propagator.py +0 -0
- {nucs-4.4 → nucs-4.4.4}/nucs/propagators/min_geq_propagator.py +0 -0
- {nucs-4.4 → nucs-4.4.4}/nucs/propagators/no_sub_cycle_propagator.py +0 -0
- {nucs-4.4 → nucs-4.4.4}/nucs/propagators/permutation_aux_propagator.py +0 -0
- {nucs-4.4 → nucs-4.4.4}/nucs/propagators/propagators.py +0 -0
- {nucs-4.4 → nucs-4.4.4}/nucs/propagators/relation_propagator.py +0 -0
- {nucs-4.4 → nucs-4.4.4}/nucs/propagators/scc_propagator.py +0 -0
- {nucs-4.4 → nucs-4.4.4}/nucs/solvers/__init__.py +0 -0
- {nucs-4.4 → nucs-4.4.4}/nucs/solvers/backtrack_solver.py +0 -0
- {nucs-4.4 → nucs-4.4.4}/nucs/solvers/bound_consistency_algorithm.py +0 -0
- {nucs-4.4 → nucs-4.4.4}/nucs/solvers/choice_points.py +0 -0
- {nucs-4.4 → nucs-4.4.4}/nucs/solvers/consistency_algorithms.py +0 -0
- {nucs-4.4 → nucs-4.4.4}/nucs/solvers/multiprocessing_solver.py +0 -0
- {nucs-4.4 → nucs-4.4.4}/nucs/solvers/shaving_consistency_algorithm.py +0 -0
- {nucs-4.4 → nucs-4.4.4}/nucs/solvers/solver.py +0 -0
- {nucs-4.4 → nucs-4.4.4}/setup.cfg +0 -0
- {nucs-4.4 → nucs-4.4.4}/tests/__init__.py +0 -0
- {nucs-4.4 → nucs-4.4.4}/tests/examples/test_alpha.py +0 -0
- {nucs-4.4 → nucs-4.4.4}/tests/examples/test_donald.py +0 -0
- {nucs-4.4 → nucs-4.4.4}/tests/examples/test_golomb.py +0 -0
- {nucs-4.4 → nucs-4.4.4}/tests/examples/test_knapsack.py +0 -0
- {nucs-4.4 → nucs-4.4.4}/tests/examples/test_latin_square.py +0 -0
- {nucs-4.4 → nucs-4.4.4}/tests/examples/test_magic_sequence.py +0 -0
- {nucs-4.4 → nucs-4.4.4}/tests/examples/test_magic_square.py +0 -0
- {nucs-4.4 → nucs-4.4.4}/tests/examples/test_queens.py +0 -0
- {nucs-4.4 → nucs-4.4.4}/tests/examples/test_schur_lemma.py +0 -0
- {nucs-4.4 → nucs-4.4.4}/tests/examples/test_sports_tournament_scheduling.py +0 -0
- {nucs-4.4 → nucs-4.4.4}/tests/examples/test_tsp.py +0 -0
- {nucs-4.4 → nucs-4.4.4}/tests/heuristics/__init__.py +0 -0
- {nucs-4.4 → nucs-4.4.4}/tests/heuristics/test_max_value_dom_heuristic.py +0 -0
- {nucs-4.4 → nucs-4.4.4}/tests/heuristics/test_mid_value_dom_heuristic.py +0 -0
- {nucs-4.4 → nucs-4.4.4}/tests/heuristics/test_min_value_dom_heuristic.py +0 -0
- {nucs-4.4 → nucs-4.4.4}/tests/problems/__init__.py +0 -0
- {nucs-4.4 → nucs-4.4.4}/tests/problems/test_circuit_problem.py +0 -0
- {nucs-4.4 → nucs-4.4.4}/tests/problems/test_permutation_problem.py +0 -0
- {nucs-4.4 → nucs-4.4.4}/tests/problems/test_problem.py +0 -0
- {nucs-4.4 → nucs-4.4.4}/tests/propagators/__init__.py +0 -0
- {nucs-4.4 → nucs-4.4.4}/tests/propagators/test_affine_eq.py +0 -0
- {nucs-4.4 → nucs-4.4.4}/tests/propagators/test_affine_geq.py +0 -0
- {nucs-4.4 → nucs-4.4.4}/tests/propagators/test_affine_leq.py +0 -0
- {nucs-4.4 → nucs-4.4.4}/tests/propagators/test_alldifferent.py +0 -0
- {nucs-4.4 → nucs-4.4.4}/tests/propagators/test_count_eq.py +0 -0
- {nucs-4.4 → nucs-4.4.4}/tests/propagators/test_element_iv.py +0 -0
- {nucs-4.4 → nucs-4.4.4}/tests/propagators/test_element_lic.py +0 -0
- {nucs-4.4 → nucs-4.4.4}/tests/propagators/test_exactly_eq.py +0 -0
- {nucs-4.4 → nucs-4.4.4}/tests/propagators/test_gcc.py +0 -0
- {nucs-4.4 → nucs-4.4.4}/tests/propagators/test_lexicographic_leq.py +0 -0
- {nucs-4.4 → nucs-4.4.4}/tests/propagators/test_max_eq.py +0 -0
- {nucs-4.4 → nucs-4.4.4}/tests/propagators/test_max_leq.py +0 -0
- {nucs-4.4 → nucs-4.4.4}/tests/propagators/test_min_eq.py +0 -0
- {nucs-4.4 → nucs-4.4.4}/tests/propagators/test_min_geq.py +0 -0
- {nucs-4.4 → nucs-4.4.4}/tests/propagators/test_no_sub_cycle.py +0 -0
- {nucs-4.4 → nucs-4.4.4}/tests/propagators/test_relation.py +0 -0
- {nucs-4.4 → nucs-4.4.4}/tests/propagators/test_scc.py +0 -0
- {nucs-4.4 → nucs-4.4.4}/tests/solvers/__init__.py +0 -0
- {nucs-4.4 → nucs-4.4.4}/tests/solvers/test_backtrack_solver.py +0 -0
- {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:
|
|
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 ::
|
|
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
|
|
25
|
+
Requires-Dist: numpy<2.1
|
|
26
|
+
Requires-Dist: rich
|
|
22
27
|
|
|
23
28
|

|
|
24
29
|
|
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
LICENSE.md
|
|
2
2
|
README.md
|
|
3
3
|
pyproject.toml
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
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
|
|
@@ -1,16 +1,20 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
|
-
Name:
|
|
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 ::
|
|
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
|
|
25
|
+
Requires-Dist: numpy<2.1
|
|
26
|
+
Requires-Dist: rich
|
|
22
27
|
|
|
23
28
|

|
|
24
29
|
|
|
@@ -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
|
|
19
|
-
from nucs.heuristics.heuristics import
|
|
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 =
|
|
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=
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
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
|
-
|
|
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
|
-
|
|
57
|
+
if start == -1:
|
|
58
|
+
start = idx
|
|
60
59
|
if idx == i[MIN]:
|
|
61
60
|
i[MIN] += 1
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
i[MAX]
|
|
66
|
-
|
|
67
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
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="
|
|
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 ::
|
|
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
|
|
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
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
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] ==
|
|
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
|
-
|
|
20
|
-
|
|
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,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
|
-
)
|