diff --git a/.github/workflows/build-test-python-package-pull.yml b/.github/workflows/build-test-python-package-pull.yml new file mode 100644 index 0000000..801a2f5 --- /dev/null +++ b/.github/workflows/build-test-python-package-pull.yml @@ -0,0 +1,23 @@ +# This workflow will use Nox to run tests and lint for the supported Python versions, and upload the test coverage data. + +name: Build & Test + +on: + pull_request: + branches: + - main + +jobs: + build: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - uses: fjwillemsen/setup-nox2@v3.0.0 + - run: | + nox -- ${{ runner.os }} + - name: Report to Coveralls + uses: coverallsapp/github-action@v2 + with: + file: coverage.xml + format: cobertura + fail-on-error: false diff --git a/.github/workflows/build-test-python-package.yml b/.github/workflows/build-test-python-package.yml index 62da4f6..a2951ed 100644 --- a/.github/workflows/build-test-python-package.yml +++ b/.github/workflows/build-test-python-package.yml @@ -2,6 +2,7 @@ name: Build & Test +# Do not run this workflow on pull request since this workflow has permission to modify contents. on: push: branches: @@ -14,20 +15,43 @@ on: - "noxfile.py" - "pyproject.toml" - ".github/workflows/build-test-python-package.yml" - pull_request: - branches: - - main + +permissions: + # deployments permission to deploy GitHub pages website + deployments: write + # contents permission to update benchmark contents in gh-pages branch + contents: write jobs: build: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 + with: + fetch-depth: 0 # fetch all history to avoid detached HEAD state when pushing benchmark results + - name: Download previous benchmark data + uses: actions/cache@v4 + with: + path: ./cache + key: ${{ runner.os }}-benchmark - uses: fjwillemsen/setup-nox2@v3.0.0 - run: | - nox + nox -- ${{ runner.os }} + - name: Store benchmark result + uses: benchmark-action/github-action-benchmark@v1 + with: + tool: "pytest" + output-file-path: .benchmarks/benchmark_${{ runner.os }}_3.13.json + external-data-json-path: ./cache/benchmark-data.json + fail-on-alert: true + # GitHub API token to make a commit comment + github-token: ${{ secrets.GITHUB_TOKEN }} + comment-always: true + summary-always: true + # alert-comment-cc-users: '@fjwillemsen' mention a GitHub user in the comment - name: Report to Coveralls uses: coverallsapp/github-action@v2 with: file: coverage.xml format: cobertura + fail-on-error: false diff --git a/.gitignore b/.gitignore index c8e2636..01fce1b 100644 --- a/.gitignore +++ b/.gitignore @@ -34,6 +34,7 @@ pip-log.txt pip-delete-this-directory.txt # Unit test / coverage reports +.benchmarks htmlcov/ .tox/ .coverage diff --git a/README.rst b/README.rst index 98ffb57..fb2cfbd 100644 --- a/README.rst +++ b/README.rst @@ -173,7 +173,8 @@ For an overview of recent changes, visit the `Changelog `_ automated with `GH actions `_ +- Rewrite hotspots in C / Pyx instead of pure python mode +- Improvements to make the ParallelSolver competitive (experiments reveal the freethreading mode to be promising) - Versioned documentation Contact diff --git a/constraint/problem.py b/constraint/problem.py index 4641718..0ae1e07 100644 --- a/constraint/problem.py +++ b/constraint/problem.py @@ -11,6 +11,12 @@ from constraint.solvers import Solver, OptimizedBacktrackingSolver, ParallelSolver from constraint.parser import compile_to_constraints +try: + from sys import _is_gil_enabled + freethreading = _is_gil_enabled() +except ImportError: + freethreading = False + class Problem: """Class used to define a problem and retrieve solutions.""" @@ -26,9 +32,14 @@ def __init__(self, solver: Solver=None): self._str_constraints: list[str] = [] self._variables: dict[Hashable, Domain] = {} + # check if solver is instance instead of class + assert isinstance(self._solver, Solver), f"`solver` is not instance of Solver class (is {type(self._solver)})." + # warn for experimental parallel solver if isinstance(self._solver, ParallelSolver): warn("ParallelSolver is currently experimental, and unlikely to be faster than OptimizedBacktrackingSolver. Please report any issues.") # future: remove # noqa E501 + if not self._solver._process_mode and not freethreading: + warn("Using the ParallelSolver in ThreadPool mode without freethreading will cause poor performance.") def reset(self): """Reset the current problem definition. diff --git a/constraint/solvers.c b/constraint/solvers.c index 0538049..a43770c 100644 --- a/constraint/solvers.c +++ b/constraint/solvers.c @@ -1497,10 +1497,10 @@ static const char *__pyx_f[] = { /*--- Type declarations ---*/ struct __pyx_obj_10constraint_7solvers___pyx_scope_struct__getSolutionIter; struct __pyx_obj_10constraint_7solvers___pyx_scope_struct_1_getSolutionIter; -struct __pyx_obj_10constraint_7solvers___pyx_scope_struct_2_is_valid; +struct __pyx_obj_10constraint_7solvers___pyx_scope_struct_2_getSolutionsList; struct __pyx_obj_10constraint_7solvers___pyx_scope_struct_3_genexpr; -struct __pyx_obj_10constraint_7solvers___pyx_scope_struct_4_genexpr; -struct __pyx_obj_10constraint_7solvers___pyx_scope_struct_5_getSolutionsList; +struct __pyx_obj_10constraint_7solvers___pyx_scope_struct_4_is_valid; +struct __pyx_obj_10constraint_7solvers___pyx_scope_struct_5_genexpr; struct __pyx_obj_10constraint_7solvers___pyx_scope_struct_6_genexpr; /* "constraint/solvers.py":153 @@ -1559,30 +1559,65 @@ struct __pyx_obj_10constraint_7solvers___pyx_scope_struct_1_getSolutionIter { }; -/* "constraint/solvers.py":609 +/* "constraint/solvers.py":662 + * raise NotImplementedError(msg) + * + * def getSolutionsList(self, domains: dict[Hashable, Domain], vconstraints: dict[Hashable, list[tuple[Constraint, Hashable]]]) -> list[dict[Hashable, any]]: # noqa: D102, E501 # <<<<<<<<<<<<<< + * """Parallelized all-solutions finder using ProcessPoolExecutor for work-stealing.""" + * # Precompute constraints lookup per variable + */ +struct __pyx_obj_10constraint_7solvers___pyx_scope_struct_2_getSolutionsList { + PyObject_HEAD + PyObject *__pyx_v_constraint_lookup; + PyObject *__pyx_v_domains; + PyObject *__pyx_v_first_var; + PyObject *__pyx_v_remaining_vars; + PyObject *__pyx_v_self; +}; + + +/* "constraint/solvers.py":675 + * + * # Create the parallel function arguments and solutions lists + * args = ((self.requires_pickling, domains, constraint_lookup, first_var, val, remaining_vars.copy()) for val in domains[first_var]) # noqa: E501 # <<<<<<<<<<<<<< + * solutions: list[dict[Hashable, any]] = [] + * + */ +struct __pyx_obj_10constraint_7solvers___pyx_scope_struct_3_genexpr { + PyObject_HEAD + struct __pyx_obj_10constraint_7solvers___pyx_scope_struct_2_getSolutionsList *__pyx_outer_scope; + PyObject *__pyx_genexpr_arg_0; + PyObject *__pyx_v_val; + PyObject *__pyx_t_0; + Py_ssize_t __pyx_t_1; + PyObject *(*__pyx_t_2)(PyObject *); +}; + + +/* "constraint/solvers.py":693 * ### Helper functions for parallel solver * * def is_valid(assignment: dict[Hashable, any], constraints_lookup: list[tuple[Constraint, Hashable]], domains: dict[Hashable, Domain]) -> bool: # noqa E501 # <<<<<<<<<<<<<< * """Check if all constraints are satisfied given the current assignment.""" * return all( */ -struct __pyx_obj_10constraint_7solvers___pyx_scope_struct_2_is_valid { +struct __pyx_obj_10constraint_7solvers___pyx_scope_struct_4_is_valid { PyObject_HEAD PyObject *__pyx_v_assignment; PyObject *__pyx_v_domains; }; -/* "constraint/solvers.py":612 +/* "constraint/solvers.py":696 * """Check if all constraints are satisfied given the current assignment.""" * return all( * constraint(vars_involved, domains, assignment, None) # <<<<<<<<<<<<<< * for constraint, vars_involved in constraints_lookup * if all(v in assignment for v in vars_involved) */ -struct __pyx_obj_10constraint_7solvers___pyx_scope_struct_3_genexpr { +struct __pyx_obj_10constraint_7solvers___pyx_scope_struct_5_genexpr { PyObject_HEAD - struct __pyx_obj_10constraint_7solvers___pyx_scope_struct_2_is_valid *__pyx_outer_scope; + struct __pyx_obj_10constraint_7solvers___pyx_scope_struct_4_is_valid *__pyx_outer_scope; PyObject *__pyx_genexpr_arg_0; PyObject *__pyx_v_constraint; PyObject *__pyx_v_genexpr; @@ -1590,53 +1625,18 @@ struct __pyx_obj_10constraint_7solvers___pyx_scope_struct_3_genexpr { }; -/* "constraint/solvers.py":614 +/* "constraint/solvers.py":698 * constraint(vars_involved, domains, assignment, None) * for constraint, vars_involved in constraints_lookup * if all(v in assignment for v in vars_involved) # <<<<<<<<<<<<<< * ) * */ -struct __pyx_obj_10constraint_7solvers___pyx_scope_struct_4_genexpr { - PyObject_HEAD - struct __pyx_obj_10constraint_7solvers___pyx_scope_struct_3_genexpr *__pyx_outer_scope; - PyObject *__pyx_genexpr_arg_0; - PyObject *__pyx_v_v; -}; - - -/* "constraint/solvers.py":760 - * raise NotImplementedError(msg) - * - * def getSolutionsList(self, domains: dict[Hashable, Domain], vconstraints: dict[Hashable, list[tuple[Constraint, Hashable]]]) -> list[dict[Hashable, any]]: # noqa: D102, E501 # <<<<<<<<<<<<<< - * """Parallelized all-solutions finder using ProcessPoolExecutor for work-stealing.""" - * # Precompute constraints lookup per variable - */ -struct __pyx_obj_10constraint_7solvers___pyx_scope_struct_5_getSolutionsList { - PyObject_HEAD - PyObject *__pyx_v_constraint_lookup; - PyObject *__pyx_v_domains; - PyObject *__pyx_v_first_var; - PyObject *__pyx_v_remaining_vars; - PyObject *__pyx_v_self; -}; - - -/* "constraint/solvers.py":773 - * - * # Create the parallel function arguments and solutions lists - * args = ((self.requires_pickling, domains, constraint_lookup, first_var, val, remaining_vars.copy()) for val in domains[first_var]) # noqa: E501 # <<<<<<<<<<<<<< - * solutions: list[dict[Hashable, any]] = [] - * - */ struct __pyx_obj_10constraint_7solvers___pyx_scope_struct_6_genexpr { PyObject_HEAD - struct __pyx_obj_10constraint_7solvers___pyx_scope_struct_5_getSolutionsList *__pyx_outer_scope; + struct __pyx_obj_10constraint_7solvers___pyx_scope_struct_5_genexpr *__pyx_outer_scope; PyObject *__pyx_genexpr_arg_0; - PyObject *__pyx_v_val; - PyObject *__pyx_t_0; - Py_ssize_t __pyx_t_1; - PyObject *(*__pyx_t_2)(PyObject *); + PyObject *__pyx_v_v; }; /* #### Code section: utility_code_proto ### */ @@ -2276,42 +2276,11 @@ static CYTHON_INLINE int __Pyx_PyObject_SetSlice( PyObject** py_start, PyObject** py_stop, PyObject** py_slice, int has_cstart, int has_cstop, int wraparound); -/* RaiseUnboundLocalError.proto */ -static CYTHON_INLINE void __Pyx_RaiseUnboundLocalError(const char *varname); - /* RaiseClosureNameError.proto */ static CYTHON_INLINE void __Pyx_RaiseClosureNameError(const char *varname); -/* GetAttr.proto */ -static CYTHON_INLINE PyObject *__Pyx_GetAttr(PyObject *, PyObject *); - -/* Globals.proto */ -static PyObject* __Pyx_Globals(void); - -/* SliceTupleAndList.proto */ -#if CYTHON_COMPILING_IN_CPYTHON -static CYTHON_INLINE PyObject* __Pyx_PyList_GetSlice(PyObject* src, Py_ssize_t start, Py_ssize_t stop); -static CYTHON_INLINE PyObject* __Pyx_PyTuple_GetSlice(PyObject* src, Py_ssize_t start, Py_ssize_t stop); -#else -#define __Pyx_PyList_GetSlice(seq, start, stop) PySequence_GetSlice(seq, start, stop) -#define __Pyx_PyTuple_GetSlice(seq, start, stop) PySequence_GetSlice(seq, start, stop) -#endif - -/* ListExtend.proto */ -static CYTHON_INLINE int __Pyx_PyList_Extend(PyObject* L, PyObject* v) { -#if CYTHON_COMPILING_IN_CPYTHON && PY_VERSION_HEX < 0x030d0000 - PyObject* none = _PyList_Extend((PyListObject*)L, v); - if (unlikely(!none)) - return -1; - Py_DECREF(none); - return 0; -#else - return PyList_SetSlice(L, PY_SSIZE_T_MAX, PY_SSIZE_T_MAX, v); -#endif -} - -/* RaiseUnexpectedTypeError.proto */ -static int __Pyx_RaiseUnexpectedTypeError(const char *expected, PyObject *obj); +/* RaiseUnboundLocalError.proto */ +static CYTHON_INLINE void __Pyx_RaiseUnboundLocalError(const char *varname); /* dict_getitem_default.proto */ static PyObject* __Pyx_PyDict_GetItemDefault(PyObject* d, PyObject* key, PyObject* default_value); @@ -2472,6 +2441,18 @@ static PyObject *__Pyx_CyFunction_New(PyMethodDef *ml, PyObject *module, PyObject *globals, PyObject* code); +/* RaiseUnexpectedTypeError.proto */ +static int __Pyx_RaiseUnexpectedTypeError(const char *expected, PyObject *obj); + +/* SliceTupleAndList.proto */ +#if CYTHON_COMPILING_IN_CPYTHON +static CYTHON_INLINE PyObject* __Pyx_PyList_GetSlice(PyObject* src, Py_ssize_t start, Py_ssize_t stop); +static CYTHON_INLINE PyObject* __Pyx_PyTuple_GetSlice(PyObject* src, Py_ssize_t start, Py_ssize_t stop); +#else +#define __Pyx_PyList_GetSlice(seq, start, stop) PySequence_GetSlice(seq, start, stop) +#define __Pyx_PyTuple_GetSlice(seq, start, stop) PySequence_GetSlice(seq, start, stop) +#endif + /* PyObjectLookupSpecial.proto */ #if CYTHON_USE_PYTYPE_LOOKUP && CYTHON_USE_TYPE_SLOTS #define __Pyx_PyObject_LookupSpecialNoError(obj, attr_name) __Pyx__PyObject_LookupSpecial(obj, attr_name, 0) @@ -2482,6 +2463,25 @@ static CYTHON_INLINE PyObject* __Pyx__PyObject_LookupSpecial(PyObject* obj, PyOb #define __Pyx_PyObject_LookupSpecial(o,n) __Pyx_PyObject_GetAttrStr(o,n) #endif +/* ListExtend.proto */ +static CYTHON_INLINE int __Pyx_PyList_Extend(PyObject* L, PyObject* v) { +#if CYTHON_COMPILING_IN_CPYTHON && PY_VERSION_HEX < 0x030d0000 + PyObject* none = _PyList_Extend((PyListObject*)L, v); + if (unlikely(!none)) + return -1; + Py_DECREF(none); + return 0; +#else + return PyList_SetSlice(L, PY_SSIZE_T_MAX, PY_SSIZE_T_MAX, v); +#endif +} + +/* GetAttr.proto */ +static CYTHON_INLINE PyObject *__Pyx_GetAttr(PyObject *, PyObject *); + +/* Globals.proto */ +static PyObject* __Pyx_Globals(void); + /* ValidateBasesTuple.proto */ #if CYTHON_COMPILING_IN_CPYTHON || CYTHON_COMPILING_IN_LIMITED_API || CYTHON_USE_TYPE_SPECS static int __Pyx_validate_bases_tuple(const char *type_name, Py_ssize_t dictoffset, PyObject *bases); @@ -2713,9 +2713,9 @@ static PyObject *__pyx_builtin_NotImplementedError; static PyObject *__pyx_builtin_RuntimeError; static PyObject *__pyx_builtin_StopIteration; static PyObject *__pyx_builtin_range; -static PyObject *__pyx_builtin_compile; static PyObject *__pyx_builtin_super; static PyObject *__pyx_builtin_sorted; +static PyObject *__pyx_builtin_compile; /* #### Code section: string_decls ### */ static const char __pyx_k_c[] = "c"; static const char __pyx_k_v[] = "v"; @@ -2914,7 +2914,7 @@ static const char __pyx_k_Module_containing_the_code_for_t[] = "Module containin static const char __pyx_k_OptimizedBacktrackingSolver___in[] = "OptimizedBacktrackingSolver.__init__"; static const char __pyx_k_OptimizedBacktrackingSolver_getS[] = "OptimizedBacktrackingSolver.getSolutionIter"; static const char __pyx_k_Problem_solver_based_on_the_mini[] = "Problem solver based on the minimum conflicts theory.\n\n Examples:\n >>> result = [[('a', 1), ('b', 2)],\n ... [('a', 1), ('b', 3)],\n ... [('a', 2), ('b', 3)]]\n\n >>> problem = Problem(MinConflictsSolver())\n >>> problem.addVariables([\"a\", \"b\"], [1, 2, 3])\n >>> problem.addConstraint(lambda a, b: b > a, [\"a\", \"b\"])\n\n >>> solution = problem.getSolution()\n >>> sorted(solution.items()) in result\n True\n\n >>> problem.getSolutions()\n Traceback (most recent call last):\n ...\n NotImplementedError: MinConflictsSolver provides only a single solution\n\n >>> problem.getSolutionIter()\n Traceback (most recent call last):\n ...\n NotImplementedError: MinConflictsSolver doesn't provide iteration\n "; -static const char __pyx_k_Problem_solver_that_executes_all[] = "Problem solver that executes all-solution solve in parallel (ProcessPool or ThreadPool mode).\n\n Sorts the domains on size, creating jobs for each value in the domain with the most variables.\n Each leaf job is solved locally with either optimized backtracking or recursion.\n Whether this is actually faster than non-parallel solving depends on your problem, and hardware and software environment. \n\n Uses ThreadPool by default. Instantiate with process_mode=True to use ProcessPool. \n In ProcessPool mode, the jobs do not share memory.\n In ProcessPool mode, precompiled FunctionConstraints are not allowed due to pickling, use string constraints instead.\n\n Examples:\n >>> result = [[('a', 1), ('b', 2)],\n ... [('a', 1), ('b', 3)],\n ... [('a', 2), ('b', 3)]]\n\n >>> problem = Problem(ParallelSolver())\n >>> problem.addVariables([\"a\", \"b\"], [1, 2, 3])\n >>> problem.addConstraint(\"b > a\", [\"a\", \"b\"])\n\n >>> for solution in problem.getSolutions():\n ... sorted(solution.items()) in result\n True\n True\n True\n\n >>> problem.getSolution()\n Traceback (most recent call last):\n ...\n NotImplementedError: ParallelSolver only provides all solutions\n\n >>> problem.getSolutionIter()\n Traceback (most recent call last):\n ...\n NotImplementedError: ParallelSolver doesn't provide iteration\n "; +static const char __pyx_k_Problem_solver_that_executes_all[] = "Problem solver that executes all-solution solve in parallel (ProcessPool or ThreadPool mode).\n\n Sorts the domains on size, creating jobs for each value in the domain with the most variables.\n Each leaf job is solved locally with either optimized backtracking or recursion.\n Whether this is actually faster than non-parallel solving depends on your problem, and hardware and software environment. \n\n Uses ThreadPool by default. Instantiate with process_mode=True to use ProcessPool. \n In ProcessPool mode, the jobs do not share memory.\n In ProcessPool mode, precompiled FunctionConstraints are not allowed due to pickling, use string constraints instead.\n\n Examples:\n >>> result = [[('a', 1), ('b', 2)],\n ... [('a', 1), ('b', 3)],\n ... [('a', 2), ('b', 3)]]\n\n >>> problem = Problem(ParallelSolver())\n >>> problem.addVariables([\"a\", \"b\"], [1, 2, 3])\n >>> problem.addConstraint(\"b > a\", [\"a\", \"b\"])\n\n >>> for solution in problem.getSolutions():\n ... sorted(solution.items()) in result\n True\n True\n True\n\n >>> problem.getSolution()\n Traceback (most recent call last):\n ...\n NotImplementedError: ParallelSolver only provides all solutions\n\n >>> problem.getSolutionIter()\n Traceback (most recent call last):\n ...\n NotImplementedError: ParallelSolver doesn't provide iteration\n "; static const char __pyx_k_Problem_solver_with_backtracking[] = "Problem solver with backtracking capabilities.\n\n Examples:\n >>> result = [[('a', 1), ('b', 2)],\n ... [('a', 1), ('b', 3)],\n ... [('a', 2), ('b', 3)]]\n\n >>> problem = Problem(BacktrackingSolver())\n >>> problem.addVariables([\"a\", \"b\"], [1, 2, 3])\n >>> problem.addConstraint(lambda a, b: b > a, [\"a\", \"b\"])\n\n >>> solution = problem.getSolution()\n >>> sorted(solution.items()) in result\n True\n\n >>> for solution in problem.getSolutionIter():\n ... sorted(solution.items()) in result\n True\n True\n True\n\n >>> for solution in problem.getSolutions():\n ... sorted(solution.items()) in result\n True\n True\n True\n "; static const char __pyx_k_RecursiveBacktrackingSolver___in[] = "RecursiveBacktrackingSolver.__init__"; static const char __pyx_k_RecursiveBacktrackingSolver_getS[] = "RecursiveBacktrackingSolver.getSolution"; @@ -2952,6 +2952,12 @@ static PyObject *__pyx_pf_10constraint_7solvers_27RecursiveBacktrackingSolver_4g static PyObject *__pyx_pf_10constraint_7solvers_27RecursiveBacktrackingSolver_6getSolutions(CYTHON_UNUSED PyObject *__pyx_self, PyObject *__pyx_v_self, PyObject *__pyx_v_domains, CYTHON_UNUSED PyObject *__pyx_v_constraints, PyObject *__pyx_v_vconstraints); /* proto */ static PyObject *__pyx_pf_10constraint_7solvers_18MinConflictsSolver___init__(CYTHON_UNUSED PyObject *__pyx_self, PyObject *__pyx_v_self, PyObject *__pyx_v_steps, PyObject *__pyx_v_rand); /* proto */ static PyObject *__pyx_pf_10constraint_7solvers_18MinConflictsSolver_2getSolution(CYTHON_UNUSED PyObject *__pyx_self, PyObject *__pyx_v_self, PyObject *__pyx_v_domains, CYTHON_UNUSED PyObject *__pyx_v_constraints, PyObject *__pyx_v_vconstraints); /* proto */ +static PyObject *__pyx_pf_10constraint_7solvers_14ParallelSolver___init__(CYTHON_UNUSED PyObject *__pyx_self, PyObject *__pyx_v_self, PyObject *__pyx_v_process_mode); /* proto */ +static PyObject *__pyx_pf_10constraint_7solvers_14ParallelSolver_2getSolution(CYTHON_UNUSED PyObject *__pyx_self, PyObject *__pyx_v_self, CYTHON_UNUSED PyObject *__pyx_v_domains, CYTHON_UNUSED PyObject *__pyx_v_constraints, CYTHON_UNUSED PyObject *__pyx_v_vconstraints); /* proto */ +static PyObject *__pyx_lambda_funcdef_lambda(PyObject *__pyx_self, PyObject *__pyx_v_v); /* proto */ +static PyObject *__pyx_pf_10constraint_7solvers_14ParallelSolver_16getSolutionsList_1genexpr(PyObject *__pyx_self, PyObject *__pyx_genexpr_arg_0); /* proto */ +static PyObject *__pyx_pf_10constraint_7solvers_14ParallelSolver_4getSolutionsList(CYTHON_UNUSED PyObject *__pyx_self, PyObject *__pyx_v_self, PyObject *__pyx_v_domains, PyObject *__pyx_v_vconstraints); /* proto */ +static PyObject *__pyx_pf_10constraint_7solvers_14ParallelSolver_6getSolutions(CYTHON_UNUSED PyObject *__pyx_self, PyObject *__pyx_v_self, PyObject *__pyx_v_domains, CYTHON_UNUSED PyObject *__pyx_v_constraints, PyObject *__pyx_v_vconstraints); /* proto */ static PyObject *__pyx_pf_10constraint_7solvers_8is_valid_7genexpr_genexpr(PyObject *__pyx_self, PyObject *__pyx_genexpr_arg_0); /* proto */ static PyObject *__pyx_pf_10constraint_7solvers_8is_valid_genexpr(PyObject *__pyx_self, PyObject *__pyx_genexpr_arg_0); /* proto */ static PyObject *__pyx_pf_10constraint_7solvers_4is_valid(CYTHON_UNUSED PyObject *__pyx_self, PyObject *__pyx_v_assignment, PyObject *__pyx_v_constraints_lookup, PyObject *__pyx_v_domains); /* proto */ @@ -2959,18 +2965,12 @@ static PyObject *__pyx_pf_10constraint_7solvers_6compile_to_function(CYTHON_UNUS static PyObject *__pyx_pf_10constraint_7solvers_8sequential_recursive_backtrack(CYTHON_UNUSED PyObject *__pyx_self, PyObject *__pyx_v_assignment, PyObject *__pyx_v_unassigned_vars, PyObject *__pyx_v_domains, PyObject *__pyx_v_constraint_lookup); /* proto */ static PyObject *__pyx_pf_10constraint_7solvers_10sequential_optimized_backtrack(CYTHON_UNUSED PyObject *__pyx_self, PyObject *__pyx_v_assignment, PyObject *__pyx_v_unassigned_vars, PyObject *__pyx_v_domains, PyObject *__pyx_v_constraint_lookup); /* proto */ static PyObject *__pyx_pf_10constraint_7solvers_12parallel_worker(CYTHON_UNUSED PyObject *__pyx_self, PyObject *__pyx_v_args); /* proto */ -static PyObject *__pyx_pf_10constraint_7solvers_14ParallelSolver___init__(CYTHON_UNUSED PyObject *__pyx_self, PyObject *__pyx_v_self, PyObject *__pyx_v_process_mode); /* proto */ -static PyObject *__pyx_pf_10constraint_7solvers_14ParallelSolver_2getSolution(CYTHON_UNUSED PyObject *__pyx_self, PyObject *__pyx_v_self, CYTHON_UNUSED PyObject *__pyx_v_domains, CYTHON_UNUSED PyObject *__pyx_v_constraints, CYTHON_UNUSED PyObject *__pyx_v_vconstraints); /* proto */ -static PyObject *__pyx_lambda_funcdef_lambda2(PyObject *__pyx_self, PyObject *__pyx_v_v); /* proto */ -static PyObject *__pyx_pf_10constraint_7solvers_14ParallelSolver_16getSolutionsList_1genexpr(PyObject *__pyx_self, PyObject *__pyx_genexpr_arg_0); /* proto */ -static PyObject *__pyx_pf_10constraint_7solvers_14ParallelSolver_4getSolutionsList(CYTHON_UNUSED PyObject *__pyx_self, PyObject *__pyx_v_self, PyObject *__pyx_v_domains, PyObject *__pyx_v_vconstraints); /* proto */ -static PyObject *__pyx_pf_10constraint_7solvers_14ParallelSolver_6getSolutions(CYTHON_UNUSED PyObject *__pyx_self, PyObject *__pyx_v_self, PyObject *__pyx_v_domains, CYTHON_UNUSED PyObject *__pyx_v_constraints, PyObject *__pyx_v_vconstraints); /* proto */ static PyObject *__pyx_tp_new_10constraint_7solvers___pyx_scope_struct__getSolutionIter(PyTypeObject *t, PyObject *a, PyObject *k); /*proto*/ static PyObject *__pyx_tp_new_10constraint_7solvers___pyx_scope_struct_1_getSolutionIter(PyTypeObject *t, PyObject *a, PyObject *k); /*proto*/ -static PyObject *__pyx_tp_new_10constraint_7solvers___pyx_scope_struct_2_is_valid(PyTypeObject *t, PyObject *a, PyObject *k); /*proto*/ +static PyObject *__pyx_tp_new_10constraint_7solvers___pyx_scope_struct_2_getSolutionsList(PyTypeObject *t, PyObject *a, PyObject *k); /*proto*/ static PyObject *__pyx_tp_new_10constraint_7solvers___pyx_scope_struct_3_genexpr(PyTypeObject *t, PyObject *a, PyObject *k); /*proto*/ -static PyObject *__pyx_tp_new_10constraint_7solvers___pyx_scope_struct_4_genexpr(PyTypeObject *t, PyObject *a, PyObject *k); /*proto*/ -static PyObject *__pyx_tp_new_10constraint_7solvers___pyx_scope_struct_5_getSolutionsList(PyTypeObject *t, PyObject *a, PyObject *k); /*proto*/ +static PyObject *__pyx_tp_new_10constraint_7solvers___pyx_scope_struct_4_is_valid(PyTypeObject *t, PyObject *a, PyObject *k); /*proto*/ +static PyObject *__pyx_tp_new_10constraint_7solvers___pyx_scope_struct_5_genexpr(PyTypeObject *t, PyObject *a, PyObject *k); /*proto*/ static PyObject *__pyx_tp_new_10constraint_7solvers___pyx_scope_struct_6_genexpr(PyTypeObject *t, PyObject *a, PyObject *k); /*proto*/ static __Pyx_CachedCFunction __pyx_umethod_PyDict_Type_get = {0, 0, 0, 0, 0}; static __Pyx_CachedCFunction __pyx_umethod_PyDict_Type_keys = {0, 0, 0, 0, 0}; @@ -3007,18 +3007,18 @@ typedef struct { #if CYTHON_USE_MODULE_STATE PyObject *__pyx_type_10constraint_7solvers___pyx_scope_struct__getSolutionIter; PyObject *__pyx_type_10constraint_7solvers___pyx_scope_struct_1_getSolutionIter; - PyObject *__pyx_type_10constraint_7solvers___pyx_scope_struct_2_is_valid; + PyObject *__pyx_type_10constraint_7solvers___pyx_scope_struct_2_getSolutionsList; PyObject *__pyx_type_10constraint_7solvers___pyx_scope_struct_3_genexpr; - PyObject *__pyx_type_10constraint_7solvers___pyx_scope_struct_4_genexpr; - PyObject *__pyx_type_10constraint_7solvers___pyx_scope_struct_5_getSolutionsList; + PyObject *__pyx_type_10constraint_7solvers___pyx_scope_struct_4_is_valid; + PyObject *__pyx_type_10constraint_7solvers___pyx_scope_struct_5_genexpr; PyObject *__pyx_type_10constraint_7solvers___pyx_scope_struct_6_genexpr; #endif PyTypeObject *__pyx_ptype_10constraint_7solvers___pyx_scope_struct__getSolutionIter; PyTypeObject *__pyx_ptype_10constraint_7solvers___pyx_scope_struct_1_getSolutionIter; - PyTypeObject *__pyx_ptype_10constraint_7solvers___pyx_scope_struct_2_is_valid; + PyTypeObject *__pyx_ptype_10constraint_7solvers___pyx_scope_struct_2_getSolutionsList; PyTypeObject *__pyx_ptype_10constraint_7solvers___pyx_scope_struct_3_genexpr; - PyTypeObject *__pyx_ptype_10constraint_7solvers___pyx_scope_struct_4_genexpr; - PyTypeObject *__pyx_ptype_10constraint_7solvers___pyx_scope_struct_5_getSolutionsList; + PyTypeObject *__pyx_ptype_10constraint_7solvers___pyx_scope_struct_4_is_valid; + PyTypeObject *__pyx_ptype_10constraint_7solvers___pyx_scope_struct_5_genexpr; PyTypeObject *__pyx_ptype_10constraint_7solvers___pyx_scope_struct_6_genexpr; PyObject *__pyx_kp_s_Abstract_base_class_for_solvers; PyObject *__pyx_n_s_BacktrackingSolver; @@ -3257,11 +3257,11 @@ typedef struct { PyObject *__pyx_tuple__44; PyObject *__pyx_tuple__46; PyObject *__pyx_tuple__48; - PyObject *__pyx_tuple__50; - PyObject *__pyx_tuple__52; - PyObject *__pyx_tuple__54; - PyObject *__pyx_tuple__56; - PyObject *__pyx_tuple__58; + PyObject *__pyx_tuple__51; + PyObject *__pyx_tuple__53; + PyObject *__pyx_tuple__55; + PyObject *__pyx_tuple__57; + PyObject *__pyx_tuple__59; PyObject *__pyx_codeobj__2; PyObject *__pyx_codeobj__4; PyObject *__pyx_codeobj__9; @@ -3286,11 +3286,11 @@ typedef struct { PyObject *__pyx_codeobj__45; PyObject *__pyx_codeobj__47; PyObject *__pyx_codeobj__49; - PyObject *__pyx_codeobj__51; - PyObject *__pyx_codeobj__53; - PyObject *__pyx_codeobj__55; - PyObject *__pyx_codeobj__57; - PyObject *__pyx_codeobj__59; + PyObject *__pyx_codeobj__50; + PyObject *__pyx_codeobj__52; + PyObject *__pyx_codeobj__54; + PyObject *__pyx_codeobj__56; + PyObject *__pyx_codeobj__58; PyObject *__pyx_codeobj__60; } __pyx_mstate; @@ -3338,14 +3338,14 @@ static int __pyx_m_clear(PyObject *m) { Py_CLEAR(clear_module_state->__pyx_type_10constraint_7solvers___pyx_scope_struct__getSolutionIter); Py_CLEAR(clear_module_state->__pyx_ptype_10constraint_7solvers___pyx_scope_struct_1_getSolutionIter); Py_CLEAR(clear_module_state->__pyx_type_10constraint_7solvers___pyx_scope_struct_1_getSolutionIter); - Py_CLEAR(clear_module_state->__pyx_ptype_10constraint_7solvers___pyx_scope_struct_2_is_valid); - Py_CLEAR(clear_module_state->__pyx_type_10constraint_7solvers___pyx_scope_struct_2_is_valid); + Py_CLEAR(clear_module_state->__pyx_ptype_10constraint_7solvers___pyx_scope_struct_2_getSolutionsList); + Py_CLEAR(clear_module_state->__pyx_type_10constraint_7solvers___pyx_scope_struct_2_getSolutionsList); Py_CLEAR(clear_module_state->__pyx_ptype_10constraint_7solvers___pyx_scope_struct_3_genexpr); Py_CLEAR(clear_module_state->__pyx_type_10constraint_7solvers___pyx_scope_struct_3_genexpr); - Py_CLEAR(clear_module_state->__pyx_ptype_10constraint_7solvers___pyx_scope_struct_4_genexpr); - Py_CLEAR(clear_module_state->__pyx_type_10constraint_7solvers___pyx_scope_struct_4_genexpr); - Py_CLEAR(clear_module_state->__pyx_ptype_10constraint_7solvers___pyx_scope_struct_5_getSolutionsList); - Py_CLEAR(clear_module_state->__pyx_type_10constraint_7solvers___pyx_scope_struct_5_getSolutionsList); + Py_CLEAR(clear_module_state->__pyx_ptype_10constraint_7solvers___pyx_scope_struct_4_is_valid); + Py_CLEAR(clear_module_state->__pyx_type_10constraint_7solvers___pyx_scope_struct_4_is_valid); + Py_CLEAR(clear_module_state->__pyx_ptype_10constraint_7solvers___pyx_scope_struct_5_genexpr); + Py_CLEAR(clear_module_state->__pyx_type_10constraint_7solvers___pyx_scope_struct_5_genexpr); Py_CLEAR(clear_module_state->__pyx_ptype_10constraint_7solvers___pyx_scope_struct_6_genexpr); Py_CLEAR(clear_module_state->__pyx_type_10constraint_7solvers___pyx_scope_struct_6_genexpr); Py_CLEAR(clear_module_state->__pyx_kp_s_Abstract_base_class_for_solvers); @@ -3585,11 +3585,11 @@ static int __pyx_m_clear(PyObject *m) { Py_CLEAR(clear_module_state->__pyx_tuple__44); Py_CLEAR(clear_module_state->__pyx_tuple__46); Py_CLEAR(clear_module_state->__pyx_tuple__48); - Py_CLEAR(clear_module_state->__pyx_tuple__50); - Py_CLEAR(clear_module_state->__pyx_tuple__52); - Py_CLEAR(clear_module_state->__pyx_tuple__54); - Py_CLEAR(clear_module_state->__pyx_tuple__56); - Py_CLEAR(clear_module_state->__pyx_tuple__58); + Py_CLEAR(clear_module_state->__pyx_tuple__51); + Py_CLEAR(clear_module_state->__pyx_tuple__53); + Py_CLEAR(clear_module_state->__pyx_tuple__55); + Py_CLEAR(clear_module_state->__pyx_tuple__57); + Py_CLEAR(clear_module_state->__pyx_tuple__59); Py_CLEAR(clear_module_state->__pyx_codeobj__2); Py_CLEAR(clear_module_state->__pyx_codeobj__4); Py_CLEAR(clear_module_state->__pyx_codeobj__9); @@ -3614,11 +3614,11 @@ static int __pyx_m_clear(PyObject *m) { Py_CLEAR(clear_module_state->__pyx_codeobj__45); Py_CLEAR(clear_module_state->__pyx_codeobj__47); Py_CLEAR(clear_module_state->__pyx_codeobj__49); - Py_CLEAR(clear_module_state->__pyx_codeobj__51); - Py_CLEAR(clear_module_state->__pyx_codeobj__53); - Py_CLEAR(clear_module_state->__pyx_codeobj__55); - Py_CLEAR(clear_module_state->__pyx_codeobj__57); - Py_CLEAR(clear_module_state->__pyx_codeobj__59); + Py_CLEAR(clear_module_state->__pyx_codeobj__50); + Py_CLEAR(clear_module_state->__pyx_codeobj__52); + Py_CLEAR(clear_module_state->__pyx_codeobj__54); + Py_CLEAR(clear_module_state->__pyx_codeobj__56); + Py_CLEAR(clear_module_state->__pyx_codeobj__58); Py_CLEAR(clear_module_state->__pyx_codeobj__60); return 0; } @@ -3644,14 +3644,14 @@ static int __pyx_m_traverse(PyObject *m, visitproc visit, void *arg) { Py_VISIT(traverse_module_state->__pyx_type_10constraint_7solvers___pyx_scope_struct__getSolutionIter); Py_VISIT(traverse_module_state->__pyx_ptype_10constraint_7solvers___pyx_scope_struct_1_getSolutionIter); Py_VISIT(traverse_module_state->__pyx_type_10constraint_7solvers___pyx_scope_struct_1_getSolutionIter); - Py_VISIT(traverse_module_state->__pyx_ptype_10constraint_7solvers___pyx_scope_struct_2_is_valid); - Py_VISIT(traverse_module_state->__pyx_type_10constraint_7solvers___pyx_scope_struct_2_is_valid); + Py_VISIT(traverse_module_state->__pyx_ptype_10constraint_7solvers___pyx_scope_struct_2_getSolutionsList); + Py_VISIT(traverse_module_state->__pyx_type_10constraint_7solvers___pyx_scope_struct_2_getSolutionsList); Py_VISIT(traverse_module_state->__pyx_ptype_10constraint_7solvers___pyx_scope_struct_3_genexpr); Py_VISIT(traverse_module_state->__pyx_type_10constraint_7solvers___pyx_scope_struct_3_genexpr); - Py_VISIT(traverse_module_state->__pyx_ptype_10constraint_7solvers___pyx_scope_struct_4_genexpr); - Py_VISIT(traverse_module_state->__pyx_type_10constraint_7solvers___pyx_scope_struct_4_genexpr); - Py_VISIT(traverse_module_state->__pyx_ptype_10constraint_7solvers___pyx_scope_struct_5_getSolutionsList); - Py_VISIT(traverse_module_state->__pyx_type_10constraint_7solvers___pyx_scope_struct_5_getSolutionsList); + Py_VISIT(traverse_module_state->__pyx_ptype_10constraint_7solvers___pyx_scope_struct_4_is_valid); + Py_VISIT(traverse_module_state->__pyx_type_10constraint_7solvers___pyx_scope_struct_4_is_valid); + Py_VISIT(traverse_module_state->__pyx_ptype_10constraint_7solvers___pyx_scope_struct_5_genexpr); + Py_VISIT(traverse_module_state->__pyx_type_10constraint_7solvers___pyx_scope_struct_5_genexpr); Py_VISIT(traverse_module_state->__pyx_ptype_10constraint_7solvers___pyx_scope_struct_6_genexpr); Py_VISIT(traverse_module_state->__pyx_type_10constraint_7solvers___pyx_scope_struct_6_genexpr); Py_VISIT(traverse_module_state->__pyx_kp_s_Abstract_base_class_for_solvers); @@ -3891,11 +3891,11 @@ static int __pyx_m_traverse(PyObject *m, visitproc visit, void *arg) { Py_VISIT(traverse_module_state->__pyx_tuple__44); Py_VISIT(traverse_module_state->__pyx_tuple__46); Py_VISIT(traverse_module_state->__pyx_tuple__48); - Py_VISIT(traverse_module_state->__pyx_tuple__50); - Py_VISIT(traverse_module_state->__pyx_tuple__52); - Py_VISIT(traverse_module_state->__pyx_tuple__54); - Py_VISIT(traverse_module_state->__pyx_tuple__56); - Py_VISIT(traverse_module_state->__pyx_tuple__58); + Py_VISIT(traverse_module_state->__pyx_tuple__51); + Py_VISIT(traverse_module_state->__pyx_tuple__53); + Py_VISIT(traverse_module_state->__pyx_tuple__55); + Py_VISIT(traverse_module_state->__pyx_tuple__57); + Py_VISIT(traverse_module_state->__pyx_tuple__59); Py_VISIT(traverse_module_state->__pyx_codeobj__2); Py_VISIT(traverse_module_state->__pyx_codeobj__4); Py_VISIT(traverse_module_state->__pyx_codeobj__9); @@ -3920,11 +3920,11 @@ static int __pyx_m_traverse(PyObject *m, visitproc visit, void *arg) { Py_VISIT(traverse_module_state->__pyx_codeobj__45); Py_VISIT(traverse_module_state->__pyx_codeobj__47); Py_VISIT(traverse_module_state->__pyx_codeobj__49); - Py_VISIT(traverse_module_state->__pyx_codeobj__51); - Py_VISIT(traverse_module_state->__pyx_codeobj__53); - Py_VISIT(traverse_module_state->__pyx_codeobj__55); - Py_VISIT(traverse_module_state->__pyx_codeobj__57); - Py_VISIT(traverse_module_state->__pyx_codeobj__59); + Py_VISIT(traverse_module_state->__pyx_codeobj__50); + Py_VISIT(traverse_module_state->__pyx_codeobj__52); + Py_VISIT(traverse_module_state->__pyx_codeobj__54); + Py_VISIT(traverse_module_state->__pyx_codeobj__56); + Py_VISIT(traverse_module_state->__pyx_codeobj__58); Py_VISIT(traverse_module_state->__pyx_codeobj__60); return 0; } @@ -3957,18 +3957,18 @@ static int __pyx_m_traverse(PyObject *m, visitproc visit, void *arg) { #if CYTHON_USE_MODULE_STATE #define __pyx_type_10constraint_7solvers___pyx_scope_struct__getSolutionIter __pyx_mstate_global->__pyx_type_10constraint_7solvers___pyx_scope_struct__getSolutionIter #define __pyx_type_10constraint_7solvers___pyx_scope_struct_1_getSolutionIter __pyx_mstate_global->__pyx_type_10constraint_7solvers___pyx_scope_struct_1_getSolutionIter -#define __pyx_type_10constraint_7solvers___pyx_scope_struct_2_is_valid __pyx_mstate_global->__pyx_type_10constraint_7solvers___pyx_scope_struct_2_is_valid +#define __pyx_type_10constraint_7solvers___pyx_scope_struct_2_getSolutionsList __pyx_mstate_global->__pyx_type_10constraint_7solvers___pyx_scope_struct_2_getSolutionsList #define __pyx_type_10constraint_7solvers___pyx_scope_struct_3_genexpr __pyx_mstate_global->__pyx_type_10constraint_7solvers___pyx_scope_struct_3_genexpr -#define __pyx_type_10constraint_7solvers___pyx_scope_struct_4_genexpr __pyx_mstate_global->__pyx_type_10constraint_7solvers___pyx_scope_struct_4_genexpr -#define __pyx_type_10constraint_7solvers___pyx_scope_struct_5_getSolutionsList __pyx_mstate_global->__pyx_type_10constraint_7solvers___pyx_scope_struct_5_getSolutionsList +#define __pyx_type_10constraint_7solvers___pyx_scope_struct_4_is_valid __pyx_mstate_global->__pyx_type_10constraint_7solvers___pyx_scope_struct_4_is_valid +#define __pyx_type_10constraint_7solvers___pyx_scope_struct_5_genexpr __pyx_mstate_global->__pyx_type_10constraint_7solvers___pyx_scope_struct_5_genexpr #define __pyx_type_10constraint_7solvers___pyx_scope_struct_6_genexpr __pyx_mstate_global->__pyx_type_10constraint_7solvers___pyx_scope_struct_6_genexpr #endif #define __pyx_ptype_10constraint_7solvers___pyx_scope_struct__getSolutionIter __pyx_mstate_global->__pyx_ptype_10constraint_7solvers___pyx_scope_struct__getSolutionIter #define __pyx_ptype_10constraint_7solvers___pyx_scope_struct_1_getSolutionIter __pyx_mstate_global->__pyx_ptype_10constraint_7solvers___pyx_scope_struct_1_getSolutionIter -#define __pyx_ptype_10constraint_7solvers___pyx_scope_struct_2_is_valid __pyx_mstate_global->__pyx_ptype_10constraint_7solvers___pyx_scope_struct_2_is_valid +#define __pyx_ptype_10constraint_7solvers___pyx_scope_struct_2_getSolutionsList __pyx_mstate_global->__pyx_ptype_10constraint_7solvers___pyx_scope_struct_2_getSolutionsList #define __pyx_ptype_10constraint_7solvers___pyx_scope_struct_3_genexpr __pyx_mstate_global->__pyx_ptype_10constraint_7solvers___pyx_scope_struct_3_genexpr -#define __pyx_ptype_10constraint_7solvers___pyx_scope_struct_4_genexpr __pyx_mstate_global->__pyx_ptype_10constraint_7solvers___pyx_scope_struct_4_genexpr -#define __pyx_ptype_10constraint_7solvers___pyx_scope_struct_5_getSolutionsList __pyx_mstate_global->__pyx_ptype_10constraint_7solvers___pyx_scope_struct_5_getSolutionsList +#define __pyx_ptype_10constraint_7solvers___pyx_scope_struct_4_is_valid __pyx_mstate_global->__pyx_ptype_10constraint_7solvers___pyx_scope_struct_4_is_valid +#define __pyx_ptype_10constraint_7solvers___pyx_scope_struct_5_genexpr __pyx_mstate_global->__pyx_ptype_10constraint_7solvers___pyx_scope_struct_5_genexpr #define __pyx_ptype_10constraint_7solvers___pyx_scope_struct_6_genexpr __pyx_mstate_global->__pyx_ptype_10constraint_7solvers___pyx_scope_struct_6_genexpr #define __pyx_kp_s_Abstract_base_class_for_solvers __pyx_mstate_global->__pyx_kp_s_Abstract_base_class_for_solvers #define __pyx_n_s_BacktrackingSolver __pyx_mstate_global->__pyx_n_s_BacktrackingSolver @@ -4207,11 +4207,11 @@ static int __pyx_m_traverse(PyObject *m, visitproc visit, void *arg) { #define __pyx_tuple__44 __pyx_mstate_global->__pyx_tuple__44 #define __pyx_tuple__46 __pyx_mstate_global->__pyx_tuple__46 #define __pyx_tuple__48 __pyx_mstate_global->__pyx_tuple__48 -#define __pyx_tuple__50 __pyx_mstate_global->__pyx_tuple__50 -#define __pyx_tuple__52 __pyx_mstate_global->__pyx_tuple__52 -#define __pyx_tuple__54 __pyx_mstate_global->__pyx_tuple__54 -#define __pyx_tuple__56 __pyx_mstate_global->__pyx_tuple__56 -#define __pyx_tuple__58 __pyx_mstate_global->__pyx_tuple__58 +#define __pyx_tuple__51 __pyx_mstate_global->__pyx_tuple__51 +#define __pyx_tuple__53 __pyx_mstate_global->__pyx_tuple__53 +#define __pyx_tuple__55 __pyx_mstate_global->__pyx_tuple__55 +#define __pyx_tuple__57 __pyx_mstate_global->__pyx_tuple__57 +#define __pyx_tuple__59 __pyx_mstate_global->__pyx_tuple__59 #define __pyx_codeobj__2 __pyx_mstate_global->__pyx_codeobj__2 #define __pyx_codeobj__4 __pyx_mstate_global->__pyx_codeobj__4 #define __pyx_codeobj__9 __pyx_mstate_global->__pyx_codeobj__9 @@ -4236,11 +4236,11 @@ static int __pyx_m_traverse(PyObject *m, visitproc visit, void *arg) { #define __pyx_codeobj__45 __pyx_mstate_global->__pyx_codeobj__45 #define __pyx_codeobj__47 __pyx_mstate_global->__pyx_codeobj__47 #define __pyx_codeobj__49 __pyx_mstate_global->__pyx_codeobj__49 -#define __pyx_codeobj__51 __pyx_mstate_global->__pyx_codeobj__51 -#define __pyx_codeobj__53 __pyx_mstate_global->__pyx_codeobj__53 -#define __pyx_codeobj__55 __pyx_mstate_global->__pyx_codeobj__55 -#define __pyx_codeobj__57 __pyx_mstate_global->__pyx_codeobj__57 -#define __pyx_codeobj__59 __pyx_mstate_global->__pyx_codeobj__59 +#define __pyx_codeobj__50 __pyx_mstate_global->__pyx_codeobj__50 +#define __pyx_codeobj__52 __pyx_mstate_global->__pyx_codeobj__52 +#define __pyx_codeobj__54 __pyx_mstate_global->__pyx_codeobj__54 +#define __pyx_codeobj__56 __pyx_mstate_global->__pyx_codeobj__56 +#define __pyx_codeobj__58 __pyx_mstate_global->__pyx_codeobj__58 #define __pyx_codeobj__60 __pyx_mstate_global->__pyx_codeobj__60 /* #### Code section: module_code ### */ @@ -15621,45 +15621,44 @@ static PyObject *__pyx_pf_10constraint_7solvers_18MinConflictsSolver_2getSolutio return __pyx_r; } -/* "constraint/solvers.py":609 - * ### Helper functions for parallel solver +/* "constraint/solvers.py":644 + * """ # noqa E501 * - * def is_valid(assignment: dict[Hashable, any], constraints_lookup: list[tuple[Constraint, Hashable]], domains: dict[Hashable, Domain]) -> bool: # noqa E501 # <<<<<<<<<<<<<< - * """Check if all constraints are satisfied given the current assignment.""" - * return all( + * def __init__(self, process_mode=False): # <<<<<<<<<<<<<< + * """Initialization method. Set `process_mode` to True for using ProcessPool, otherwise uses ThreadPool.""" + * super().__init__() */ /* Python wrapper */ -static PyObject *__pyx_pw_10constraint_7solvers_5is_valid(PyObject *__pyx_self, +static PyObject *__pyx_pw_10constraint_7solvers_14ParallelSolver_1__init__(PyObject *__pyx_self, #if CYTHON_METH_FASTCALL PyObject *const *__pyx_args, Py_ssize_t __pyx_nargs, PyObject *__pyx_kwds #else PyObject *__pyx_args, PyObject *__pyx_kwds #endif ); /*proto*/ -PyDoc_STRVAR(__pyx_doc_10constraint_7solvers_4is_valid, "Check if all constraints are satisfied given the current assignment."); -static PyMethodDef __pyx_mdef_10constraint_7solvers_5is_valid = {"is_valid", (PyCFunction)(void*)(__Pyx_PyCFunction_FastCallWithKeywords)__pyx_pw_10constraint_7solvers_5is_valid, __Pyx_METH_FASTCALL|METH_KEYWORDS, __pyx_doc_10constraint_7solvers_4is_valid}; -static PyObject *__pyx_pw_10constraint_7solvers_5is_valid(PyObject *__pyx_self, +PyDoc_STRVAR(__pyx_doc_10constraint_7solvers_14ParallelSolver___init__, "Initialization method. Set `process_mode` to True for using ProcessPool, otherwise uses ThreadPool."); +static PyMethodDef __pyx_mdef_10constraint_7solvers_14ParallelSolver_1__init__ = {"__init__", (PyCFunction)(void*)(__Pyx_PyCFunction_FastCallWithKeywords)__pyx_pw_10constraint_7solvers_14ParallelSolver_1__init__, __Pyx_METH_FASTCALL|METH_KEYWORDS, __pyx_doc_10constraint_7solvers_14ParallelSolver___init__}; +static PyObject *__pyx_pw_10constraint_7solvers_14ParallelSolver_1__init__(PyObject *__pyx_self, #if CYTHON_METH_FASTCALL PyObject *const *__pyx_args, Py_ssize_t __pyx_nargs, PyObject *__pyx_kwds #else PyObject *__pyx_args, PyObject *__pyx_kwds #endif ) { - PyObject *__pyx_v_assignment = 0; - PyObject *__pyx_v_constraints_lookup = 0; - PyObject *__pyx_v_domains = 0; + PyObject *__pyx_v_self = 0; + PyObject *__pyx_v_process_mode = 0; #if !CYTHON_METH_FASTCALL CYTHON_UNUSED Py_ssize_t __pyx_nargs; #endif CYTHON_UNUSED PyObject *const *__pyx_kwvalues; - PyObject* values[3] = {0,0,0}; + PyObject* values[2] = {0,0}; int __pyx_lineno = 0; const char *__pyx_filename = NULL; int __pyx_clineno = 0; PyObject *__pyx_r = 0; __Pyx_RefNannyDeclarations - __Pyx_RefNannySetupContext("is_valid (wrapper)", 0); + __Pyx_RefNannySetupContext("__init__ (wrapper)", 0); #if !CYTHON_METH_FASTCALL #if CYTHON_ASSUME_SAFE_MACROS __pyx_nargs = PyTuple_GET_SIZE(__pyx_args); @@ -15669,12 +15668,11 @@ PyObject *__pyx_args, PyObject *__pyx_kwds #endif __pyx_kwvalues = __Pyx_KwValues_FASTCALL(__pyx_args, __pyx_nargs); { - PyObject **__pyx_pyargnames[] = {&__pyx_n_s_assignment,&__pyx_n_s_constraints_lookup,&__pyx_n_s_domains,0}; + PyObject **__pyx_pyargnames[] = {&__pyx_n_s_self,&__pyx_n_s_process_mode,0}; + values[1] = __Pyx_Arg_NewRef_FASTCALL(((PyObject *)((PyObject *)Py_False))); if (__pyx_kwds) { Py_ssize_t kw_args; switch (__pyx_nargs) { - case 3: values[2] = __Pyx_Arg_FASTCALL(__pyx_args, 2); - CYTHON_FALLTHROUGH; case 2: values[1] = __Pyx_Arg_FASTCALL(__pyx_args, 1); CYTHON_FALLTHROUGH; case 1: values[0] = __Pyx_Arg_FASTCALL(__pyx_args, 0); @@ -15685,51 +15683,39 @@ PyObject *__pyx_args, PyObject *__pyx_kwds kw_args = __Pyx_NumKwargs_FASTCALL(__pyx_kwds); switch (__pyx_nargs) { case 0: - if (likely((values[0] = __Pyx_GetKwValue_FASTCALL(__pyx_kwds, __pyx_kwvalues, __pyx_n_s_assignment)) != 0)) { + if (likely((values[0] = __Pyx_GetKwValue_FASTCALL(__pyx_kwds, __pyx_kwvalues, __pyx_n_s_self)) != 0)) { (void)__Pyx_Arg_NewRef_FASTCALL(values[0]); kw_args--; } - else if (unlikely(PyErr_Occurred())) __PYX_ERR(0, 609, __pyx_L3_error) + else if (unlikely(PyErr_Occurred())) __PYX_ERR(0, 644, __pyx_L3_error) else goto __pyx_L5_argtuple_error; CYTHON_FALLTHROUGH; case 1: - if (likely((values[1] = __Pyx_GetKwValue_FASTCALL(__pyx_kwds, __pyx_kwvalues, __pyx_n_s_constraints_lookup)) != 0)) { - (void)__Pyx_Arg_NewRef_FASTCALL(values[1]); - kw_args--; - } - else if (unlikely(PyErr_Occurred())) __PYX_ERR(0, 609, __pyx_L3_error) - else { - __Pyx_RaiseArgtupleInvalid("is_valid", 1, 3, 3, 1); __PYX_ERR(0, 609, __pyx_L3_error) - } - CYTHON_FALLTHROUGH; - case 2: - if (likely((values[2] = __Pyx_GetKwValue_FASTCALL(__pyx_kwds, __pyx_kwvalues, __pyx_n_s_domains)) != 0)) { - (void)__Pyx_Arg_NewRef_FASTCALL(values[2]); - kw_args--; - } - else if (unlikely(PyErr_Occurred())) __PYX_ERR(0, 609, __pyx_L3_error) - else { - __Pyx_RaiseArgtupleInvalid("is_valid", 1, 3, 3, 2); __PYX_ERR(0, 609, __pyx_L3_error) + if (kw_args > 0) { + PyObject* value = __Pyx_GetKwValue_FASTCALL(__pyx_kwds, __pyx_kwvalues, __pyx_n_s_process_mode); + if (value) { values[1] = __Pyx_Arg_NewRef_FASTCALL(value); kw_args--; } + else if (unlikely(PyErr_Occurred())) __PYX_ERR(0, 644, __pyx_L3_error) } } if (unlikely(kw_args > 0)) { const Py_ssize_t kwd_pos_args = __pyx_nargs; - if (unlikely(__Pyx_ParseOptionalKeywords(__pyx_kwds, __pyx_kwvalues, __pyx_pyargnames, 0, values + 0, kwd_pos_args, "is_valid") < 0)) __PYX_ERR(0, 609, __pyx_L3_error) + if (unlikely(__Pyx_ParseOptionalKeywords(__pyx_kwds, __pyx_kwvalues, __pyx_pyargnames, 0, values + 0, kwd_pos_args, "__init__") < 0)) __PYX_ERR(0, 644, __pyx_L3_error) } - } else if (unlikely(__pyx_nargs != 3)) { - goto __pyx_L5_argtuple_error; } else { - values[0] = __Pyx_Arg_FASTCALL(__pyx_args, 0); - values[1] = __Pyx_Arg_FASTCALL(__pyx_args, 1); - values[2] = __Pyx_Arg_FASTCALL(__pyx_args, 2); + switch (__pyx_nargs) { + case 2: values[1] = __Pyx_Arg_FASTCALL(__pyx_args, 1); + CYTHON_FALLTHROUGH; + case 1: values[0] = __Pyx_Arg_FASTCALL(__pyx_args, 0); + break; + default: goto __pyx_L5_argtuple_error; + } } - __pyx_v_assignment = ((PyObject*)values[0]); - __pyx_v_constraints_lookup = ((PyObject*)values[1]); - __pyx_v_domains = ((PyObject*)values[2]); + __pyx_v_self = values[0]; + __pyx_v_process_mode = values[1]; } goto __pyx_L6_skip; __pyx_L5_argtuple_error:; - __Pyx_RaiseArgtupleInvalid("is_valid", 1, 3, 3, __pyx_nargs); __PYX_ERR(0, 609, __pyx_L3_error) + __Pyx_RaiseArgtupleInvalid("__init__", 0, 1, 2, __pyx_nargs); __PYX_ERR(0, 644, __pyx_L3_error) __pyx_L6_skip:; goto __pyx_L4_argument_unpacking_done; __pyx_L3_error:; @@ -15739,20 +15725,13 @@ PyObject *__pyx_args, PyObject *__pyx_kwds __Pyx_Arg_XDECREF_FASTCALL(values[__pyx_temp]); } } - __Pyx_AddTraceback("constraint.solvers.is_valid", __pyx_clineno, __pyx_lineno, __pyx_filename); + __Pyx_AddTraceback("constraint.solvers.ParallelSolver.__init__", __pyx_clineno, __pyx_lineno, __pyx_filename); __Pyx_RefNannyFinishContext(); return NULL; __pyx_L4_argument_unpacking_done:; - if (unlikely(!__Pyx_ArgTypeTest(((PyObject *)__pyx_v_assignment), (&PyDict_Type), 0, "assignment", 1))) __PYX_ERR(0, 609, __pyx_L1_error) - if (unlikely(!__Pyx_ArgTypeTest(((PyObject *)__pyx_v_constraints_lookup), (&PyList_Type), 0, "constraints_lookup", 1))) __PYX_ERR(0, 609, __pyx_L1_error) - if (unlikely(!__Pyx_ArgTypeTest(((PyObject *)__pyx_v_domains), (&PyDict_Type), 0, "domains", 1))) __PYX_ERR(0, 609, __pyx_L1_error) - __pyx_r = __pyx_pf_10constraint_7solvers_4is_valid(__pyx_self, __pyx_v_assignment, __pyx_v_constraints_lookup, __pyx_v_domains); + __pyx_r = __pyx_pf_10constraint_7solvers_14ParallelSolver___init__(__pyx_self, __pyx_v_self, __pyx_v_process_mode); /* function exit code */ - goto __pyx_L0; - __pyx_L1_error:; - __pyx_r = NULL; - __pyx_L0:; { Py_ssize_t __pyx_temp; for (__pyx_temp=0; __pyx_temp < (Py_ssize_t)(sizeof(values)/sizeof(values[0])); ++__pyx_temp) { @@ -15762,579 +15741,496 @@ PyObject *__pyx_args, PyObject *__pyx_kwds __Pyx_RefNannyFinishContext(); return __pyx_r; } -static PyObject *__pyx_gb_10constraint_7solvers_8is_valid_2generator2(__pyx_CoroutineObject *__pyx_generator, CYTHON_UNUSED PyThreadState *__pyx_tstate, PyObject *__pyx_sent_value); /* proto */ -static PyObject *__pyx_gb_10constraint_7solvers_8is_valid_7genexpr_2generator3(__pyx_CoroutineObject *__pyx_generator, CYTHON_UNUSED PyThreadState *__pyx_tstate, PyObject *__pyx_sent_value); /* proto */ - -/* "constraint/solvers.py":614 - * constraint(vars_involved, domains, assignment, None) - * for constraint, vars_involved in constraints_lookup - * if all(v in assignment for v in vars_involved) # <<<<<<<<<<<<<< - * ) - * - */ -static PyObject *__pyx_pf_10constraint_7solvers_8is_valid_7genexpr_genexpr(PyObject *__pyx_self, PyObject *__pyx_genexpr_arg_0) { - struct __pyx_obj_10constraint_7solvers___pyx_scope_struct_4_genexpr *__pyx_cur_scope; +static PyObject *__pyx_pf_10constraint_7solvers_14ParallelSolver___init__(CYTHON_UNUSED PyObject *__pyx_self, PyObject *__pyx_v_self, PyObject *__pyx_v_process_mode) { PyObject *__pyx_r = NULL; __Pyx_RefNannyDeclarations + PyObject *__pyx_t_1 = NULL; + PyObject *__pyx_t_2 = NULL; + PyObject *__pyx_t_3 = NULL; + unsigned int __pyx_t_4; int __pyx_lineno = 0; const char *__pyx_filename = NULL; int __pyx_clineno = 0; - __Pyx_RefNannySetupContext("genexpr", 0); - __pyx_cur_scope = (struct __pyx_obj_10constraint_7solvers___pyx_scope_struct_4_genexpr *)__pyx_tp_new_10constraint_7solvers___pyx_scope_struct_4_genexpr(__pyx_ptype_10constraint_7solvers___pyx_scope_struct_4_genexpr, __pyx_empty_tuple, NULL); - if (unlikely(!__pyx_cur_scope)) { - __pyx_cur_scope = ((struct __pyx_obj_10constraint_7solvers___pyx_scope_struct_4_genexpr *)Py_None); - __Pyx_INCREF(Py_None); - __PYX_ERR(0, 614, __pyx_L1_error) - } else { - __Pyx_GOTREF((PyObject *)__pyx_cur_scope); - } - __pyx_cur_scope->__pyx_outer_scope = (struct __pyx_obj_10constraint_7solvers___pyx_scope_struct_3_genexpr *) __pyx_self; - __Pyx_INCREF((PyObject *)__pyx_cur_scope->__pyx_outer_scope); - __Pyx_GIVEREF((PyObject *)__pyx_cur_scope->__pyx_outer_scope); - __pyx_cur_scope->__pyx_genexpr_arg_0 = __pyx_genexpr_arg_0; - __Pyx_INCREF(__pyx_cur_scope->__pyx_genexpr_arg_0); - __Pyx_GIVEREF(__pyx_cur_scope->__pyx_genexpr_arg_0); - { - __pyx_CoroutineObject *gen = __Pyx_Generator_New((__pyx_coroutine_body_t) __pyx_gb_10constraint_7solvers_8is_valid_7genexpr_2generator3, NULL, (PyObject *) __pyx_cur_scope, __pyx_n_s_genexpr, __pyx_n_s_is_valid_locals_genexpr_locals_g, __pyx_n_s_constraint_solvers); if (unlikely(!gen)) __PYX_ERR(0, 614, __pyx_L1_error) - __Pyx_DECREF(__pyx_cur_scope); - __Pyx_RefNannyFinishContext(); - return (PyObject *) gen; - } - - /* function exit code */ - __pyx_L1_error:; - __Pyx_AddTraceback("constraint.solvers.is_valid.genexpr.genexpr", __pyx_clineno, __pyx_lineno, __pyx_filename); - __pyx_r = NULL; - __Pyx_DECREF((PyObject *)__pyx_cur_scope); - __Pyx_XGIVEREF(__pyx_r); - __Pyx_RefNannyFinishContext(); - return __pyx_r; -} + __Pyx_RefNannySetupContext("__init__", 1); -static PyObject *__pyx_gb_10constraint_7solvers_8is_valid_7genexpr_2generator3(__pyx_CoroutineObject *__pyx_generator, CYTHON_UNUSED PyThreadState *__pyx_tstate, PyObject *__pyx_sent_value) /* generator body */ -{ - struct __pyx_obj_10constraint_7solvers___pyx_scope_struct_4_genexpr *__pyx_cur_scope = ((struct __pyx_obj_10constraint_7solvers___pyx_scope_struct_4_genexpr *)__pyx_generator->closure); - PyObject *__pyx_r = NULL; - PyObject *__pyx_t_1 = NULL; - Py_ssize_t __pyx_t_2; - PyObject *(*__pyx_t_3)(PyObject *); - PyObject *__pyx_t_4 = NULL; - int __pyx_t_5; - int __pyx_t_6; - int __pyx_lineno = 0; - const char *__pyx_filename = NULL; - int __pyx_clineno = 0; - __Pyx_RefNannyDeclarations - __Pyx_RefNannySetupContext("genexpr", 0); - switch (__pyx_generator->resume_label) { - case 0: goto __pyx_L3_first_run; - default: /* CPython raises the right error here */ - __Pyx_RefNannyFinishContext(); - return NULL; + /* "constraint/solvers.py":646 + * def __init__(self, process_mode=False): + * """Initialization method. Set `process_mode` to True for using ProcessPool, otherwise uses ThreadPool.""" + * super().__init__() # <<<<<<<<<<<<<< + * self._process_mode = process_mode + * self.requires_pickling = process_mode + */ + __pyx_t_2 = __Pyx_CyFunction_GetClassObj(__pyx_self); + if (!__pyx_t_2) { PyErr_SetString(PyExc_SystemError, "super(): empty __class__ cell"); __PYX_ERR(0, 646, __pyx_L1_error) } + __Pyx_INCREF(__pyx_t_2); + __pyx_t_3 = PyTuple_New(2); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 646, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_3); + __Pyx_GIVEREF(__pyx_t_2); + if (__Pyx_PyTuple_SET_ITEM(__pyx_t_3, 0, __pyx_t_2)) __PYX_ERR(0, 646, __pyx_L1_error); + __Pyx_INCREF(__pyx_v_self); + __Pyx_GIVEREF(__pyx_v_self); + if (__Pyx_PyTuple_SET_ITEM(__pyx_t_3, 1, __pyx_v_self)) __PYX_ERR(0, 646, __pyx_L1_error); + __pyx_t_2 = 0; + __pyx_t_2 = __Pyx_PyObject_Call(__pyx_builtin_super, __pyx_t_3, NULL); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 646, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_2); + __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; + __pyx_t_3 = __Pyx_PyObject_GetAttrStr(__pyx_t_2, __pyx_n_s_init); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 646, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_3); + __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; + __pyx_t_2 = NULL; + __pyx_t_4 = 0; + #if CYTHON_UNPACK_METHODS + if (likely(PyMethod_Check(__pyx_t_3))) { + __pyx_t_2 = PyMethod_GET_SELF(__pyx_t_3); + if (likely(__pyx_t_2)) { + PyObject* function = PyMethod_GET_FUNCTION(__pyx_t_3); + __Pyx_INCREF(__pyx_t_2); + __Pyx_INCREF(function); + __Pyx_DECREF_SET(__pyx_t_3, function); + __pyx_t_4 = 1; + } } - __pyx_L3_first_run:; - if (unlikely(!__pyx_sent_value)) __PYX_ERR(0, 614, __pyx_L1_error) - if (unlikely(!__pyx_cur_scope->__pyx_genexpr_arg_0)) { __Pyx_RaiseUnboundLocalError(".0"); __PYX_ERR(0, 614, __pyx_L1_error) } - if (likely(PyList_CheckExact(__pyx_cur_scope->__pyx_genexpr_arg_0)) || PyTuple_CheckExact(__pyx_cur_scope->__pyx_genexpr_arg_0)) { - __pyx_t_1 = __pyx_cur_scope->__pyx_genexpr_arg_0; __Pyx_INCREF(__pyx_t_1); - __pyx_t_2 = 0; - __pyx_t_3 = NULL; - } else { - __pyx_t_2 = -1; __pyx_t_1 = PyObject_GetIter(__pyx_cur_scope->__pyx_genexpr_arg_0); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 614, __pyx_L1_error) + #endif + { + PyObject *__pyx_callargs[2] = {__pyx_t_2, NULL}; + __pyx_t_1 = __Pyx_PyObject_FastCall(__pyx_t_3, __pyx_callargs+1-__pyx_t_4, 0+__pyx_t_4); + __Pyx_XDECREF(__pyx_t_2); __pyx_t_2 = 0; + if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 646, __pyx_L1_error) __Pyx_GOTREF(__pyx_t_1); - __pyx_t_3 = __Pyx_PyObject_GetIterNextFunc(__pyx_t_1); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 614, __pyx_L1_error) - } - for (;;) { - if (likely(!__pyx_t_3)) { - if (likely(PyList_CheckExact(__pyx_t_1))) { - { - Py_ssize_t __pyx_temp = __Pyx_PyList_GET_SIZE(__pyx_t_1); - #if !CYTHON_ASSUME_SAFE_MACROS - if (unlikely((__pyx_temp < 0))) __PYX_ERR(0, 614, __pyx_L1_error) - #endif - if (__pyx_t_2 >= __pyx_temp) break; - } - #if CYTHON_ASSUME_SAFE_MACROS && !CYTHON_AVOID_BORROWED_REFS - __pyx_t_4 = PyList_GET_ITEM(__pyx_t_1, __pyx_t_2); __Pyx_INCREF(__pyx_t_4); __pyx_t_2++; if (unlikely((0 < 0))) __PYX_ERR(0, 614, __pyx_L1_error) - #else - __pyx_t_4 = __Pyx_PySequence_ITEM(__pyx_t_1, __pyx_t_2); __pyx_t_2++; if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 614, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_4); - #endif - } else { - { - Py_ssize_t __pyx_temp = __Pyx_PyTuple_GET_SIZE(__pyx_t_1); - #if !CYTHON_ASSUME_SAFE_MACROS - if (unlikely((__pyx_temp < 0))) __PYX_ERR(0, 614, __pyx_L1_error) - #endif - if (__pyx_t_2 >= __pyx_temp) break; - } - #if CYTHON_ASSUME_SAFE_MACROS && !CYTHON_AVOID_BORROWED_REFS - __pyx_t_4 = PyTuple_GET_ITEM(__pyx_t_1, __pyx_t_2); __Pyx_INCREF(__pyx_t_4); __pyx_t_2++; if (unlikely((0 < 0))) __PYX_ERR(0, 614, __pyx_L1_error) - #else - __pyx_t_4 = __Pyx_PySequence_ITEM(__pyx_t_1, __pyx_t_2); __pyx_t_2++; if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 614, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_4); - #endif - } - } else { - __pyx_t_4 = __pyx_t_3(__pyx_t_1); - if (unlikely(!__pyx_t_4)) { - PyObject* exc_type = PyErr_Occurred(); - if (exc_type) { - if (likely(__Pyx_PyErr_GivenExceptionMatches(exc_type, PyExc_StopIteration))) PyErr_Clear(); - else __PYX_ERR(0, 614, __pyx_L1_error) - } - break; - } - __Pyx_GOTREF(__pyx_t_4); - } - __Pyx_XGOTREF(__pyx_cur_scope->__pyx_v_v); - __Pyx_XDECREF_SET(__pyx_cur_scope->__pyx_v_v, __pyx_t_4); - __Pyx_GIVEREF(__pyx_t_4); - __pyx_t_4 = 0; - if (unlikely(!__pyx_cur_scope->__pyx_outer_scope->__pyx_outer_scope->__pyx_v_assignment)) { __Pyx_RaiseClosureNameError("assignment"); __PYX_ERR(0, 614, __pyx_L1_error) } - if (unlikely(__pyx_cur_scope->__pyx_outer_scope->__pyx_outer_scope->__pyx_v_assignment == Py_None)) { - PyErr_SetString(PyExc_TypeError, "'NoneType' object is not iterable"); - __PYX_ERR(0, 614, __pyx_L1_error) - } - __pyx_t_5 = (__Pyx_PyDict_ContainsTF(__pyx_cur_scope->__pyx_v_v, __pyx_cur_scope->__pyx_outer_scope->__pyx_outer_scope->__pyx_v_assignment, Py_EQ)); if (unlikely((__pyx_t_5 < 0))) __PYX_ERR(0, 614, __pyx_L1_error) - __pyx_t_6 = (!__pyx_t_5); - if (__pyx_t_6) { - __Pyx_XDECREF(__pyx_r); - __Pyx_INCREF(Py_False); - __pyx_r = Py_False; - __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; - goto __pyx_L0; - } + __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; } __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; - /*else*/ { - __Pyx_XDECREF(__pyx_r); - __Pyx_INCREF(Py_True); - __pyx_r = Py_True; - goto __pyx_L0; - } - CYTHON_MAYBE_UNUSED_VAR(__pyx_cur_scope); - /* function exit code */ - goto __pyx_L0; - __pyx_L1_error:; - __Pyx_Generator_Replace_StopIteration(0); - __Pyx_XDECREF(__pyx_t_1); - __Pyx_XDECREF(__pyx_t_4); - __Pyx_AddTraceback("genexpr", __pyx_clineno, __pyx_lineno, __pyx_filename); - __pyx_L0:; - __Pyx_XGIVEREF(__pyx_r); - #if !CYTHON_USE_EXC_INFO_STACK - __Pyx_Coroutine_ResetAndClearException(__pyx_generator); - #endif - __pyx_generator->resume_label = -1; - __Pyx_Coroutine_clear((PyObject*)__pyx_generator); - __Pyx_RefNannyFinishContext(); - return __pyx_r; -} + /* "constraint/solvers.py":647 + * """Initialization method. Set `process_mode` to True for using ProcessPool, otherwise uses ThreadPool.""" + * super().__init__() + * self._process_mode = process_mode # <<<<<<<<<<<<<< + * self.requires_pickling = process_mode + * + */ + if (__Pyx_PyObject_SetAttrStr(__pyx_v_self, __pyx_n_s_process_mode_2, __pyx_v_process_mode) < 0) __PYX_ERR(0, 647, __pyx_L1_error) -/* "constraint/solvers.py":612 - * """Check if all constraints are satisfied given the current assignment.""" - * return all( - * constraint(vars_involved, domains, assignment, None) # <<<<<<<<<<<<<< - * for constraint, vars_involved in constraints_lookup - * if all(v in assignment for v in vars_involved) + /* "constraint/solvers.py":648 + * super().__init__() + * self._process_mode = process_mode + * self.requires_pickling = process_mode # <<<<<<<<<<<<<< + * + * def getSolution(self, domains: dict, constraints: list[tuple], vconstraints: dict): */ + if (__Pyx_PyObject_SetAttrStr(__pyx_v_self, __pyx_n_s_requires_pickling, __pyx_v_process_mode) < 0) __PYX_ERR(0, 648, __pyx_L1_error) -static PyObject *__pyx_pf_10constraint_7solvers_8is_valid_genexpr(PyObject *__pyx_self, PyObject *__pyx_genexpr_arg_0) { - struct __pyx_obj_10constraint_7solvers___pyx_scope_struct_3_genexpr *__pyx_cur_scope; - PyObject *__pyx_gb_10constraint_7solvers_8is_valid_7genexpr_2generator3 = 0; - PyObject *__pyx_r = NULL; - __Pyx_RefNannyDeclarations - int __pyx_lineno = 0; - const char *__pyx_filename = NULL; - int __pyx_clineno = 0; - __Pyx_RefNannySetupContext("genexpr", 0); - __pyx_cur_scope = (struct __pyx_obj_10constraint_7solvers___pyx_scope_struct_3_genexpr *)__pyx_tp_new_10constraint_7solvers___pyx_scope_struct_3_genexpr(__pyx_ptype_10constraint_7solvers___pyx_scope_struct_3_genexpr, __pyx_empty_tuple, NULL); - if (unlikely(!__pyx_cur_scope)) { - __pyx_cur_scope = ((struct __pyx_obj_10constraint_7solvers___pyx_scope_struct_3_genexpr *)Py_None); - __Pyx_INCREF(Py_None); - __PYX_ERR(0, 612, __pyx_L1_error) - } else { - __Pyx_GOTREF((PyObject *)__pyx_cur_scope); - } - __pyx_cur_scope->__pyx_outer_scope = (struct __pyx_obj_10constraint_7solvers___pyx_scope_struct_2_is_valid *) __pyx_self; - __Pyx_INCREF((PyObject *)__pyx_cur_scope->__pyx_outer_scope); - __Pyx_GIVEREF((PyObject *)__pyx_cur_scope->__pyx_outer_scope); - __pyx_cur_scope->__pyx_genexpr_arg_0 = __pyx_genexpr_arg_0; - __Pyx_INCREF(__pyx_cur_scope->__pyx_genexpr_arg_0); - __Pyx_GIVEREF(__pyx_cur_scope->__pyx_genexpr_arg_0); - { - __pyx_CoroutineObject *gen = __Pyx_Generator_New((__pyx_coroutine_body_t) __pyx_gb_10constraint_7solvers_8is_valid_2generator2, NULL, (PyObject *) __pyx_cur_scope, __pyx_n_s_genexpr, __pyx_n_s_is_valid_locals_genexpr, __pyx_n_s_constraint_solvers); if (unlikely(!gen)) __PYX_ERR(0, 612, __pyx_L1_error) - __Pyx_DECREF(__pyx_cur_scope); - __Pyx_RefNannyFinishContext(); - return (PyObject *) gen; - } + /* "constraint/solvers.py":644 + * """ # noqa E501 + * + * def __init__(self, process_mode=False): # <<<<<<<<<<<<<< + * """Initialization method. Set `process_mode` to True for using ProcessPool, otherwise uses ThreadPool.""" + * super().__init__() + */ /* function exit code */ + __pyx_r = Py_None; __Pyx_INCREF(Py_None); + goto __pyx_L0; __pyx_L1_error:; - __Pyx_AddTraceback("constraint.solvers.is_valid.genexpr", __pyx_clineno, __pyx_lineno, __pyx_filename); + __Pyx_XDECREF(__pyx_t_1); + __Pyx_XDECREF(__pyx_t_2); + __Pyx_XDECREF(__pyx_t_3); + __Pyx_AddTraceback("constraint.solvers.ParallelSolver.__init__", __pyx_clineno, __pyx_lineno, __pyx_filename); __pyx_r = NULL; - __Pyx_XDECREF(__pyx_gb_10constraint_7solvers_8is_valid_7genexpr_2generator3); - __Pyx_DECREF((PyObject *)__pyx_cur_scope); + __pyx_L0:; __Pyx_XGIVEREF(__pyx_r); __Pyx_RefNannyFinishContext(); return __pyx_r; } -static PyObject *__pyx_gb_10constraint_7solvers_8is_valid_2generator2(__pyx_CoroutineObject *__pyx_generator, CYTHON_UNUSED PyThreadState *__pyx_tstate, PyObject *__pyx_sent_value) /* generator body */ -{ - struct __pyx_obj_10constraint_7solvers___pyx_scope_struct_3_genexpr *__pyx_cur_scope = ((struct __pyx_obj_10constraint_7solvers___pyx_scope_struct_3_genexpr *)__pyx_generator->closure); - PyObject *__pyx_r = NULL; - PyObject *__pyx_t_1 = NULL; - Py_ssize_t __pyx_t_2; - PyObject *__pyx_t_3 = NULL; - PyObject *__pyx_t_4 = NULL; - PyObject *__pyx_t_5 = NULL; - PyObject *__pyx_t_6 = NULL; - PyObject *(*__pyx_t_7)(PyObject *); - int __pyx_t_8; - unsigned int __pyx_t_9; - int __pyx_t_10; +/* "constraint/solvers.py":650 + * self.requires_pickling = process_mode + * + * def getSolution(self, domains: dict, constraints: list[tuple], vconstraints: dict): # <<<<<<<<<<<<<< + * """Return one solution for the given problem. + * + */ + +/* Python wrapper */ +static PyObject *__pyx_pw_10constraint_7solvers_14ParallelSolver_3getSolution(PyObject *__pyx_self, +#if CYTHON_METH_FASTCALL +PyObject *const *__pyx_args, Py_ssize_t __pyx_nargs, PyObject *__pyx_kwds +#else +PyObject *__pyx_args, PyObject *__pyx_kwds +#endif +); /*proto*/ +PyDoc_STRVAR(__pyx_doc_10constraint_7solvers_14ParallelSolver_2getSolution, "Return one solution for the given problem.\n\n Args:\n domains (dict): Dictionary mapping variables to their domains\n constraints (list): List of pairs of (constraint, variables)\n vconstraints (dict): Dictionary mapping variables to a list\n of constraints affecting the given variables.\n "); +static PyMethodDef __pyx_mdef_10constraint_7solvers_14ParallelSolver_3getSolution = {"getSolution", (PyCFunction)(void*)(__Pyx_PyCFunction_FastCallWithKeywords)__pyx_pw_10constraint_7solvers_14ParallelSolver_3getSolution, __Pyx_METH_FASTCALL|METH_KEYWORDS, __pyx_doc_10constraint_7solvers_14ParallelSolver_2getSolution}; +static PyObject *__pyx_pw_10constraint_7solvers_14ParallelSolver_3getSolution(PyObject *__pyx_self, +#if CYTHON_METH_FASTCALL +PyObject *const *__pyx_args, Py_ssize_t __pyx_nargs, PyObject *__pyx_kwds +#else +PyObject *__pyx_args, PyObject *__pyx_kwds +#endif +) { + PyObject *__pyx_v_self = 0; + CYTHON_UNUSED PyObject *__pyx_v_domains = 0; + CYTHON_UNUSED PyObject *__pyx_v_constraints = 0; + CYTHON_UNUSED PyObject *__pyx_v_vconstraints = 0; + #if !CYTHON_METH_FASTCALL + CYTHON_UNUSED Py_ssize_t __pyx_nargs; + #endif + CYTHON_UNUSED PyObject *const *__pyx_kwvalues; + PyObject* values[4] = {0,0,0,0}; int __pyx_lineno = 0; const char *__pyx_filename = NULL; int __pyx_clineno = 0; + PyObject *__pyx_r = 0; __Pyx_RefNannyDeclarations - __Pyx_RefNannySetupContext("genexpr", 0); - switch (__pyx_generator->resume_label) { - case 0: goto __pyx_L3_first_run; - default: /* CPython raises the right error here */ - __Pyx_RefNannyFinishContext(); - return NULL; - } - __pyx_L3_first_run:; - if (unlikely(!__pyx_sent_value)) __PYX_ERR(0, 612, __pyx_L1_error) - - /* "constraint/solvers.py":613 - * return all( - * constraint(vars_involved, domains, assignment, None) - * for constraint, vars_involved in constraints_lookup # <<<<<<<<<<<<<< - * if all(v in assignment for v in vars_involved) - * ) - */ - if (unlikely(!__pyx_cur_scope->__pyx_genexpr_arg_0)) { __Pyx_RaiseUnboundLocalError(".0"); __PYX_ERR(0, 613, __pyx_L1_error) } - __pyx_t_1 = __pyx_cur_scope->__pyx_genexpr_arg_0; __Pyx_INCREF(__pyx_t_1); - __pyx_t_2 = 0; - for (;;) { - { - Py_ssize_t __pyx_temp = __Pyx_PyList_GET_SIZE(__pyx_t_1); - #if !CYTHON_ASSUME_SAFE_MACROS - if (unlikely((__pyx_temp < 0))) __PYX_ERR(0, 613, __pyx_L1_error) - #endif - if (__pyx_t_2 >= __pyx_temp) break; - } - #if CYTHON_ASSUME_SAFE_MACROS && !CYTHON_AVOID_BORROWED_REFS - __pyx_t_3 = PyList_GET_ITEM(__pyx_t_1, __pyx_t_2); __Pyx_INCREF(__pyx_t_3); __pyx_t_2++; if (unlikely((0 < 0))) __PYX_ERR(0, 613, __pyx_L1_error) - #else - __pyx_t_3 = __Pyx_PySequence_ITEM(__pyx_t_1, __pyx_t_2); __pyx_t_2++; if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 613, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_3); - #endif - if ((likely(PyTuple_CheckExact(__pyx_t_3))) || (PyList_CheckExact(__pyx_t_3))) { - PyObject* sequence = __pyx_t_3; - Py_ssize_t size = __Pyx_PySequence_SIZE(sequence); - if (unlikely(size != 2)) { - if (size > 2) __Pyx_RaiseTooManyValuesError(2); - else if (size >= 0) __Pyx_RaiseNeedMoreValuesError(size); - __PYX_ERR(0, 613, __pyx_L1_error) + __Pyx_RefNannySetupContext("getSolution (wrapper)", 0); + #if !CYTHON_METH_FASTCALL + #if CYTHON_ASSUME_SAFE_MACROS + __pyx_nargs = PyTuple_GET_SIZE(__pyx_args); + #else + __pyx_nargs = PyTuple_Size(__pyx_args); if (unlikely(__pyx_nargs < 0)) return NULL; + #endif + #endif + __pyx_kwvalues = __Pyx_KwValues_FASTCALL(__pyx_args, __pyx_nargs); + { + PyObject **__pyx_pyargnames[] = {&__pyx_n_s_self,&__pyx_n_s_domains,&__pyx_n_s_constraints,&__pyx_n_s_vconstraints,0}; + if (__pyx_kwds) { + Py_ssize_t kw_args; + switch (__pyx_nargs) { + case 4: values[3] = __Pyx_Arg_FASTCALL(__pyx_args, 3); + CYTHON_FALLTHROUGH; + case 3: values[2] = __Pyx_Arg_FASTCALL(__pyx_args, 2); + CYTHON_FALLTHROUGH; + case 2: values[1] = __Pyx_Arg_FASTCALL(__pyx_args, 1); + CYTHON_FALLTHROUGH; + case 1: values[0] = __Pyx_Arg_FASTCALL(__pyx_args, 0); + CYTHON_FALLTHROUGH; + case 0: break; + default: goto __pyx_L5_argtuple_error; } - #if CYTHON_ASSUME_SAFE_MACROS && !CYTHON_AVOID_BORROWED_REFS - if (likely(PyTuple_CheckExact(sequence))) { - __pyx_t_4 = PyTuple_GET_ITEM(sequence, 0); - __pyx_t_5 = PyTuple_GET_ITEM(sequence, 1); - } else { - __pyx_t_4 = PyList_GET_ITEM(sequence, 0); - __pyx_t_5 = PyList_GET_ITEM(sequence, 1); + kw_args = __Pyx_NumKwargs_FASTCALL(__pyx_kwds); + switch (__pyx_nargs) { + case 0: + if (likely((values[0] = __Pyx_GetKwValue_FASTCALL(__pyx_kwds, __pyx_kwvalues, __pyx_n_s_self)) != 0)) { + (void)__Pyx_Arg_NewRef_FASTCALL(values[0]); + kw_args--; + } + else if (unlikely(PyErr_Occurred())) __PYX_ERR(0, 650, __pyx_L3_error) + else goto __pyx_L5_argtuple_error; + CYTHON_FALLTHROUGH; + case 1: + if (likely((values[1] = __Pyx_GetKwValue_FASTCALL(__pyx_kwds, __pyx_kwvalues, __pyx_n_s_domains)) != 0)) { + (void)__Pyx_Arg_NewRef_FASTCALL(values[1]); + kw_args--; + } + else if (unlikely(PyErr_Occurred())) __PYX_ERR(0, 650, __pyx_L3_error) + else { + __Pyx_RaiseArgtupleInvalid("getSolution", 1, 4, 4, 1); __PYX_ERR(0, 650, __pyx_L3_error) + } + CYTHON_FALLTHROUGH; + case 2: + if (likely((values[2] = __Pyx_GetKwValue_FASTCALL(__pyx_kwds, __pyx_kwvalues, __pyx_n_s_constraints)) != 0)) { + (void)__Pyx_Arg_NewRef_FASTCALL(values[2]); + kw_args--; + } + else if (unlikely(PyErr_Occurred())) __PYX_ERR(0, 650, __pyx_L3_error) + else { + __Pyx_RaiseArgtupleInvalid("getSolution", 1, 4, 4, 2); __PYX_ERR(0, 650, __pyx_L3_error) + } + CYTHON_FALLTHROUGH; + case 3: + if (likely((values[3] = __Pyx_GetKwValue_FASTCALL(__pyx_kwds, __pyx_kwvalues, __pyx_n_s_vconstraints)) != 0)) { + (void)__Pyx_Arg_NewRef_FASTCALL(values[3]); + kw_args--; + } + else if (unlikely(PyErr_Occurred())) __PYX_ERR(0, 650, __pyx_L3_error) + else { + __Pyx_RaiseArgtupleInvalid("getSolution", 1, 4, 4, 3); __PYX_ERR(0, 650, __pyx_L3_error) + } } - __Pyx_INCREF(__pyx_t_4); - __Pyx_INCREF(__pyx_t_5); - #else - __pyx_t_4 = PySequence_ITEM(sequence, 0); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 613, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_4); - __pyx_t_5 = PySequence_ITEM(sequence, 1); if (unlikely(!__pyx_t_5)) __PYX_ERR(0, 613, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_5); - #endif - __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; + if (unlikely(kw_args > 0)) { + const Py_ssize_t kwd_pos_args = __pyx_nargs; + if (unlikely(__Pyx_ParseOptionalKeywords(__pyx_kwds, __pyx_kwvalues, __pyx_pyargnames, 0, values + 0, kwd_pos_args, "getSolution") < 0)) __PYX_ERR(0, 650, __pyx_L3_error) + } + } else if (unlikely(__pyx_nargs != 4)) { + goto __pyx_L5_argtuple_error; } else { - Py_ssize_t index = -1; - __pyx_t_6 = PyObject_GetIter(__pyx_t_3); if (unlikely(!__pyx_t_6)) __PYX_ERR(0, 613, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_6); - __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; - __pyx_t_7 = __Pyx_PyObject_GetIterNextFunc(__pyx_t_6); - index = 0; __pyx_t_4 = __pyx_t_7(__pyx_t_6); if (unlikely(!__pyx_t_4)) goto __pyx_L6_unpacking_failed; - __Pyx_GOTREF(__pyx_t_4); - index = 1; __pyx_t_5 = __pyx_t_7(__pyx_t_6); if (unlikely(!__pyx_t_5)) goto __pyx_L6_unpacking_failed; - __Pyx_GOTREF(__pyx_t_5); - if (__Pyx_IternextUnpackEndCheck(__pyx_t_7(__pyx_t_6), 2) < 0) __PYX_ERR(0, 613, __pyx_L1_error) - __pyx_t_7 = NULL; - __Pyx_DECREF(__pyx_t_6); __pyx_t_6 = 0; - goto __pyx_L7_unpacking_done; - __pyx_L6_unpacking_failed:; - __Pyx_DECREF(__pyx_t_6); __pyx_t_6 = 0; - __pyx_t_7 = NULL; - if (__Pyx_IterFinish() == 0) __Pyx_RaiseNeedMoreValuesError(index); - __PYX_ERR(0, 613, __pyx_L1_error) - __pyx_L7_unpacking_done:; + values[0] = __Pyx_Arg_FASTCALL(__pyx_args, 0); + values[1] = __Pyx_Arg_FASTCALL(__pyx_args, 1); + values[2] = __Pyx_Arg_FASTCALL(__pyx_args, 2); + values[3] = __Pyx_Arg_FASTCALL(__pyx_args, 3); } - __Pyx_XGOTREF(__pyx_cur_scope->__pyx_v_constraint); - __Pyx_XDECREF_SET(__pyx_cur_scope->__pyx_v_constraint, __pyx_t_4); - __Pyx_GIVEREF(__pyx_t_4); - __pyx_t_4 = 0; - __Pyx_XGOTREF(__pyx_cur_scope->__pyx_v_vars_involved); - __Pyx_XDECREF_SET(__pyx_cur_scope->__pyx_v_vars_involved, __pyx_t_5); - __Pyx_GIVEREF(__pyx_t_5); - __pyx_t_5 = 0; + __pyx_v_self = values[0]; + __pyx_v_domains = ((PyObject*)values[1]); + __pyx_v_constraints = ((PyObject*)values[2]); + __pyx_v_vconstraints = ((PyObject*)values[3]); + } + goto __pyx_L6_skip; + __pyx_L5_argtuple_error:; + __Pyx_RaiseArgtupleInvalid("getSolution", 1, 4, 4, __pyx_nargs); __PYX_ERR(0, 650, __pyx_L3_error) + __pyx_L6_skip:; + goto __pyx_L4_argument_unpacking_done; + __pyx_L3_error:; + { + Py_ssize_t __pyx_temp; + for (__pyx_temp=0; __pyx_temp < (Py_ssize_t)(sizeof(values)/sizeof(values[0])); ++__pyx_temp) { + __Pyx_Arg_XDECREF_FASTCALL(values[__pyx_temp]); + } + } + __Pyx_AddTraceback("constraint.solvers.ParallelSolver.getSolution", __pyx_clineno, __pyx_lineno, __pyx_filename); + __Pyx_RefNannyFinishContext(); + return NULL; + __pyx_L4_argument_unpacking_done:; + if (unlikely(!__Pyx_ArgTypeTest(((PyObject *)__pyx_v_domains), (&PyDict_Type), 0, "domains", 1))) __PYX_ERR(0, 650, __pyx_L1_error) + if (unlikely(!__Pyx_ArgTypeTest(((PyObject *)__pyx_v_constraints), (&PyList_Type), 0, "constraints", 1))) __PYX_ERR(0, 650, __pyx_L1_error) + if (unlikely(!__Pyx_ArgTypeTest(((PyObject *)__pyx_v_vconstraints), (&PyDict_Type), 0, "vconstraints", 1))) __PYX_ERR(0, 650, __pyx_L1_error) + __pyx_r = __pyx_pf_10constraint_7solvers_14ParallelSolver_2getSolution(__pyx_self, __pyx_v_self, __pyx_v_domains, __pyx_v_constraints, __pyx_v_vconstraints); - /* "constraint/solvers.py":614 - * constraint(vars_involved, domains, assignment, None) - * for constraint, vars_involved in constraints_lookup - * if all(v in assignment for v in vars_involved) # <<<<<<<<<<<<<< - * ) - * - */ - __pyx_t_3 = __pyx_pf_10constraint_7solvers_8is_valid_7genexpr_genexpr(((PyObject*)__pyx_cur_scope), __pyx_cur_scope->__pyx_v_vars_involved); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 614, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_3); - __pyx_t_5 = __Pyx_Generator_Next(__pyx_t_3); if (unlikely(!__pyx_t_5)) __PYX_ERR(0, 614, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_5); - __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; - __pyx_t_8 = __Pyx_PyObject_IsTrue(__pyx_t_5); if (unlikely((__pyx_t_8 < 0))) __PYX_ERR(0, 614, __pyx_L1_error) - __Pyx_DECREF(__pyx_t_5); __pyx_t_5 = 0; - if (__pyx_t_8) { + /* function exit code */ + goto __pyx_L0; + __pyx_L1_error:; + __pyx_r = NULL; + __pyx_L0:; + { + Py_ssize_t __pyx_temp; + for (__pyx_temp=0; __pyx_temp < (Py_ssize_t)(sizeof(values)/sizeof(values[0])); ++__pyx_temp) { + __Pyx_Arg_XDECREF_FASTCALL(values[__pyx_temp]); + } + } + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} - /* "constraint/solvers.py":612 - * """Check if all constraints are satisfied given the current assignment.""" - * return all( - * constraint(vars_involved, domains, assignment, None) # <<<<<<<<<<<<<< - * for constraint, vars_involved in constraints_lookup - * if all(v in assignment for v in vars_involved) - */ - if (unlikely(!__pyx_cur_scope->__pyx_outer_scope->__pyx_v_domains)) { __Pyx_RaiseClosureNameError("domains"); __PYX_ERR(0, 612, __pyx_L1_error) } - if (unlikely(!__pyx_cur_scope->__pyx_outer_scope->__pyx_v_assignment)) { __Pyx_RaiseClosureNameError("assignment"); __PYX_ERR(0, 612, __pyx_L1_error) } - __Pyx_INCREF(__pyx_cur_scope->__pyx_v_constraint); - __pyx_t_3 = __pyx_cur_scope->__pyx_v_constraint; __pyx_t_4 = NULL; - __pyx_t_9 = 0; - #if CYTHON_UNPACK_METHODS - if (unlikely(PyMethod_Check(__pyx_t_3))) { - __pyx_t_4 = PyMethod_GET_SELF(__pyx_t_3); - if (likely(__pyx_t_4)) { - PyObject* function = PyMethod_GET_FUNCTION(__pyx_t_3); - __Pyx_INCREF(__pyx_t_4); - __Pyx_INCREF(function); - __Pyx_DECREF_SET(__pyx_t_3, function); - __pyx_t_9 = 1; - } - } - #endif - { - PyObject *__pyx_callargs[5] = {__pyx_t_4, __pyx_cur_scope->__pyx_v_vars_involved, __pyx_cur_scope->__pyx_outer_scope->__pyx_v_domains, __pyx_cur_scope->__pyx_outer_scope->__pyx_v_assignment, Py_None}; - __pyx_t_5 = __Pyx_PyObject_FastCall(__pyx_t_3, __pyx_callargs+1-__pyx_t_9, 4+__pyx_t_9); - __Pyx_XDECREF(__pyx_t_4); __pyx_t_4 = 0; - if (unlikely(!__pyx_t_5)) __PYX_ERR(0, 612, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_5); - __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; - } - __pyx_t_8 = __Pyx_PyObject_IsTrue(__pyx_t_5); if (unlikely((__pyx_t_8 < 0))) __PYX_ERR(0, 612, __pyx_L1_error) - __Pyx_DECREF(__pyx_t_5); __pyx_t_5 = 0; - __pyx_t_10 = (!__pyx_t_8); - if (__pyx_t_10) { +static PyObject *__pyx_pf_10constraint_7solvers_14ParallelSolver_2getSolution(CYTHON_UNUSED PyObject *__pyx_self, PyObject *__pyx_v_self, CYTHON_UNUSED PyObject *__pyx_v_domains, CYTHON_UNUSED PyObject *__pyx_v_constraints, CYTHON_UNUSED PyObject *__pyx_v_vconstraints) { + PyObject *__pyx_v_msg = NULL; + PyObject *__pyx_r = NULL; + __Pyx_RefNannyDeclarations + PyObject *__pyx_t_1 = NULL; + PyObject *__pyx_t_2 = NULL; + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + __Pyx_RefNannySetupContext("getSolution", 1); - /* "constraint/solvers.py":611 - * def is_valid(assignment: dict[Hashable, any], constraints_lookup: list[tuple[Constraint, Hashable]], domains: dict[Hashable, Domain]) -> bool: # noqa E501 - * """Check if all constraints are satisfied given the current assignment.""" - * return all( # <<<<<<<<<<<<<< - * constraint(vars_involved, domains, assignment, None) - * for constraint, vars_involved in constraints_lookup + /* "constraint/solvers.py":659 + * of constraints affecting the given variables. + * """ + * msg = f"{self.__class__.__name__} only provides all solutions" # <<<<<<<<<<<<<< + * raise NotImplementedError(msg) + * */ - __Pyx_XDECREF(__pyx_r); + __pyx_t_1 = __Pyx_PyObject_GetAttrStr(__pyx_v_self, __pyx_n_s_class); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 659, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __pyx_t_2 = __Pyx_PyObject_GetAttrStr(__pyx_t_1, __pyx_n_s_name); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 659, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_2); + __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; + __pyx_t_1 = __Pyx_PyObject_FormatSimple(__pyx_t_2, __pyx_empty_unicode); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 659, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; + __pyx_t_2 = __Pyx_PyUnicode_ConcatInPlace(__pyx_t_1, __pyx_kp_u_only_provides_all_solutions); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 659, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_2); + __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; + __pyx_v_msg = ((PyObject*)__pyx_t_2); + __pyx_t_2 = 0; - /* "constraint/solvers.py":612 - * """Check if all constraints are satisfied given the current assignment.""" - * return all( - * constraint(vars_involved, domains, assignment, None) # <<<<<<<<<<<<<< - * for constraint, vars_involved in constraints_lookup - * if all(v in assignment for v in vars_involved) + /* "constraint/solvers.py":660 + * """ + * msg = f"{self.__class__.__name__} only provides all solutions" + * raise NotImplementedError(msg) # <<<<<<<<<<<<<< + * + * def getSolutionsList(self, domains: dict[Hashable, Domain], vconstraints: dict[Hashable, list[tuple[Constraint, Hashable]]]) -> list[dict[Hashable, any]]: # noqa: D102, E501 */ - __Pyx_INCREF(Py_False); - __pyx_r = Py_False; - __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; - goto __pyx_L0; - } + __pyx_t_2 = __Pyx_PyObject_CallOneArg(__pyx_builtin_NotImplementedError, __pyx_v_msg); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 660, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_2); + __Pyx_Raise(__pyx_t_2, 0, 0, 0); + __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; + __PYX_ERR(0, 660, __pyx_L1_error) - /* "constraint/solvers.py":614 - * constraint(vars_involved, domains, assignment, None) - * for constraint, vars_involved in constraints_lookup - * if all(v in assignment for v in vars_involved) # <<<<<<<<<<<<<< - * ) + /* "constraint/solvers.py":650 + * self.requires_pickling = process_mode + * + * def getSolution(self, domains: dict, constraints: list[tuple], vconstraints: dict): # <<<<<<<<<<<<<< + * """Return one solution for the given problem. * */ - } - - /* "constraint/solvers.py":613 - * return all( - * constraint(vars_involved, domains, assignment, None) - * for constraint, vars_involved in constraints_lookup # <<<<<<<<<<<<<< - * if all(v in assignment for v in vars_involved) - * ) - */ - } - __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; - /*else*/ { - - /* "constraint/solvers.py":611 - * def is_valid(assignment: dict[Hashable, any], constraints_lookup: list[tuple[Constraint, Hashable]], domains: dict[Hashable, Domain]) -> bool: # noqa E501 - * """Check if all constraints are satisfied given the current assignment.""" - * return all( # <<<<<<<<<<<<<< - * constraint(vars_involved, domains, assignment, None) - * for constraint, vars_involved in constraints_lookup - */ - __Pyx_XDECREF(__pyx_r); - - /* "constraint/solvers.py":612 - * """Check if all constraints are satisfied given the current assignment.""" - * return all( - * constraint(vars_involved, domains, assignment, None) # <<<<<<<<<<<<<< - * for constraint, vars_involved in constraints_lookup - * if all(v in assignment for v in vars_involved) - */ - __Pyx_INCREF(Py_True); - __pyx_r = Py_True; - goto __pyx_L0; - } - CYTHON_MAYBE_UNUSED_VAR(__pyx_cur_scope); /* function exit code */ - goto __pyx_L0; __pyx_L1_error:; - __Pyx_Generator_Replace_StopIteration(0); __Pyx_XDECREF(__pyx_t_1); - __Pyx_XDECREF(__pyx_t_3); - __Pyx_XDECREF(__pyx_t_4); - __Pyx_XDECREF(__pyx_t_5); - __Pyx_XDECREF(__pyx_t_6); - __Pyx_AddTraceback("genexpr", __pyx_clineno, __pyx_lineno, __pyx_filename); - __pyx_L0:; + __Pyx_XDECREF(__pyx_t_2); + __Pyx_AddTraceback("constraint.solvers.ParallelSolver.getSolution", __pyx_clineno, __pyx_lineno, __pyx_filename); + __pyx_r = NULL; + __Pyx_XDECREF(__pyx_v_msg); __Pyx_XGIVEREF(__pyx_r); - #if !CYTHON_USE_EXC_INFO_STACK - __Pyx_Coroutine_ResetAndClearException(__pyx_generator); - #endif - __pyx_generator->resume_label = -1; - __Pyx_Coroutine_clear((PyObject*)__pyx_generator); __Pyx_RefNannyFinishContext(); return __pyx_r; } -/* "constraint/solvers.py":609 - * ### Helper functions for parallel solver +/* "constraint/solvers.py":662 + * raise NotImplementedError(msg) * - * def is_valid(assignment: dict[Hashable, any], constraints_lookup: list[tuple[Constraint, Hashable]], domains: dict[Hashable, Domain]) -> bool: # noqa E501 # <<<<<<<<<<<<<< - * """Check if all constraints are satisfied given the current assignment.""" - * return all( + * def getSolutionsList(self, domains: dict[Hashable, Domain], vconstraints: dict[Hashable, list[tuple[Constraint, Hashable]]]) -> list[dict[Hashable, any]]: # noqa: D102, E501 # <<<<<<<<<<<<<< + * """Parallelized all-solutions finder using ProcessPoolExecutor for work-stealing.""" + * # Precompute constraints lookup per variable */ -static PyObject *__pyx_pf_10constraint_7solvers_4is_valid(CYTHON_UNUSED PyObject *__pyx_self, PyObject *__pyx_v_assignment, PyObject *__pyx_v_constraints_lookup, PyObject *__pyx_v_domains) { - struct __pyx_obj_10constraint_7solvers___pyx_scope_struct_2_is_valid *__pyx_cur_scope; - PyObject *__pyx_gb_10constraint_7solvers_8is_valid_2generator2 = 0; - PyObject *__pyx_r = NULL; - __Pyx_RefNannyDeclarations - PyObject *__pyx_t_1 = NULL; - PyObject *__pyx_t_2 = NULL; +/* Python wrapper */ +static PyObject *__pyx_pw_10constraint_7solvers_14ParallelSolver_5getSolutionsList(PyObject *__pyx_self, +#if CYTHON_METH_FASTCALL +PyObject *const *__pyx_args, Py_ssize_t __pyx_nargs, PyObject *__pyx_kwds +#else +PyObject *__pyx_args, PyObject *__pyx_kwds +#endif +); /*proto*/ +PyDoc_STRVAR(__pyx_doc_10constraint_7solvers_14ParallelSolver_4getSolutionsList, "Parallelized all-solutions finder using ProcessPoolExecutor for work-stealing."); +static PyMethodDef __pyx_mdef_10constraint_7solvers_14ParallelSolver_5getSolutionsList = {"getSolutionsList", (PyCFunction)(void*)(__Pyx_PyCFunction_FastCallWithKeywords)__pyx_pw_10constraint_7solvers_14ParallelSolver_5getSolutionsList, __Pyx_METH_FASTCALL|METH_KEYWORDS, __pyx_doc_10constraint_7solvers_14ParallelSolver_4getSolutionsList}; +static PyObject *__pyx_pw_10constraint_7solvers_14ParallelSolver_5getSolutionsList(PyObject *__pyx_self, +#if CYTHON_METH_FASTCALL +PyObject *const *__pyx_args, Py_ssize_t __pyx_nargs, PyObject *__pyx_kwds +#else +PyObject *__pyx_args, PyObject *__pyx_kwds +#endif +) { + PyObject *__pyx_v_self = 0; + PyObject *__pyx_v_domains = 0; + PyObject *__pyx_v_vconstraints = 0; + #if !CYTHON_METH_FASTCALL + CYTHON_UNUSED Py_ssize_t __pyx_nargs; + #endif + CYTHON_UNUSED PyObject *const *__pyx_kwvalues; + PyObject* values[3] = {0,0,0}; int __pyx_lineno = 0; const char *__pyx_filename = NULL; int __pyx_clineno = 0; - __Pyx_RefNannySetupContext("is_valid", 0); - __pyx_cur_scope = (struct __pyx_obj_10constraint_7solvers___pyx_scope_struct_2_is_valid *)__pyx_tp_new_10constraint_7solvers___pyx_scope_struct_2_is_valid(__pyx_ptype_10constraint_7solvers___pyx_scope_struct_2_is_valid, __pyx_empty_tuple, NULL); - if (unlikely(!__pyx_cur_scope)) { - __pyx_cur_scope = ((struct __pyx_obj_10constraint_7solvers___pyx_scope_struct_2_is_valid *)Py_None); - __Pyx_INCREF(Py_None); - __PYX_ERR(0, 609, __pyx_L1_error) - } else { - __Pyx_GOTREF((PyObject *)__pyx_cur_scope); + PyObject *__pyx_r = 0; + __Pyx_RefNannyDeclarations + __Pyx_RefNannySetupContext("getSolutionsList (wrapper)", 0); + #if !CYTHON_METH_FASTCALL + #if CYTHON_ASSUME_SAFE_MACROS + __pyx_nargs = PyTuple_GET_SIZE(__pyx_args); + #else + __pyx_nargs = PyTuple_Size(__pyx_args); if (unlikely(__pyx_nargs < 0)) return NULL; + #endif + #endif + __pyx_kwvalues = __Pyx_KwValues_FASTCALL(__pyx_args, __pyx_nargs); + { + PyObject **__pyx_pyargnames[] = {&__pyx_n_s_self,&__pyx_n_s_domains,&__pyx_n_s_vconstraints,0}; + if (__pyx_kwds) { + Py_ssize_t kw_args; + switch (__pyx_nargs) { + case 3: values[2] = __Pyx_Arg_FASTCALL(__pyx_args, 2); + CYTHON_FALLTHROUGH; + case 2: values[1] = __Pyx_Arg_FASTCALL(__pyx_args, 1); + CYTHON_FALLTHROUGH; + case 1: values[0] = __Pyx_Arg_FASTCALL(__pyx_args, 0); + CYTHON_FALLTHROUGH; + case 0: break; + default: goto __pyx_L5_argtuple_error; + } + kw_args = __Pyx_NumKwargs_FASTCALL(__pyx_kwds); + switch (__pyx_nargs) { + case 0: + if (likely((values[0] = __Pyx_GetKwValue_FASTCALL(__pyx_kwds, __pyx_kwvalues, __pyx_n_s_self)) != 0)) { + (void)__Pyx_Arg_NewRef_FASTCALL(values[0]); + kw_args--; + } + else if (unlikely(PyErr_Occurred())) __PYX_ERR(0, 662, __pyx_L3_error) + else goto __pyx_L5_argtuple_error; + CYTHON_FALLTHROUGH; + case 1: + if (likely((values[1] = __Pyx_GetKwValue_FASTCALL(__pyx_kwds, __pyx_kwvalues, __pyx_n_s_domains)) != 0)) { + (void)__Pyx_Arg_NewRef_FASTCALL(values[1]); + kw_args--; + } + else if (unlikely(PyErr_Occurred())) __PYX_ERR(0, 662, __pyx_L3_error) + else { + __Pyx_RaiseArgtupleInvalid("getSolutionsList", 1, 3, 3, 1); __PYX_ERR(0, 662, __pyx_L3_error) + } + CYTHON_FALLTHROUGH; + case 2: + if (likely((values[2] = __Pyx_GetKwValue_FASTCALL(__pyx_kwds, __pyx_kwvalues, __pyx_n_s_vconstraints)) != 0)) { + (void)__Pyx_Arg_NewRef_FASTCALL(values[2]); + kw_args--; + } + else if (unlikely(PyErr_Occurred())) __PYX_ERR(0, 662, __pyx_L3_error) + else { + __Pyx_RaiseArgtupleInvalid("getSolutionsList", 1, 3, 3, 2); __PYX_ERR(0, 662, __pyx_L3_error) + } + } + if (unlikely(kw_args > 0)) { + const Py_ssize_t kwd_pos_args = __pyx_nargs; + if (unlikely(__Pyx_ParseOptionalKeywords(__pyx_kwds, __pyx_kwvalues, __pyx_pyargnames, 0, values + 0, kwd_pos_args, "getSolutionsList") < 0)) __PYX_ERR(0, 662, __pyx_L3_error) + } + } else if (unlikely(__pyx_nargs != 3)) { + goto __pyx_L5_argtuple_error; + } else { + values[0] = __Pyx_Arg_FASTCALL(__pyx_args, 0); + values[1] = __Pyx_Arg_FASTCALL(__pyx_args, 1); + values[2] = __Pyx_Arg_FASTCALL(__pyx_args, 2); + } + __pyx_v_self = values[0]; + __pyx_v_domains = ((PyObject*)values[1]); + __pyx_v_vconstraints = ((PyObject*)values[2]); } - __pyx_cur_scope->__pyx_v_assignment = __pyx_v_assignment; - __Pyx_INCREF(__pyx_cur_scope->__pyx_v_assignment); - __Pyx_GIVEREF(__pyx_cur_scope->__pyx_v_assignment); - __pyx_cur_scope->__pyx_v_domains = __pyx_v_domains; - __Pyx_INCREF(__pyx_cur_scope->__pyx_v_domains); - __Pyx_GIVEREF(__pyx_cur_scope->__pyx_v_domains); - - /* "constraint/solvers.py":611 - * def is_valid(assignment: dict[Hashable, any], constraints_lookup: list[tuple[Constraint, Hashable]], domains: dict[Hashable, Domain]) -> bool: # noqa E501 - * """Check if all constraints are satisfied given the current assignment.""" - * return all( # <<<<<<<<<<<<<< - * constraint(vars_involved, domains, assignment, None) - * for constraint, vars_involved in constraints_lookup - */ - __Pyx_XDECREF(__pyx_r); - - /* "constraint/solvers.py":612 - * """Check if all constraints are satisfied given the current assignment.""" - * return all( - * constraint(vars_involved, domains, assignment, None) # <<<<<<<<<<<<<< - * for constraint, vars_involved in constraints_lookup - * if all(v in assignment for v in vars_involved) - */ - __pyx_t_1 = __pyx_pf_10constraint_7solvers_8is_valid_genexpr(((PyObject*)__pyx_cur_scope), __pyx_v_constraints_lookup); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 612, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_1); - __pyx_t_2 = __Pyx_Generator_Next(__pyx_t_1); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 612, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_2); - __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; - __pyx_r = __pyx_t_2; - __pyx_t_2 = 0; - goto __pyx_L0; - - /* "constraint/solvers.py":609 - * ### Helper functions for parallel solver - * - * def is_valid(assignment: dict[Hashable, any], constraints_lookup: list[tuple[Constraint, Hashable]], domains: dict[Hashable, Domain]) -> bool: # noqa E501 # <<<<<<<<<<<<<< - * """Check if all constraints are satisfied given the current assignment.""" - * return all( - */ + goto __pyx_L6_skip; + __pyx_L5_argtuple_error:; + __Pyx_RaiseArgtupleInvalid("getSolutionsList", 1, 3, 3, __pyx_nargs); __PYX_ERR(0, 662, __pyx_L3_error) + __pyx_L6_skip:; + goto __pyx_L4_argument_unpacking_done; + __pyx_L3_error:; + { + Py_ssize_t __pyx_temp; + for (__pyx_temp=0; __pyx_temp < (Py_ssize_t)(sizeof(values)/sizeof(values[0])); ++__pyx_temp) { + __Pyx_Arg_XDECREF_FASTCALL(values[__pyx_temp]); + } + } + __Pyx_AddTraceback("constraint.solvers.ParallelSolver.getSolutionsList", __pyx_clineno, __pyx_lineno, __pyx_filename); + __Pyx_RefNannyFinishContext(); + return NULL; + __pyx_L4_argument_unpacking_done:; + if (unlikely(!__Pyx_ArgTypeTest(((PyObject *)__pyx_v_domains), (&PyDict_Type), 0, "domains", 1))) __PYX_ERR(0, 662, __pyx_L1_error) + if (unlikely(!__Pyx_ArgTypeTest(((PyObject *)__pyx_v_vconstraints), (&PyDict_Type), 0, "vconstraints", 1))) __PYX_ERR(0, 662, __pyx_L1_error) + __pyx_r = __pyx_pf_10constraint_7solvers_14ParallelSolver_4getSolutionsList(__pyx_self, __pyx_v_self, __pyx_v_domains, __pyx_v_vconstraints); /* function exit code */ + goto __pyx_L0; __pyx_L1_error:; - __Pyx_XDECREF(__pyx_t_1); - __Pyx_XDECREF(__pyx_t_2); - __Pyx_AddTraceback("constraint.solvers.is_valid", __pyx_clineno, __pyx_lineno, __pyx_filename); __pyx_r = NULL; __pyx_L0:; - __Pyx_XDECREF(__pyx_gb_10constraint_7solvers_8is_valid_2generator2); - __Pyx_DECREF((PyObject *)__pyx_cur_scope); - __Pyx_XGIVEREF(__pyx_r); + { + Py_ssize_t __pyx_temp; + for (__pyx_temp=0; __pyx_temp < (Py_ssize_t)(sizeof(values)/sizeof(values[0])); ++__pyx_temp) { + __Pyx_Arg_XDECREF_FASTCALL(values[__pyx_temp]); + } + } __Pyx_RefNannyFinishContext(); return __pyx_r; } -/* "constraint/solvers.py":617 - * ) +/* "constraint/solvers.py":668 * - * def compile_to_function(constraint: CompilableFunctionConstraint) -> FunctionConstraint: # <<<<<<<<<<<<<< - * """Compile a CompilableFunctionConstraint to a function, wrapped by a FunctionConstraint.""" - * func_string = constraint._func + * # Sort variables by domain size (heuristic) + * sorted_vars: list[Hashable] = sorted(domains.keys(), key=lambda v: len(domains[v])) # <<<<<<<<<<<<<< + * + * # Split parallel and sequential parts */ /* Python wrapper */ -static PyObject *__pyx_pw_10constraint_7solvers_7compile_to_function(PyObject *__pyx_self, +static PyObject *__pyx_pw_10constraint_7solvers_14ParallelSolver_16getSolutionsList_lambda(PyObject *__pyx_self, #if CYTHON_METH_FASTCALL PyObject *const *__pyx_args, Py_ssize_t __pyx_nargs, PyObject *__pyx_kwds #else PyObject *__pyx_args, PyObject *__pyx_kwds #endif ); /*proto*/ -PyDoc_STRVAR(__pyx_doc_10constraint_7solvers_6compile_to_function, "Compile a CompilableFunctionConstraint to a function, wrapped by a FunctionConstraint."); -static PyMethodDef __pyx_mdef_10constraint_7solvers_7compile_to_function = {"compile_to_function", (PyCFunction)(void*)(__Pyx_PyCFunction_FastCallWithKeywords)__pyx_pw_10constraint_7solvers_7compile_to_function, __Pyx_METH_FASTCALL|METH_KEYWORDS, __pyx_doc_10constraint_7solvers_6compile_to_function}; -static PyObject *__pyx_pw_10constraint_7solvers_7compile_to_function(PyObject *__pyx_self, +static PyMethodDef __pyx_mdef_10constraint_7solvers_14ParallelSolver_16getSolutionsList_lambda = {"lambda", (PyCFunction)(void*)(__Pyx_PyCFunction_FastCallWithKeywords)__pyx_pw_10constraint_7solvers_14ParallelSolver_16getSolutionsList_lambda, __Pyx_METH_FASTCALL|METH_KEYWORDS, 0}; +static PyObject *__pyx_pw_10constraint_7solvers_14ParallelSolver_16getSolutionsList_lambda(PyObject *__pyx_self, #if CYTHON_METH_FASTCALL PyObject *const *__pyx_args, Py_ssize_t __pyx_nargs, PyObject *__pyx_kwds #else PyObject *__pyx_args, PyObject *__pyx_kwds #endif ) { - PyObject *__pyx_v_constraint = 0; + PyObject *__pyx_v_v = 0; #if !CYTHON_METH_FASTCALL CYTHON_UNUSED Py_ssize_t __pyx_nargs; #endif @@ -16345,7 +16241,7 @@ PyObject *__pyx_args, PyObject *__pyx_kwds int __pyx_clineno = 0; PyObject *__pyx_r = 0; __Pyx_RefNannyDeclarations - __Pyx_RefNannySetupContext("compile_to_function (wrapper)", 0); + __Pyx_RefNannySetupContext("lambda (wrapper)", 0); #if !CYTHON_METH_FASTCALL #if CYTHON_ASSUME_SAFE_MACROS __pyx_nargs = PyTuple_GET_SIZE(__pyx_args); @@ -16355,7 +16251,7 @@ PyObject *__pyx_args, PyObject *__pyx_kwds #endif __pyx_kwvalues = __Pyx_KwValues_FASTCALL(__pyx_args, __pyx_nargs); { - PyObject **__pyx_pyargnames[] = {&__pyx_n_s_constraint,0}; + PyObject **__pyx_pyargnames[] = {&__pyx_n_s_v,0}; if (__pyx_kwds) { Py_ssize_t kw_args; switch (__pyx_nargs) { @@ -16367,27 +16263,27 @@ PyObject *__pyx_args, PyObject *__pyx_kwds kw_args = __Pyx_NumKwargs_FASTCALL(__pyx_kwds); switch (__pyx_nargs) { case 0: - if (likely((values[0] = __Pyx_GetKwValue_FASTCALL(__pyx_kwds, __pyx_kwvalues, __pyx_n_s_constraint)) != 0)) { + if (likely((values[0] = __Pyx_GetKwValue_FASTCALL(__pyx_kwds, __pyx_kwvalues, __pyx_n_s_v)) != 0)) { (void)__Pyx_Arg_NewRef_FASTCALL(values[0]); kw_args--; } - else if (unlikely(PyErr_Occurred())) __PYX_ERR(0, 617, __pyx_L3_error) + else if (unlikely(PyErr_Occurred())) __PYX_ERR(0, 668, __pyx_L3_error) else goto __pyx_L5_argtuple_error; } if (unlikely(kw_args > 0)) { const Py_ssize_t kwd_pos_args = __pyx_nargs; - if (unlikely(__Pyx_ParseOptionalKeywords(__pyx_kwds, __pyx_kwvalues, __pyx_pyargnames, 0, values + 0, kwd_pos_args, "compile_to_function") < 0)) __PYX_ERR(0, 617, __pyx_L3_error) + if (unlikely(__Pyx_ParseOptionalKeywords(__pyx_kwds, __pyx_kwvalues, __pyx_pyargnames, 0, values + 0, kwd_pos_args, "lambda") < 0)) __PYX_ERR(0, 668, __pyx_L3_error) } } else if (unlikely(__pyx_nargs != 1)) { goto __pyx_L5_argtuple_error; } else { values[0] = __Pyx_Arg_FASTCALL(__pyx_args, 0); } - __pyx_v_constraint = values[0]; + __pyx_v_v = values[0]; } goto __pyx_L6_skip; __pyx_L5_argtuple_error:; - __Pyx_RaiseArgtupleInvalid("compile_to_function", 1, 1, 1, __pyx_nargs); __PYX_ERR(0, 617, __pyx_L3_error) + __Pyx_RaiseArgtupleInvalid("lambda", 1, 1, 1, __pyx_nargs); __PYX_ERR(0, 668, __pyx_L3_error) __pyx_L6_skip:; goto __pyx_L4_argument_unpacking_done; __pyx_L3_error:; @@ -16397,11 +16293,11 @@ PyObject *__pyx_args, PyObject *__pyx_kwds __Pyx_Arg_XDECREF_FASTCALL(values[__pyx_temp]); } } - __Pyx_AddTraceback("constraint.solvers.compile_to_function", __pyx_clineno, __pyx_lineno, __pyx_filename); + __Pyx_AddTraceback("constraint.solvers.ParallelSolver.getSolutionsList.lambda", __pyx_clineno, __pyx_lineno, __pyx_filename); __Pyx_RefNannyFinishContext(); return NULL; __pyx_L4_argument_unpacking_done:; - __pyx_r = __pyx_pf_10constraint_7solvers_6compile_to_function(__pyx_self, __pyx_v_constraint); + __pyx_r = __pyx_lambda_funcdef_lambda(__pyx_self, __pyx_v_v); /* function exit code */ { @@ -16414,2090 +16310,1721 @@ PyObject *__pyx_args, PyObject *__pyx_kwds return __pyx_r; } -static PyObject *__pyx_pf_10constraint_7solvers_6compile_to_function(CYTHON_UNUSED PyObject *__pyx_self, PyObject *__pyx_v_constraint) { - PyObject *__pyx_v_func_string = NULL; - PyObject *__pyx_v_code_object = NULL; - PyObject *__pyx_v_func = NULL; +static PyObject *__pyx_lambda_funcdef_lambda(PyObject *__pyx_self, PyObject *__pyx_v_v) { + struct __pyx_obj_10constraint_7solvers___pyx_scope_struct_2_getSolutionsList *__pyx_cur_scope; + struct __pyx_obj_10constraint_7solvers___pyx_scope_struct_2_getSolutionsList *__pyx_outer_scope; PyObject *__pyx_r = NULL; __Pyx_RefNannyDeclarations PyObject *__pyx_t_1 = NULL; - PyObject *__pyx_t_2 = NULL; - PyObject *__pyx_t_3 = NULL; - PyObject *__pyx_t_4 = NULL; - PyObject *__pyx_t_5 = NULL; - unsigned int __pyx_t_6; + Py_ssize_t __pyx_t_2; int __pyx_lineno = 0; const char *__pyx_filename = NULL; int __pyx_clineno = 0; - __Pyx_RefNannySetupContext("compile_to_function", 1); - - /* "constraint/solvers.py":619 - * def compile_to_function(constraint: CompilableFunctionConstraint) -> FunctionConstraint: - * """Compile a CompilableFunctionConstraint to a function, wrapped by a FunctionConstraint.""" - * func_string = constraint._func # <<<<<<<<<<<<<< - * code_object = compile(func_string, "", "exec") - * func = FunctionType(code_object.co_consts[0], globals()) - */ - __pyx_t_1 = __Pyx_PyObject_GetAttrStr(__pyx_v_constraint, __pyx_n_s_func); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 619, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_1); - __pyx_v_func_string = __pyx_t_1; - __pyx_t_1 = 0; - - /* "constraint/solvers.py":620 - * """Compile a CompilableFunctionConstraint to a function, wrapped by a FunctionConstraint.""" - * func_string = constraint._func - * code_object = compile(func_string, "", "exec") # <<<<<<<<<<<<<< - * func = FunctionType(code_object.co_consts[0], globals()) - * return FunctionConstraint(func) - */ - __pyx_t_1 = PyTuple_New(3); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 620, __pyx_L1_error) + __Pyx_RefNannySetupContext("lambda", 1); + __pyx_outer_scope = (struct __pyx_obj_10constraint_7solvers___pyx_scope_struct_2_getSolutionsList *) __Pyx_CyFunction_GetClosure(__pyx_self); + __pyx_cur_scope = __pyx_outer_scope; + __Pyx_XDECREF(__pyx_r); + if (unlikely(!__pyx_cur_scope->__pyx_v_domains)) { __Pyx_RaiseClosureNameError("domains"); __PYX_ERR(0, 668, __pyx_L1_error) } + if (unlikely(__pyx_cur_scope->__pyx_v_domains == Py_None)) { + PyErr_SetString(PyExc_TypeError, "'NoneType' object is not subscriptable"); + __PYX_ERR(0, 668, __pyx_L1_error) + } + __pyx_t_1 = __Pyx_PyDict_GetItem(__pyx_cur_scope->__pyx_v_domains, __pyx_v_v); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 668, __pyx_L1_error) __Pyx_GOTREF(__pyx_t_1); - __Pyx_INCREF(__pyx_v_func_string); - __Pyx_GIVEREF(__pyx_v_func_string); - if (__Pyx_PyTuple_SET_ITEM(__pyx_t_1, 0, __pyx_v_func_string)) __PYX_ERR(0, 620, __pyx_L1_error); - __Pyx_INCREF(__pyx_kp_u_string); - __Pyx_GIVEREF(__pyx_kp_u_string); - if (__Pyx_PyTuple_SET_ITEM(__pyx_t_1, 1, __pyx_kp_u_string)) __PYX_ERR(0, 620, __pyx_L1_error); - __Pyx_INCREF(__pyx_n_u_exec); - __Pyx_GIVEREF(__pyx_n_u_exec); - if (__Pyx_PyTuple_SET_ITEM(__pyx_t_1, 2, __pyx_n_u_exec)) __PYX_ERR(0, 620, __pyx_L1_error); - __pyx_t_2 = __Pyx_PyObject_Call(__pyx_builtin_compile, __pyx_t_1, NULL); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 620, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_2); + __pyx_t_2 = PyObject_Length(__pyx_t_1); if (unlikely(__pyx_t_2 == ((Py_ssize_t)-1))) __PYX_ERR(0, 668, __pyx_L1_error) __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; - __pyx_v_code_object = __pyx_t_2; - __pyx_t_2 = 0; - - /* "constraint/solvers.py":621 - * func_string = constraint._func - * code_object = compile(func_string, "", "exec") - * func = FunctionType(code_object.co_consts[0], globals()) # <<<<<<<<<<<<<< - * return FunctionConstraint(func) - * - */ - __Pyx_GetModuleGlobalName(__pyx_t_1, __pyx_n_s_FunctionType); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 621, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_1); - __pyx_t_3 = __Pyx_PyObject_GetAttrStr(__pyx_v_code_object, __pyx_n_s_co_consts); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 621, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_3); - __pyx_t_4 = __Pyx_GetItemInt(__pyx_t_3, 0, long, 1, __Pyx_PyInt_From_long, 0, 0, 1); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 621, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_4); - __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; - __pyx_t_3 = __Pyx_Globals(); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 621, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_3); - __pyx_t_5 = NULL; - __pyx_t_6 = 0; - #if CYTHON_UNPACK_METHODS - if (unlikely(PyMethod_Check(__pyx_t_1))) { - __pyx_t_5 = PyMethod_GET_SELF(__pyx_t_1); - if (likely(__pyx_t_5)) { - PyObject* function = PyMethod_GET_FUNCTION(__pyx_t_1); - __Pyx_INCREF(__pyx_t_5); - __Pyx_INCREF(function); - __Pyx_DECREF_SET(__pyx_t_1, function); - __pyx_t_6 = 1; - } - } - #endif - { - PyObject *__pyx_callargs[3] = {__pyx_t_5, __pyx_t_4, __pyx_t_3}; - __pyx_t_2 = __Pyx_PyObject_FastCall(__pyx_t_1, __pyx_callargs+1-__pyx_t_6, 2+__pyx_t_6); - __Pyx_XDECREF(__pyx_t_5); __pyx_t_5 = 0; - __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; - __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; - if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 621, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_2); - __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; - } - __pyx_v_func = __pyx_t_2; - __pyx_t_2 = 0; - - /* "constraint/solvers.py":622 - * code_object = compile(func_string, "", "exec") - * func = FunctionType(code_object.co_consts[0], globals()) - * return FunctionConstraint(func) # <<<<<<<<<<<<<< - * - * def sequential_recursive_backtrack(assignment: dict[Hashable, any], unassigned_vars: list[Hashable], domains: dict[Hashable, Domain], constraint_lookup: dict[Hashable, list[tuple[Constraint, Hashable]]]) -> list[dict[Hashable, any]]: # noqa E501 - */ - __Pyx_XDECREF(__pyx_r); - __Pyx_GetModuleGlobalName(__pyx_t_1, __pyx_n_s_FunctionConstraint); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 622, __pyx_L1_error) + __pyx_t_1 = PyInt_FromSsize_t(__pyx_t_2); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 668, __pyx_L1_error) __Pyx_GOTREF(__pyx_t_1); - __pyx_t_3 = NULL; - __pyx_t_6 = 0; - #if CYTHON_UNPACK_METHODS - if (unlikely(PyMethod_Check(__pyx_t_1))) { - __pyx_t_3 = PyMethod_GET_SELF(__pyx_t_1); - if (likely(__pyx_t_3)) { - PyObject* function = PyMethod_GET_FUNCTION(__pyx_t_1); - __Pyx_INCREF(__pyx_t_3); - __Pyx_INCREF(function); - __Pyx_DECREF_SET(__pyx_t_1, function); - __pyx_t_6 = 1; - } - } - #endif - { - PyObject *__pyx_callargs[2] = {__pyx_t_3, __pyx_v_func}; - __pyx_t_2 = __Pyx_PyObject_FastCall(__pyx_t_1, __pyx_callargs+1-__pyx_t_6, 1+__pyx_t_6); - __Pyx_XDECREF(__pyx_t_3); __pyx_t_3 = 0; - if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 622, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_2); - __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; - } - __pyx_r = __pyx_t_2; - __pyx_t_2 = 0; + __pyx_r = __pyx_t_1; + __pyx_t_1 = 0; goto __pyx_L0; - /* "constraint/solvers.py":617 - * ) - * - * def compile_to_function(constraint: CompilableFunctionConstraint) -> FunctionConstraint: # <<<<<<<<<<<<<< - * """Compile a CompilableFunctionConstraint to a function, wrapped by a FunctionConstraint.""" - * func_string = constraint._func - */ - /* function exit code */ __pyx_L1_error:; __Pyx_XDECREF(__pyx_t_1); - __Pyx_XDECREF(__pyx_t_2); - __Pyx_XDECREF(__pyx_t_3); - __Pyx_XDECREF(__pyx_t_4); - __Pyx_XDECREF(__pyx_t_5); - __Pyx_AddTraceback("constraint.solvers.compile_to_function", __pyx_clineno, __pyx_lineno, __pyx_filename); + __Pyx_AddTraceback("constraint.solvers.ParallelSolver.getSolutionsList.lambda", __pyx_clineno, __pyx_lineno, __pyx_filename); __pyx_r = NULL; __pyx_L0:; - __Pyx_XDECREF(__pyx_v_func_string); - __Pyx_XDECREF(__pyx_v_code_object); - __Pyx_XDECREF(__pyx_v_func); __Pyx_XGIVEREF(__pyx_r); __Pyx_RefNannyFinishContext(); return __pyx_r; } +static PyObject *__pyx_gb_10constraint_7solvers_14ParallelSolver_16getSolutionsList_3generator2(__pyx_CoroutineObject *__pyx_generator, CYTHON_UNUSED PyThreadState *__pyx_tstate, PyObject *__pyx_sent_value); /* proto */ -/* "constraint/solvers.py":624 - * return FunctionConstraint(func) +/* "constraint/solvers.py":675 + * + * # Create the parallel function arguments and solutions lists + * args = ((self.requires_pickling, domains, constraint_lookup, first_var, val, remaining_vars.copy()) for val in domains[first_var]) # noqa: E501 # <<<<<<<<<<<<<< + * solutions: list[dict[Hashable, any]] = [] * - * def sequential_recursive_backtrack(assignment: dict[Hashable, any], unassigned_vars: list[Hashable], domains: dict[Hashable, Domain], constraint_lookup: dict[Hashable, list[tuple[Constraint, Hashable]]]) -> list[dict[Hashable, any]]: # noqa E501 # <<<<<<<<<<<<<< - * """Sequential recursive backtracking function for subproblems.""" - * if not unassigned_vars: */ -/* Python wrapper */ -static PyObject *__pyx_pw_10constraint_7solvers_9sequential_recursive_backtrack(PyObject *__pyx_self, -#if CYTHON_METH_FASTCALL -PyObject *const *__pyx_args, Py_ssize_t __pyx_nargs, PyObject *__pyx_kwds -#else -PyObject *__pyx_args, PyObject *__pyx_kwds -#endif -); /*proto*/ -PyDoc_STRVAR(__pyx_doc_10constraint_7solvers_8sequential_recursive_backtrack, "Sequential recursive backtracking function for subproblems."); -static PyMethodDef __pyx_mdef_10constraint_7solvers_9sequential_recursive_backtrack = {"sequential_recursive_backtrack", (PyCFunction)(void*)(__Pyx_PyCFunction_FastCallWithKeywords)__pyx_pw_10constraint_7solvers_9sequential_recursive_backtrack, __Pyx_METH_FASTCALL|METH_KEYWORDS, __pyx_doc_10constraint_7solvers_8sequential_recursive_backtrack}; -static PyObject *__pyx_pw_10constraint_7solvers_9sequential_recursive_backtrack(PyObject *__pyx_self, -#if CYTHON_METH_FASTCALL -PyObject *const *__pyx_args, Py_ssize_t __pyx_nargs, PyObject *__pyx_kwds -#else -PyObject *__pyx_args, PyObject *__pyx_kwds -#endif -) { - PyObject *__pyx_v_assignment = 0; - PyObject *__pyx_v_unassigned_vars = 0; - PyObject *__pyx_v_domains = 0; - PyObject *__pyx_v_constraint_lookup = 0; - #if !CYTHON_METH_FASTCALL - CYTHON_UNUSED Py_ssize_t __pyx_nargs; - #endif - CYTHON_UNUSED PyObject *const *__pyx_kwvalues; - PyObject* values[4] = {0,0,0,0}; +static PyObject *__pyx_pf_10constraint_7solvers_14ParallelSolver_16getSolutionsList_1genexpr(PyObject *__pyx_self, PyObject *__pyx_genexpr_arg_0) { + struct __pyx_obj_10constraint_7solvers___pyx_scope_struct_3_genexpr *__pyx_cur_scope; + PyObject *__pyx_r = NULL; + __Pyx_RefNannyDeclarations int __pyx_lineno = 0; const char *__pyx_filename = NULL; int __pyx_clineno = 0; - PyObject *__pyx_r = 0; - __Pyx_RefNannyDeclarations - __Pyx_RefNannySetupContext("sequential_recursive_backtrack (wrapper)", 0); - #if !CYTHON_METH_FASTCALL - #if CYTHON_ASSUME_SAFE_MACROS - __pyx_nargs = PyTuple_GET_SIZE(__pyx_args); - #else - __pyx_nargs = PyTuple_Size(__pyx_args); if (unlikely(__pyx_nargs < 0)) return NULL; - #endif - #endif - __pyx_kwvalues = __Pyx_KwValues_FASTCALL(__pyx_args, __pyx_nargs); - { - PyObject **__pyx_pyargnames[] = {&__pyx_n_s_assignment,&__pyx_n_s_unassigned_vars,&__pyx_n_s_domains,&__pyx_n_s_constraint_lookup,0}; - if (__pyx_kwds) { - Py_ssize_t kw_args; - switch (__pyx_nargs) { - case 4: values[3] = __Pyx_Arg_FASTCALL(__pyx_args, 3); - CYTHON_FALLTHROUGH; - case 3: values[2] = __Pyx_Arg_FASTCALL(__pyx_args, 2); - CYTHON_FALLTHROUGH; - case 2: values[1] = __Pyx_Arg_FASTCALL(__pyx_args, 1); - CYTHON_FALLTHROUGH; - case 1: values[0] = __Pyx_Arg_FASTCALL(__pyx_args, 0); - CYTHON_FALLTHROUGH; - case 0: break; - default: goto __pyx_L5_argtuple_error; - } - kw_args = __Pyx_NumKwargs_FASTCALL(__pyx_kwds); - switch (__pyx_nargs) { - case 0: - if (likely((values[0] = __Pyx_GetKwValue_FASTCALL(__pyx_kwds, __pyx_kwvalues, __pyx_n_s_assignment)) != 0)) { - (void)__Pyx_Arg_NewRef_FASTCALL(values[0]); - kw_args--; - } - else if (unlikely(PyErr_Occurred())) __PYX_ERR(0, 624, __pyx_L3_error) - else goto __pyx_L5_argtuple_error; - CYTHON_FALLTHROUGH; - case 1: - if (likely((values[1] = __Pyx_GetKwValue_FASTCALL(__pyx_kwds, __pyx_kwvalues, __pyx_n_s_unassigned_vars)) != 0)) { - (void)__Pyx_Arg_NewRef_FASTCALL(values[1]); - kw_args--; - } - else if (unlikely(PyErr_Occurred())) __PYX_ERR(0, 624, __pyx_L3_error) - else { - __Pyx_RaiseArgtupleInvalid("sequential_recursive_backtrack", 1, 4, 4, 1); __PYX_ERR(0, 624, __pyx_L3_error) - } - CYTHON_FALLTHROUGH; - case 2: - if (likely((values[2] = __Pyx_GetKwValue_FASTCALL(__pyx_kwds, __pyx_kwvalues, __pyx_n_s_domains)) != 0)) { - (void)__Pyx_Arg_NewRef_FASTCALL(values[2]); - kw_args--; - } - else if (unlikely(PyErr_Occurred())) __PYX_ERR(0, 624, __pyx_L3_error) - else { - __Pyx_RaiseArgtupleInvalid("sequential_recursive_backtrack", 1, 4, 4, 2); __PYX_ERR(0, 624, __pyx_L3_error) - } - CYTHON_FALLTHROUGH; - case 3: - if (likely((values[3] = __Pyx_GetKwValue_FASTCALL(__pyx_kwds, __pyx_kwvalues, __pyx_n_s_constraint_lookup)) != 0)) { - (void)__Pyx_Arg_NewRef_FASTCALL(values[3]); - kw_args--; - } - else if (unlikely(PyErr_Occurred())) __PYX_ERR(0, 624, __pyx_L3_error) - else { - __Pyx_RaiseArgtupleInvalid("sequential_recursive_backtrack", 1, 4, 4, 3); __PYX_ERR(0, 624, __pyx_L3_error) - } - } - if (unlikely(kw_args > 0)) { - const Py_ssize_t kwd_pos_args = __pyx_nargs; - if (unlikely(__Pyx_ParseOptionalKeywords(__pyx_kwds, __pyx_kwvalues, __pyx_pyargnames, 0, values + 0, kwd_pos_args, "sequential_recursive_backtrack") < 0)) __PYX_ERR(0, 624, __pyx_L3_error) - } - } else if (unlikely(__pyx_nargs != 4)) { - goto __pyx_L5_argtuple_error; - } else { - values[0] = __Pyx_Arg_FASTCALL(__pyx_args, 0); - values[1] = __Pyx_Arg_FASTCALL(__pyx_args, 1); - values[2] = __Pyx_Arg_FASTCALL(__pyx_args, 2); - values[3] = __Pyx_Arg_FASTCALL(__pyx_args, 3); - } - __pyx_v_assignment = ((PyObject*)values[0]); - __pyx_v_unassigned_vars = ((PyObject*)values[1]); - __pyx_v_domains = ((PyObject*)values[2]); - __pyx_v_constraint_lookup = ((PyObject*)values[3]); + __Pyx_RefNannySetupContext("genexpr", 0); + __pyx_cur_scope = (struct __pyx_obj_10constraint_7solvers___pyx_scope_struct_3_genexpr *)__pyx_tp_new_10constraint_7solvers___pyx_scope_struct_3_genexpr(__pyx_ptype_10constraint_7solvers___pyx_scope_struct_3_genexpr, __pyx_empty_tuple, NULL); + if (unlikely(!__pyx_cur_scope)) { + __pyx_cur_scope = ((struct __pyx_obj_10constraint_7solvers___pyx_scope_struct_3_genexpr *)Py_None); + __Pyx_INCREF(Py_None); + __PYX_ERR(0, 675, __pyx_L1_error) + } else { + __Pyx_GOTREF((PyObject *)__pyx_cur_scope); } - goto __pyx_L6_skip; - __pyx_L5_argtuple_error:; - __Pyx_RaiseArgtupleInvalid("sequential_recursive_backtrack", 1, 4, 4, __pyx_nargs); __PYX_ERR(0, 624, __pyx_L3_error) - __pyx_L6_skip:; - goto __pyx_L4_argument_unpacking_done; - __pyx_L3_error:; + __pyx_cur_scope->__pyx_outer_scope = (struct __pyx_obj_10constraint_7solvers___pyx_scope_struct_2_getSolutionsList *) __pyx_self; + __Pyx_INCREF((PyObject *)__pyx_cur_scope->__pyx_outer_scope); + __Pyx_GIVEREF((PyObject *)__pyx_cur_scope->__pyx_outer_scope); + __pyx_cur_scope->__pyx_genexpr_arg_0 = __pyx_genexpr_arg_0; + __Pyx_INCREF(__pyx_cur_scope->__pyx_genexpr_arg_0); + __Pyx_GIVEREF(__pyx_cur_scope->__pyx_genexpr_arg_0); { - Py_ssize_t __pyx_temp; - for (__pyx_temp=0; __pyx_temp < (Py_ssize_t)(sizeof(values)/sizeof(values[0])); ++__pyx_temp) { - __Pyx_Arg_XDECREF_FASTCALL(values[__pyx_temp]); - } + __pyx_CoroutineObject *gen = __Pyx_Generator_New((__pyx_coroutine_body_t) __pyx_gb_10constraint_7solvers_14ParallelSolver_16getSolutionsList_3generator2, NULL, (PyObject *) __pyx_cur_scope, __pyx_n_s_genexpr, __pyx_n_s_ParallelSolver_getSolutionsList, __pyx_n_s_constraint_solvers); if (unlikely(!gen)) __PYX_ERR(0, 675, __pyx_L1_error) + __Pyx_DECREF(__pyx_cur_scope); + __Pyx_RefNannyFinishContext(); + return (PyObject *) gen; } - __Pyx_AddTraceback("constraint.solvers.sequential_recursive_backtrack", __pyx_clineno, __pyx_lineno, __pyx_filename); - __Pyx_RefNannyFinishContext(); - return NULL; - __pyx_L4_argument_unpacking_done:; - if (unlikely(!__Pyx_ArgTypeTest(((PyObject *)__pyx_v_assignment), (&PyDict_Type), 0, "assignment", 1))) __PYX_ERR(0, 624, __pyx_L1_error) - if (unlikely(!__Pyx_ArgTypeTest(((PyObject *)__pyx_v_unassigned_vars), (&PyList_Type), 0, "unassigned_vars", 1))) __PYX_ERR(0, 624, __pyx_L1_error) - if (unlikely(!__Pyx_ArgTypeTest(((PyObject *)__pyx_v_domains), (&PyDict_Type), 0, "domains", 1))) __PYX_ERR(0, 624, __pyx_L1_error) - if (unlikely(!__Pyx_ArgTypeTest(((PyObject *)__pyx_v_constraint_lookup), (&PyDict_Type), 0, "constraint_lookup", 1))) __PYX_ERR(0, 624, __pyx_L1_error) - __pyx_r = __pyx_pf_10constraint_7solvers_8sequential_recursive_backtrack(__pyx_self, __pyx_v_assignment, __pyx_v_unassigned_vars, __pyx_v_domains, __pyx_v_constraint_lookup); /* function exit code */ - goto __pyx_L0; __pyx_L1_error:; + __Pyx_AddTraceback("constraint.solvers.ParallelSolver.getSolutionsList.genexpr", __pyx_clineno, __pyx_lineno, __pyx_filename); __pyx_r = NULL; - __pyx_L0:; - { - Py_ssize_t __pyx_temp; - for (__pyx_temp=0; __pyx_temp < (Py_ssize_t)(sizeof(values)/sizeof(values[0])); ++__pyx_temp) { - __Pyx_Arg_XDECREF_FASTCALL(values[__pyx_temp]); - } - } + __Pyx_DECREF((PyObject *)__pyx_cur_scope); + __Pyx_XGIVEREF(__pyx_r); __Pyx_RefNannyFinishContext(); return __pyx_r; } -static PyObject *__pyx_pf_10constraint_7solvers_8sequential_recursive_backtrack(CYTHON_UNUSED PyObject *__pyx_self, PyObject *__pyx_v_assignment, PyObject *__pyx_v_unassigned_vars, PyObject *__pyx_v_domains, PyObject *__pyx_v_constraint_lookup) { - PyObject *__pyx_v_var = NULL; - PyObject *__pyx_v_remaining_vars = NULL; - PyObject *__pyx_v_solutions = 0; - PyObject *__pyx_v_value = NULL; +static PyObject *__pyx_gb_10constraint_7solvers_14ParallelSolver_16getSolutionsList_3generator2(__pyx_CoroutineObject *__pyx_generator, CYTHON_UNUSED PyThreadState *__pyx_tstate, PyObject *__pyx_sent_value) /* generator body */ +{ + struct __pyx_obj_10constraint_7solvers___pyx_scope_struct_3_genexpr *__pyx_cur_scope = ((struct __pyx_obj_10constraint_7solvers___pyx_scope_struct_3_genexpr *)__pyx_generator->closure); PyObject *__pyx_r = NULL; - __Pyx_RefNannyDeclarations - int __pyx_t_1; - int __pyx_t_2; - PyObject *__pyx_t_3 = NULL; + PyObject *__pyx_t_1 = NULL; + Py_ssize_t __pyx_t_2; + PyObject *(*__pyx_t_3)(PyObject *); PyObject *__pyx_t_4 = NULL; - Py_ssize_t __pyx_t_5; - PyObject *(*__pyx_t_6)(PyObject *); - PyObject *__pyx_t_7 = NULL; - PyObject *__pyx_t_8 = NULL; - PyObject *__pyx_t_9 = NULL; - unsigned int __pyx_t_10; - int __pyx_t_11; + PyObject *__pyx_t_5 = NULL; + PyObject *__pyx_t_6 = NULL; int __pyx_lineno = 0; const char *__pyx_filename = NULL; int __pyx_clineno = 0; - __Pyx_RefNannySetupContext("sequential_recursive_backtrack", 1); - - /* "constraint/solvers.py":626 - * def sequential_recursive_backtrack(assignment: dict[Hashable, any], unassigned_vars: list[Hashable], domains: dict[Hashable, Domain], constraint_lookup: dict[Hashable, list[tuple[Constraint, Hashable]]]) -> list[dict[Hashable, any]]: # noqa E501 - * """Sequential recursive backtracking function for subproblems.""" - * if not unassigned_vars: # <<<<<<<<<<<<<< - * return [assignment.copy()] - * - */ - __pyx_t_1 = (PyList_GET_SIZE(__pyx_v_unassigned_vars) != 0); - __pyx_t_2 = (!__pyx_t_1); - if (__pyx_t_2) { - - /* "constraint/solvers.py":627 - * """Sequential recursive backtracking function for subproblems.""" - * if not unassigned_vars: - * return [assignment.copy()] # <<<<<<<<<<<<<< - * - * var = unassigned_vars[-1] - */ - __Pyx_XDECREF(__pyx_r); - __pyx_t_3 = PyDict_Copy(__pyx_v_assignment); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 627, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_3); - __pyx_t_4 = PyList_New(1); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 627, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_4); - __Pyx_GIVEREF(__pyx_t_3); - if (__Pyx_PyList_SET_ITEM(__pyx_t_4, 0, __pyx_t_3)) __PYX_ERR(0, 627, __pyx_L1_error); - __pyx_t_3 = 0; - __pyx_r = ((PyObject*)__pyx_t_4); - __pyx_t_4 = 0; - goto __pyx_L0; - - /* "constraint/solvers.py":626 - * def sequential_recursive_backtrack(assignment: dict[Hashable, any], unassigned_vars: list[Hashable], domains: dict[Hashable, Domain], constraint_lookup: dict[Hashable, list[tuple[Constraint, Hashable]]]) -> list[dict[Hashable, any]]: # noqa E501 - * """Sequential recursive backtracking function for subproblems.""" - * if not unassigned_vars: # <<<<<<<<<<<<<< - * return [assignment.copy()] - * - */ + __Pyx_RefNannyDeclarations + __Pyx_RefNannySetupContext("genexpr", 0); + switch (__pyx_generator->resume_label) { + case 0: goto __pyx_L3_first_run; + case 1: goto __pyx_L6_resume_from_yield; + default: /* CPython raises the right error here */ + __Pyx_RefNannyFinishContext(); + return NULL; } - - /* "constraint/solvers.py":629 - * return [assignment.copy()] - * - * var = unassigned_vars[-1] # <<<<<<<<<<<<<< - * remaining_vars = unassigned_vars[:-1] - * - */ - __pyx_t_4 = __Pyx_GetItemInt_List(__pyx_v_unassigned_vars, -1L, long, 1, __Pyx_PyInt_From_long, 1, 1, 1); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 629, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_4); - __pyx_v_var = __pyx_t_4; - __pyx_t_4 = 0; - - /* "constraint/solvers.py":630 - * - * var = unassigned_vars[-1] - * remaining_vars = unassigned_vars[:-1] # <<<<<<<<<<<<<< - * - * solutions: list[dict[Hashable, any]] = [] - */ - __pyx_t_4 = __Pyx_PyList_GetSlice(__pyx_v_unassigned_vars, 0, -1L); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 630, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_4); - __pyx_v_remaining_vars = ((PyObject*)__pyx_t_4); - __pyx_t_4 = 0; - - /* "constraint/solvers.py":632 - * remaining_vars = unassigned_vars[:-1] - * - * solutions: list[dict[Hashable, any]] = [] # <<<<<<<<<<<<<< - * for value in domains[var]: - * assignment[var] = value - */ - __pyx_t_4 = PyList_New(0); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 632, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_4); - __pyx_v_solutions = ((PyObject*)__pyx_t_4); - __pyx_t_4 = 0; - - /* "constraint/solvers.py":633 - * - * solutions: list[dict[Hashable, any]] = [] - * for value in domains[var]: # <<<<<<<<<<<<<< - * assignment[var] = value - * if is_valid(assignment, constraint_lookup[var], domains): - */ - __pyx_t_4 = __Pyx_PyDict_GetItem(__pyx_v_domains, __pyx_v_var); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 633, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_4); - if (likely(PyList_CheckExact(__pyx_t_4)) || PyTuple_CheckExact(__pyx_t_4)) { - __pyx_t_3 = __pyx_t_4; __Pyx_INCREF(__pyx_t_3); - __pyx_t_5 = 0; - __pyx_t_6 = NULL; + __pyx_L3_first_run:; + if (unlikely(!__pyx_sent_value)) __PYX_ERR(0, 675, __pyx_L1_error) + if (unlikely(!__pyx_cur_scope->__pyx_genexpr_arg_0)) { __Pyx_RaiseUnboundLocalError(".0"); __PYX_ERR(0, 675, __pyx_L1_error) } + if (likely(PyList_CheckExact(__pyx_cur_scope->__pyx_genexpr_arg_0)) || PyTuple_CheckExact(__pyx_cur_scope->__pyx_genexpr_arg_0)) { + __pyx_t_1 = __pyx_cur_scope->__pyx_genexpr_arg_0; __Pyx_INCREF(__pyx_t_1); + __pyx_t_2 = 0; + __pyx_t_3 = NULL; } else { - __pyx_t_5 = -1; __pyx_t_3 = PyObject_GetIter(__pyx_t_4); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 633, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_3); - __pyx_t_6 = __Pyx_PyObject_GetIterNextFunc(__pyx_t_3); if (unlikely(!__pyx_t_6)) __PYX_ERR(0, 633, __pyx_L1_error) + __pyx_t_2 = -1; __pyx_t_1 = PyObject_GetIter(__pyx_cur_scope->__pyx_genexpr_arg_0); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 675, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __pyx_t_3 = __Pyx_PyObject_GetIterNextFunc(__pyx_t_1); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 675, __pyx_L1_error) } - __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; for (;;) { - if (likely(!__pyx_t_6)) { - if (likely(PyList_CheckExact(__pyx_t_3))) { + if (likely(!__pyx_t_3)) { + if (likely(PyList_CheckExact(__pyx_t_1))) { { - Py_ssize_t __pyx_temp = __Pyx_PyList_GET_SIZE(__pyx_t_3); + Py_ssize_t __pyx_temp = __Pyx_PyList_GET_SIZE(__pyx_t_1); #if !CYTHON_ASSUME_SAFE_MACROS - if (unlikely((__pyx_temp < 0))) __PYX_ERR(0, 633, __pyx_L1_error) + if (unlikely((__pyx_temp < 0))) __PYX_ERR(0, 675, __pyx_L1_error) #endif - if (__pyx_t_5 >= __pyx_temp) break; + if (__pyx_t_2 >= __pyx_temp) break; } #if CYTHON_ASSUME_SAFE_MACROS && !CYTHON_AVOID_BORROWED_REFS - __pyx_t_4 = PyList_GET_ITEM(__pyx_t_3, __pyx_t_5); __Pyx_INCREF(__pyx_t_4); __pyx_t_5++; if (unlikely((0 < 0))) __PYX_ERR(0, 633, __pyx_L1_error) + __pyx_t_4 = PyList_GET_ITEM(__pyx_t_1, __pyx_t_2); __Pyx_INCREF(__pyx_t_4); __pyx_t_2++; if (unlikely((0 < 0))) __PYX_ERR(0, 675, __pyx_L1_error) #else - __pyx_t_4 = __Pyx_PySequence_ITEM(__pyx_t_3, __pyx_t_5); __pyx_t_5++; if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 633, __pyx_L1_error) + __pyx_t_4 = __Pyx_PySequence_ITEM(__pyx_t_1, __pyx_t_2); __pyx_t_2++; if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 675, __pyx_L1_error) __Pyx_GOTREF(__pyx_t_4); #endif } else { { - Py_ssize_t __pyx_temp = __Pyx_PyTuple_GET_SIZE(__pyx_t_3); + Py_ssize_t __pyx_temp = __Pyx_PyTuple_GET_SIZE(__pyx_t_1); #if !CYTHON_ASSUME_SAFE_MACROS - if (unlikely((__pyx_temp < 0))) __PYX_ERR(0, 633, __pyx_L1_error) + if (unlikely((__pyx_temp < 0))) __PYX_ERR(0, 675, __pyx_L1_error) #endif - if (__pyx_t_5 >= __pyx_temp) break; + if (__pyx_t_2 >= __pyx_temp) break; } #if CYTHON_ASSUME_SAFE_MACROS && !CYTHON_AVOID_BORROWED_REFS - __pyx_t_4 = PyTuple_GET_ITEM(__pyx_t_3, __pyx_t_5); __Pyx_INCREF(__pyx_t_4); __pyx_t_5++; if (unlikely((0 < 0))) __PYX_ERR(0, 633, __pyx_L1_error) + __pyx_t_4 = PyTuple_GET_ITEM(__pyx_t_1, __pyx_t_2); __Pyx_INCREF(__pyx_t_4); __pyx_t_2++; if (unlikely((0 < 0))) __PYX_ERR(0, 675, __pyx_L1_error) #else - __pyx_t_4 = __Pyx_PySequence_ITEM(__pyx_t_3, __pyx_t_5); __pyx_t_5++; if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 633, __pyx_L1_error) + __pyx_t_4 = __Pyx_PySequence_ITEM(__pyx_t_1, __pyx_t_2); __pyx_t_2++; if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 675, __pyx_L1_error) __Pyx_GOTREF(__pyx_t_4); #endif } } else { - __pyx_t_4 = __pyx_t_6(__pyx_t_3); + __pyx_t_4 = __pyx_t_3(__pyx_t_1); if (unlikely(!__pyx_t_4)) { PyObject* exc_type = PyErr_Occurred(); if (exc_type) { if (likely(__Pyx_PyErr_GivenExceptionMatches(exc_type, PyExc_StopIteration))) PyErr_Clear(); - else __PYX_ERR(0, 633, __pyx_L1_error) + else __PYX_ERR(0, 675, __pyx_L1_error) } break; } __Pyx_GOTREF(__pyx_t_4); } - __Pyx_XDECREF_SET(__pyx_v_value, __pyx_t_4); + __Pyx_XGOTREF(__pyx_cur_scope->__pyx_v_val); + __Pyx_XDECREF_SET(__pyx_cur_scope->__pyx_v_val, __pyx_t_4); + __Pyx_GIVEREF(__pyx_t_4); + __pyx_t_4 = 0; + if (unlikely(!__pyx_cur_scope->__pyx_outer_scope->__pyx_v_self)) { __Pyx_RaiseClosureNameError("self"); __PYX_ERR(0, 675, __pyx_L1_error) } + __pyx_t_4 = __Pyx_PyObject_GetAttrStr(__pyx_cur_scope->__pyx_outer_scope->__pyx_v_self, __pyx_n_s_requires_pickling); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 675, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_4); + if (unlikely(!__pyx_cur_scope->__pyx_outer_scope->__pyx_v_domains)) { __Pyx_RaiseClosureNameError("domains"); __PYX_ERR(0, 675, __pyx_L1_error) } + if (unlikely(!__pyx_cur_scope->__pyx_outer_scope->__pyx_v_constraint_lookup)) { __Pyx_RaiseClosureNameError("constraint_lookup"); __PYX_ERR(0, 675, __pyx_L1_error) } + if (unlikely(!__pyx_cur_scope->__pyx_outer_scope->__pyx_v_first_var)) { __Pyx_RaiseClosureNameError("first_var"); __PYX_ERR(0, 675, __pyx_L1_error) } + if (unlikely(!__pyx_cur_scope->__pyx_outer_scope->__pyx_v_remaining_vars)) { __Pyx_RaiseClosureNameError("remaining_vars"); __PYX_ERR(0, 675, __pyx_L1_error) } + __pyx_t_5 = __Pyx_CallUnboundCMethod0(&__pyx_umethod_PyList_Type_copy, __pyx_cur_scope->__pyx_outer_scope->__pyx_v_remaining_vars); if (unlikely(!__pyx_t_5)) __PYX_ERR(0, 675, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_5); + __pyx_t_6 = PyTuple_New(6); if (unlikely(!__pyx_t_6)) __PYX_ERR(0, 675, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_6); + __Pyx_GIVEREF(__pyx_t_4); + if (__Pyx_PyTuple_SET_ITEM(__pyx_t_6, 0, __pyx_t_4)) __PYX_ERR(0, 675, __pyx_L1_error); + __Pyx_INCREF(__pyx_cur_scope->__pyx_outer_scope->__pyx_v_domains); + __Pyx_GIVEREF(__pyx_cur_scope->__pyx_outer_scope->__pyx_v_domains); + if (__Pyx_PyTuple_SET_ITEM(__pyx_t_6, 1, __pyx_cur_scope->__pyx_outer_scope->__pyx_v_domains)) __PYX_ERR(0, 675, __pyx_L1_error); + __Pyx_INCREF(__pyx_cur_scope->__pyx_outer_scope->__pyx_v_constraint_lookup); + __Pyx_GIVEREF(__pyx_cur_scope->__pyx_outer_scope->__pyx_v_constraint_lookup); + if (__Pyx_PyTuple_SET_ITEM(__pyx_t_6, 2, __pyx_cur_scope->__pyx_outer_scope->__pyx_v_constraint_lookup)) __PYX_ERR(0, 675, __pyx_L1_error); + __Pyx_INCREF(__pyx_cur_scope->__pyx_outer_scope->__pyx_v_first_var); + __Pyx_GIVEREF(__pyx_cur_scope->__pyx_outer_scope->__pyx_v_first_var); + if (__Pyx_PyTuple_SET_ITEM(__pyx_t_6, 3, __pyx_cur_scope->__pyx_outer_scope->__pyx_v_first_var)) __PYX_ERR(0, 675, __pyx_L1_error); + __Pyx_INCREF(__pyx_cur_scope->__pyx_v_val); + __Pyx_GIVEREF(__pyx_cur_scope->__pyx_v_val); + if (__Pyx_PyTuple_SET_ITEM(__pyx_t_6, 4, __pyx_cur_scope->__pyx_v_val)) __PYX_ERR(0, 675, __pyx_L1_error); + __Pyx_GIVEREF(__pyx_t_5); + if (__Pyx_PyTuple_SET_ITEM(__pyx_t_6, 5, __pyx_t_5)) __PYX_ERR(0, 675, __pyx_L1_error); __pyx_t_4 = 0; + __pyx_t_5 = 0; + __pyx_r = __pyx_t_6; + __pyx_t_6 = 0; + __Pyx_XGIVEREF(__pyx_t_1); + __pyx_cur_scope->__pyx_t_0 = __pyx_t_1; + __pyx_cur_scope->__pyx_t_1 = __pyx_t_2; + __pyx_cur_scope->__pyx_t_2 = __pyx_t_3; + __Pyx_XGIVEREF(__pyx_r); + __Pyx_RefNannyFinishContext(); + __Pyx_Coroutine_ResetAndClearException(__pyx_generator); + /* return from generator, yielding value */ + __pyx_generator->resume_label = 1; + return __pyx_r; + __pyx_L6_resume_from_yield:; + __pyx_t_1 = __pyx_cur_scope->__pyx_t_0; + __pyx_cur_scope->__pyx_t_0 = 0; + __Pyx_XGOTREF(__pyx_t_1); + __pyx_t_2 = __pyx_cur_scope->__pyx_t_1; + __pyx_t_3 = __pyx_cur_scope->__pyx_t_2; + if (unlikely(!__pyx_sent_value)) __PYX_ERR(0, 675, __pyx_L1_error) + } + __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; + CYTHON_MAYBE_UNUSED_VAR(__pyx_cur_scope); - /* "constraint/solvers.py":634 - * solutions: list[dict[Hashable, any]] = [] - * for value in domains[var]: - * assignment[var] = value # <<<<<<<<<<<<<< - * if is_valid(assignment, constraint_lookup[var], domains): - * solutions.extend(sequential_recursive_backtrack(assignment, remaining_vars, domains, constraint_lookup)) - */ - if (unlikely((PyDict_SetItem(__pyx_v_assignment, __pyx_v_var, __pyx_v_value) < 0))) __PYX_ERR(0, 634, __pyx_L1_error) + /* function exit code */ + PyErr_SetNone(PyExc_StopIteration); + goto __pyx_L0; + __pyx_L1_error:; + __Pyx_Generator_Replace_StopIteration(0); + __Pyx_XDECREF(__pyx_t_1); + __Pyx_XDECREF(__pyx_t_4); + __Pyx_XDECREF(__pyx_t_5); + __Pyx_XDECREF(__pyx_t_6); + __Pyx_AddTraceback("genexpr", __pyx_clineno, __pyx_lineno, __pyx_filename); + __pyx_L0:; + __Pyx_XDECREF(__pyx_r); __pyx_r = 0; + #if !CYTHON_USE_EXC_INFO_STACK + __Pyx_Coroutine_ResetAndClearException(__pyx_generator); + #endif + __pyx_generator->resume_label = -1; + __Pyx_Coroutine_clear((PyObject*)__pyx_generator); + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} - /* "constraint/solvers.py":635 - * for value in domains[var]: - * assignment[var] = value - * if is_valid(assignment, constraint_lookup[var], domains): # <<<<<<<<<<<<<< - * solutions.extend(sequential_recursive_backtrack(assignment, remaining_vars, domains, constraint_lookup)) - * del assignment[var] +/* "constraint/solvers.py":662 + * raise NotImplementedError(msg) + * + * def getSolutionsList(self, domains: dict[Hashable, Domain], vconstraints: dict[Hashable, list[tuple[Constraint, Hashable]]]) -> list[dict[Hashable, any]]: # noqa: D102, E501 # <<<<<<<<<<<<<< + * """Parallelized all-solutions finder using ProcessPoolExecutor for work-stealing.""" + * # Precompute constraints lookup per variable */ - __Pyx_GetModuleGlobalName(__pyx_t_7, __pyx_n_s_is_valid); if (unlikely(!__pyx_t_7)) __PYX_ERR(0, 635, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_7); - __pyx_t_8 = __Pyx_PyDict_GetItem(__pyx_v_constraint_lookup, __pyx_v_var); if (unlikely(!__pyx_t_8)) __PYX_ERR(0, 635, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_8); - __pyx_t_9 = NULL; - __pyx_t_10 = 0; - #if CYTHON_UNPACK_METHODS - if (unlikely(PyMethod_Check(__pyx_t_7))) { - __pyx_t_9 = PyMethod_GET_SELF(__pyx_t_7); - if (likely(__pyx_t_9)) { - PyObject* function = PyMethod_GET_FUNCTION(__pyx_t_7); - __Pyx_INCREF(__pyx_t_9); - __Pyx_INCREF(function); - __Pyx_DECREF_SET(__pyx_t_7, function); - __pyx_t_10 = 1; - } - } - #endif - { - PyObject *__pyx_callargs[4] = {__pyx_t_9, __pyx_v_assignment, __pyx_t_8, __pyx_v_domains}; - __pyx_t_4 = __Pyx_PyObject_FastCall(__pyx_t_7, __pyx_callargs+1-__pyx_t_10, 3+__pyx_t_10); - __Pyx_XDECREF(__pyx_t_9); __pyx_t_9 = 0; - __Pyx_DECREF(__pyx_t_8); __pyx_t_8 = 0; - if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 635, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_4); - __Pyx_DECREF(__pyx_t_7); __pyx_t_7 = 0; - } - __pyx_t_2 = __Pyx_PyObject_IsTrue(__pyx_t_4); if (unlikely((__pyx_t_2 < 0))) __PYX_ERR(0, 635, __pyx_L1_error) - __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; - if (__pyx_t_2) { - /* "constraint/solvers.py":636 - * assignment[var] = value - * if is_valid(assignment, constraint_lookup[var], domains): - * solutions.extend(sequential_recursive_backtrack(assignment, remaining_vars, domains, constraint_lookup)) # <<<<<<<<<<<<<< - * del assignment[var] - * return solutions - */ - __Pyx_GetModuleGlobalName(__pyx_t_7, __pyx_n_s_sequential_recursive_backtrack); if (unlikely(!__pyx_t_7)) __PYX_ERR(0, 636, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_7); - __pyx_t_8 = NULL; - __pyx_t_10 = 0; - #if CYTHON_UNPACK_METHODS - if (unlikely(PyMethod_Check(__pyx_t_7))) { - __pyx_t_8 = PyMethod_GET_SELF(__pyx_t_7); - if (likely(__pyx_t_8)) { - PyObject* function = PyMethod_GET_FUNCTION(__pyx_t_7); - __Pyx_INCREF(__pyx_t_8); - __Pyx_INCREF(function); - __Pyx_DECREF_SET(__pyx_t_7, function); - __pyx_t_10 = 1; - } - } - #endif - { - PyObject *__pyx_callargs[5] = {__pyx_t_8, __pyx_v_assignment, __pyx_v_remaining_vars, __pyx_v_domains, __pyx_v_constraint_lookup}; - __pyx_t_4 = __Pyx_PyObject_FastCall(__pyx_t_7, __pyx_callargs+1-__pyx_t_10, 4+__pyx_t_10); - __Pyx_XDECREF(__pyx_t_8); __pyx_t_8 = 0; - if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 636, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_4); - __Pyx_DECREF(__pyx_t_7); __pyx_t_7 = 0; - } - __pyx_t_11 = __Pyx_PyList_Extend(__pyx_v_solutions, __pyx_t_4); if (unlikely(__pyx_t_11 == ((int)-1))) __PYX_ERR(0, 636, __pyx_L1_error) - __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; +static PyObject *__pyx_pf_10constraint_7solvers_14ParallelSolver_4getSolutionsList(CYTHON_UNUSED PyObject *__pyx_self, PyObject *__pyx_v_self, PyObject *__pyx_v_domains, PyObject *__pyx_v_vconstraints) { + struct __pyx_obj_10constraint_7solvers___pyx_scope_struct_2_getSolutionsList *__pyx_cur_scope; + PyObject *__pyx_v_sorted_vars = 0; + PyObject *__pyx_v_args = NULL; + PyObject *__pyx_v_solutions = 0; + PyObject *__pyx_v_parallel_pool = NULL; + PyObject *__pyx_v_executor = NULL; + PyObject *__pyx_v_results = NULL; + PyObject *__pyx_v_result = NULL; + PyObject *__pyx_8genexpr7__pyx_v_var = NULL; + PyObject *__pyx_gb_10constraint_7solvers_14ParallelSolver_16getSolutionsList_3generator2 = 0; + PyObject *__pyx_r = NULL; + __Pyx_RefNannyDeclarations + PyObject *__pyx_t_1 = NULL; + PyObject *__pyx_t_2 = NULL; + Py_ssize_t __pyx_t_3; + Py_ssize_t __pyx_t_4; + int __pyx_t_5; + PyObject *__pyx_t_6 = NULL; + int __pyx_t_7; + PyObject *__pyx_t_8 = NULL; + int __pyx_t_9; + unsigned int __pyx_t_10; + PyObject *__pyx_t_11 = NULL; + PyObject *__pyx_t_12 = NULL; + PyObject *__pyx_t_13 = NULL; + PyObject *__pyx_t_14 = NULL; + PyObject *(*__pyx_t_15)(PyObject *); + int __pyx_t_16; + PyObject *__pyx_t_17 = NULL; + int __pyx_t_18; + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + __Pyx_RefNannySetupContext("getSolutionsList", 0); + __pyx_cur_scope = (struct __pyx_obj_10constraint_7solvers___pyx_scope_struct_2_getSolutionsList *)__pyx_tp_new_10constraint_7solvers___pyx_scope_struct_2_getSolutionsList(__pyx_ptype_10constraint_7solvers___pyx_scope_struct_2_getSolutionsList, __pyx_empty_tuple, NULL); + if (unlikely(!__pyx_cur_scope)) { + __pyx_cur_scope = ((struct __pyx_obj_10constraint_7solvers___pyx_scope_struct_2_getSolutionsList *)Py_None); + __Pyx_INCREF(Py_None); + __PYX_ERR(0, 662, __pyx_L1_error) + } else { + __Pyx_GOTREF((PyObject *)__pyx_cur_scope); + } + __pyx_cur_scope->__pyx_v_self = __pyx_v_self; + __Pyx_INCREF(__pyx_cur_scope->__pyx_v_self); + __Pyx_GIVEREF(__pyx_cur_scope->__pyx_v_self); + __pyx_cur_scope->__pyx_v_domains = __pyx_v_domains; + __Pyx_INCREF(__pyx_cur_scope->__pyx_v_domains); + __Pyx_GIVEREF(__pyx_cur_scope->__pyx_v_domains); - /* "constraint/solvers.py":635 - * for value in domains[var]: - * assignment[var] = value - * if is_valid(assignment, constraint_lookup[var], domains): # <<<<<<<<<<<<<< - * solutions.extend(sequential_recursive_backtrack(assignment, remaining_vars, domains, constraint_lookup)) - * del assignment[var] + /* "constraint/solvers.py":665 + * """Parallelized all-solutions finder using ProcessPoolExecutor for work-stealing.""" + * # Precompute constraints lookup per variable + * constraint_lookup: dict[Hashable, list[tuple[Constraint, Hashable]]] = {var: vconstraints.get(var, []) for var in domains} # noqa: E501 # <<<<<<<<<<<<<< + * + * # Sort variables by domain size (heuristic) */ + { /* enter inner scope */ + __pyx_t_1 = PyDict_New(); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 665, __pyx_L5_error) + __Pyx_GOTREF(__pyx_t_1); + __pyx_t_3 = 0; + __pyx_t_6 = __Pyx_dict_iterator(__pyx_cur_scope->__pyx_v_domains, 1, ((PyObject *)NULL), (&__pyx_t_4), (&__pyx_t_5)); if (unlikely(!__pyx_t_6)) __PYX_ERR(0, 665, __pyx_L5_error) + __Pyx_GOTREF(__pyx_t_6); + __Pyx_XDECREF(__pyx_t_2); + __pyx_t_2 = __pyx_t_6; + __pyx_t_6 = 0; + while (1) { + __pyx_t_7 = __Pyx_dict_iter_next(__pyx_t_2, __pyx_t_4, &__pyx_t_3, &__pyx_t_6, NULL, NULL, __pyx_t_5); + if (unlikely(__pyx_t_7 == 0)) break; + if (unlikely(__pyx_t_7 == -1)) __PYX_ERR(0, 665, __pyx_L5_error) + __Pyx_GOTREF(__pyx_t_6); + __Pyx_XDECREF_SET(__pyx_8genexpr7__pyx_v_var, __pyx_t_6); + __pyx_t_6 = 0; + __pyx_t_6 = PyList_New(0); if (unlikely(!__pyx_t_6)) __PYX_ERR(0, 665, __pyx_L5_error) + __Pyx_GOTREF(__pyx_t_6); + __pyx_t_8 = __Pyx_PyDict_GetItemDefault(__pyx_v_vconstraints, __pyx_8genexpr7__pyx_v_var, __pyx_t_6); if (unlikely(!__pyx_t_8)) __PYX_ERR(0, 665, __pyx_L5_error) + __Pyx_GOTREF(__pyx_t_8); + __Pyx_DECREF(__pyx_t_6); __pyx_t_6 = 0; + if (unlikely(PyDict_SetItem(__pyx_t_1, (PyObject*)__pyx_8genexpr7__pyx_v_var, (PyObject*)__pyx_t_8))) __PYX_ERR(0, 665, __pyx_L5_error) + __Pyx_DECREF(__pyx_t_8); __pyx_t_8 = 0; } + __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; + __Pyx_XDECREF(__pyx_8genexpr7__pyx_v_var); __pyx_8genexpr7__pyx_v_var = 0; + goto __pyx_L8_exit_scope; + __pyx_L5_error:; + __Pyx_XDECREF(__pyx_8genexpr7__pyx_v_var); __pyx_8genexpr7__pyx_v_var = 0; + goto __pyx_L1_error; + __pyx_L8_exit_scope:; + } /* exit inner scope */ + __Pyx_GIVEREF(__pyx_t_1); + __pyx_cur_scope->__pyx_v_constraint_lookup = ((PyObject*)__pyx_t_1); + __pyx_t_1 = 0; - /* "constraint/solvers.py":637 - * if is_valid(assignment, constraint_lookup[var], domains): - * solutions.extend(sequential_recursive_backtrack(assignment, remaining_vars, domains, constraint_lookup)) - * del assignment[var] # <<<<<<<<<<<<<< - * return solutions + /* "constraint/solvers.py":668 + * + * # Sort variables by domain size (heuristic) + * sorted_vars: list[Hashable] = sorted(domains.keys(), key=lambda v: len(domains[v])) # <<<<<<<<<<<<<< * + * # Split parallel and sequential parts */ - if (unlikely((PyDict_DelItem(__pyx_v_assignment, __pyx_v_var) < 0))) __PYX_ERR(0, 637, __pyx_L1_error) + __pyx_t_1 = __Pyx_PyDict_Keys(__pyx_cur_scope->__pyx_v_domains); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 668, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __pyx_t_2 = PyTuple_New(1); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 668, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_2); + __Pyx_GIVEREF(__pyx_t_1); + if (__Pyx_PyTuple_SET_ITEM(__pyx_t_2, 0, __pyx_t_1)) __PYX_ERR(0, 668, __pyx_L1_error); + __pyx_t_1 = 0; + __pyx_t_1 = __Pyx_PyDict_NewPresized(1); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 668, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __pyx_t_8 = __Pyx_CyFunction_New(&__pyx_mdef_10constraint_7solvers_14ParallelSolver_16getSolutionsList_lambda, 0, __pyx_n_s_ParallelSolver_getSolutionsList_2, ((PyObject*)__pyx_cur_scope), __pyx_n_s_constraint_solvers, __pyx_d, NULL); if (unlikely(!__pyx_t_8)) __PYX_ERR(0, 668, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_8); + if (PyDict_SetItem(__pyx_t_1, __pyx_n_s_key, __pyx_t_8) < 0) __PYX_ERR(0, 668, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_8); __pyx_t_8 = 0; + __pyx_t_8 = __Pyx_PyObject_Call(__pyx_builtin_sorted, __pyx_t_2, __pyx_t_1); if (unlikely(!__pyx_t_8)) __PYX_ERR(0, 668, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_8); + __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; + __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; + if (!(likely(PyList_CheckExact(__pyx_t_8))||((__pyx_t_8) == Py_None) || __Pyx_RaiseUnexpectedTypeError("list", __pyx_t_8))) __PYX_ERR(0, 668, __pyx_L1_error) + __pyx_v_sorted_vars = ((PyObject*)__pyx_t_8); + __pyx_t_8 = 0; - /* "constraint/solvers.py":633 + /* "constraint/solvers.py":671 + * + * # Split parallel and sequential parts + * first_var = sorted_vars[0] # <<<<<<<<<<<<<< + * remaining_vars = sorted_vars[1:] * - * solutions: list[dict[Hashable, any]] = [] - * for value in domains[var]: # <<<<<<<<<<<<<< - * assignment[var] = value - * if is_valid(assignment, constraint_lookup[var], domains): */ + if (unlikely(__pyx_v_sorted_vars == Py_None)) { + PyErr_SetString(PyExc_TypeError, "'NoneType' object is not subscriptable"); + __PYX_ERR(0, 671, __pyx_L1_error) } - __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; + __pyx_t_8 = __Pyx_GetItemInt_List(__pyx_v_sorted_vars, 0, long, 1, __Pyx_PyInt_From_long, 1, 0, 1); if (unlikely(!__pyx_t_8)) __PYX_ERR(0, 671, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_8); + __Pyx_GIVEREF(__pyx_t_8); + __pyx_cur_scope->__pyx_v_first_var = __pyx_t_8; + __pyx_t_8 = 0; - /* "constraint/solvers.py":638 - * solutions.extend(sequential_recursive_backtrack(assignment, remaining_vars, domains, constraint_lookup)) - * del assignment[var] - * return solutions # <<<<<<<<<<<<<< + /* "constraint/solvers.py":672 + * # Split parallel and sequential parts + * first_var = sorted_vars[0] + * remaining_vars = sorted_vars[1:] # <<<<<<<<<<<<<< * - * def sequential_optimized_backtrack(assignment: dict[Hashable, any], unassigned_vars: list[Hashable], domains: dict[Hashable, Domain], constraint_lookup: dict[Hashable, list[tuple[Constraint, Hashable]]]) -> list[dict[Hashable, any]]: # noqa E501 + * # Create the parallel function arguments and solutions lists */ - __Pyx_XDECREF(__pyx_r); - __Pyx_INCREF(__pyx_v_solutions); - __pyx_r = __pyx_v_solutions; - goto __pyx_L0; + if (unlikely(__pyx_v_sorted_vars == Py_None)) { + PyErr_SetString(PyExc_TypeError, "'NoneType' object is not subscriptable"); + __PYX_ERR(0, 672, __pyx_L1_error) + } + __pyx_t_8 = __Pyx_PyList_GetSlice(__pyx_v_sorted_vars, 1, PY_SSIZE_T_MAX); if (unlikely(!__pyx_t_8)) __PYX_ERR(0, 672, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_8); + __Pyx_GIVEREF(__pyx_t_8); + __pyx_cur_scope->__pyx_v_remaining_vars = ((PyObject*)__pyx_t_8); + __pyx_t_8 = 0; - /* "constraint/solvers.py":624 - * return FunctionConstraint(func) + /* "constraint/solvers.py":675 + * + * # Create the parallel function arguments and solutions lists + * args = ((self.requires_pickling, domains, constraint_lookup, first_var, val, remaining_vars.copy()) for val in domains[first_var]) # noqa: E501 # <<<<<<<<<<<<<< + * solutions: list[dict[Hashable, any]] = [] * - * def sequential_recursive_backtrack(assignment: dict[Hashable, any], unassigned_vars: list[Hashable], domains: dict[Hashable, Domain], constraint_lookup: dict[Hashable, list[tuple[Constraint, Hashable]]]) -> list[dict[Hashable, any]]: # noqa E501 # <<<<<<<<<<<<<< - * """Sequential recursive backtracking function for subproblems.""" - * if not unassigned_vars: */ + __pyx_t_8 = __Pyx_PyDict_GetItem(__pyx_cur_scope->__pyx_v_domains, __pyx_cur_scope->__pyx_v_first_var); if (unlikely(!__pyx_t_8)) __PYX_ERR(0, 675, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_8); + __pyx_t_1 = __pyx_pf_10constraint_7solvers_14ParallelSolver_16getSolutionsList_1genexpr(((PyObject*)__pyx_cur_scope), __pyx_t_8); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 675, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __Pyx_DECREF(__pyx_t_8); __pyx_t_8 = 0; + __pyx_v_args = __pyx_t_1; + __pyx_t_1 = 0; - /* function exit code */ - __pyx_L1_error:; - __Pyx_XDECREF(__pyx_t_3); - __Pyx_XDECREF(__pyx_t_4); - __Pyx_XDECREF(__pyx_t_7); - __Pyx_XDECREF(__pyx_t_8); - __Pyx_XDECREF(__pyx_t_9); - __Pyx_AddTraceback("constraint.solvers.sequential_recursive_backtrack", __pyx_clineno, __pyx_lineno, __pyx_filename); - __pyx_r = NULL; - __pyx_L0:; - __Pyx_XDECREF(__pyx_v_var); - __Pyx_XDECREF(__pyx_v_remaining_vars); - __Pyx_XDECREF(__pyx_v_solutions); - __Pyx_XDECREF(__pyx_v_value); - __Pyx_XGIVEREF(__pyx_r); - __Pyx_RefNannyFinishContext(); - return __pyx_r; -} + /* "constraint/solvers.py":676 + * # Create the parallel function arguments and solutions lists + * args = ((self.requires_pickling, domains, constraint_lookup, first_var, val, remaining_vars.copy()) for val in domains[first_var]) # noqa: E501 + * solutions: list[dict[Hashable, any]] = [] # <<<<<<<<<<<<<< + * + * # execute in parallel + */ + __pyx_t_1 = PyList_New(0); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 676, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __pyx_v_solutions = ((PyObject*)__pyx_t_1); + __pyx_t_1 = 0; -/* "constraint/solvers.py":640 - * return solutions + /* "constraint/solvers.py":679 * - * def sequential_optimized_backtrack(assignment: dict[Hashable, any], unassigned_vars: list[Hashable], domains: dict[Hashable, Domain], constraint_lookup: dict[Hashable, list[tuple[Constraint, Hashable]]]) -> list[dict[Hashable, any]]: # noqa E501 # <<<<<<<<<<<<<< - * """Sequential optimized backtracking (as in OptimizedBacktrackingSolver) function for subproblems.""" - * # Does not do forwardcheck for simplicity + * # execute in parallel + * parallel_pool = ProcessPoolExecutor if self._process_mode else ThreadPoolExecutor # <<<<<<<<<<<<<< + * with parallel_pool() as executor: + * # results = map(parallel_worker, args) # sequential */ + __pyx_t_8 = __Pyx_PyObject_GetAttrStr(__pyx_cur_scope->__pyx_v_self, __pyx_n_s_process_mode_2); if (unlikely(!__pyx_t_8)) __PYX_ERR(0, 679, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_8); + __pyx_t_9 = __Pyx_PyObject_IsTrue(__pyx_t_8); if (unlikely((__pyx_t_9 < 0))) __PYX_ERR(0, 679, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_8); __pyx_t_8 = 0; + if (__pyx_t_9) { + __Pyx_GetModuleGlobalName(__pyx_t_8, __pyx_n_s_ProcessPoolExecutor); if (unlikely(!__pyx_t_8)) __PYX_ERR(0, 679, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_8); + __pyx_t_1 = __pyx_t_8; + __pyx_t_8 = 0; + } else { + __Pyx_GetModuleGlobalName(__pyx_t_8, __pyx_n_s_ThreadPoolExecutor); if (unlikely(!__pyx_t_8)) __PYX_ERR(0, 679, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_8); + __pyx_t_1 = __pyx_t_8; + __pyx_t_8 = 0; + } + __pyx_v_parallel_pool = __pyx_t_1; + __pyx_t_1 = 0; -/* Python wrapper */ -static PyObject *__pyx_pw_10constraint_7solvers_11sequential_optimized_backtrack(PyObject *__pyx_self, -#if CYTHON_METH_FASTCALL -PyObject *const *__pyx_args, Py_ssize_t __pyx_nargs, PyObject *__pyx_kwds -#else -PyObject *__pyx_args, PyObject *__pyx_kwds -#endif -); /*proto*/ -PyDoc_STRVAR(__pyx_doc_10constraint_7solvers_10sequential_optimized_backtrack, "Sequential optimized backtracking (as in OptimizedBacktrackingSolver) function for subproblems."); -static PyMethodDef __pyx_mdef_10constraint_7solvers_11sequential_optimized_backtrack = {"sequential_optimized_backtrack", (PyCFunction)(void*)(__Pyx_PyCFunction_FastCallWithKeywords)__pyx_pw_10constraint_7solvers_11sequential_optimized_backtrack, __Pyx_METH_FASTCALL|METH_KEYWORDS, __pyx_doc_10constraint_7solvers_10sequential_optimized_backtrack}; -static PyObject *__pyx_pw_10constraint_7solvers_11sequential_optimized_backtrack(PyObject *__pyx_self, -#if CYTHON_METH_FASTCALL -PyObject *const *__pyx_args, Py_ssize_t __pyx_nargs, PyObject *__pyx_kwds -#else -PyObject *__pyx_args, PyObject *__pyx_kwds -#endif -) { - PyObject *__pyx_v_assignment = 0; - PyObject *__pyx_v_unassigned_vars = 0; - PyObject *__pyx_v_domains = 0; - PyObject *__pyx_v_constraint_lookup = 0; - #if !CYTHON_METH_FASTCALL - CYTHON_UNUSED Py_ssize_t __pyx_nargs; - #endif - CYTHON_UNUSED PyObject *const *__pyx_kwvalues; - PyObject* values[4] = {0,0,0,0}; - int __pyx_lineno = 0; - const char *__pyx_filename = NULL; - int __pyx_clineno = 0; - PyObject *__pyx_r = 0; - __Pyx_RefNannyDeclarations - __Pyx_RefNannySetupContext("sequential_optimized_backtrack (wrapper)", 0); - #if !CYTHON_METH_FASTCALL - #if CYTHON_ASSUME_SAFE_MACROS - __pyx_nargs = PyTuple_GET_SIZE(__pyx_args); - #else - __pyx_nargs = PyTuple_Size(__pyx_args); if (unlikely(__pyx_nargs < 0)) return NULL; - #endif - #endif - __pyx_kwvalues = __Pyx_KwValues_FASTCALL(__pyx_args, __pyx_nargs); - { - PyObject **__pyx_pyargnames[] = {&__pyx_n_s_assignment,&__pyx_n_s_unassigned_vars,&__pyx_n_s_domains,&__pyx_n_s_constraint_lookup,0}; - if (__pyx_kwds) { - Py_ssize_t kw_args; - switch (__pyx_nargs) { - case 4: values[3] = __Pyx_Arg_FASTCALL(__pyx_args, 3); - CYTHON_FALLTHROUGH; - case 3: values[2] = __Pyx_Arg_FASTCALL(__pyx_args, 2); - CYTHON_FALLTHROUGH; - case 2: values[1] = __Pyx_Arg_FASTCALL(__pyx_args, 1); - CYTHON_FALLTHROUGH; - case 1: values[0] = __Pyx_Arg_FASTCALL(__pyx_args, 0); - CYTHON_FALLTHROUGH; - case 0: break; - default: goto __pyx_L5_argtuple_error; - } - kw_args = __Pyx_NumKwargs_FASTCALL(__pyx_kwds); - switch (__pyx_nargs) { - case 0: - if (likely((values[0] = __Pyx_GetKwValue_FASTCALL(__pyx_kwds, __pyx_kwvalues, __pyx_n_s_assignment)) != 0)) { - (void)__Pyx_Arg_NewRef_FASTCALL(values[0]); - kw_args--; - } - else if (unlikely(PyErr_Occurred())) __PYX_ERR(0, 640, __pyx_L3_error) - else goto __pyx_L5_argtuple_error; - CYTHON_FALLTHROUGH; - case 1: - if (likely((values[1] = __Pyx_GetKwValue_FASTCALL(__pyx_kwds, __pyx_kwvalues, __pyx_n_s_unassigned_vars)) != 0)) { - (void)__Pyx_Arg_NewRef_FASTCALL(values[1]); - kw_args--; - } - else if (unlikely(PyErr_Occurred())) __PYX_ERR(0, 640, __pyx_L3_error) - else { - __Pyx_RaiseArgtupleInvalid("sequential_optimized_backtrack", 1, 4, 4, 1); __PYX_ERR(0, 640, __pyx_L3_error) - } - CYTHON_FALLTHROUGH; - case 2: - if (likely((values[2] = __Pyx_GetKwValue_FASTCALL(__pyx_kwds, __pyx_kwvalues, __pyx_n_s_domains)) != 0)) { - (void)__Pyx_Arg_NewRef_FASTCALL(values[2]); - kw_args--; - } - else if (unlikely(PyErr_Occurred())) __PYX_ERR(0, 640, __pyx_L3_error) - else { - __Pyx_RaiseArgtupleInvalid("sequential_optimized_backtrack", 1, 4, 4, 2); __PYX_ERR(0, 640, __pyx_L3_error) - } - CYTHON_FALLTHROUGH; - case 3: - if (likely((values[3] = __Pyx_GetKwValue_FASTCALL(__pyx_kwds, __pyx_kwvalues, __pyx_n_s_constraint_lookup)) != 0)) { - (void)__Pyx_Arg_NewRef_FASTCALL(values[3]); - kw_args--; - } - else if (unlikely(PyErr_Occurred())) __PYX_ERR(0, 640, __pyx_L3_error) - else { - __Pyx_RaiseArgtupleInvalid("sequential_optimized_backtrack", 1, 4, 4, 3); __PYX_ERR(0, 640, __pyx_L3_error) - } - } - if (unlikely(kw_args > 0)) { - const Py_ssize_t kwd_pos_args = __pyx_nargs; - if (unlikely(__Pyx_ParseOptionalKeywords(__pyx_kwds, __pyx_kwvalues, __pyx_pyargnames, 0, values + 0, kwd_pos_args, "sequential_optimized_backtrack") < 0)) __PYX_ERR(0, 640, __pyx_L3_error) + /* "constraint/solvers.py":680 + * # execute in parallel + * parallel_pool = ProcessPoolExecutor if self._process_mode else ThreadPoolExecutor + * with parallel_pool() as executor: # <<<<<<<<<<<<<< + * # results = map(parallel_worker, args) # sequential + * results = executor.map(parallel_worker, args, chunksize=1) # parallel + */ + /*with:*/ { + __Pyx_INCREF(__pyx_v_parallel_pool); + __pyx_t_8 = __pyx_v_parallel_pool; __pyx_t_2 = NULL; + __pyx_t_10 = 0; + #if CYTHON_UNPACK_METHODS + if (unlikely(PyMethod_Check(__pyx_t_8))) { + __pyx_t_2 = PyMethod_GET_SELF(__pyx_t_8); + if (likely(__pyx_t_2)) { + PyObject* function = PyMethod_GET_FUNCTION(__pyx_t_8); + __Pyx_INCREF(__pyx_t_2); + __Pyx_INCREF(function); + __Pyx_DECREF_SET(__pyx_t_8, function); + __pyx_t_10 = 1; } - } else if (unlikely(__pyx_nargs != 4)) { - goto __pyx_L5_argtuple_error; - } else { - values[0] = __Pyx_Arg_FASTCALL(__pyx_args, 0); - values[1] = __Pyx_Arg_FASTCALL(__pyx_args, 1); - values[2] = __Pyx_Arg_FASTCALL(__pyx_args, 2); - values[3] = __Pyx_Arg_FASTCALL(__pyx_args, 3); } - __pyx_v_assignment = ((PyObject*)values[0]); - __pyx_v_unassigned_vars = ((PyObject*)values[1]); - __pyx_v_domains = ((PyObject*)values[2]); - __pyx_v_constraint_lookup = ((PyObject*)values[3]); - } - goto __pyx_L6_skip; - __pyx_L5_argtuple_error:; - __Pyx_RaiseArgtupleInvalid("sequential_optimized_backtrack", 1, 4, 4, __pyx_nargs); __PYX_ERR(0, 640, __pyx_L3_error) - __pyx_L6_skip:; - goto __pyx_L4_argument_unpacking_done; - __pyx_L3_error:; - { - Py_ssize_t __pyx_temp; - for (__pyx_temp=0; __pyx_temp < (Py_ssize_t)(sizeof(values)/sizeof(values[0])); ++__pyx_temp) { - __Pyx_Arg_XDECREF_FASTCALL(values[__pyx_temp]); + #endif + { + PyObject *__pyx_callargs[2] = {__pyx_t_2, NULL}; + __pyx_t_1 = __Pyx_PyObject_FastCall(__pyx_t_8, __pyx_callargs+1-__pyx_t_10, 0+__pyx_t_10); + __Pyx_XDECREF(__pyx_t_2); __pyx_t_2 = 0; + if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 680, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __Pyx_DECREF(__pyx_t_8); __pyx_t_8 = 0; } - } - __Pyx_AddTraceback("constraint.solvers.sequential_optimized_backtrack", __pyx_clineno, __pyx_lineno, __pyx_filename); - __Pyx_RefNannyFinishContext(); - return NULL; - __pyx_L4_argument_unpacking_done:; - if (unlikely(!__Pyx_ArgTypeTest(((PyObject *)__pyx_v_assignment), (&PyDict_Type), 0, "assignment", 1))) __PYX_ERR(0, 640, __pyx_L1_error) - if (unlikely(!__Pyx_ArgTypeTest(((PyObject *)__pyx_v_unassigned_vars), (&PyList_Type), 0, "unassigned_vars", 1))) __PYX_ERR(0, 640, __pyx_L1_error) - if (unlikely(!__Pyx_ArgTypeTest(((PyObject *)__pyx_v_domains), (&PyDict_Type), 0, "domains", 1))) __PYX_ERR(0, 640, __pyx_L1_error) - if (unlikely(!__Pyx_ArgTypeTest(((PyObject *)__pyx_v_constraint_lookup), (&PyDict_Type), 0, "constraint_lookup", 1))) __PYX_ERR(0, 640, __pyx_L1_error) - __pyx_r = __pyx_pf_10constraint_7solvers_10sequential_optimized_backtrack(__pyx_self, __pyx_v_assignment, __pyx_v_unassigned_vars, __pyx_v_domains, __pyx_v_constraint_lookup); - - /* function exit code */ - goto __pyx_L0; - __pyx_L1_error:; - __pyx_r = NULL; - __pyx_L0:; - { - Py_ssize_t __pyx_temp; - for (__pyx_temp=0; __pyx_temp < (Py_ssize_t)(sizeof(values)/sizeof(values[0])); ++__pyx_temp) { - __Pyx_Arg_XDECREF_FASTCALL(values[__pyx_temp]); + __pyx_t_11 = __Pyx_PyObject_LookupSpecial(__pyx_t_1, __pyx_n_s_exit); if (unlikely(!__pyx_t_11)) __PYX_ERR(0, 680, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_11); + __pyx_t_2 = __Pyx_PyObject_LookupSpecial(__pyx_t_1, __pyx_n_s_enter); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 680, __pyx_L9_error) + __Pyx_GOTREF(__pyx_t_2); + __pyx_t_6 = NULL; + __pyx_t_10 = 0; + #if CYTHON_UNPACK_METHODS + if (likely(PyMethod_Check(__pyx_t_2))) { + __pyx_t_6 = PyMethod_GET_SELF(__pyx_t_2); + if (likely(__pyx_t_6)) { + PyObject* function = PyMethod_GET_FUNCTION(__pyx_t_2); + __Pyx_INCREF(__pyx_t_6); + __Pyx_INCREF(function); + __Pyx_DECREF_SET(__pyx_t_2, function); + __pyx_t_10 = 1; + } } - } - __Pyx_RefNannyFinishContext(); - return __pyx_r; -} + #endif + { + PyObject *__pyx_callargs[2] = {__pyx_t_6, NULL}; + __pyx_t_8 = __Pyx_PyObject_FastCall(__pyx_t_2, __pyx_callargs+1-__pyx_t_10, 0+__pyx_t_10); + __Pyx_XDECREF(__pyx_t_6); __pyx_t_6 = 0; + if (unlikely(!__pyx_t_8)) __PYX_ERR(0, 680, __pyx_L9_error) + __Pyx_GOTREF(__pyx_t_8); + __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; + } + __pyx_t_2 = __pyx_t_8; + __pyx_t_8 = 0; + __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; + /*try:*/ { + { + __Pyx_PyThreadState_declare + __Pyx_PyThreadState_assign + __Pyx_ExceptionSave(&__pyx_t_12, &__pyx_t_13, &__pyx_t_14); + __Pyx_XGOTREF(__pyx_t_12); + __Pyx_XGOTREF(__pyx_t_13); + __Pyx_XGOTREF(__pyx_t_14); + /*try:*/ { + __pyx_v_executor = __pyx_t_2; + __pyx_t_2 = 0; -static PyObject *__pyx_pf_10constraint_7solvers_10sequential_optimized_backtrack(CYTHON_UNUSED PyObject *__pyx_self, PyObject *__pyx_v_assignment, PyObject *__pyx_v_unassigned_vars, PyObject *__pyx_v_domains, PyObject *__pyx_v_constraint_lookup) { - PyObject *__pyx_v_assignments = NULL; - PyObject *__pyx_v_sorted_variables = NULL; - PyObject *__pyx_v_queue = 0; - PyObject *__pyx_v_solutions = 0; - PyObject *__pyx_v_variable = NULL; - PyObject *__pyx_v_values = NULL; - PyObject *__pyx_v_constraint = NULL; - PyObject *__pyx_v_variables = NULL; - PyObject *__pyx_r = NULL; - __Pyx_RefNannyDeclarations - PyObject *__pyx_t_1 = NULL; - Py_ssize_t __pyx_t_2; - PyObject *__pyx_t_3 = NULL; - int __pyx_t_4; - PyObject *__pyx_t_5 = NULL; - int __pyx_t_6; - int __pyx_t_7; - PyObject *__pyx_t_8 = NULL; - PyObject *(*__pyx_t_9)(PyObject *); - PyObject *(*__pyx_t_10)(PyObject *); - PyObject *__pyx_t_11 = NULL; - unsigned int __pyx_t_12; - int __pyx_lineno = 0; - const char *__pyx_filename = NULL; - int __pyx_clineno = 0; - __Pyx_RefNannySetupContext("sequential_optimized_backtrack", 1); + /* "constraint/solvers.py":682 + * with parallel_pool() as executor: + * # results = map(parallel_worker, args) # sequential + * results = executor.map(parallel_worker, args, chunksize=1) # parallel # <<<<<<<<<<<<<< + * for result in results: + * solutions.extend(result) + */ + __pyx_t_2 = __Pyx_PyObject_GetAttrStr(__pyx_v_executor, __pyx_n_s_map); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 682, __pyx_L13_error) + __Pyx_GOTREF(__pyx_t_2); + __Pyx_GetModuleGlobalName(__pyx_t_1, __pyx_n_s_parallel_worker); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 682, __pyx_L13_error) + __Pyx_GOTREF(__pyx_t_1); + __pyx_t_8 = PyTuple_New(2); if (unlikely(!__pyx_t_8)) __PYX_ERR(0, 682, __pyx_L13_error) + __Pyx_GOTREF(__pyx_t_8); + __Pyx_GIVEREF(__pyx_t_1); + if (__Pyx_PyTuple_SET_ITEM(__pyx_t_8, 0, __pyx_t_1)) __PYX_ERR(0, 682, __pyx_L13_error); + __Pyx_INCREF(__pyx_v_args); + __Pyx_GIVEREF(__pyx_v_args); + if (__Pyx_PyTuple_SET_ITEM(__pyx_t_8, 1, __pyx_v_args)) __PYX_ERR(0, 682, __pyx_L13_error); + __pyx_t_1 = 0; + __pyx_t_1 = __Pyx_PyDict_NewPresized(1); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 682, __pyx_L13_error) + __Pyx_GOTREF(__pyx_t_1); + if (PyDict_SetItem(__pyx_t_1, __pyx_n_s_chunksize, __pyx_int_1) < 0) __PYX_ERR(0, 682, __pyx_L13_error) + __pyx_t_6 = __Pyx_PyObject_Call(__pyx_t_2, __pyx_t_8, __pyx_t_1); if (unlikely(!__pyx_t_6)) __PYX_ERR(0, 682, __pyx_L13_error) + __Pyx_GOTREF(__pyx_t_6); + __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; + __Pyx_DECREF(__pyx_t_8); __pyx_t_8 = 0; + __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; + __pyx_v_results = __pyx_t_6; + __pyx_t_6 = 0; - /* "constraint/solvers.py":644 - * # Does not do forwardcheck for simplicity + /* "constraint/solvers.py":683 + * # results = map(parallel_worker, args) # sequential + * results = executor.map(parallel_worker, args, chunksize=1) # parallel + * for result in results: # <<<<<<<<<<<<<< + * solutions.extend(result) * - * assignments = assignment # <<<<<<<<<<<<<< - * sorted_variables = unassigned_vars - * queue: list[tuple] = [] */ - __Pyx_INCREF(__pyx_v_assignment); - __pyx_v_assignments = __pyx_v_assignment; + if (likely(PyList_CheckExact(__pyx_v_results)) || PyTuple_CheckExact(__pyx_v_results)) { + __pyx_t_6 = __pyx_v_results; __Pyx_INCREF(__pyx_t_6); + __pyx_t_4 = 0; + __pyx_t_15 = NULL; + } else { + __pyx_t_4 = -1; __pyx_t_6 = PyObject_GetIter(__pyx_v_results); if (unlikely(!__pyx_t_6)) __PYX_ERR(0, 683, __pyx_L13_error) + __Pyx_GOTREF(__pyx_t_6); + __pyx_t_15 = __Pyx_PyObject_GetIterNextFunc(__pyx_t_6); if (unlikely(!__pyx_t_15)) __PYX_ERR(0, 683, __pyx_L13_error) + } + for (;;) { + if (likely(!__pyx_t_15)) { + if (likely(PyList_CheckExact(__pyx_t_6))) { + { + Py_ssize_t __pyx_temp = __Pyx_PyList_GET_SIZE(__pyx_t_6); + #if !CYTHON_ASSUME_SAFE_MACROS + if (unlikely((__pyx_temp < 0))) __PYX_ERR(0, 683, __pyx_L13_error) + #endif + if (__pyx_t_4 >= __pyx_temp) break; + } + #if CYTHON_ASSUME_SAFE_MACROS && !CYTHON_AVOID_BORROWED_REFS + __pyx_t_1 = PyList_GET_ITEM(__pyx_t_6, __pyx_t_4); __Pyx_INCREF(__pyx_t_1); __pyx_t_4++; if (unlikely((0 < 0))) __PYX_ERR(0, 683, __pyx_L13_error) + #else + __pyx_t_1 = __Pyx_PySequence_ITEM(__pyx_t_6, __pyx_t_4); __pyx_t_4++; if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 683, __pyx_L13_error) + __Pyx_GOTREF(__pyx_t_1); + #endif + } else { + { + Py_ssize_t __pyx_temp = __Pyx_PyTuple_GET_SIZE(__pyx_t_6); + #if !CYTHON_ASSUME_SAFE_MACROS + if (unlikely((__pyx_temp < 0))) __PYX_ERR(0, 683, __pyx_L13_error) + #endif + if (__pyx_t_4 >= __pyx_temp) break; + } + #if CYTHON_ASSUME_SAFE_MACROS && !CYTHON_AVOID_BORROWED_REFS + __pyx_t_1 = PyTuple_GET_ITEM(__pyx_t_6, __pyx_t_4); __Pyx_INCREF(__pyx_t_1); __pyx_t_4++; if (unlikely((0 < 0))) __PYX_ERR(0, 683, __pyx_L13_error) + #else + __pyx_t_1 = __Pyx_PySequence_ITEM(__pyx_t_6, __pyx_t_4); __pyx_t_4++; if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 683, __pyx_L13_error) + __Pyx_GOTREF(__pyx_t_1); + #endif + } + } else { + __pyx_t_1 = __pyx_t_15(__pyx_t_6); + if (unlikely(!__pyx_t_1)) { + PyObject* exc_type = PyErr_Occurred(); + if (exc_type) { + if (likely(__Pyx_PyErr_GivenExceptionMatches(exc_type, PyExc_StopIteration))) PyErr_Clear(); + else __PYX_ERR(0, 683, __pyx_L13_error) + } + break; + } + __Pyx_GOTREF(__pyx_t_1); + } + __Pyx_XDECREF_SET(__pyx_v_result, __pyx_t_1); + __pyx_t_1 = 0; - /* "constraint/solvers.py":645 + /* "constraint/solvers.py":684 + * results = executor.map(parallel_worker, args, chunksize=1) # parallel + * for result in results: + * solutions.extend(result) # <<<<<<<<<<<<<< * - * assignments = assignment - * sorted_variables = unassigned_vars # <<<<<<<<<<<<<< - * queue: list[tuple] = [] - * solutions: list[dict] = list() + * return solutions */ - __Pyx_INCREF(__pyx_v_unassigned_vars); - __pyx_v_sorted_variables = __pyx_v_unassigned_vars; + __pyx_t_16 = __Pyx_PyList_Extend(__pyx_v_solutions, __pyx_v_result); if (unlikely(__pyx_t_16 == ((int)-1))) __PYX_ERR(0, 684, __pyx_L13_error) - /* "constraint/solvers.py":646 - * assignments = assignment - * sorted_variables = unassigned_vars - * queue: list[tuple] = [] # <<<<<<<<<<<<<< - * solutions: list[dict] = list() - * - */ - __pyx_t_1 = PyList_New(0); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 646, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_1); - __pyx_v_queue = ((PyObject*)__pyx_t_1); - __pyx_t_1 = 0; - - /* "constraint/solvers.py":647 - * sorted_variables = unassigned_vars - * queue: list[tuple] = [] - * solutions: list[dict] = list() # <<<<<<<<<<<<<< - * - * while True: - */ - __pyx_t_1 = PyList_New(0); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 647, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_1); - __pyx_v_solutions = ((PyObject*)__pyx_t_1); - __pyx_t_1 = 0; - - /* "constraint/solvers.py":649 - * solutions: list[dict] = list() + /* "constraint/solvers.py":683 + * # results = map(parallel_worker, args) # sequential + * results = executor.map(parallel_worker, args, chunksize=1) # parallel + * for result in results: # <<<<<<<<<<<<<< + * solutions.extend(result) * - * while True: # <<<<<<<<<<<<<< - * # Mix the Degree and Minimum Remaing Values (MRV) heuristics - * for variable in sorted_variables: */ - while (1) { + } + __Pyx_DECREF(__pyx_t_6); __pyx_t_6 = 0; - /* "constraint/solvers.py":651 - * while True: - * # Mix the Degree and Minimum Remaing Values (MRV) heuristics - * for variable in sorted_variables: # <<<<<<<<<<<<<< - * if variable not in assignments: - * # Found unassigned variable + /* "constraint/solvers.py":680 + * # execute in parallel + * parallel_pool = ProcessPoolExecutor if self._process_mode else ThreadPoolExecutor + * with parallel_pool() as executor: # <<<<<<<<<<<<<< + * # results = map(parallel_worker, args) # sequential + * results = executor.map(parallel_worker, args, chunksize=1) # parallel */ - __pyx_t_1 = __pyx_v_sorted_variables; __Pyx_INCREF(__pyx_t_1); - __pyx_t_2 = 0; - for (;;) { - { - Py_ssize_t __pyx_temp = __Pyx_PyList_GET_SIZE(__pyx_t_1); - #if !CYTHON_ASSUME_SAFE_MACROS - if (unlikely((__pyx_temp < 0))) __PYX_ERR(0, 651, __pyx_L1_error) - #endif - if (__pyx_t_2 >= __pyx_temp) break; + } + __Pyx_XDECREF(__pyx_t_12); __pyx_t_12 = 0; + __Pyx_XDECREF(__pyx_t_13); __pyx_t_13 = 0; + __Pyx_XDECREF(__pyx_t_14); __pyx_t_14 = 0; + goto __pyx_L18_try_end; + __pyx_L13_error:; + __Pyx_XDECREF(__pyx_t_1); __pyx_t_1 = 0; + __Pyx_XDECREF(__pyx_t_2); __pyx_t_2 = 0; + __Pyx_XDECREF(__pyx_t_6); __pyx_t_6 = 0; + __Pyx_XDECREF(__pyx_t_8); __pyx_t_8 = 0; + /*except:*/ { + __Pyx_AddTraceback("constraint.solvers.ParallelSolver.getSolutionsList", __pyx_clineno, __pyx_lineno, __pyx_filename); + if (__Pyx_GetException(&__pyx_t_6, &__pyx_t_1, &__pyx_t_8) < 0) __PYX_ERR(0, 680, __pyx_L15_except_error) + __Pyx_XGOTREF(__pyx_t_6); + __Pyx_XGOTREF(__pyx_t_1); + __Pyx_XGOTREF(__pyx_t_8); + __pyx_t_2 = PyTuple_Pack(3, __pyx_t_6, __pyx_t_1, __pyx_t_8); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 680, __pyx_L15_except_error) + __Pyx_GOTREF(__pyx_t_2); + __pyx_t_17 = __Pyx_PyObject_Call(__pyx_t_11, __pyx_t_2, NULL); + __Pyx_DECREF(__pyx_t_11); __pyx_t_11 = 0; + __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; + if (unlikely(!__pyx_t_17)) __PYX_ERR(0, 680, __pyx_L15_except_error) + __Pyx_GOTREF(__pyx_t_17); + __pyx_t_9 = __Pyx_PyObject_IsTrue(__pyx_t_17); + __Pyx_DECREF(__pyx_t_17); __pyx_t_17 = 0; + if (__pyx_t_9 < 0) __PYX_ERR(0, 680, __pyx_L15_except_error) + __pyx_t_18 = (!__pyx_t_9); + if (unlikely(__pyx_t_18)) { + __Pyx_GIVEREF(__pyx_t_6); + __Pyx_GIVEREF(__pyx_t_1); + __Pyx_XGIVEREF(__pyx_t_8); + __Pyx_ErrRestoreWithState(__pyx_t_6, __pyx_t_1, __pyx_t_8); + __pyx_t_6 = 0; __pyx_t_1 = 0; __pyx_t_8 = 0; + __PYX_ERR(0, 680, __pyx_L15_except_error) + } + __Pyx_XDECREF(__pyx_t_6); __pyx_t_6 = 0; + __Pyx_XDECREF(__pyx_t_1); __pyx_t_1 = 0; + __Pyx_XDECREF(__pyx_t_8); __pyx_t_8 = 0; + goto __pyx_L14_exception_handled; + } + __pyx_L15_except_error:; + __Pyx_XGIVEREF(__pyx_t_12); + __Pyx_XGIVEREF(__pyx_t_13); + __Pyx_XGIVEREF(__pyx_t_14); + __Pyx_ExceptionReset(__pyx_t_12, __pyx_t_13, __pyx_t_14); + goto __pyx_L1_error; + __pyx_L14_exception_handled:; + __Pyx_XGIVEREF(__pyx_t_12); + __Pyx_XGIVEREF(__pyx_t_13); + __Pyx_XGIVEREF(__pyx_t_14); + __Pyx_ExceptionReset(__pyx_t_12, __pyx_t_13, __pyx_t_14); + __pyx_L18_try_end:; } - #if CYTHON_ASSUME_SAFE_MACROS && !CYTHON_AVOID_BORROWED_REFS - __pyx_t_3 = PyList_GET_ITEM(__pyx_t_1, __pyx_t_2); __Pyx_INCREF(__pyx_t_3); __pyx_t_2++; if (unlikely((0 < 0))) __PYX_ERR(0, 651, __pyx_L1_error) - #else - __pyx_t_3 = __Pyx_PySequence_ITEM(__pyx_t_1, __pyx_t_2); __pyx_t_2++; if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 651, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_3); - #endif - __Pyx_XDECREF_SET(__pyx_v_variable, __pyx_t_3); - __pyx_t_3 = 0; - - /* "constraint/solvers.py":652 - * # Mix the Degree and Minimum Remaing Values (MRV) heuristics - * for variable in sorted_variables: - * if variable not in assignments: # <<<<<<<<<<<<<< - * # Found unassigned variable - * values = domains[variable][:] - */ - __pyx_t_4 = (__Pyx_PyDict_ContainsTF(__pyx_v_variable, __pyx_v_assignments, Py_NE)); if (unlikely((__pyx_t_4 < 0))) __PYX_ERR(0, 652, __pyx_L1_error) - if (__pyx_t_4) { - - /* "constraint/solvers.py":654 - * if variable not in assignments: - * # Found unassigned variable - * values = domains[variable][:] # <<<<<<<<<<<<<< - * break - * else: - */ - __pyx_t_3 = __Pyx_PyDict_GetItem(__pyx_v_domains, __pyx_v_variable); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 654, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_3); - __pyx_t_5 = __Pyx_PyObject_GetSlice(__pyx_t_3, 0, 0, NULL, NULL, &__pyx_slice_, 0, 0, 1); if (unlikely(!__pyx_t_5)) __PYX_ERR(0, 654, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_5); - __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; - __Pyx_XDECREF_SET(__pyx_v_values, __pyx_t_5); - __pyx_t_5 = 0; - - /* "constraint/solvers.py":655 - * # Found unassigned variable - * values = domains[variable][:] - * break # <<<<<<<<<<<<<< - * else: - * # No unassigned variables. We've got a solution. Go back - */ - goto __pyx_L6_break; - - /* "constraint/solvers.py":652 - * # Mix the Degree and Minimum Remaing Values (MRV) heuristics - * for variable in sorted_variables: - * if variable not in assignments: # <<<<<<<<<<<<<< - * # Found unassigned variable - * values = domains[variable][:] - */ + } + /*finally:*/ { + /*normal exit:*/{ + if (__pyx_t_11) { + __pyx_t_14 = __Pyx_PyObject_Call(__pyx_t_11, __pyx_tuple__5, NULL); + __Pyx_DECREF(__pyx_t_11); __pyx_t_11 = 0; + if (unlikely(!__pyx_t_14)) __PYX_ERR(0, 680, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_14); + __Pyx_DECREF(__pyx_t_14); __pyx_t_14 = 0; + } + goto __pyx_L12; } - - /* "constraint/solvers.py":651 - * while True: - * # Mix the Degree and Minimum Remaing Values (MRV) heuristics - * for variable in sorted_variables: # <<<<<<<<<<<<<< - * if variable not in assignments: - * # Found unassigned variable - */ + __pyx_L12:; } - __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; - goto __pyx_L8_for_else; - __pyx_L6_break:; - __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; - goto __pyx_L9_for_end; - /*else*/ { - __pyx_L8_for_else:; - - /* "constraint/solvers.py":659 - * # No unassigned variables. We've got a solution. Go back - * # to last variable, if there's one. - * solutions.append(assignments.copy()) # <<<<<<<<<<<<<< - * if not queue: - * return solutions - */ - __pyx_t_1 = PyDict_Copy(__pyx_v_assignments); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 659, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_1); - __pyx_t_6 = __Pyx_PyList_Append(__pyx_v_solutions, __pyx_t_1); if (unlikely(__pyx_t_6 == ((int)-1))) __PYX_ERR(0, 659, __pyx_L1_error) - __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; + goto __pyx_L25; + __pyx_L9_error:; + __Pyx_DECREF(__pyx_t_11); __pyx_t_11 = 0; + goto __pyx_L1_error; + __pyx_L25:; + } - /* "constraint/solvers.py":660 - * # to last variable, if there's one. - * solutions.append(assignments.copy()) - * if not queue: # <<<<<<<<<<<<<< - * return solutions - * variable, values = queue.pop() + /* "constraint/solvers.py":686 + * solutions.extend(result) + * + * return solutions # <<<<<<<<<<<<<< + * + * def getSolutions(self, domains: dict, constraints: list[tuple], vconstraints: dict): # noqa: D102 */ - __pyx_t_4 = (PyList_GET_SIZE(__pyx_v_queue) != 0); - __pyx_t_7 = (!__pyx_t_4); - if (__pyx_t_7) { + __Pyx_XDECREF(__pyx_r); + __Pyx_INCREF(__pyx_v_solutions); + __pyx_r = __pyx_v_solutions; + goto __pyx_L0; - /* "constraint/solvers.py":661 - * solutions.append(assignments.copy()) - * if not queue: - * return solutions # <<<<<<<<<<<<<< - * variable, values = queue.pop() + /* "constraint/solvers.py":662 + * raise NotImplementedError(msg) * + * def getSolutionsList(self, domains: dict[Hashable, Domain], vconstraints: dict[Hashable, list[tuple[Constraint, Hashable]]]) -> list[dict[Hashable, any]]: # noqa: D102, E501 # <<<<<<<<<<<<<< + * """Parallelized all-solutions finder using ProcessPoolExecutor for work-stealing.""" + * # Precompute constraints lookup per variable */ - __Pyx_XDECREF(__pyx_r); - __Pyx_INCREF(__pyx_v_solutions); - __pyx_r = __pyx_v_solutions; - goto __pyx_L0; - /* "constraint/solvers.py":660 - * # to last variable, if there's one. - * solutions.append(assignments.copy()) - * if not queue: # <<<<<<<<<<<<<< - * return solutions - * variable, values = queue.pop() - */ - } + /* function exit code */ + __pyx_L1_error:; + __Pyx_XDECREF(__pyx_t_1); + __Pyx_XDECREF(__pyx_t_2); + __Pyx_XDECREF(__pyx_t_6); + __Pyx_XDECREF(__pyx_t_8); + __Pyx_AddTraceback("constraint.solvers.ParallelSolver.getSolutionsList", __pyx_clineno, __pyx_lineno, __pyx_filename); + __pyx_r = NULL; + __pyx_L0:; + __Pyx_XDECREF(__pyx_v_sorted_vars); + __Pyx_XDECREF(__pyx_v_args); + __Pyx_XDECREF(__pyx_v_solutions); + __Pyx_XDECREF(__pyx_v_parallel_pool); + __Pyx_XDECREF(__pyx_v_executor); + __Pyx_XDECREF(__pyx_v_results); + __Pyx_XDECREF(__pyx_v_result); + __Pyx_XDECREF(__pyx_8genexpr7__pyx_v_var); + __Pyx_XDECREF(__pyx_gb_10constraint_7solvers_14ParallelSolver_16getSolutionsList_3generator2); + __Pyx_DECREF((PyObject *)__pyx_cur_scope); + __Pyx_XGIVEREF(__pyx_r); + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} - /* "constraint/solvers.py":662 - * if not queue: - * return solutions - * variable, values = queue.pop() # <<<<<<<<<<<<<< +/* "constraint/solvers.py":688 + * return solutions + * + * def getSolutions(self, domains: dict, constraints: list[tuple], vconstraints: dict): # noqa: D102 # <<<<<<<<<<<<<< + * return self.getSolutionsList(domains, vconstraints) * - * while True: */ - __pyx_t_1 = __Pyx_PyList_Pop(__pyx_v_queue); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 662, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_1); - if ((likely(PyTuple_CheckExact(__pyx_t_1))) || (PyList_CheckExact(__pyx_t_1))) { - PyObject* sequence = __pyx_t_1; - Py_ssize_t size = __Pyx_PySequence_SIZE(sequence); - if (unlikely(size != 2)) { - if (size > 2) __Pyx_RaiseTooManyValuesError(2); - else if (size >= 0) __Pyx_RaiseNeedMoreValuesError(size); - __PYX_ERR(0, 662, __pyx_L1_error) - } - #if CYTHON_ASSUME_SAFE_MACROS && !CYTHON_AVOID_BORROWED_REFS - if (likely(PyTuple_CheckExact(sequence))) { - __pyx_t_5 = PyTuple_GET_ITEM(sequence, 0); - __pyx_t_3 = PyTuple_GET_ITEM(sequence, 1); - } else { - __pyx_t_5 = PyList_GET_ITEM(sequence, 0); - __pyx_t_3 = PyList_GET_ITEM(sequence, 1); + +/* Python wrapper */ +static PyObject *__pyx_pw_10constraint_7solvers_14ParallelSolver_7getSolutions(PyObject *__pyx_self, +#if CYTHON_METH_FASTCALL +PyObject *const *__pyx_args, Py_ssize_t __pyx_nargs, PyObject *__pyx_kwds +#else +PyObject *__pyx_args, PyObject *__pyx_kwds +#endif +); /*proto*/ +static PyMethodDef __pyx_mdef_10constraint_7solvers_14ParallelSolver_7getSolutions = {"getSolutions", (PyCFunction)(void*)(__Pyx_PyCFunction_FastCallWithKeywords)__pyx_pw_10constraint_7solvers_14ParallelSolver_7getSolutions, __Pyx_METH_FASTCALL|METH_KEYWORDS, 0}; +static PyObject *__pyx_pw_10constraint_7solvers_14ParallelSolver_7getSolutions(PyObject *__pyx_self, +#if CYTHON_METH_FASTCALL +PyObject *const *__pyx_args, Py_ssize_t __pyx_nargs, PyObject *__pyx_kwds +#else +PyObject *__pyx_args, PyObject *__pyx_kwds +#endif +) { + PyObject *__pyx_v_self = 0; + PyObject *__pyx_v_domains = 0; + CYTHON_UNUSED PyObject *__pyx_v_constraints = 0; + PyObject *__pyx_v_vconstraints = 0; + #if !CYTHON_METH_FASTCALL + CYTHON_UNUSED Py_ssize_t __pyx_nargs; + #endif + CYTHON_UNUSED PyObject *const *__pyx_kwvalues; + PyObject* values[4] = {0,0,0,0}; + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + PyObject *__pyx_r = 0; + __Pyx_RefNannyDeclarations + __Pyx_RefNannySetupContext("getSolutions (wrapper)", 0); + #if !CYTHON_METH_FASTCALL + #if CYTHON_ASSUME_SAFE_MACROS + __pyx_nargs = PyTuple_GET_SIZE(__pyx_args); + #else + __pyx_nargs = PyTuple_Size(__pyx_args); if (unlikely(__pyx_nargs < 0)) return NULL; + #endif + #endif + __pyx_kwvalues = __Pyx_KwValues_FASTCALL(__pyx_args, __pyx_nargs); + { + PyObject **__pyx_pyargnames[] = {&__pyx_n_s_self,&__pyx_n_s_domains,&__pyx_n_s_constraints,&__pyx_n_s_vconstraints,0}; + if (__pyx_kwds) { + Py_ssize_t kw_args; + switch (__pyx_nargs) { + case 4: values[3] = __Pyx_Arg_FASTCALL(__pyx_args, 3); + CYTHON_FALLTHROUGH; + case 3: values[2] = __Pyx_Arg_FASTCALL(__pyx_args, 2); + CYTHON_FALLTHROUGH; + case 2: values[1] = __Pyx_Arg_FASTCALL(__pyx_args, 1); + CYTHON_FALLTHROUGH; + case 1: values[0] = __Pyx_Arg_FASTCALL(__pyx_args, 0); + CYTHON_FALLTHROUGH; + case 0: break; + default: goto __pyx_L5_argtuple_error; + } + kw_args = __Pyx_NumKwargs_FASTCALL(__pyx_kwds); + switch (__pyx_nargs) { + case 0: + if (likely((values[0] = __Pyx_GetKwValue_FASTCALL(__pyx_kwds, __pyx_kwvalues, __pyx_n_s_self)) != 0)) { + (void)__Pyx_Arg_NewRef_FASTCALL(values[0]); + kw_args--; + } + else if (unlikely(PyErr_Occurred())) __PYX_ERR(0, 688, __pyx_L3_error) + else goto __pyx_L5_argtuple_error; + CYTHON_FALLTHROUGH; + case 1: + if (likely((values[1] = __Pyx_GetKwValue_FASTCALL(__pyx_kwds, __pyx_kwvalues, __pyx_n_s_domains)) != 0)) { + (void)__Pyx_Arg_NewRef_FASTCALL(values[1]); + kw_args--; + } + else if (unlikely(PyErr_Occurred())) __PYX_ERR(0, 688, __pyx_L3_error) + else { + __Pyx_RaiseArgtupleInvalid("getSolutions", 1, 4, 4, 1); __PYX_ERR(0, 688, __pyx_L3_error) + } + CYTHON_FALLTHROUGH; + case 2: + if (likely((values[2] = __Pyx_GetKwValue_FASTCALL(__pyx_kwds, __pyx_kwvalues, __pyx_n_s_constraints)) != 0)) { + (void)__Pyx_Arg_NewRef_FASTCALL(values[2]); + kw_args--; + } + else if (unlikely(PyErr_Occurred())) __PYX_ERR(0, 688, __pyx_L3_error) + else { + __Pyx_RaiseArgtupleInvalid("getSolutions", 1, 4, 4, 2); __PYX_ERR(0, 688, __pyx_L3_error) + } + CYTHON_FALLTHROUGH; + case 3: + if (likely((values[3] = __Pyx_GetKwValue_FASTCALL(__pyx_kwds, __pyx_kwvalues, __pyx_n_s_vconstraints)) != 0)) { + (void)__Pyx_Arg_NewRef_FASTCALL(values[3]); + kw_args--; + } + else if (unlikely(PyErr_Occurred())) __PYX_ERR(0, 688, __pyx_L3_error) + else { + __Pyx_RaiseArgtupleInvalid("getSolutions", 1, 4, 4, 3); __PYX_ERR(0, 688, __pyx_L3_error) } - __Pyx_INCREF(__pyx_t_5); - __Pyx_INCREF(__pyx_t_3); - #else - __pyx_t_5 = PySequence_ITEM(sequence, 0); if (unlikely(!__pyx_t_5)) __PYX_ERR(0, 662, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_5); - __pyx_t_3 = PySequence_ITEM(sequence, 1); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 662, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_3); - #endif - __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; - } else { - Py_ssize_t index = -1; - __pyx_t_8 = PyObject_GetIter(__pyx_t_1); if (unlikely(!__pyx_t_8)) __PYX_ERR(0, 662, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_8); - __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; - __pyx_t_9 = __Pyx_PyObject_GetIterNextFunc(__pyx_t_8); - index = 0; __pyx_t_5 = __pyx_t_9(__pyx_t_8); if (unlikely(!__pyx_t_5)) goto __pyx_L11_unpacking_failed; - __Pyx_GOTREF(__pyx_t_5); - index = 1; __pyx_t_3 = __pyx_t_9(__pyx_t_8); if (unlikely(!__pyx_t_3)) goto __pyx_L11_unpacking_failed; - __Pyx_GOTREF(__pyx_t_3); - if (__Pyx_IternextUnpackEndCheck(__pyx_t_9(__pyx_t_8), 2) < 0) __PYX_ERR(0, 662, __pyx_L1_error) - __pyx_t_9 = NULL; - __Pyx_DECREF(__pyx_t_8); __pyx_t_8 = 0; - goto __pyx_L12_unpacking_done; - __pyx_L11_unpacking_failed:; - __Pyx_DECREF(__pyx_t_8); __pyx_t_8 = 0; - __pyx_t_9 = NULL; - if (__Pyx_IterFinish() == 0) __Pyx_RaiseNeedMoreValuesError(index); - __PYX_ERR(0, 662, __pyx_L1_error) - __pyx_L12_unpacking_done:; } - __Pyx_XDECREF_SET(__pyx_v_variable, __pyx_t_5); - __pyx_t_5 = 0; - __Pyx_XDECREF_SET(__pyx_v_values, __pyx_t_3); - __pyx_t_3 = 0; + if (unlikely(kw_args > 0)) { + const Py_ssize_t kwd_pos_args = __pyx_nargs; + if (unlikely(__Pyx_ParseOptionalKeywords(__pyx_kwds, __pyx_kwvalues, __pyx_pyargnames, 0, values + 0, kwd_pos_args, "getSolutions") < 0)) __PYX_ERR(0, 688, __pyx_L3_error) + } + } else if (unlikely(__pyx_nargs != 4)) { + goto __pyx_L5_argtuple_error; + } else { + values[0] = __Pyx_Arg_FASTCALL(__pyx_args, 0); + values[1] = __Pyx_Arg_FASTCALL(__pyx_args, 1); + values[2] = __Pyx_Arg_FASTCALL(__pyx_args, 2); + values[3] = __Pyx_Arg_FASTCALL(__pyx_args, 3); } - __pyx_L9_for_end:; + __pyx_v_self = values[0]; + __pyx_v_domains = ((PyObject*)values[1]); + __pyx_v_constraints = ((PyObject*)values[2]); + __pyx_v_vconstraints = ((PyObject*)values[3]); + } + goto __pyx_L6_skip; + __pyx_L5_argtuple_error:; + __Pyx_RaiseArgtupleInvalid("getSolutions", 1, 4, 4, __pyx_nargs); __PYX_ERR(0, 688, __pyx_L3_error) + __pyx_L6_skip:; + goto __pyx_L4_argument_unpacking_done; + __pyx_L3_error:; + { + Py_ssize_t __pyx_temp; + for (__pyx_temp=0; __pyx_temp < (Py_ssize_t)(sizeof(values)/sizeof(values[0])); ++__pyx_temp) { + __Pyx_Arg_XDECREF_FASTCALL(values[__pyx_temp]); + } + } + __Pyx_AddTraceback("constraint.solvers.ParallelSolver.getSolutions", __pyx_clineno, __pyx_lineno, __pyx_filename); + __Pyx_RefNannyFinishContext(); + return NULL; + __pyx_L4_argument_unpacking_done:; + if (unlikely(!__Pyx_ArgTypeTest(((PyObject *)__pyx_v_domains), (&PyDict_Type), 0, "domains", 1))) __PYX_ERR(0, 688, __pyx_L1_error) + if (unlikely(!__Pyx_ArgTypeTest(((PyObject *)__pyx_v_constraints), (&PyList_Type), 0, "constraints", 1))) __PYX_ERR(0, 688, __pyx_L1_error) + if (unlikely(!__Pyx_ArgTypeTest(((PyObject *)__pyx_v_vconstraints), (&PyDict_Type), 0, "vconstraints", 1))) __PYX_ERR(0, 688, __pyx_L1_error) + __pyx_r = __pyx_pf_10constraint_7solvers_14ParallelSolver_6getSolutions(__pyx_self, __pyx_v_self, __pyx_v_domains, __pyx_v_constraints, __pyx_v_vconstraints); - /* "constraint/solvers.py":664 - * variable, values = queue.pop() + /* function exit code */ + goto __pyx_L0; + __pyx_L1_error:; + __pyx_r = NULL; + __pyx_L0:; + { + Py_ssize_t __pyx_temp; + for (__pyx_temp=0; __pyx_temp < (Py_ssize_t)(sizeof(values)/sizeof(values[0])); ++__pyx_temp) { + __Pyx_Arg_XDECREF_FASTCALL(values[__pyx_temp]); + } + } + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +static PyObject *__pyx_pf_10constraint_7solvers_14ParallelSolver_6getSolutions(CYTHON_UNUSED PyObject *__pyx_self, PyObject *__pyx_v_self, PyObject *__pyx_v_domains, CYTHON_UNUSED PyObject *__pyx_v_constraints, PyObject *__pyx_v_vconstraints) { + PyObject *__pyx_r = NULL; + __Pyx_RefNannyDeclarations + PyObject *__pyx_t_1 = NULL; + PyObject *__pyx_t_2 = NULL; + PyObject *__pyx_t_3 = NULL; + unsigned int __pyx_t_4; + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + __Pyx_RefNannySetupContext("getSolutions", 1); + + /* "constraint/solvers.py":689 * - * while True: # <<<<<<<<<<<<<< - * # We have a variable. Do we have any values left? - * if not values: + * def getSolutions(self, domains: dict, constraints: list[tuple], vconstraints: dict): # noqa: D102 + * return self.getSolutionsList(domains, vconstraints) # <<<<<<<<<<<<<< + * + * ### Helper functions for parallel solver */ - while (1) { + __Pyx_XDECREF(__pyx_r); + __pyx_t_2 = __Pyx_PyObject_GetAttrStr(__pyx_v_self, __pyx_n_s_getSolutionsList); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 689, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_2); + __pyx_t_3 = NULL; + __pyx_t_4 = 0; + #if CYTHON_UNPACK_METHODS + if (likely(PyMethod_Check(__pyx_t_2))) { + __pyx_t_3 = PyMethod_GET_SELF(__pyx_t_2); + if (likely(__pyx_t_3)) { + PyObject* function = PyMethod_GET_FUNCTION(__pyx_t_2); + __Pyx_INCREF(__pyx_t_3); + __Pyx_INCREF(function); + __Pyx_DECREF_SET(__pyx_t_2, function); + __pyx_t_4 = 1; + } + } + #endif + { + PyObject *__pyx_callargs[3] = {__pyx_t_3, __pyx_v_domains, __pyx_v_vconstraints}; + __pyx_t_1 = __Pyx_PyObject_FastCall(__pyx_t_2, __pyx_callargs+1-__pyx_t_4, 2+__pyx_t_4); + __Pyx_XDECREF(__pyx_t_3); __pyx_t_3 = 0; + if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 689, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; + } + __pyx_r = __pyx_t_1; + __pyx_t_1 = 0; + goto __pyx_L0; - /* "constraint/solvers.py":666 - * while True: - * # We have a variable. Do we have any values left? - * if not values: # <<<<<<<<<<<<<< - * # No. Go back to last variable, if there's one. - * del assignments[variable] + /* "constraint/solvers.py":688 + * return solutions + * + * def getSolutions(self, domains: dict, constraints: list[tuple], vconstraints: dict): # noqa: D102 # <<<<<<<<<<<<<< + * return self.getSolutionsList(domains, vconstraints) + * */ - __pyx_t_7 = __Pyx_PyObject_IsTrue(__pyx_v_values); if (unlikely((__pyx_t_7 < 0))) __PYX_ERR(0, 666, __pyx_L1_error) - __pyx_t_4 = (!__pyx_t_7); - if (__pyx_t_4) { - /* "constraint/solvers.py":668 - * if not values: - * # No. Go back to last variable, if there's one. - * del assignments[variable] # <<<<<<<<<<<<<< - * while queue: - * variable, values = queue.pop() - */ - if (unlikely((PyDict_DelItem(__pyx_v_assignments, __pyx_v_variable) < 0))) __PYX_ERR(0, 668, __pyx_L1_error) + /* function exit code */ + __pyx_L1_error:; + __Pyx_XDECREF(__pyx_t_1); + __Pyx_XDECREF(__pyx_t_2); + __Pyx_XDECREF(__pyx_t_3); + __Pyx_AddTraceback("constraint.solvers.ParallelSolver.getSolutions", __pyx_clineno, __pyx_lineno, __pyx_filename); + __pyx_r = NULL; + __pyx_L0:; + __Pyx_XGIVEREF(__pyx_r); + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} - /* "constraint/solvers.py":669 - * # No. Go back to last variable, if there's one. - * del assignments[variable] - * while queue: # <<<<<<<<<<<<<< - * variable, values = queue.pop() - * if values: +/* "constraint/solvers.py":693 + * ### Helper functions for parallel solver + * + * def is_valid(assignment: dict[Hashable, any], constraints_lookup: list[tuple[Constraint, Hashable]], domains: dict[Hashable, Domain]) -> bool: # noqa E501 # <<<<<<<<<<<<<< + * """Check if all constraints are satisfied given the current assignment.""" + * return all( */ - while (1) { - __pyx_t_4 = (PyList_GET_SIZE(__pyx_v_queue) != 0); - if (!__pyx_t_4) break; - /* "constraint/solvers.py":670 - * del assignments[variable] - * while queue: - * variable, values = queue.pop() # <<<<<<<<<<<<<< - * if values: - * break - */ - __pyx_t_1 = __Pyx_PyList_Pop(__pyx_v_queue); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 670, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_1); - if ((likely(PyTuple_CheckExact(__pyx_t_1))) || (PyList_CheckExact(__pyx_t_1))) { - PyObject* sequence = __pyx_t_1; - Py_ssize_t size = __Pyx_PySequence_SIZE(sequence); - if (unlikely(size != 2)) { - if (size > 2) __Pyx_RaiseTooManyValuesError(2); - else if (size >= 0) __Pyx_RaiseNeedMoreValuesError(size); - __PYX_ERR(0, 670, __pyx_L1_error) - } - #if CYTHON_ASSUME_SAFE_MACROS && !CYTHON_AVOID_BORROWED_REFS - if (likely(PyTuple_CheckExact(sequence))) { - __pyx_t_3 = PyTuple_GET_ITEM(sequence, 0); - __pyx_t_5 = PyTuple_GET_ITEM(sequence, 1); - } else { - __pyx_t_3 = PyList_GET_ITEM(sequence, 0); - __pyx_t_5 = PyList_GET_ITEM(sequence, 1); - } - __Pyx_INCREF(__pyx_t_3); - __Pyx_INCREF(__pyx_t_5); - #else - __pyx_t_3 = PySequence_ITEM(sequence, 0); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 670, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_3); - __pyx_t_5 = PySequence_ITEM(sequence, 1); if (unlikely(!__pyx_t_5)) __PYX_ERR(0, 670, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_5); - #endif - __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; - } else { - Py_ssize_t index = -1; - __pyx_t_8 = PyObject_GetIter(__pyx_t_1); if (unlikely(!__pyx_t_8)) __PYX_ERR(0, 670, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_8); - __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; - __pyx_t_9 = __Pyx_PyObject_GetIterNextFunc(__pyx_t_8); - index = 0; __pyx_t_3 = __pyx_t_9(__pyx_t_8); if (unlikely(!__pyx_t_3)) goto __pyx_L18_unpacking_failed; - __Pyx_GOTREF(__pyx_t_3); - index = 1; __pyx_t_5 = __pyx_t_9(__pyx_t_8); if (unlikely(!__pyx_t_5)) goto __pyx_L18_unpacking_failed; - __Pyx_GOTREF(__pyx_t_5); - if (__Pyx_IternextUnpackEndCheck(__pyx_t_9(__pyx_t_8), 2) < 0) __PYX_ERR(0, 670, __pyx_L1_error) - __pyx_t_9 = NULL; - __Pyx_DECREF(__pyx_t_8); __pyx_t_8 = 0; - goto __pyx_L19_unpacking_done; - __pyx_L18_unpacking_failed:; - __Pyx_DECREF(__pyx_t_8); __pyx_t_8 = 0; - __pyx_t_9 = NULL; - if (__Pyx_IterFinish() == 0) __Pyx_RaiseNeedMoreValuesError(index); - __PYX_ERR(0, 670, __pyx_L1_error) - __pyx_L19_unpacking_done:; - } - __Pyx_DECREF_SET(__pyx_v_variable, __pyx_t_3); - __pyx_t_3 = 0; - __Pyx_DECREF_SET(__pyx_v_values, __pyx_t_5); - __pyx_t_5 = 0; - - /* "constraint/solvers.py":671 - * while queue: - * variable, values = queue.pop() - * if values: # <<<<<<<<<<<<<< - * break - * del assignments[variable] - */ - __pyx_t_4 = __Pyx_PyObject_IsTrue(__pyx_v_values); if (unlikely((__pyx_t_4 < 0))) __PYX_ERR(0, 671, __pyx_L1_error) - if (__pyx_t_4) { - - /* "constraint/solvers.py":672 - * variable, values = queue.pop() - * if values: - * break # <<<<<<<<<<<<<< - * del assignments[variable] - * else: - */ - goto __pyx_L17_break; - - /* "constraint/solvers.py":671 - * while queue: - * variable, values = queue.pop() - * if values: # <<<<<<<<<<<<<< - * break - * del assignments[variable] - */ - } - - /* "constraint/solvers.py":673 - * if values: - * break - * del assignments[variable] # <<<<<<<<<<<<<< - * else: - * return solutions - */ - if (unlikely((PyDict_DelItem(__pyx_v_assignments, __pyx_v_variable) < 0))) __PYX_ERR(0, 673, __pyx_L1_error) +/* Python wrapper */ +static PyObject *__pyx_pw_10constraint_7solvers_5is_valid(PyObject *__pyx_self, +#if CYTHON_METH_FASTCALL +PyObject *const *__pyx_args, Py_ssize_t __pyx_nargs, PyObject *__pyx_kwds +#else +PyObject *__pyx_args, PyObject *__pyx_kwds +#endif +); /*proto*/ +PyDoc_STRVAR(__pyx_doc_10constraint_7solvers_4is_valid, "Check if all constraints are satisfied given the current assignment."); +static PyMethodDef __pyx_mdef_10constraint_7solvers_5is_valid = {"is_valid", (PyCFunction)(void*)(__Pyx_PyCFunction_FastCallWithKeywords)__pyx_pw_10constraint_7solvers_5is_valid, __Pyx_METH_FASTCALL|METH_KEYWORDS, __pyx_doc_10constraint_7solvers_4is_valid}; +static PyObject *__pyx_pw_10constraint_7solvers_5is_valid(PyObject *__pyx_self, +#if CYTHON_METH_FASTCALL +PyObject *const *__pyx_args, Py_ssize_t __pyx_nargs, PyObject *__pyx_kwds +#else +PyObject *__pyx_args, PyObject *__pyx_kwds +#endif +) { + PyObject *__pyx_v_assignment = 0; + PyObject *__pyx_v_constraints_lookup = 0; + PyObject *__pyx_v_domains = 0; + #if !CYTHON_METH_FASTCALL + CYTHON_UNUSED Py_ssize_t __pyx_nargs; + #endif + CYTHON_UNUSED PyObject *const *__pyx_kwvalues; + PyObject* values[3] = {0,0,0}; + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + PyObject *__pyx_r = 0; + __Pyx_RefNannyDeclarations + __Pyx_RefNannySetupContext("is_valid (wrapper)", 0); + #if !CYTHON_METH_FASTCALL + #if CYTHON_ASSUME_SAFE_MACROS + __pyx_nargs = PyTuple_GET_SIZE(__pyx_args); + #else + __pyx_nargs = PyTuple_Size(__pyx_args); if (unlikely(__pyx_nargs < 0)) return NULL; + #endif + #endif + __pyx_kwvalues = __Pyx_KwValues_FASTCALL(__pyx_args, __pyx_nargs); + { + PyObject **__pyx_pyargnames[] = {&__pyx_n_s_assignment,&__pyx_n_s_constraints_lookup,&__pyx_n_s_domains,0}; + if (__pyx_kwds) { + Py_ssize_t kw_args; + switch (__pyx_nargs) { + case 3: values[2] = __Pyx_Arg_FASTCALL(__pyx_args, 2); + CYTHON_FALLTHROUGH; + case 2: values[1] = __Pyx_Arg_FASTCALL(__pyx_args, 1); + CYTHON_FALLTHROUGH; + case 1: values[0] = __Pyx_Arg_FASTCALL(__pyx_args, 0); + CYTHON_FALLTHROUGH; + case 0: break; + default: goto __pyx_L5_argtuple_error; + } + kw_args = __Pyx_NumKwargs_FASTCALL(__pyx_kwds); + switch (__pyx_nargs) { + case 0: + if (likely((values[0] = __Pyx_GetKwValue_FASTCALL(__pyx_kwds, __pyx_kwvalues, __pyx_n_s_assignment)) != 0)) { + (void)__Pyx_Arg_NewRef_FASTCALL(values[0]); + kw_args--; } - - /* "constraint/solvers.py":675 - * del assignments[variable] - * else: - * return solutions # <<<<<<<<<<<<<< - * - * # Got a value. Check it. - */ - /*else*/ { - __Pyx_XDECREF(__pyx_r); - __Pyx_INCREF(__pyx_v_solutions); - __pyx_r = __pyx_v_solutions; - goto __pyx_L0; + else if (unlikely(PyErr_Occurred())) __PYX_ERR(0, 693, __pyx_L3_error) + else goto __pyx_L5_argtuple_error; + CYTHON_FALLTHROUGH; + case 1: + if (likely((values[1] = __Pyx_GetKwValue_FASTCALL(__pyx_kwds, __pyx_kwvalues, __pyx_n_s_constraints_lookup)) != 0)) { + (void)__Pyx_Arg_NewRef_FASTCALL(values[1]); + kw_args--; } - __pyx_L17_break:; - - /* "constraint/solvers.py":666 - * while True: - * # We have a variable. Do we have any values left? - * if not values: # <<<<<<<<<<<<<< - * # No. Go back to last variable, if there's one. - * del assignments[variable] - */ + else if (unlikely(PyErr_Occurred())) __PYX_ERR(0, 693, __pyx_L3_error) + else { + __Pyx_RaiseArgtupleInvalid("is_valid", 1, 3, 3, 1); __PYX_ERR(0, 693, __pyx_L3_error) + } + CYTHON_FALLTHROUGH; + case 2: + if (likely((values[2] = __Pyx_GetKwValue_FASTCALL(__pyx_kwds, __pyx_kwvalues, __pyx_n_s_domains)) != 0)) { + (void)__Pyx_Arg_NewRef_FASTCALL(values[2]); + kw_args--; + } + else if (unlikely(PyErr_Occurred())) __PYX_ERR(0, 693, __pyx_L3_error) + else { + __Pyx_RaiseArgtupleInvalid("is_valid", 1, 3, 3, 2); __PYX_ERR(0, 693, __pyx_L3_error) + } + } + if (unlikely(kw_args > 0)) { + const Py_ssize_t kwd_pos_args = __pyx_nargs; + if (unlikely(__Pyx_ParseOptionalKeywords(__pyx_kwds, __pyx_kwvalues, __pyx_pyargnames, 0, values + 0, kwd_pos_args, "is_valid") < 0)) __PYX_ERR(0, 693, __pyx_L3_error) } + } else if (unlikely(__pyx_nargs != 3)) { + goto __pyx_L5_argtuple_error; + } else { + values[0] = __Pyx_Arg_FASTCALL(__pyx_args, 0); + values[1] = __Pyx_Arg_FASTCALL(__pyx_args, 1); + values[2] = __Pyx_Arg_FASTCALL(__pyx_args, 2); + } + __pyx_v_assignment = ((PyObject*)values[0]); + __pyx_v_constraints_lookup = ((PyObject*)values[1]); + __pyx_v_domains = ((PyObject*)values[2]); + } + goto __pyx_L6_skip; + __pyx_L5_argtuple_error:; + __Pyx_RaiseArgtupleInvalid("is_valid", 1, 3, 3, __pyx_nargs); __PYX_ERR(0, 693, __pyx_L3_error) + __pyx_L6_skip:; + goto __pyx_L4_argument_unpacking_done; + __pyx_L3_error:; + { + Py_ssize_t __pyx_temp; + for (__pyx_temp=0; __pyx_temp < (Py_ssize_t)(sizeof(values)/sizeof(values[0])); ++__pyx_temp) { + __Pyx_Arg_XDECREF_FASTCALL(values[__pyx_temp]); + } + } + __Pyx_AddTraceback("constraint.solvers.is_valid", __pyx_clineno, __pyx_lineno, __pyx_filename); + __Pyx_RefNannyFinishContext(); + return NULL; + __pyx_L4_argument_unpacking_done:; + if (unlikely(!__Pyx_ArgTypeTest(((PyObject *)__pyx_v_assignment), (&PyDict_Type), 0, "assignment", 1))) __PYX_ERR(0, 693, __pyx_L1_error) + if (unlikely(!__Pyx_ArgTypeTest(((PyObject *)__pyx_v_constraints_lookup), (&PyList_Type), 0, "constraints_lookup", 1))) __PYX_ERR(0, 693, __pyx_L1_error) + if (unlikely(!__Pyx_ArgTypeTest(((PyObject *)__pyx_v_domains), (&PyDict_Type), 0, "domains", 1))) __PYX_ERR(0, 693, __pyx_L1_error) + __pyx_r = __pyx_pf_10constraint_7solvers_4is_valid(__pyx_self, __pyx_v_assignment, __pyx_v_constraints_lookup, __pyx_v_domains); + + /* function exit code */ + goto __pyx_L0; + __pyx_L1_error:; + __pyx_r = NULL; + __pyx_L0:; + { + Py_ssize_t __pyx_temp; + for (__pyx_temp=0; __pyx_temp < (Py_ssize_t)(sizeof(values)/sizeof(values[0])); ++__pyx_temp) { + __Pyx_Arg_XDECREF_FASTCALL(values[__pyx_temp]); + } + } + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} +static PyObject *__pyx_gb_10constraint_7solvers_8is_valid_2generator3(__pyx_CoroutineObject *__pyx_generator, CYTHON_UNUSED PyThreadState *__pyx_tstate, PyObject *__pyx_sent_value); /* proto */ +static PyObject *__pyx_gb_10constraint_7solvers_8is_valid_7genexpr_2generator4(__pyx_CoroutineObject *__pyx_generator, CYTHON_UNUSED PyThreadState *__pyx_tstate, PyObject *__pyx_sent_value); /* proto */ - /* "constraint/solvers.py":678 +/* "constraint/solvers.py":698 + * constraint(vars_involved, domains, assignment, None) + * for constraint, vars_involved in constraints_lookup + * if all(v in assignment for v in vars_involved) # <<<<<<<<<<<<<< + * ) * - * # Got a value. Check it. - * assignments[variable] = values.pop() # <<<<<<<<<<<<<< - * for constraint, variables in constraint_lookup[variable]: - * if not constraint(variables, domains, assignments, None): */ - __pyx_t_1 = __Pyx_PyObject_Pop(__pyx_v_values); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 678, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_1); - if (unlikely((PyDict_SetItem(__pyx_v_assignments, __pyx_v_variable, __pyx_t_1) < 0))) __PYX_ERR(0, 678, __pyx_L1_error) - __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; - /* "constraint/solvers.py":679 - * # Got a value. Check it. - * assignments[variable] = values.pop() - * for constraint, variables in constraint_lookup[variable]: # <<<<<<<<<<<<<< - * if not constraint(variables, domains, assignments, None): - * # Value is not good. - */ - __pyx_t_1 = __Pyx_PyDict_GetItem(__pyx_v_constraint_lookup, __pyx_v_variable); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 679, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_1); - if (likely(PyList_CheckExact(__pyx_t_1)) || PyTuple_CheckExact(__pyx_t_1)) { - __pyx_t_5 = __pyx_t_1; __Pyx_INCREF(__pyx_t_5); - __pyx_t_2 = 0; - __pyx_t_10 = NULL; - } else { - __pyx_t_2 = -1; __pyx_t_5 = PyObject_GetIter(__pyx_t_1); if (unlikely(!__pyx_t_5)) __PYX_ERR(0, 679, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_5); - __pyx_t_10 = __Pyx_PyObject_GetIterNextFunc(__pyx_t_5); if (unlikely(!__pyx_t_10)) __PYX_ERR(0, 679, __pyx_L1_error) - } - __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; - for (;;) { - if (likely(!__pyx_t_10)) { - if (likely(PyList_CheckExact(__pyx_t_5))) { - { - Py_ssize_t __pyx_temp = __Pyx_PyList_GET_SIZE(__pyx_t_5); - #if !CYTHON_ASSUME_SAFE_MACROS - if (unlikely((__pyx_temp < 0))) __PYX_ERR(0, 679, __pyx_L1_error) - #endif - if (__pyx_t_2 >= __pyx_temp) break; - } - #if CYTHON_ASSUME_SAFE_MACROS && !CYTHON_AVOID_BORROWED_REFS - __pyx_t_1 = PyList_GET_ITEM(__pyx_t_5, __pyx_t_2); __Pyx_INCREF(__pyx_t_1); __pyx_t_2++; if (unlikely((0 < 0))) __PYX_ERR(0, 679, __pyx_L1_error) - #else - __pyx_t_1 = __Pyx_PySequence_ITEM(__pyx_t_5, __pyx_t_2); __pyx_t_2++; if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 679, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_1); - #endif - } else { - { - Py_ssize_t __pyx_temp = __Pyx_PyTuple_GET_SIZE(__pyx_t_5); - #if !CYTHON_ASSUME_SAFE_MACROS - if (unlikely((__pyx_temp < 0))) __PYX_ERR(0, 679, __pyx_L1_error) - #endif - if (__pyx_t_2 >= __pyx_temp) break; - } - #if CYTHON_ASSUME_SAFE_MACROS && !CYTHON_AVOID_BORROWED_REFS - __pyx_t_1 = PyTuple_GET_ITEM(__pyx_t_5, __pyx_t_2); __Pyx_INCREF(__pyx_t_1); __pyx_t_2++; if (unlikely((0 < 0))) __PYX_ERR(0, 679, __pyx_L1_error) - #else - __pyx_t_1 = __Pyx_PySequence_ITEM(__pyx_t_5, __pyx_t_2); __pyx_t_2++; if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 679, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_1); - #endif - } - } else { - __pyx_t_1 = __pyx_t_10(__pyx_t_5); - if (unlikely(!__pyx_t_1)) { - PyObject* exc_type = PyErr_Occurred(); - if (exc_type) { - if (likely(__Pyx_PyErr_GivenExceptionMatches(exc_type, PyExc_StopIteration))) PyErr_Clear(); - else __PYX_ERR(0, 679, __pyx_L1_error) - } - break; - } - __Pyx_GOTREF(__pyx_t_1); - } - if ((likely(PyTuple_CheckExact(__pyx_t_1))) || (PyList_CheckExact(__pyx_t_1))) { - PyObject* sequence = __pyx_t_1; - Py_ssize_t size = __Pyx_PySequence_SIZE(sequence); - if (unlikely(size != 2)) { - if (size > 2) __Pyx_RaiseTooManyValuesError(2); - else if (size >= 0) __Pyx_RaiseNeedMoreValuesError(size); - __PYX_ERR(0, 679, __pyx_L1_error) - } - #if CYTHON_ASSUME_SAFE_MACROS && !CYTHON_AVOID_BORROWED_REFS - if (likely(PyTuple_CheckExact(sequence))) { - __pyx_t_3 = PyTuple_GET_ITEM(sequence, 0); - __pyx_t_8 = PyTuple_GET_ITEM(sequence, 1); - } else { - __pyx_t_3 = PyList_GET_ITEM(sequence, 0); - __pyx_t_8 = PyList_GET_ITEM(sequence, 1); - } - __Pyx_INCREF(__pyx_t_3); - __Pyx_INCREF(__pyx_t_8); - #else - __pyx_t_3 = PySequence_ITEM(sequence, 0); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 679, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_3); - __pyx_t_8 = PySequence_ITEM(sequence, 1); if (unlikely(!__pyx_t_8)) __PYX_ERR(0, 679, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_8); - #endif - __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; - } else { - Py_ssize_t index = -1; - __pyx_t_11 = PyObject_GetIter(__pyx_t_1); if (unlikely(!__pyx_t_11)) __PYX_ERR(0, 679, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_11); - __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; - __pyx_t_9 = __Pyx_PyObject_GetIterNextFunc(__pyx_t_11); - index = 0; __pyx_t_3 = __pyx_t_9(__pyx_t_11); if (unlikely(!__pyx_t_3)) goto __pyx_L23_unpacking_failed; - __Pyx_GOTREF(__pyx_t_3); - index = 1; __pyx_t_8 = __pyx_t_9(__pyx_t_11); if (unlikely(!__pyx_t_8)) goto __pyx_L23_unpacking_failed; - __Pyx_GOTREF(__pyx_t_8); - if (__Pyx_IternextUnpackEndCheck(__pyx_t_9(__pyx_t_11), 2) < 0) __PYX_ERR(0, 679, __pyx_L1_error) - __pyx_t_9 = NULL; - __Pyx_DECREF(__pyx_t_11); __pyx_t_11 = 0; - goto __pyx_L24_unpacking_done; - __pyx_L23_unpacking_failed:; - __Pyx_DECREF(__pyx_t_11); __pyx_t_11 = 0; - __pyx_t_9 = NULL; - if (__Pyx_IterFinish() == 0) __Pyx_RaiseNeedMoreValuesError(index); - __PYX_ERR(0, 679, __pyx_L1_error) - __pyx_L24_unpacking_done:; - } - __Pyx_XDECREF_SET(__pyx_v_constraint, __pyx_t_3); - __pyx_t_3 = 0; - __Pyx_XDECREF_SET(__pyx_v_variables, __pyx_t_8); - __pyx_t_8 = 0; - - /* "constraint/solvers.py":680 - * assignments[variable] = values.pop() - * for constraint, variables in constraint_lookup[variable]: - * if not constraint(variables, domains, assignments, None): # <<<<<<<<<<<<<< - * # Value is not good. - * break - */ - __Pyx_INCREF(__pyx_v_constraint); - __pyx_t_8 = __pyx_v_constraint; __pyx_t_3 = NULL; - __pyx_t_12 = 0; - #if CYTHON_UNPACK_METHODS - if (unlikely(PyMethod_Check(__pyx_t_8))) { - __pyx_t_3 = PyMethod_GET_SELF(__pyx_t_8); - if (likely(__pyx_t_3)) { - PyObject* function = PyMethod_GET_FUNCTION(__pyx_t_8); - __Pyx_INCREF(__pyx_t_3); - __Pyx_INCREF(function); - __Pyx_DECREF_SET(__pyx_t_8, function); - __pyx_t_12 = 1; - } - } - #endif - { - PyObject *__pyx_callargs[5] = {__pyx_t_3, __pyx_v_variables, __pyx_v_domains, __pyx_v_assignments, Py_None}; - __pyx_t_1 = __Pyx_PyObject_FastCall(__pyx_t_8, __pyx_callargs+1-__pyx_t_12, 4+__pyx_t_12); - __Pyx_XDECREF(__pyx_t_3); __pyx_t_3 = 0; - if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 680, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_1); - __Pyx_DECREF(__pyx_t_8); __pyx_t_8 = 0; - } - __pyx_t_4 = __Pyx_PyObject_IsTrue(__pyx_t_1); if (unlikely((__pyx_t_4 < 0))) __PYX_ERR(0, 680, __pyx_L1_error) - __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; - __pyx_t_7 = (!__pyx_t_4); - if (__pyx_t_7) { - - /* "constraint/solvers.py":682 - * if not constraint(variables, domains, assignments, None): - * # Value is not good. - * break # <<<<<<<<<<<<<< - * else: - * break - */ - goto __pyx_L22_break; - - /* "constraint/solvers.py":680 - * assignments[variable] = values.pop() - * for constraint, variables in constraint_lookup[variable]: - * if not constraint(variables, domains, assignments, None): # <<<<<<<<<<<<<< - * # Value is not good. - * break - */ - } - - /* "constraint/solvers.py":679 - * # Got a value. Check it. - * assignments[variable] = values.pop() - * for constraint, variables in constraint_lookup[variable]: # <<<<<<<<<<<<<< - * if not constraint(variables, domains, assignments, None): - * # Value is not good. - */ - } - __Pyx_DECREF(__pyx_t_5); __pyx_t_5 = 0; - goto __pyx_L26_for_else; - __pyx_L22_break:; - __Pyx_DECREF(__pyx_t_5); __pyx_t_5 = 0; - goto __pyx_L27_for_end; - /*else*/ { - __pyx_L26_for_else:; - - /* "constraint/solvers.py":684 - * break - * else: - * break # <<<<<<<<<<<<<< - * - * # Push state before looking for next variable. - */ - goto __pyx_L14_break; - } - __pyx_L27_for_end:; - } - __pyx_L14_break:; - - /* "constraint/solvers.py":687 - * - * # Push state before looking for next variable. - * queue.append((variable, values)) # <<<<<<<<<<<<<< - * - * - */ - __pyx_t_5 = PyTuple_New(2); if (unlikely(!__pyx_t_5)) __PYX_ERR(0, 687, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_5); - __Pyx_INCREF(__pyx_v_variable); - __Pyx_GIVEREF(__pyx_v_variable); - if (__Pyx_PyTuple_SET_ITEM(__pyx_t_5, 0, __pyx_v_variable)) __PYX_ERR(0, 687, __pyx_L1_error); - __Pyx_INCREF(__pyx_v_values); - __Pyx_GIVEREF(__pyx_v_values); - if (__Pyx_PyTuple_SET_ITEM(__pyx_t_5, 1, __pyx_v_values)) __PYX_ERR(0, 687, __pyx_L1_error); - __pyx_t_6 = __Pyx_PyList_Append(__pyx_v_queue, __pyx_t_5); if (unlikely(__pyx_t_6 == ((int)-1))) __PYX_ERR(0, 687, __pyx_L1_error) - __Pyx_DECREF(__pyx_t_5); __pyx_t_5 = 0; +static PyObject *__pyx_pf_10constraint_7solvers_8is_valid_7genexpr_genexpr(PyObject *__pyx_self, PyObject *__pyx_genexpr_arg_0) { + struct __pyx_obj_10constraint_7solvers___pyx_scope_struct_6_genexpr *__pyx_cur_scope; + PyObject *__pyx_r = NULL; + __Pyx_RefNannyDeclarations + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + __Pyx_RefNannySetupContext("genexpr", 0); + __pyx_cur_scope = (struct __pyx_obj_10constraint_7solvers___pyx_scope_struct_6_genexpr *)__pyx_tp_new_10constraint_7solvers___pyx_scope_struct_6_genexpr(__pyx_ptype_10constraint_7solvers___pyx_scope_struct_6_genexpr, __pyx_empty_tuple, NULL); + if (unlikely(!__pyx_cur_scope)) { + __pyx_cur_scope = ((struct __pyx_obj_10constraint_7solvers___pyx_scope_struct_6_genexpr *)Py_None); + __Pyx_INCREF(Py_None); + __PYX_ERR(0, 698, __pyx_L1_error) + } else { + __Pyx_GOTREF((PyObject *)__pyx_cur_scope); + } + __pyx_cur_scope->__pyx_outer_scope = (struct __pyx_obj_10constraint_7solvers___pyx_scope_struct_5_genexpr *) __pyx_self; + __Pyx_INCREF((PyObject *)__pyx_cur_scope->__pyx_outer_scope); + __Pyx_GIVEREF((PyObject *)__pyx_cur_scope->__pyx_outer_scope); + __pyx_cur_scope->__pyx_genexpr_arg_0 = __pyx_genexpr_arg_0; + __Pyx_INCREF(__pyx_cur_scope->__pyx_genexpr_arg_0); + __Pyx_GIVEREF(__pyx_cur_scope->__pyx_genexpr_arg_0); + { + __pyx_CoroutineObject *gen = __Pyx_Generator_New((__pyx_coroutine_body_t) __pyx_gb_10constraint_7solvers_8is_valid_7genexpr_2generator4, NULL, (PyObject *) __pyx_cur_scope, __pyx_n_s_genexpr, __pyx_n_s_is_valid_locals_genexpr_locals_g, __pyx_n_s_constraint_solvers); if (unlikely(!gen)) __PYX_ERR(0, 698, __pyx_L1_error) + __Pyx_DECREF(__pyx_cur_scope); + __Pyx_RefNannyFinishContext(); + return (PyObject *) gen; } - - /* "constraint/solvers.py":640 - * return solutions - * - * def sequential_optimized_backtrack(assignment: dict[Hashable, any], unassigned_vars: list[Hashable], domains: dict[Hashable, Domain], constraint_lookup: dict[Hashable, list[tuple[Constraint, Hashable]]]) -> list[dict[Hashable, any]]: # noqa E501 # <<<<<<<<<<<<<< - * """Sequential optimized backtracking (as in OptimizedBacktrackingSolver) function for subproblems.""" - * # Does not do forwardcheck for simplicity - */ /* function exit code */ - __pyx_r = ((PyObject*)Py_None); __Pyx_INCREF(Py_None); - goto __pyx_L0; __pyx_L1_error:; - __Pyx_XDECREF(__pyx_t_1); - __Pyx_XDECREF(__pyx_t_3); - __Pyx_XDECREF(__pyx_t_5); - __Pyx_XDECREF(__pyx_t_8); - __Pyx_XDECREF(__pyx_t_11); - __Pyx_AddTraceback("constraint.solvers.sequential_optimized_backtrack", __pyx_clineno, __pyx_lineno, __pyx_filename); + __Pyx_AddTraceback("constraint.solvers.is_valid.genexpr.genexpr", __pyx_clineno, __pyx_lineno, __pyx_filename); __pyx_r = NULL; - __pyx_L0:; - __Pyx_XDECREF(__pyx_v_assignments); - __Pyx_XDECREF(__pyx_v_sorted_variables); - __Pyx_XDECREF(__pyx_v_queue); - __Pyx_XDECREF(__pyx_v_solutions); - __Pyx_XDECREF(__pyx_v_variable); - __Pyx_XDECREF(__pyx_v_values); - __Pyx_XDECREF(__pyx_v_constraint); - __Pyx_XDECREF(__pyx_v_variables); + __Pyx_DECREF((PyObject *)__pyx_cur_scope); __Pyx_XGIVEREF(__pyx_r); __Pyx_RefNannyFinishContext(); return __pyx_r; } -/* "constraint/solvers.py":690 - * - * - * def parallel_worker(args: tuple[bool, dict[Hashable, Domain], dict[Hashable, list[tuple[Constraint, Hashable]]], Hashable, any, list[Hashable]]) -> list[dict[Hashable, any]]: # noqa E501 # <<<<<<<<<<<<<< - * """Worker function for parallel execution on first variable.""" - * process_mode, domains, constraint_lookup, first_var, first_value, remaining_vars = args - */ - -/* Python wrapper */ -static PyObject *__pyx_pw_10constraint_7solvers_13parallel_worker(PyObject *__pyx_self, -#if CYTHON_METH_FASTCALL -PyObject *const *__pyx_args, Py_ssize_t __pyx_nargs, PyObject *__pyx_kwds -#else -PyObject *__pyx_args, PyObject *__pyx_kwds -#endif -); /*proto*/ -PyDoc_STRVAR(__pyx_doc_10constraint_7solvers_12parallel_worker, "Worker function for parallel execution on first variable."); -static PyMethodDef __pyx_mdef_10constraint_7solvers_13parallel_worker = {"parallel_worker", (PyCFunction)(void*)(__Pyx_PyCFunction_FastCallWithKeywords)__pyx_pw_10constraint_7solvers_13parallel_worker, __Pyx_METH_FASTCALL|METH_KEYWORDS, __pyx_doc_10constraint_7solvers_12parallel_worker}; -static PyObject *__pyx_pw_10constraint_7solvers_13parallel_worker(PyObject *__pyx_self, -#if CYTHON_METH_FASTCALL -PyObject *const *__pyx_args, Py_ssize_t __pyx_nargs, PyObject *__pyx_kwds -#else -PyObject *__pyx_args, PyObject *__pyx_kwds -#endif -) { - PyObject *__pyx_v_args = 0; - #if !CYTHON_METH_FASTCALL - CYTHON_UNUSED Py_ssize_t __pyx_nargs; - #endif - CYTHON_UNUSED PyObject *const *__pyx_kwvalues; - PyObject* values[1] = {0}; +static PyObject *__pyx_gb_10constraint_7solvers_8is_valid_7genexpr_2generator4(__pyx_CoroutineObject *__pyx_generator, CYTHON_UNUSED PyThreadState *__pyx_tstate, PyObject *__pyx_sent_value) /* generator body */ +{ + struct __pyx_obj_10constraint_7solvers___pyx_scope_struct_6_genexpr *__pyx_cur_scope = ((struct __pyx_obj_10constraint_7solvers___pyx_scope_struct_6_genexpr *)__pyx_generator->closure); + PyObject *__pyx_r = NULL; + PyObject *__pyx_t_1 = NULL; + Py_ssize_t __pyx_t_2; + PyObject *(*__pyx_t_3)(PyObject *); + PyObject *__pyx_t_4 = NULL; + int __pyx_t_5; + int __pyx_t_6; int __pyx_lineno = 0; const char *__pyx_filename = NULL; int __pyx_clineno = 0; - PyObject *__pyx_r = 0; __Pyx_RefNannyDeclarations - __Pyx_RefNannySetupContext("parallel_worker (wrapper)", 0); - #if !CYTHON_METH_FASTCALL - #if CYTHON_ASSUME_SAFE_MACROS - __pyx_nargs = PyTuple_GET_SIZE(__pyx_args); - #else - __pyx_nargs = PyTuple_Size(__pyx_args); if (unlikely(__pyx_nargs < 0)) return NULL; - #endif - #endif - __pyx_kwvalues = __Pyx_KwValues_FASTCALL(__pyx_args, __pyx_nargs); - { - PyObject **__pyx_pyargnames[] = {&__pyx_n_s_args,0}; - if (__pyx_kwds) { - Py_ssize_t kw_args; - switch (__pyx_nargs) { - case 1: values[0] = __Pyx_Arg_FASTCALL(__pyx_args, 0); - CYTHON_FALLTHROUGH; - case 0: break; - default: goto __pyx_L5_argtuple_error; - } - kw_args = __Pyx_NumKwargs_FASTCALL(__pyx_kwds); - switch (__pyx_nargs) { - case 0: - if (likely((values[0] = __Pyx_GetKwValue_FASTCALL(__pyx_kwds, __pyx_kwvalues, __pyx_n_s_args)) != 0)) { - (void)__Pyx_Arg_NewRef_FASTCALL(values[0]); - kw_args--; + __Pyx_RefNannySetupContext("genexpr", 0); + switch (__pyx_generator->resume_label) { + case 0: goto __pyx_L3_first_run; + default: /* CPython raises the right error here */ + __Pyx_RefNannyFinishContext(); + return NULL; + } + __pyx_L3_first_run:; + if (unlikely(!__pyx_sent_value)) __PYX_ERR(0, 698, __pyx_L1_error) + if (unlikely(!__pyx_cur_scope->__pyx_genexpr_arg_0)) { __Pyx_RaiseUnboundLocalError(".0"); __PYX_ERR(0, 698, __pyx_L1_error) } + if (likely(PyList_CheckExact(__pyx_cur_scope->__pyx_genexpr_arg_0)) || PyTuple_CheckExact(__pyx_cur_scope->__pyx_genexpr_arg_0)) { + __pyx_t_1 = __pyx_cur_scope->__pyx_genexpr_arg_0; __Pyx_INCREF(__pyx_t_1); + __pyx_t_2 = 0; + __pyx_t_3 = NULL; + } else { + __pyx_t_2 = -1; __pyx_t_1 = PyObject_GetIter(__pyx_cur_scope->__pyx_genexpr_arg_0); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 698, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __pyx_t_3 = __Pyx_PyObject_GetIterNextFunc(__pyx_t_1); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 698, __pyx_L1_error) + } + for (;;) { + if (likely(!__pyx_t_3)) { + if (likely(PyList_CheckExact(__pyx_t_1))) { + { + Py_ssize_t __pyx_temp = __Pyx_PyList_GET_SIZE(__pyx_t_1); + #if !CYTHON_ASSUME_SAFE_MACROS + if (unlikely((__pyx_temp < 0))) __PYX_ERR(0, 698, __pyx_L1_error) + #endif + if (__pyx_t_2 >= __pyx_temp) break; } - else if (unlikely(PyErr_Occurred())) __PYX_ERR(0, 690, __pyx_L3_error) - else goto __pyx_L5_argtuple_error; - } - if (unlikely(kw_args > 0)) { - const Py_ssize_t kwd_pos_args = __pyx_nargs; - if (unlikely(__Pyx_ParseOptionalKeywords(__pyx_kwds, __pyx_kwvalues, __pyx_pyargnames, 0, values + 0, kwd_pos_args, "parallel_worker") < 0)) __PYX_ERR(0, 690, __pyx_L3_error) + #if CYTHON_ASSUME_SAFE_MACROS && !CYTHON_AVOID_BORROWED_REFS + __pyx_t_4 = PyList_GET_ITEM(__pyx_t_1, __pyx_t_2); __Pyx_INCREF(__pyx_t_4); __pyx_t_2++; if (unlikely((0 < 0))) __PYX_ERR(0, 698, __pyx_L1_error) + #else + __pyx_t_4 = __Pyx_PySequence_ITEM(__pyx_t_1, __pyx_t_2); __pyx_t_2++; if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 698, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_4); + #endif + } else { + { + Py_ssize_t __pyx_temp = __Pyx_PyTuple_GET_SIZE(__pyx_t_1); + #if !CYTHON_ASSUME_SAFE_MACROS + if (unlikely((__pyx_temp < 0))) __PYX_ERR(0, 698, __pyx_L1_error) + #endif + if (__pyx_t_2 >= __pyx_temp) break; + } + #if CYTHON_ASSUME_SAFE_MACROS && !CYTHON_AVOID_BORROWED_REFS + __pyx_t_4 = PyTuple_GET_ITEM(__pyx_t_1, __pyx_t_2); __Pyx_INCREF(__pyx_t_4); __pyx_t_2++; if (unlikely((0 < 0))) __PYX_ERR(0, 698, __pyx_L1_error) + #else + __pyx_t_4 = __Pyx_PySequence_ITEM(__pyx_t_1, __pyx_t_2); __pyx_t_2++; if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 698, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_4); + #endif } - } else if (unlikely(__pyx_nargs != 1)) { - goto __pyx_L5_argtuple_error; } else { - values[0] = __Pyx_Arg_FASTCALL(__pyx_args, 0); + __pyx_t_4 = __pyx_t_3(__pyx_t_1); + if (unlikely(!__pyx_t_4)) { + PyObject* exc_type = PyErr_Occurred(); + if (exc_type) { + if (likely(__Pyx_PyErr_GivenExceptionMatches(exc_type, PyExc_StopIteration))) PyErr_Clear(); + else __PYX_ERR(0, 698, __pyx_L1_error) + } + break; + } + __Pyx_GOTREF(__pyx_t_4); } - __pyx_v_args = ((PyObject*)values[0]); - } - goto __pyx_L6_skip; - __pyx_L5_argtuple_error:; - __Pyx_RaiseArgtupleInvalid("parallel_worker", 1, 1, 1, __pyx_nargs); __PYX_ERR(0, 690, __pyx_L3_error) - __pyx_L6_skip:; - goto __pyx_L4_argument_unpacking_done; - __pyx_L3_error:; - { - Py_ssize_t __pyx_temp; - for (__pyx_temp=0; __pyx_temp < (Py_ssize_t)(sizeof(values)/sizeof(values[0])); ++__pyx_temp) { - __Pyx_Arg_XDECREF_FASTCALL(values[__pyx_temp]); + __Pyx_XGOTREF(__pyx_cur_scope->__pyx_v_v); + __Pyx_XDECREF_SET(__pyx_cur_scope->__pyx_v_v, __pyx_t_4); + __Pyx_GIVEREF(__pyx_t_4); + __pyx_t_4 = 0; + if (unlikely(!__pyx_cur_scope->__pyx_outer_scope->__pyx_outer_scope->__pyx_v_assignment)) { __Pyx_RaiseClosureNameError("assignment"); __PYX_ERR(0, 698, __pyx_L1_error) } + if (unlikely(__pyx_cur_scope->__pyx_outer_scope->__pyx_outer_scope->__pyx_v_assignment == Py_None)) { + PyErr_SetString(PyExc_TypeError, "'NoneType' object is not iterable"); + __PYX_ERR(0, 698, __pyx_L1_error) + } + __pyx_t_5 = (__Pyx_PyDict_ContainsTF(__pyx_cur_scope->__pyx_v_v, __pyx_cur_scope->__pyx_outer_scope->__pyx_outer_scope->__pyx_v_assignment, Py_EQ)); if (unlikely((__pyx_t_5 < 0))) __PYX_ERR(0, 698, __pyx_L1_error) + __pyx_t_6 = (!__pyx_t_5); + if (__pyx_t_6) { + __Pyx_XDECREF(__pyx_r); + __Pyx_INCREF(Py_False); + __pyx_r = Py_False; + __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; + goto __pyx_L0; } } - __Pyx_AddTraceback("constraint.solvers.parallel_worker", __pyx_clineno, __pyx_lineno, __pyx_filename); - __Pyx_RefNannyFinishContext(); - return NULL; - __pyx_L4_argument_unpacking_done:; - if (unlikely(!__Pyx_ArgTypeTest(((PyObject *)__pyx_v_args), (&PyTuple_Type), 0, "args", 1))) __PYX_ERR(0, 690, __pyx_L1_error) - __pyx_r = __pyx_pf_10constraint_7solvers_12parallel_worker(__pyx_self, __pyx_v_args); + __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; + /*else*/ { + __Pyx_XDECREF(__pyx_r); + __Pyx_INCREF(Py_True); + __pyx_r = Py_True; + goto __pyx_L0; + } + CYTHON_MAYBE_UNUSED_VAR(__pyx_cur_scope); /* function exit code */ goto __pyx_L0; __pyx_L1_error:; - __pyx_r = NULL; + __Pyx_Generator_Replace_StopIteration(0); + __Pyx_XDECREF(__pyx_t_1); + __Pyx_XDECREF(__pyx_t_4); + __Pyx_AddTraceback("genexpr", __pyx_clineno, __pyx_lineno, __pyx_filename); __pyx_L0:; + __Pyx_XGIVEREF(__pyx_r); + #if !CYTHON_USE_EXC_INFO_STACK + __Pyx_Coroutine_ResetAndClearException(__pyx_generator); + #endif + __pyx_generator->resume_label = -1; + __Pyx_Coroutine_clear((PyObject*)__pyx_generator); + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +/* "constraint/solvers.py":696 + * """Check if all constraints are satisfied given the current assignment.""" + * return all( + * constraint(vars_involved, domains, assignment, None) # <<<<<<<<<<<<<< + * for constraint, vars_involved in constraints_lookup + * if all(v in assignment for v in vars_involved) + */ + +static PyObject *__pyx_pf_10constraint_7solvers_8is_valid_genexpr(PyObject *__pyx_self, PyObject *__pyx_genexpr_arg_0) { + struct __pyx_obj_10constraint_7solvers___pyx_scope_struct_5_genexpr *__pyx_cur_scope; + PyObject *__pyx_gb_10constraint_7solvers_8is_valid_7genexpr_2generator4 = 0; + PyObject *__pyx_r = NULL; + __Pyx_RefNannyDeclarations + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + __Pyx_RefNannySetupContext("genexpr", 0); + __pyx_cur_scope = (struct __pyx_obj_10constraint_7solvers___pyx_scope_struct_5_genexpr *)__pyx_tp_new_10constraint_7solvers___pyx_scope_struct_5_genexpr(__pyx_ptype_10constraint_7solvers___pyx_scope_struct_5_genexpr, __pyx_empty_tuple, NULL); + if (unlikely(!__pyx_cur_scope)) { + __pyx_cur_scope = ((struct __pyx_obj_10constraint_7solvers___pyx_scope_struct_5_genexpr *)Py_None); + __Pyx_INCREF(Py_None); + __PYX_ERR(0, 696, __pyx_L1_error) + } else { + __Pyx_GOTREF((PyObject *)__pyx_cur_scope); + } + __pyx_cur_scope->__pyx_outer_scope = (struct __pyx_obj_10constraint_7solvers___pyx_scope_struct_4_is_valid *) __pyx_self; + __Pyx_INCREF((PyObject *)__pyx_cur_scope->__pyx_outer_scope); + __Pyx_GIVEREF((PyObject *)__pyx_cur_scope->__pyx_outer_scope); + __pyx_cur_scope->__pyx_genexpr_arg_0 = __pyx_genexpr_arg_0; + __Pyx_INCREF(__pyx_cur_scope->__pyx_genexpr_arg_0); + __Pyx_GIVEREF(__pyx_cur_scope->__pyx_genexpr_arg_0); { - Py_ssize_t __pyx_temp; - for (__pyx_temp=0; __pyx_temp < (Py_ssize_t)(sizeof(values)/sizeof(values[0])); ++__pyx_temp) { - __Pyx_Arg_XDECREF_FASTCALL(values[__pyx_temp]); - } + __pyx_CoroutineObject *gen = __Pyx_Generator_New((__pyx_coroutine_body_t) __pyx_gb_10constraint_7solvers_8is_valid_2generator3, NULL, (PyObject *) __pyx_cur_scope, __pyx_n_s_genexpr, __pyx_n_s_is_valid_locals_genexpr, __pyx_n_s_constraint_solvers); if (unlikely(!gen)) __PYX_ERR(0, 696, __pyx_L1_error) + __Pyx_DECREF(__pyx_cur_scope); + __Pyx_RefNannyFinishContext(); + return (PyObject *) gen; } + + /* function exit code */ + __pyx_L1_error:; + __Pyx_AddTraceback("constraint.solvers.is_valid.genexpr", __pyx_clineno, __pyx_lineno, __pyx_filename); + __pyx_r = NULL; + __Pyx_XDECREF(__pyx_gb_10constraint_7solvers_8is_valid_7genexpr_2generator4); + __Pyx_DECREF((PyObject *)__pyx_cur_scope); + __Pyx_XGIVEREF(__pyx_r); __Pyx_RefNannyFinishContext(); return __pyx_r; } -static PyObject *__pyx_pf_10constraint_7solvers_12parallel_worker(CYTHON_UNUSED PyObject *__pyx_self, PyObject *__pyx_v_args) { - PyObject *__pyx_v_process_mode = NULL; - PyObject *__pyx_v_domains = NULL; - PyObject *__pyx_v_constraint_lookup = NULL; - PyObject *__pyx_v_first_var = NULL; - PyObject *__pyx_v_first_value = NULL; - PyObject *__pyx_v_remaining_vars = NULL; - PyObject *__pyx_v_local_assignment = NULL; - PyObject *__pyx_v_var = NULL; - PyObject *__pyx_v_constraints = NULL; - PyObject *__pyx_8genexpr9__pyx_v_constraint = NULL; - PyObject *__pyx_8genexpr9__pyx_v_vals = NULL; +static PyObject *__pyx_gb_10constraint_7solvers_8is_valid_2generator3(__pyx_CoroutineObject *__pyx_generator, CYTHON_UNUSED PyThreadState *__pyx_tstate, PyObject *__pyx_sent_value) /* generator body */ +{ + struct __pyx_obj_10constraint_7solvers___pyx_scope_struct_5_genexpr *__pyx_cur_scope = ((struct __pyx_obj_10constraint_7solvers___pyx_scope_struct_5_genexpr *)__pyx_generator->closure); PyObject *__pyx_r = NULL; - __Pyx_RefNannyDeclarations PyObject *__pyx_t_1 = NULL; - PyObject *__pyx_t_2 = NULL; + Py_ssize_t __pyx_t_2; PyObject *__pyx_t_3 = NULL; PyObject *__pyx_t_4 = NULL; PyObject *__pyx_t_5 = NULL; PyObject *__pyx_t_6 = NULL; - int __pyx_t_7; - Py_ssize_t __pyx_t_8; - Py_ssize_t __pyx_t_9; + PyObject *(*__pyx_t_7)(PyObject *); + int __pyx_t_8; + unsigned int __pyx_t_9; int __pyx_t_10; - int __pyx_t_11; - Py_ssize_t __pyx_t_12; - PyObject *(*__pyx_t_13)(PyObject *); - PyObject *__pyx_t_14 = NULL; - PyObject *(*__pyx_t_15)(PyObject *); - unsigned int __pyx_t_16; int __pyx_lineno = 0; const char *__pyx_filename = NULL; int __pyx_clineno = 0; - __Pyx_RefNannySetupContext("parallel_worker", 1); + __Pyx_RefNannyDeclarations + __Pyx_RefNannySetupContext("genexpr", 0); + switch (__pyx_generator->resume_label) { + case 0: goto __pyx_L3_first_run; + default: /* CPython raises the right error here */ + __Pyx_RefNannyFinishContext(); + return NULL; + } + __pyx_L3_first_run:; + if (unlikely(!__pyx_sent_value)) __PYX_ERR(0, 696, __pyx_L1_error) - /* "constraint/solvers.py":692 - * def parallel_worker(args: tuple[bool, dict[Hashable, Domain], dict[Hashable, list[tuple[Constraint, Hashable]]], Hashable, any, list[Hashable]]) -> list[dict[Hashable, any]]: # noqa E501 - * """Worker function for parallel execution on first variable.""" - * process_mode, domains, constraint_lookup, first_var, first_value, remaining_vars = args # <<<<<<<<<<<<<< - * local_assignment = {first_var: first_value} - * + /* "constraint/solvers.py":697 + * return all( + * constraint(vars_involved, domains, assignment, None) + * for constraint, vars_involved in constraints_lookup # <<<<<<<<<<<<<< + * if all(v in assignment for v in vars_involved) + * ) */ - if (1) { - PyObject* sequence = __pyx_v_args; - Py_ssize_t size = __Pyx_PySequence_SIZE(sequence); - if (unlikely(size != 6)) { - if (size > 6) __Pyx_RaiseTooManyValuesError(6); - else if (size >= 0) __Pyx_RaiseNeedMoreValuesError(size); - __PYX_ERR(0, 692, __pyx_L1_error) + if (unlikely(!__pyx_cur_scope->__pyx_genexpr_arg_0)) { __Pyx_RaiseUnboundLocalError(".0"); __PYX_ERR(0, 697, __pyx_L1_error) } + __pyx_t_1 = __pyx_cur_scope->__pyx_genexpr_arg_0; __Pyx_INCREF(__pyx_t_1); + __pyx_t_2 = 0; + for (;;) { + { + Py_ssize_t __pyx_temp = __Pyx_PyList_GET_SIZE(__pyx_t_1); + #if !CYTHON_ASSUME_SAFE_MACROS + if (unlikely((__pyx_temp < 0))) __PYX_ERR(0, 697, __pyx_L1_error) + #endif + if (__pyx_t_2 >= __pyx_temp) break; } #if CYTHON_ASSUME_SAFE_MACROS && !CYTHON_AVOID_BORROWED_REFS - __pyx_t_1 = PyTuple_GET_ITEM(sequence, 0); - __pyx_t_2 = PyTuple_GET_ITEM(sequence, 1); - __pyx_t_3 = PyTuple_GET_ITEM(sequence, 2); - __pyx_t_4 = PyTuple_GET_ITEM(sequence, 3); - __pyx_t_5 = PyTuple_GET_ITEM(sequence, 4); - __pyx_t_6 = PyTuple_GET_ITEM(sequence, 5); - __Pyx_INCREF(__pyx_t_1); - __Pyx_INCREF(__pyx_t_2); - __Pyx_INCREF(__pyx_t_3); - __Pyx_INCREF(__pyx_t_4); - __Pyx_INCREF(__pyx_t_5); - __Pyx_INCREF(__pyx_t_6); + __pyx_t_3 = PyList_GET_ITEM(__pyx_t_1, __pyx_t_2); __Pyx_INCREF(__pyx_t_3); __pyx_t_2++; if (unlikely((0 < 0))) __PYX_ERR(0, 697, __pyx_L1_error) #else - { - Py_ssize_t i; - PyObject** temps[6] = {&__pyx_t_1,&__pyx_t_2,&__pyx_t_3,&__pyx_t_4,&__pyx_t_5,&__pyx_t_6}; - for (i=0; i < 6; i++) { - PyObject* item = PySequence_ITEM(sequence, i); if (unlikely(!item)) __PYX_ERR(0, 692, __pyx_L1_error) - __Pyx_GOTREF(item); - *(temps[i]) = item; - } - } + __pyx_t_3 = __Pyx_PySequence_ITEM(__pyx_t_1, __pyx_t_2); __pyx_t_2++; if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 697, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_3); #endif - } - __pyx_v_process_mode = __pyx_t_1; - __pyx_t_1 = 0; - __pyx_v_domains = __pyx_t_2; - __pyx_t_2 = 0; - __pyx_v_constraint_lookup = __pyx_t_3; - __pyx_t_3 = 0; - __pyx_v_first_var = __pyx_t_4; - __pyx_t_4 = 0; - __pyx_v_first_value = __pyx_t_5; - __pyx_t_5 = 0; - __pyx_v_remaining_vars = __pyx_t_6; - __pyx_t_6 = 0; - - /* "constraint/solvers.py":693 - * """Worker function for parallel execution on first variable.""" - * process_mode, domains, constraint_lookup, first_var, first_value, remaining_vars = args - * local_assignment = {first_var: first_value} # <<<<<<<<<<<<<< - * - * if process_mode: - */ - __pyx_t_6 = __Pyx_PyDict_NewPresized(1); if (unlikely(!__pyx_t_6)) __PYX_ERR(0, 693, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_6); - if (PyDict_SetItem(__pyx_t_6, __pyx_v_first_var, __pyx_v_first_value) < 0) __PYX_ERR(0, 693, __pyx_L1_error) - __pyx_v_local_assignment = ((PyObject*)__pyx_t_6); - __pyx_t_6 = 0; - - /* "constraint/solvers.py":695 - * local_assignment = {first_var: first_value} - * - * if process_mode: # <<<<<<<<<<<<<< - * # if there are any CompilableFunctionConstraint, they must be compiled locally first - * for var, constraints in constraint_lookup.items(): - */ - __pyx_t_7 = __Pyx_PyObject_IsTrue(__pyx_v_process_mode); if (unlikely((__pyx_t_7 < 0))) __PYX_ERR(0, 695, __pyx_L1_error) - if (__pyx_t_7) { - - /* "constraint/solvers.py":697 - * if process_mode: - * # if there are any CompilableFunctionConstraint, they must be compiled locally first - * for var, constraints in constraint_lookup.items(): # <<<<<<<<<<<<<< - * constraint_lookup[var] = [tuple([compile_to_function(constraint) if isinstance(constraint, CompilableFunctionConstraint) else constraint, vals]) for constraint, vals in constraints] # noqa E501 - * - */ - __pyx_t_8 = 0; - if (unlikely(__pyx_v_constraint_lookup == Py_None)) { - PyErr_Format(PyExc_AttributeError, "'NoneType' object has no attribute '%.30s'", "items"); - __PYX_ERR(0, 697, __pyx_L1_error) - } - __pyx_t_5 = __Pyx_dict_iterator(__pyx_v_constraint_lookup, 0, __pyx_n_s_items, (&__pyx_t_9), (&__pyx_t_10)); if (unlikely(!__pyx_t_5)) __PYX_ERR(0, 697, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_5); - __Pyx_XDECREF(__pyx_t_6); - __pyx_t_6 = __pyx_t_5; - __pyx_t_5 = 0; - while (1) { - __pyx_t_11 = __Pyx_dict_iter_next(__pyx_t_6, __pyx_t_9, &__pyx_t_8, &__pyx_t_5, &__pyx_t_4, NULL, __pyx_t_10); - if (unlikely(__pyx_t_11 == 0)) break; - if (unlikely(__pyx_t_11 == -1)) __PYX_ERR(0, 697, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_5); - __Pyx_GOTREF(__pyx_t_4); - __Pyx_XDECREF_SET(__pyx_v_var, __pyx_t_5); - __pyx_t_5 = 0; - __Pyx_XDECREF_SET(__pyx_v_constraints, __pyx_t_4); - __pyx_t_4 = 0; - - /* "constraint/solvers.py":698 - * # if there are any CompilableFunctionConstraint, they must be compiled locally first - * for var, constraints in constraint_lookup.items(): - * constraint_lookup[var] = [tuple([compile_to_function(constraint) if isinstance(constraint, CompilableFunctionConstraint) else constraint, vals]) for constraint, vals in constraints] # noqa E501 # <<<<<<<<<<<<<< - * - * # continue solving sequentially on this process - */ - { /* enter inner scope */ - __pyx_t_4 = PyList_New(0); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 698, __pyx_L8_error) - __Pyx_GOTREF(__pyx_t_4); - if (likely(PyList_CheckExact(__pyx_v_constraints)) || PyTuple_CheckExact(__pyx_v_constraints)) { - __pyx_t_5 = __pyx_v_constraints; __Pyx_INCREF(__pyx_t_5); - __pyx_t_12 = 0; - __pyx_t_13 = NULL; - } else { - __pyx_t_12 = -1; __pyx_t_5 = PyObject_GetIter(__pyx_v_constraints); if (unlikely(!__pyx_t_5)) __PYX_ERR(0, 698, __pyx_L8_error) - __Pyx_GOTREF(__pyx_t_5); - __pyx_t_13 = __Pyx_PyObject_GetIterNextFunc(__pyx_t_5); if (unlikely(!__pyx_t_13)) __PYX_ERR(0, 698, __pyx_L8_error) - } - for (;;) { - if (likely(!__pyx_t_13)) { - if (likely(PyList_CheckExact(__pyx_t_5))) { - { - Py_ssize_t __pyx_temp = __Pyx_PyList_GET_SIZE(__pyx_t_5); - #if !CYTHON_ASSUME_SAFE_MACROS - if (unlikely((__pyx_temp < 0))) __PYX_ERR(0, 698, __pyx_L8_error) - #endif - if (__pyx_t_12 >= __pyx_temp) break; - } - #if CYTHON_ASSUME_SAFE_MACROS && !CYTHON_AVOID_BORROWED_REFS - __pyx_t_3 = PyList_GET_ITEM(__pyx_t_5, __pyx_t_12); __Pyx_INCREF(__pyx_t_3); __pyx_t_12++; if (unlikely((0 < 0))) __PYX_ERR(0, 698, __pyx_L8_error) - #else - __pyx_t_3 = __Pyx_PySequence_ITEM(__pyx_t_5, __pyx_t_12); __pyx_t_12++; if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 698, __pyx_L8_error) - __Pyx_GOTREF(__pyx_t_3); - #endif - } else { - { - Py_ssize_t __pyx_temp = __Pyx_PyTuple_GET_SIZE(__pyx_t_5); - #if !CYTHON_ASSUME_SAFE_MACROS - if (unlikely((__pyx_temp < 0))) __PYX_ERR(0, 698, __pyx_L8_error) - #endif - if (__pyx_t_12 >= __pyx_temp) break; - } - #if CYTHON_ASSUME_SAFE_MACROS && !CYTHON_AVOID_BORROWED_REFS - __pyx_t_3 = PyTuple_GET_ITEM(__pyx_t_5, __pyx_t_12); __Pyx_INCREF(__pyx_t_3); __pyx_t_12++; if (unlikely((0 < 0))) __PYX_ERR(0, 698, __pyx_L8_error) - #else - __pyx_t_3 = __Pyx_PySequence_ITEM(__pyx_t_5, __pyx_t_12); __pyx_t_12++; if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 698, __pyx_L8_error) - __Pyx_GOTREF(__pyx_t_3); - #endif - } - } else { - __pyx_t_3 = __pyx_t_13(__pyx_t_5); - if (unlikely(!__pyx_t_3)) { - PyObject* exc_type = PyErr_Occurred(); - if (exc_type) { - if (likely(__Pyx_PyErr_GivenExceptionMatches(exc_type, PyExc_StopIteration))) PyErr_Clear(); - else __PYX_ERR(0, 698, __pyx_L8_error) - } - break; - } - __Pyx_GOTREF(__pyx_t_3); - } - if ((likely(PyTuple_CheckExact(__pyx_t_3))) || (PyList_CheckExact(__pyx_t_3))) { - PyObject* sequence = __pyx_t_3; - Py_ssize_t size = __Pyx_PySequence_SIZE(sequence); - if (unlikely(size != 2)) { - if (size > 2) __Pyx_RaiseTooManyValuesError(2); - else if (size >= 0) __Pyx_RaiseNeedMoreValuesError(size); - __PYX_ERR(0, 698, __pyx_L8_error) - } - #if CYTHON_ASSUME_SAFE_MACROS && !CYTHON_AVOID_BORROWED_REFS - if (likely(PyTuple_CheckExact(sequence))) { - __pyx_t_2 = PyTuple_GET_ITEM(sequence, 0); - __pyx_t_1 = PyTuple_GET_ITEM(sequence, 1); - } else { - __pyx_t_2 = PyList_GET_ITEM(sequence, 0); - __pyx_t_1 = PyList_GET_ITEM(sequence, 1); - } - __Pyx_INCREF(__pyx_t_2); - __Pyx_INCREF(__pyx_t_1); - #else - __pyx_t_2 = PySequence_ITEM(sequence, 0); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 698, __pyx_L8_error) - __Pyx_GOTREF(__pyx_t_2); - __pyx_t_1 = PySequence_ITEM(sequence, 1); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 698, __pyx_L8_error) - __Pyx_GOTREF(__pyx_t_1); - #endif - __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; - } else { - Py_ssize_t index = -1; - __pyx_t_14 = PyObject_GetIter(__pyx_t_3); if (unlikely(!__pyx_t_14)) __PYX_ERR(0, 698, __pyx_L8_error) - __Pyx_GOTREF(__pyx_t_14); - __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; - __pyx_t_15 = __Pyx_PyObject_GetIterNextFunc(__pyx_t_14); - index = 0; __pyx_t_2 = __pyx_t_15(__pyx_t_14); if (unlikely(!__pyx_t_2)) goto __pyx_L11_unpacking_failed; - __Pyx_GOTREF(__pyx_t_2); - index = 1; __pyx_t_1 = __pyx_t_15(__pyx_t_14); if (unlikely(!__pyx_t_1)) goto __pyx_L11_unpacking_failed; - __Pyx_GOTREF(__pyx_t_1); - if (__Pyx_IternextUnpackEndCheck(__pyx_t_15(__pyx_t_14), 2) < 0) __PYX_ERR(0, 698, __pyx_L8_error) - __pyx_t_15 = NULL; - __Pyx_DECREF(__pyx_t_14); __pyx_t_14 = 0; - goto __pyx_L12_unpacking_done; - __pyx_L11_unpacking_failed:; - __Pyx_DECREF(__pyx_t_14); __pyx_t_14 = 0; - __pyx_t_15 = NULL; - if (__Pyx_IterFinish() == 0) __Pyx_RaiseNeedMoreValuesError(index); - __PYX_ERR(0, 698, __pyx_L8_error) - __pyx_L12_unpacking_done:; - } - __Pyx_XDECREF_SET(__pyx_8genexpr9__pyx_v_constraint, __pyx_t_2); - __pyx_t_2 = 0; - __Pyx_XDECREF_SET(__pyx_8genexpr9__pyx_v_vals, __pyx_t_1); - __pyx_t_1 = 0; - __Pyx_GetModuleGlobalName(__pyx_t_1, __pyx_n_s_CompilableFunctionConstraint); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 698, __pyx_L8_error) - __Pyx_GOTREF(__pyx_t_1); - __pyx_t_7 = PyObject_IsInstance(__pyx_8genexpr9__pyx_v_constraint, __pyx_t_1); if (unlikely(__pyx_t_7 == ((int)-1))) __PYX_ERR(0, 698, __pyx_L8_error) - __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; - if (__pyx_t_7) { - __Pyx_GetModuleGlobalName(__pyx_t_2, __pyx_n_s_compile_to_function); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 698, __pyx_L8_error) - __Pyx_GOTREF(__pyx_t_2); - __pyx_t_14 = NULL; - __pyx_t_16 = 0; - #if CYTHON_UNPACK_METHODS - if (unlikely(PyMethod_Check(__pyx_t_2))) { - __pyx_t_14 = PyMethod_GET_SELF(__pyx_t_2); - if (likely(__pyx_t_14)) { - PyObject* function = PyMethod_GET_FUNCTION(__pyx_t_2); - __Pyx_INCREF(__pyx_t_14); - __Pyx_INCREF(function); - __Pyx_DECREF_SET(__pyx_t_2, function); - __pyx_t_16 = 1; - } - } - #endif - { - PyObject *__pyx_callargs[2] = {__pyx_t_14, __pyx_8genexpr9__pyx_v_constraint}; - __pyx_t_1 = __Pyx_PyObject_FastCall(__pyx_t_2, __pyx_callargs+1-__pyx_t_16, 1+__pyx_t_16); - __Pyx_XDECREF(__pyx_t_14); __pyx_t_14 = 0; - if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 698, __pyx_L8_error) - __Pyx_GOTREF(__pyx_t_1); - __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; - } - __pyx_t_3 = __pyx_t_1; - __pyx_t_1 = 0; - } else { - __Pyx_INCREF(__pyx_8genexpr9__pyx_v_constraint); - __pyx_t_3 = __pyx_8genexpr9__pyx_v_constraint; - } - __pyx_t_1 = PyList_New(2); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 698, __pyx_L8_error) - __Pyx_GOTREF(__pyx_t_1); - __Pyx_GIVEREF(__pyx_t_3); - if (__Pyx_PyList_SET_ITEM(__pyx_t_1, 0, __pyx_t_3)) __PYX_ERR(0, 698, __pyx_L8_error); - __Pyx_INCREF(__pyx_8genexpr9__pyx_v_vals); - __Pyx_GIVEREF(__pyx_8genexpr9__pyx_v_vals); - if (__Pyx_PyList_SET_ITEM(__pyx_t_1, 1, __pyx_8genexpr9__pyx_v_vals)) __PYX_ERR(0, 698, __pyx_L8_error); - __pyx_t_3 = 0; - __pyx_t_3 = PyList_AsTuple(((PyObject*)__pyx_t_1)); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 698, __pyx_L8_error) - __Pyx_GOTREF(__pyx_t_3); - __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; - if (unlikely(__Pyx_ListComp_Append(__pyx_t_4, (PyObject*)__pyx_t_3))) __PYX_ERR(0, 698, __pyx_L8_error) - __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; - } - __Pyx_DECREF(__pyx_t_5); __pyx_t_5 = 0; - __Pyx_XDECREF(__pyx_8genexpr9__pyx_v_constraint); __pyx_8genexpr9__pyx_v_constraint = 0; - __Pyx_XDECREF(__pyx_8genexpr9__pyx_v_vals); __pyx_8genexpr9__pyx_v_vals = 0; - goto __pyx_L14_exit_scope; - __pyx_L8_error:; - __Pyx_XDECREF(__pyx_8genexpr9__pyx_v_constraint); __pyx_8genexpr9__pyx_v_constraint = 0; - __Pyx_XDECREF(__pyx_8genexpr9__pyx_v_vals); __pyx_8genexpr9__pyx_v_vals = 0; - goto __pyx_L1_error; - __pyx_L14_exit_scope:; - } /* exit inner scope */ - if (unlikely((PyObject_SetItem(__pyx_v_constraint_lookup, __pyx_v_var, __pyx_t_4) < 0))) __PYX_ERR(0, 698, __pyx_L1_error) - __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; + if ((likely(PyTuple_CheckExact(__pyx_t_3))) || (PyList_CheckExact(__pyx_t_3))) { + PyObject* sequence = __pyx_t_3; + Py_ssize_t size = __Pyx_PySequence_SIZE(sequence); + if (unlikely(size != 2)) { + if (size > 2) __Pyx_RaiseTooManyValuesError(2); + else if (size >= 0) __Pyx_RaiseNeedMoreValuesError(size); + __PYX_ERR(0, 697, __pyx_L1_error) + } + #if CYTHON_ASSUME_SAFE_MACROS && !CYTHON_AVOID_BORROWED_REFS + if (likely(PyTuple_CheckExact(sequence))) { + __pyx_t_4 = PyTuple_GET_ITEM(sequence, 0); + __pyx_t_5 = PyTuple_GET_ITEM(sequence, 1); + } else { + __pyx_t_4 = PyList_GET_ITEM(sequence, 0); + __pyx_t_5 = PyList_GET_ITEM(sequence, 1); + } + __Pyx_INCREF(__pyx_t_4); + __Pyx_INCREF(__pyx_t_5); + #else + __pyx_t_4 = PySequence_ITEM(sequence, 0); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 697, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_4); + __pyx_t_5 = PySequence_ITEM(sequence, 1); if (unlikely(!__pyx_t_5)) __PYX_ERR(0, 697, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_5); + #endif + __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; + } else { + Py_ssize_t index = -1; + __pyx_t_6 = PyObject_GetIter(__pyx_t_3); if (unlikely(!__pyx_t_6)) __PYX_ERR(0, 697, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_6); + __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; + __pyx_t_7 = __Pyx_PyObject_GetIterNextFunc(__pyx_t_6); + index = 0; __pyx_t_4 = __pyx_t_7(__pyx_t_6); if (unlikely(!__pyx_t_4)) goto __pyx_L6_unpacking_failed; + __Pyx_GOTREF(__pyx_t_4); + index = 1; __pyx_t_5 = __pyx_t_7(__pyx_t_6); if (unlikely(!__pyx_t_5)) goto __pyx_L6_unpacking_failed; + __Pyx_GOTREF(__pyx_t_5); + if (__Pyx_IternextUnpackEndCheck(__pyx_t_7(__pyx_t_6), 2) < 0) __PYX_ERR(0, 697, __pyx_L1_error) + __pyx_t_7 = NULL; + __Pyx_DECREF(__pyx_t_6); __pyx_t_6 = 0; + goto __pyx_L7_unpacking_done; + __pyx_L6_unpacking_failed:; + __Pyx_DECREF(__pyx_t_6); __pyx_t_6 = 0; + __pyx_t_7 = NULL; + if (__Pyx_IterFinish() == 0) __Pyx_RaiseNeedMoreValuesError(index); + __PYX_ERR(0, 697, __pyx_L1_error) + __pyx_L7_unpacking_done:; } - __Pyx_DECREF(__pyx_t_6); __pyx_t_6 = 0; + __Pyx_XGOTREF(__pyx_cur_scope->__pyx_v_constraint); + __Pyx_XDECREF_SET(__pyx_cur_scope->__pyx_v_constraint, __pyx_t_4); + __Pyx_GIVEREF(__pyx_t_4); + __pyx_t_4 = 0; + __Pyx_XGOTREF(__pyx_cur_scope->__pyx_v_vars_involved); + __Pyx_XDECREF_SET(__pyx_cur_scope->__pyx_v_vars_involved, __pyx_t_5); + __Pyx_GIVEREF(__pyx_t_5); + __pyx_t_5 = 0; - /* "constraint/solvers.py":695 - * local_assignment = {first_var: first_value} + /* "constraint/solvers.py":698 + * constraint(vars_involved, domains, assignment, None) + * for constraint, vars_involved in constraints_lookup + * if all(v in assignment for v in vars_involved) # <<<<<<<<<<<<<< + * ) * - * if process_mode: # <<<<<<<<<<<<<< - * # if there are any CompilableFunctionConstraint, they must be compiled locally first - * for var, constraints in constraint_lookup.items(): */ - } + __pyx_t_3 = __pyx_pf_10constraint_7solvers_8is_valid_7genexpr_genexpr(((PyObject*)__pyx_cur_scope), __pyx_cur_scope->__pyx_v_vars_involved); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 698, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_3); + __pyx_t_5 = __Pyx_Generator_Next(__pyx_t_3); if (unlikely(!__pyx_t_5)) __PYX_ERR(0, 698, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_5); + __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; + __pyx_t_8 = __Pyx_PyObject_IsTrue(__pyx_t_5); if (unlikely((__pyx_t_8 < 0))) __PYX_ERR(0, 698, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_5); __pyx_t_5 = 0; + if (__pyx_t_8) { - /* "constraint/solvers.py":701 + /* "constraint/solvers.py":696 + * """Check if all constraints are satisfied given the current assignment.""" + * return all( + * constraint(vars_involved, domains, assignment, None) # <<<<<<<<<<<<<< + * for constraint, vars_involved in constraints_lookup + * if all(v in assignment for v in vars_involved) + */ + if (unlikely(!__pyx_cur_scope->__pyx_outer_scope->__pyx_v_domains)) { __Pyx_RaiseClosureNameError("domains"); __PYX_ERR(0, 696, __pyx_L1_error) } + if (unlikely(!__pyx_cur_scope->__pyx_outer_scope->__pyx_v_assignment)) { __Pyx_RaiseClosureNameError("assignment"); __PYX_ERR(0, 696, __pyx_L1_error) } + __Pyx_INCREF(__pyx_cur_scope->__pyx_v_constraint); + __pyx_t_3 = __pyx_cur_scope->__pyx_v_constraint; __pyx_t_4 = NULL; + __pyx_t_9 = 0; + #if CYTHON_UNPACK_METHODS + if (unlikely(PyMethod_Check(__pyx_t_3))) { + __pyx_t_4 = PyMethod_GET_SELF(__pyx_t_3); + if (likely(__pyx_t_4)) { + PyObject* function = PyMethod_GET_FUNCTION(__pyx_t_3); + __Pyx_INCREF(__pyx_t_4); + __Pyx_INCREF(function); + __Pyx_DECREF_SET(__pyx_t_3, function); + __pyx_t_9 = 1; + } + } + #endif + { + PyObject *__pyx_callargs[5] = {__pyx_t_4, __pyx_cur_scope->__pyx_v_vars_involved, __pyx_cur_scope->__pyx_outer_scope->__pyx_v_domains, __pyx_cur_scope->__pyx_outer_scope->__pyx_v_assignment, Py_None}; + __pyx_t_5 = __Pyx_PyObject_FastCall(__pyx_t_3, __pyx_callargs+1-__pyx_t_9, 4+__pyx_t_9); + __Pyx_XDECREF(__pyx_t_4); __pyx_t_4 = 0; + if (unlikely(!__pyx_t_5)) __PYX_ERR(0, 696, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_5); + __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; + } + __pyx_t_8 = __Pyx_PyObject_IsTrue(__pyx_t_5); if (unlikely((__pyx_t_8 < 0))) __PYX_ERR(0, 696, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_5); __pyx_t_5 = 0; + __pyx_t_10 = (!__pyx_t_8); + if (__pyx_t_10) { + + /* "constraint/solvers.py":695 + * def is_valid(assignment: dict[Hashable, any], constraints_lookup: list[tuple[Constraint, Hashable]], domains: dict[Hashable, Domain]) -> bool: # noqa E501 + * """Check if all constraints are satisfied given the current assignment.""" + * return all( # <<<<<<<<<<<<<< + * constraint(vars_involved, domains, assignment, None) + * for constraint, vars_involved in constraints_lookup + */ + __Pyx_XDECREF(__pyx_r); + + /* "constraint/solvers.py":696 + * """Check if all constraints are satisfied given the current assignment.""" + * return all( + * constraint(vars_involved, domains, assignment, None) # <<<<<<<<<<<<<< + * for constraint, vars_involved in constraints_lookup + * if all(v in assignment for v in vars_involved) + */ + __Pyx_INCREF(Py_False); + __pyx_r = Py_False; + __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; + goto __pyx_L0; + } + + /* "constraint/solvers.py":698 + * constraint(vars_involved, domains, assignment, None) + * for constraint, vars_involved in constraints_lookup + * if all(v in assignment for v in vars_involved) # <<<<<<<<<<<<<< + * ) * - * # continue solving sequentially on this process - * if is_valid(local_assignment, constraint_lookup[first_var], domains): # <<<<<<<<<<<<<< - * return sequential_optimized_backtrack(local_assignment, remaining_vars, domains, constraint_lookup) - * return [] */ - __Pyx_GetModuleGlobalName(__pyx_t_4, __pyx_n_s_is_valid); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 701, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_4); - __pyx_t_5 = __Pyx_PyObject_GetItem(__pyx_v_constraint_lookup, __pyx_v_first_var); if (unlikely(!__pyx_t_5)) __PYX_ERR(0, 701, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_5); - __pyx_t_3 = NULL; - __pyx_t_16 = 0; - #if CYTHON_UNPACK_METHODS - if (unlikely(PyMethod_Check(__pyx_t_4))) { - __pyx_t_3 = PyMethod_GET_SELF(__pyx_t_4); - if (likely(__pyx_t_3)) { - PyObject* function = PyMethod_GET_FUNCTION(__pyx_t_4); - __Pyx_INCREF(__pyx_t_3); - __Pyx_INCREF(function); - __Pyx_DECREF_SET(__pyx_t_4, function); - __pyx_t_16 = 1; } + + /* "constraint/solvers.py":697 + * return all( + * constraint(vars_involved, domains, assignment, None) + * for constraint, vars_involved in constraints_lookup # <<<<<<<<<<<<<< + * if all(v in assignment for v in vars_involved) + * ) + */ } - #endif - { - PyObject *__pyx_callargs[4] = {__pyx_t_3, __pyx_v_local_assignment, __pyx_t_5, __pyx_v_domains}; - __pyx_t_6 = __Pyx_PyObject_FastCall(__pyx_t_4, __pyx_callargs+1-__pyx_t_16, 3+__pyx_t_16); - __Pyx_XDECREF(__pyx_t_3); __pyx_t_3 = 0; - __Pyx_DECREF(__pyx_t_5); __pyx_t_5 = 0; - if (unlikely(!__pyx_t_6)) __PYX_ERR(0, 701, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_6); - __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; - } - __pyx_t_7 = __Pyx_PyObject_IsTrue(__pyx_t_6); if (unlikely((__pyx_t_7 < 0))) __PYX_ERR(0, 701, __pyx_L1_error) - __Pyx_DECREF(__pyx_t_6); __pyx_t_6 = 0; - if (__pyx_t_7) { + __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; + /*else*/ { - /* "constraint/solvers.py":702 - * # continue solving sequentially on this process - * if is_valid(local_assignment, constraint_lookup[first_var], domains): - * return sequential_optimized_backtrack(local_assignment, remaining_vars, domains, constraint_lookup) # <<<<<<<<<<<<<< - * return [] - * + /* "constraint/solvers.py":695 + * def is_valid(assignment: dict[Hashable, any], constraints_lookup: list[tuple[Constraint, Hashable]], domains: dict[Hashable, Domain]) -> bool: # noqa E501 + * """Check if all constraints are satisfied given the current assignment.""" + * return all( # <<<<<<<<<<<<<< + * constraint(vars_involved, domains, assignment, None) + * for constraint, vars_involved in constraints_lookup */ __Pyx_XDECREF(__pyx_r); - __Pyx_GetModuleGlobalName(__pyx_t_4, __pyx_n_s_sequential_optimized_backtrack); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 702, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_4); - __pyx_t_5 = NULL; - __pyx_t_16 = 0; - #if CYTHON_UNPACK_METHODS - if (unlikely(PyMethod_Check(__pyx_t_4))) { - __pyx_t_5 = PyMethod_GET_SELF(__pyx_t_4); - if (likely(__pyx_t_5)) { - PyObject* function = PyMethod_GET_FUNCTION(__pyx_t_4); - __Pyx_INCREF(__pyx_t_5); - __Pyx_INCREF(function); - __Pyx_DECREF_SET(__pyx_t_4, function); - __pyx_t_16 = 1; - } - } - #endif - { - PyObject *__pyx_callargs[5] = {__pyx_t_5, __pyx_v_local_assignment, __pyx_v_remaining_vars, __pyx_v_domains, __pyx_v_constraint_lookup}; - __pyx_t_6 = __Pyx_PyObject_FastCall(__pyx_t_4, __pyx_callargs+1-__pyx_t_16, 4+__pyx_t_16); - __Pyx_XDECREF(__pyx_t_5); __pyx_t_5 = 0; - if (unlikely(!__pyx_t_6)) __PYX_ERR(0, 702, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_6); - __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; - } - if (!(likely(PyList_CheckExact(__pyx_t_6))||((__pyx_t_6) == Py_None) || __Pyx_RaiseUnexpectedTypeError("list", __pyx_t_6))) __PYX_ERR(0, 702, __pyx_L1_error) - __pyx_r = ((PyObject*)__pyx_t_6); - __pyx_t_6 = 0; + + /* "constraint/solvers.py":696 + * """Check if all constraints are satisfied given the current assignment.""" + * return all( + * constraint(vars_involved, domains, assignment, None) # <<<<<<<<<<<<<< + * for constraint, vars_involved in constraints_lookup + * if all(v in assignment for v in vars_involved) + */ + __Pyx_INCREF(Py_True); + __pyx_r = Py_True; goto __pyx_L0; + } + CYTHON_MAYBE_UNUSED_VAR(__pyx_cur_scope); + + /* function exit code */ + goto __pyx_L0; + __pyx_L1_error:; + __Pyx_Generator_Replace_StopIteration(0); + __Pyx_XDECREF(__pyx_t_1); + __Pyx_XDECREF(__pyx_t_3); + __Pyx_XDECREF(__pyx_t_4); + __Pyx_XDECREF(__pyx_t_5); + __Pyx_XDECREF(__pyx_t_6); + __Pyx_AddTraceback("genexpr", __pyx_clineno, __pyx_lineno, __pyx_filename); + __pyx_L0:; + __Pyx_XGIVEREF(__pyx_r); + #if !CYTHON_USE_EXC_INFO_STACK + __Pyx_Coroutine_ResetAndClearException(__pyx_generator); + #endif + __pyx_generator->resume_label = -1; + __Pyx_Coroutine_clear((PyObject*)__pyx_generator); + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} - /* "constraint/solvers.py":701 +/* "constraint/solvers.py":693 + * ### Helper functions for parallel solver * - * # continue solving sequentially on this process - * if is_valid(local_assignment, constraint_lookup[first_var], domains): # <<<<<<<<<<<<<< - * return sequential_optimized_backtrack(local_assignment, remaining_vars, domains, constraint_lookup) - * return [] + * def is_valid(assignment: dict[Hashable, any], constraints_lookup: list[tuple[Constraint, Hashable]], domains: dict[Hashable, Domain]) -> bool: # noqa E501 # <<<<<<<<<<<<<< + * """Check if all constraints are satisfied given the current assignment.""" + * return all( + */ + +static PyObject *__pyx_pf_10constraint_7solvers_4is_valid(CYTHON_UNUSED PyObject *__pyx_self, PyObject *__pyx_v_assignment, PyObject *__pyx_v_constraints_lookup, PyObject *__pyx_v_domains) { + struct __pyx_obj_10constraint_7solvers___pyx_scope_struct_4_is_valid *__pyx_cur_scope; + PyObject *__pyx_gb_10constraint_7solvers_8is_valid_2generator3 = 0; + PyObject *__pyx_r = NULL; + __Pyx_RefNannyDeclarations + PyObject *__pyx_t_1 = NULL; + PyObject *__pyx_t_2 = NULL; + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + __Pyx_RefNannySetupContext("is_valid", 0); + __pyx_cur_scope = (struct __pyx_obj_10constraint_7solvers___pyx_scope_struct_4_is_valid *)__pyx_tp_new_10constraint_7solvers___pyx_scope_struct_4_is_valid(__pyx_ptype_10constraint_7solvers___pyx_scope_struct_4_is_valid, __pyx_empty_tuple, NULL); + if (unlikely(!__pyx_cur_scope)) { + __pyx_cur_scope = ((struct __pyx_obj_10constraint_7solvers___pyx_scope_struct_4_is_valid *)Py_None); + __Pyx_INCREF(Py_None); + __PYX_ERR(0, 693, __pyx_L1_error) + } else { + __Pyx_GOTREF((PyObject *)__pyx_cur_scope); + } + __pyx_cur_scope->__pyx_v_assignment = __pyx_v_assignment; + __Pyx_INCREF(__pyx_cur_scope->__pyx_v_assignment); + __Pyx_GIVEREF(__pyx_cur_scope->__pyx_v_assignment); + __pyx_cur_scope->__pyx_v_domains = __pyx_v_domains; + __Pyx_INCREF(__pyx_cur_scope->__pyx_v_domains); + __Pyx_GIVEREF(__pyx_cur_scope->__pyx_v_domains); + + /* "constraint/solvers.py":695 + * def is_valid(assignment: dict[Hashable, any], constraints_lookup: list[tuple[Constraint, Hashable]], domains: dict[Hashable, Domain]) -> bool: # noqa E501 + * """Check if all constraints are satisfied given the current assignment.""" + * return all( # <<<<<<<<<<<<<< + * constraint(vars_involved, domains, assignment, None) + * for constraint, vars_involved in constraints_lookup */ - } + __Pyx_XDECREF(__pyx_r); - /* "constraint/solvers.py":703 - * if is_valid(local_assignment, constraint_lookup[first_var], domains): - * return sequential_optimized_backtrack(local_assignment, remaining_vars, domains, constraint_lookup) - * return [] # <<<<<<<<<<<<<< - * - * class ParallelSolver(Solver): + /* "constraint/solvers.py":696 + * """Check if all constraints are satisfied given the current assignment.""" + * return all( + * constraint(vars_involved, domains, assignment, None) # <<<<<<<<<<<<<< + * for constraint, vars_involved in constraints_lookup + * if all(v in assignment for v in vars_involved) */ - __Pyx_XDECREF(__pyx_r); - __pyx_t_6 = PyList_New(0); if (unlikely(!__pyx_t_6)) __PYX_ERR(0, 703, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_6); - __pyx_r = ((PyObject*)__pyx_t_6); - __pyx_t_6 = 0; + __pyx_t_1 = __pyx_pf_10constraint_7solvers_8is_valid_genexpr(((PyObject*)__pyx_cur_scope), __pyx_v_constraints_lookup); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 696, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __pyx_t_2 = __Pyx_Generator_Next(__pyx_t_1); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 696, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_2); + __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; + __pyx_r = __pyx_t_2; + __pyx_t_2 = 0; goto __pyx_L0; - /* "constraint/solvers.py":690 - * + /* "constraint/solvers.py":693 + * ### Helper functions for parallel solver * - * def parallel_worker(args: tuple[bool, dict[Hashable, Domain], dict[Hashable, list[tuple[Constraint, Hashable]]], Hashable, any, list[Hashable]]) -> list[dict[Hashable, any]]: # noqa E501 # <<<<<<<<<<<<<< - * """Worker function for parallel execution on first variable.""" - * process_mode, domains, constraint_lookup, first_var, first_value, remaining_vars = args + * def is_valid(assignment: dict[Hashable, any], constraints_lookup: list[tuple[Constraint, Hashable]], domains: dict[Hashable, Domain]) -> bool: # noqa E501 # <<<<<<<<<<<<<< + * """Check if all constraints are satisfied given the current assignment.""" + * return all( */ /* function exit code */ __pyx_L1_error:; __Pyx_XDECREF(__pyx_t_1); __Pyx_XDECREF(__pyx_t_2); - __Pyx_XDECREF(__pyx_t_3); - __Pyx_XDECREF(__pyx_t_4); - __Pyx_XDECREF(__pyx_t_5); - __Pyx_XDECREF(__pyx_t_6); - __Pyx_XDECREF(__pyx_t_14); - __Pyx_AddTraceback("constraint.solvers.parallel_worker", __pyx_clineno, __pyx_lineno, __pyx_filename); + __Pyx_AddTraceback("constraint.solvers.is_valid", __pyx_clineno, __pyx_lineno, __pyx_filename); __pyx_r = NULL; __pyx_L0:; - __Pyx_XDECREF(__pyx_v_process_mode); - __Pyx_XDECREF(__pyx_v_domains); - __Pyx_XDECREF(__pyx_v_constraint_lookup); - __Pyx_XDECREF(__pyx_v_first_var); - __Pyx_XDECREF(__pyx_v_first_value); - __Pyx_XDECREF(__pyx_v_remaining_vars); - __Pyx_XDECREF(__pyx_v_local_assignment); - __Pyx_XDECREF(__pyx_v_var); - __Pyx_XDECREF(__pyx_v_constraints); - __Pyx_XDECREF(__pyx_8genexpr9__pyx_v_constraint); - __Pyx_XDECREF(__pyx_8genexpr9__pyx_v_vals); + __Pyx_XDECREF(__pyx_gb_10constraint_7solvers_8is_valid_2generator3); + __Pyx_DECREF((PyObject *)__pyx_cur_scope); __Pyx_XGIVEREF(__pyx_r); __Pyx_RefNannyFinishContext(); return __pyx_r; } -/* "constraint/solvers.py":742 - * """ # noqa E501 +/* "constraint/solvers.py":701 + * ) * - * def __init__(self, process_mode=False): # <<<<<<<<<<<<<< - * """Initialization method. Set `process_mode` to True for using ProcessPool, otherwise uses ThreadPool.""" - * super().__init__() + * def compile_to_function(constraint: CompilableFunctionConstraint) -> FunctionConstraint: # <<<<<<<<<<<<<< + * """Compile a CompilableFunctionConstraint to a function, wrapped by a FunctionConstraint.""" + * func_string = constraint._func */ /* Python wrapper */ -static PyObject *__pyx_pw_10constraint_7solvers_14ParallelSolver_1__init__(PyObject *__pyx_self, +static PyObject *__pyx_pw_10constraint_7solvers_7compile_to_function(PyObject *__pyx_self, #if CYTHON_METH_FASTCALL PyObject *const *__pyx_args, Py_ssize_t __pyx_nargs, PyObject *__pyx_kwds #else PyObject *__pyx_args, PyObject *__pyx_kwds #endif ); /*proto*/ -PyDoc_STRVAR(__pyx_doc_10constraint_7solvers_14ParallelSolver___init__, "Initialization method. Set `process_mode` to True for using ProcessPool, otherwise uses ThreadPool."); -static PyMethodDef __pyx_mdef_10constraint_7solvers_14ParallelSolver_1__init__ = {"__init__", (PyCFunction)(void*)(__Pyx_PyCFunction_FastCallWithKeywords)__pyx_pw_10constraint_7solvers_14ParallelSolver_1__init__, __Pyx_METH_FASTCALL|METH_KEYWORDS, __pyx_doc_10constraint_7solvers_14ParallelSolver___init__}; -static PyObject *__pyx_pw_10constraint_7solvers_14ParallelSolver_1__init__(PyObject *__pyx_self, +PyDoc_STRVAR(__pyx_doc_10constraint_7solvers_6compile_to_function, "Compile a CompilableFunctionConstraint to a function, wrapped by a FunctionConstraint."); +static PyMethodDef __pyx_mdef_10constraint_7solvers_7compile_to_function = {"compile_to_function", (PyCFunction)(void*)(__Pyx_PyCFunction_FastCallWithKeywords)__pyx_pw_10constraint_7solvers_7compile_to_function, __Pyx_METH_FASTCALL|METH_KEYWORDS, __pyx_doc_10constraint_7solvers_6compile_to_function}; +static PyObject *__pyx_pw_10constraint_7solvers_7compile_to_function(PyObject *__pyx_self, #if CYTHON_METH_FASTCALL PyObject *const *__pyx_args, Py_ssize_t __pyx_nargs, PyObject *__pyx_kwds #else PyObject *__pyx_args, PyObject *__pyx_kwds #endif ) { - PyObject *__pyx_v_self = 0; - PyObject *__pyx_v_process_mode = 0; + PyObject *__pyx_v_constraint = 0; #if !CYTHON_METH_FASTCALL CYTHON_UNUSED Py_ssize_t __pyx_nargs; #endif CYTHON_UNUSED PyObject *const *__pyx_kwvalues; - PyObject* values[2] = {0,0}; + PyObject* values[1] = {0}; int __pyx_lineno = 0; const char *__pyx_filename = NULL; int __pyx_clineno = 0; PyObject *__pyx_r = 0; __Pyx_RefNannyDeclarations - __Pyx_RefNannySetupContext("__init__ (wrapper)", 0); + __Pyx_RefNannySetupContext("compile_to_function (wrapper)", 0); #if !CYTHON_METH_FASTCALL #if CYTHON_ASSUME_SAFE_MACROS __pyx_nargs = PyTuple_GET_SIZE(__pyx_args); @@ -18507,13 +18034,10 @@ PyObject *__pyx_args, PyObject *__pyx_kwds #endif __pyx_kwvalues = __Pyx_KwValues_FASTCALL(__pyx_args, __pyx_nargs); { - PyObject **__pyx_pyargnames[] = {&__pyx_n_s_self,&__pyx_n_s_process_mode,0}; - values[1] = __Pyx_Arg_NewRef_FASTCALL(((PyObject *)((PyObject *)Py_False))); + PyObject **__pyx_pyargnames[] = {&__pyx_n_s_constraint,0}; if (__pyx_kwds) { Py_ssize_t kw_args; switch (__pyx_nargs) { - case 2: values[1] = __Pyx_Arg_FASTCALL(__pyx_args, 1); - CYTHON_FALLTHROUGH; case 1: values[0] = __Pyx_Arg_FASTCALL(__pyx_args, 0); CYTHON_FALLTHROUGH; case 0: break; @@ -18522,39 +18046,27 @@ PyObject *__pyx_args, PyObject *__pyx_kwds kw_args = __Pyx_NumKwargs_FASTCALL(__pyx_kwds); switch (__pyx_nargs) { case 0: - if (likely((values[0] = __Pyx_GetKwValue_FASTCALL(__pyx_kwds, __pyx_kwvalues, __pyx_n_s_self)) != 0)) { + if (likely((values[0] = __Pyx_GetKwValue_FASTCALL(__pyx_kwds, __pyx_kwvalues, __pyx_n_s_constraint)) != 0)) { (void)__Pyx_Arg_NewRef_FASTCALL(values[0]); kw_args--; } - else if (unlikely(PyErr_Occurred())) __PYX_ERR(0, 742, __pyx_L3_error) + else if (unlikely(PyErr_Occurred())) __PYX_ERR(0, 701, __pyx_L3_error) else goto __pyx_L5_argtuple_error; - CYTHON_FALLTHROUGH; - case 1: - if (kw_args > 0) { - PyObject* value = __Pyx_GetKwValue_FASTCALL(__pyx_kwds, __pyx_kwvalues, __pyx_n_s_process_mode); - if (value) { values[1] = __Pyx_Arg_NewRef_FASTCALL(value); kw_args--; } - else if (unlikely(PyErr_Occurred())) __PYX_ERR(0, 742, __pyx_L3_error) - } } if (unlikely(kw_args > 0)) { const Py_ssize_t kwd_pos_args = __pyx_nargs; - if (unlikely(__Pyx_ParseOptionalKeywords(__pyx_kwds, __pyx_kwvalues, __pyx_pyargnames, 0, values + 0, kwd_pos_args, "__init__") < 0)) __PYX_ERR(0, 742, __pyx_L3_error) + if (unlikely(__Pyx_ParseOptionalKeywords(__pyx_kwds, __pyx_kwvalues, __pyx_pyargnames, 0, values + 0, kwd_pos_args, "compile_to_function") < 0)) __PYX_ERR(0, 701, __pyx_L3_error) } + } else if (unlikely(__pyx_nargs != 1)) { + goto __pyx_L5_argtuple_error; } else { - switch (__pyx_nargs) { - case 2: values[1] = __Pyx_Arg_FASTCALL(__pyx_args, 1); - CYTHON_FALLTHROUGH; - case 1: values[0] = __Pyx_Arg_FASTCALL(__pyx_args, 0); - break; - default: goto __pyx_L5_argtuple_error; - } + values[0] = __Pyx_Arg_FASTCALL(__pyx_args, 0); } - __pyx_v_self = values[0]; - __pyx_v_process_mode = values[1]; + __pyx_v_constraint = values[0]; } goto __pyx_L6_skip; __pyx_L5_argtuple_error:; - __Pyx_RaiseArgtupleInvalid("__init__", 0, 1, 2, __pyx_nargs); __PYX_ERR(0, 742, __pyx_L3_error) + __Pyx_RaiseArgtupleInvalid("compile_to_function", 1, 1, 1, __pyx_nargs); __PYX_ERR(0, 701, __pyx_L3_error) __pyx_L6_skip:; goto __pyx_L4_argument_unpacking_done; __pyx_L3_error:; @@ -18564,11 +18076,11 @@ PyObject *__pyx_args, PyObject *__pyx_kwds __Pyx_Arg_XDECREF_FASTCALL(values[__pyx_temp]); } } - __Pyx_AddTraceback("constraint.solvers.ParallelSolver.__init__", __pyx_clineno, __pyx_lineno, __pyx_filename); + __Pyx_AddTraceback("constraint.solvers.compile_to_function", __pyx_clineno, __pyx_lineno, __pyx_filename); __Pyx_RefNannyFinishContext(); return NULL; __pyx_L4_argument_unpacking_done:; - __pyx_r = __pyx_pf_10constraint_7solvers_14ParallelSolver___init__(__pyx_self, __pyx_v_self, __pyx_v_process_mode); + __pyx_r = __pyx_pf_10constraint_7solvers_6compile_to_function(__pyx_self, __pyx_v_constraint); /* function exit code */ { @@ -18581,136 +18093,193 @@ PyObject *__pyx_args, PyObject *__pyx_kwds return __pyx_r; } -static PyObject *__pyx_pf_10constraint_7solvers_14ParallelSolver___init__(CYTHON_UNUSED PyObject *__pyx_self, PyObject *__pyx_v_self, PyObject *__pyx_v_process_mode) { +static PyObject *__pyx_pf_10constraint_7solvers_6compile_to_function(CYTHON_UNUSED PyObject *__pyx_self, PyObject *__pyx_v_constraint) { + PyObject *__pyx_v_func_string = NULL; + PyObject *__pyx_v_code_object = NULL; + PyObject *__pyx_v_func = NULL; PyObject *__pyx_r = NULL; __Pyx_RefNannyDeclarations PyObject *__pyx_t_1 = NULL; PyObject *__pyx_t_2 = NULL; PyObject *__pyx_t_3 = NULL; - unsigned int __pyx_t_4; + PyObject *__pyx_t_4 = NULL; + PyObject *__pyx_t_5 = NULL; + unsigned int __pyx_t_6; int __pyx_lineno = 0; const char *__pyx_filename = NULL; int __pyx_clineno = 0; - __Pyx_RefNannySetupContext("__init__", 1); + __Pyx_RefNannySetupContext("compile_to_function", 1); - /* "constraint/solvers.py":744 - * def __init__(self, process_mode=False): - * """Initialization method. Set `process_mode` to True for using ProcessPool, otherwise uses ThreadPool.""" - * super().__init__() # <<<<<<<<<<<<<< - * self._process_mode = process_mode - * self.requires_pickling = process_mode + /* "constraint/solvers.py":703 + * def compile_to_function(constraint: CompilableFunctionConstraint) -> FunctionConstraint: + * """Compile a CompilableFunctionConstraint to a function, wrapped by a FunctionConstraint.""" + * func_string = constraint._func # <<<<<<<<<<<<<< + * code_object = compile(func_string, "", "exec") + * func = FunctionType(code_object.co_consts[0], globals()) */ - __pyx_t_2 = __Pyx_CyFunction_GetClassObj(__pyx_self); - if (!__pyx_t_2) { PyErr_SetString(PyExc_SystemError, "super(): empty __class__ cell"); __PYX_ERR(0, 744, __pyx_L1_error) } - __Pyx_INCREF(__pyx_t_2); - __pyx_t_3 = PyTuple_New(2); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 744, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_3); - __Pyx_GIVEREF(__pyx_t_2); - if (__Pyx_PyTuple_SET_ITEM(__pyx_t_3, 0, __pyx_t_2)) __PYX_ERR(0, 744, __pyx_L1_error); - __Pyx_INCREF(__pyx_v_self); - __Pyx_GIVEREF(__pyx_v_self); - if (__Pyx_PyTuple_SET_ITEM(__pyx_t_3, 1, __pyx_v_self)) __PYX_ERR(0, 744, __pyx_L1_error); - __pyx_t_2 = 0; - __pyx_t_2 = __Pyx_PyObject_Call(__pyx_builtin_super, __pyx_t_3, NULL); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 744, __pyx_L1_error) + __pyx_t_1 = __Pyx_PyObject_GetAttrStr(__pyx_v_constraint, __pyx_n_s_func); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 703, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __pyx_v_func_string = __pyx_t_1; + __pyx_t_1 = 0; + + /* "constraint/solvers.py":704 + * """Compile a CompilableFunctionConstraint to a function, wrapped by a FunctionConstraint.""" + * func_string = constraint._func + * code_object = compile(func_string, "", "exec") # <<<<<<<<<<<<<< + * func = FunctionType(code_object.co_consts[0], globals()) + * return FunctionConstraint(func) + */ + __pyx_t_1 = PyTuple_New(3); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 704, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __Pyx_INCREF(__pyx_v_func_string); + __Pyx_GIVEREF(__pyx_v_func_string); + if (__Pyx_PyTuple_SET_ITEM(__pyx_t_1, 0, __pyx_v_func_string)) __PYX_ERR(0, 704, __pyx_L1_error); + __Pyx_INCREF(__pyx_kp_u_string); + __Pyx_GIVEREF(__pyx_kp_u_string); + if (__Pyx_PyTuple_SET_ITEM(__pyx_t_1, 1, __pyx_kp_u_string)) __PYX_ERR(0, 704, __pyx_L1_error); + __Pyx_INCREF(__pyx_n_u_exec); + __Pyx_GIVEREF(__pyx_n_u_exec); + if (__Pyx_PyTuple_SET_ITEM(__pyx_t_1, 2, __pyx_n_u_exec)) __PYX_ERR(0, 704, __pyx_L1_error); + __pyx_t_2 = __Pyx_PyObject_Call(__pyx_builtin_compile, __pyx_t_1, NULL); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 704, __pyx_L1_error) __Pyx_GOTREF(__pyx_t_2); + __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; + __pyx_v_code_object = __pyx_t_2; + __pyx_t_2 = 0; + + /* "constraint/solvers.py":705 + * func_string = constraint._func + * code_object = compile(func_string, "", "exec") + * func = FunctionType(code_object.co_consts[0], globals()) # <<<<<<<<<<<<<< + * return FunctionConstraint(func) + * + */ + __Pyx_GetModuleGlobalName(__pyx_t_1, __pyx_n_s_FunctionType); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 705, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __pyx_t_3 = __Pyx_PyObject_GetAttrStr(__pyx_v_code_object, __pyx_n_s_co_consts); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 705, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_3); + __pyx_t_4 = __Pyx_GetItemInt(__pyx_t_3, 0, long, 1, __Pyx_PyInt_From_long, 0, 0, 1); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 705, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_4); __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; - __pyx_t_3 = __Pyx_PyObject_GetAttrStr(__pyx_t_2, __pyx_n_s_init); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 744, __pyx_L1_error) + __pyx_t_3 = __Pyx_Globals(); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 705, __pyx_L1_error) __Pyx_GOTREF(__pyx_t_3); - __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; - __pyx_t_2 = NULL; - __pyx_t_4 = 0; + __pyx_t_5 = NULL; + __pyx_t_6 = 0; #if CYTHON_UNPACK_METHODS - if (likely(PyMethod_Check(__pyx_t_3))) { - __pyx_t_2 = PyMethod_GET_SELF(__pyx_t_3); - if (likely(__pyx_t_2)) { - PyObject* function = PyMethod_GET_FUNCTION(__pyx_t_3); - __Pyx_INCREF(__pyx_t_2); + if (unlikely(PyMethod_Check(__pyx_t_1))) { + __pyx_t_5 = PyMethod_GET_SELF(__pyx_t_1); + if (likely(__pyx_t_5)) { + PyObject* function = PyMethod_GET_FUNCTION(__pyx_t_1); + __Pyx_INCREF(__pyx_t_5); __Pyx_INCREF(function); - __Pyx_DECREF_SET(__pyx_t_3, function); - __pyx_t_4 = 1; + __Pyx_DECREF_SET(__pyx_t_1, function); + __pyx_t_6 = 1; } } #endif { - PyObject *__pyx_callargs[2] = {__pyx_t_2, NULL}; - __pyx_t_1 = __Pyx_PyObject_FastCall(__pyx_t_3, __pyx_callargs+1-__pyx_t_4, 0+__pyx_t_4); - __Pyx_XDECREF(__pyx_t_2); __pyx_t_2 = 0; - if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 744, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_1); + PyObject *__pyx_callargs[3] = {__pyx_t_5, __pyx_t_4, __pyx_t_3}; + __pyx_t_2 = __Pyx_PyObject_FastCall(__pyx_t_1, __pyx_callargs+1-__pyx_t_6, 2+__pyx_t_6); + __Pyx_XDECREF(__pyx_t_5); __pyx_t_5 = 0; + __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; + if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 705, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_2); + __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; } - __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; - - /* "constraint/solvers.py":745 - * """Initialization method. Set `process_mode` to True for using ProcessPool, otherwise uses ThreadPool.""" - * super().__init__() - * self._process_mode = process_mode # <<<<<<<<<<<<<< - * self.requires_pickling = process_mode - * - */ - if (__Pyx_PyObject_SetAttrStr(__pyx_v_self, __pyx_n_s_process_mode_2, __pyx_v_process_mode) < 0) __PYX_ERR(0, 745, __pyx_L1_error) + __pyx_v_func = __pyx_t_2; + __pyx_t_2 = 0; - /* "constraint/solvers.py":746 - * super().__init__() - * self._process_mode = process_mode - * self.requires_pickling = process_mode # <<<<<<<<<<<<<< + /* "constraint/solvers.py":706 + * code_object = compile(func_string, "", "exec") + * func = FunctionType(code_object.co_consts[0], globals()) + * return FunctionConstraint(func) # <<<<<<<<<<<<<< * - * def getSolution(self, domains: dict, constraints: list[tuple], vconstraints: dict): + * def sequential_recursive_backtrack(assignment: dict[Hashable, any], unassigned_vars: list[Hashable], domains: dict[Hashable, Domain], constraint_lookup: dict[Hashable, list[tuple[Constraint, Hashable]]]) -> list[dict[Hashable, any]]: # noqa E501 */ - if (__Pyx_PyObject_SetAttrStr(__pyx_v_self, __pyx_n_s_requires_pickling, __pyx_v_process_mode) < 0) __PYX_ERR(0, 746, __pyx_L1_error) + __Pyx_XDECREF(__pyx_r); + __Pyx_GetModuleGlobalName(__pyx_t_1, __pyx_n_s_FunctionConstraint); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 706, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __pyx_t_3 = NULL; + __pyx_t_6 = 0; + #if CYTHON_UNPACK_METHODS + if (unlikely(PyMethod_Check(__pyx_t_1))) { + __pyx_t_3 = PyMethod_GET_SELF(__pyx_t_1); + if (likely(__pyx_t_3)) { + PyObject* function = PyMethod_GET_FUNCTION(__pyx_t_1); + __Pyx_INCREF(__pyx_t_3); + __Pyx_INCREF(function); + __Pyx_DECREF_SET(__pyx_t_1, function); + __pyx_t_6 = 1; + } + } + #endif + { + PyObject *__pyx_callargs[2] = {__pyx_t_3, __pyx_v_func}; + __pyx_t_2 = __Pyx_PyObject_FastCall(__pyx_t_1, __pyx_callargs+1-__pyx_t_6, 1+__pyx_t_6); + __Pyx_XDECREF(__pyx_t_3); __pyx_t_3 = 0; + if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 706, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_2); + __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; + } + __pyx_r = __pyx_t_2; + __pyx_t_2 = 0; + goto __pyx_L0; - /* "constraint/solvers.py":742 - * """ # noqa E501 + /* "constraint/solvers.py":701 + * ) * - * def __init__(self, process_mode=False): # <<<<<<<<<<<<<< - * """Initialization method. Set `process_mode` to True for using ProcessPool, otherwise uses ThreadPool.""" - * super().__init__() + * def compile_to_function(constraint: CompilableFunctionConstraint) -> FunctionConstraint: # <<<<<<<<<<<<<< + * """Compile a CompilableFunctionConstraint to a function, wrapped by a FunctionConstraint.""" + * func_string = constraint._func */ /* function exit code */ - __pyx_r = Py_None; __Pyx_INCREF(Py_None); - goto __pyx_L0; __pyx_L1_error:; __Pyx_XDECREF(__pyx_t_1); __Pyx_XDECREF(__pyx_t_2); __Pyx_XDECREF(__pyx_t_3); - __Pyx_AddTraceback("constraint.solvers.ParallelSolver.__init__", __pyx_clineno, __pyx_lineno, __pyx_filename); + __Pyx_XDECREF(__pyx_t_4); + __Pyx_XDECREF(__pyx_t_5); + __Pyx_AddTraceback("constraint.solvers.compile_to_function", __pyx_clineno, __pyx_lineno, __pyx_filename); __pyx_r = NULL; __pyx_L0:; + __Pyx_XDECREF(__pyx_v_func_string); + __Pyx_XDECREF(__pyx_v_code_object); + __Pyx_XDECREF(__pyx_v_func); __Pyx_XGIVEREF(__pyx_r); __Pyx_RefNannyFinishContext(); return __pyx_r; } -/* "constraint/solvers.py":748 - * self.requires_pickling = process_mode - * - * def getSolution(self, domains: dict, constraints: list[tuple], vconstraints: dict): # <<<<<<<<<<<<<< - * """Return one solution for the given problem. +/* "constraint/solvers.py":708 + * return FunctionConstraint(func) * + * def sequential_recursive_backtrack(assignment: dict[Hashable, any], unassigned_vars: list[Hashable], domains: dict[Hashable, Domain], constraint_lookup: dict[Hashable, list[tuple[Constraint, Hashable]]]) -> list[dict[Hashable, any]]: # noqa E501 # <<<<<<<<<<<<<< + * """Sequential recursive backtracking function for subproblems.""" + * if not unassigned_vars: */ /* Python wrapper */ -static PyObject *__pyx_pw_10constraint_7solvers_14ParallelSolver_3getSolution(PyObject *__pyx_self, +static PyObject *__pyx_pw_10constraint_7solvers_9sequential_recursive_backtrack(PyObject *__pyx_self, #if CYTHON_METH_FASTCALL PyObject *const *__pyx_args, Py_ssize_t __pyx_nargs, PyObject *__pyx_kwds #else PyObject *__pyx_args, PyObject *__pyx_kwds #endif ); /*proto*/ -PyDoc_STRVAR(__pyx_doc_10constraint_7solvers_14ParallelSolver_2getSolution, "Return one solution for the given problem.\n\n Args:\n domains (dict): Dictionary mapping variables to their domains\n constraints (list): List of pairs of (constraint, variables)\n vconstraints (dict): Dictionary mapping variables to a list\n of constraints affecting the given variables.\n "); -static PyMethodDef __pyx_mdef_10constraint_7solvers_14ParallelSolver_3getSolution = {"getSolution", (PyCFunction)(void*)(__Pyx_PyCFunction_FastCallWithKeywords)__pyx_pw_10constraint_7solvers_14ParallelSolver_3getSolution, __Pyx_METH_FASTCALL|METH_KEYWORDS, __pyx_doc_10constraint_7solvers_14ParallelSolver_2getSolution}; -static PyObject *__pyx_pw_10constraint_7solvers_14ParallelSolver_3getSolution(PyObject *__pyx_self, +PyDoc_STRVAR(__pyx_doc_10constraint_7solvers_8sequential_recursive_backtrack, "Sequential recursive backtracking function for subproblems."); +static PyMethodDef __pyx_mdef_10constraint_7solvers_9sequential_recursive_backtrack = {"sequential_recursive_backtrack", (PyCFunction)(void*)(__Pyx_PyCFunction_FastCallWithKeywords)__pyx_pw_10constraint_7solvers_9sequential_recursive_backtrack, __Pyx_METH_FASTCALL|METH_KEYWORDS, __pyx_doc_10constraint_7solvers_8sequential_recursive_backtrack}; +static PyObject *__pyx_pw_10constraint_7solvers_9sequential_recursive_backtrack(PyObject *__pyx_self, #if CYTHON_METH_FASTCALL PyObject *const *__pyx_args, Py_ssize_t __pyx_nargs, PyObject *__pyx_kwds #else PyObject *__pyx_args, PyObject *__pyx_kwds #endif ) { - PyObject *__pyx_v_self = 0; - CYTHON_UNUSED PyObject *__pyx_v_domains = 0; - CYTHON_UNUSED PyObject *__pyx_v_constraints = 0; - CYTHON_UNUSED PyObject *__pyx_v_vconstraints = 0; + PyObject *__pyx_v_assignment = 0; + PyObject *__pyx_v_unassigned_vars = 0; + PyObject *__pyx_v_domains = 0; + PyObject *__pyx_v_constraint_lookup = 0; #if !CYTHON_METH_FASTCALL CYTHON_UNUSED Py_ssize_t __pyx_nargs; #endif @@ -18721,7 +18290,7 @@ PyObject *__pyx_args, PyObject *__pyx_kwds int __pyx_clineno = 0; PyObject *__pyx_r = 0; __Pyx_RefNannyDeclarations - __Pyx_RefNannySetupContext("getSolution (wrapper)", 0); + __Pyx_RefNannySetupContext("sequential_recursive_backtrack (wrapper)", 0); #if !CYTHON_METH_FASTCALL #if CYTHON_ASSUME_SAFE_MACROS __pyx_nargs = PyTuple_GET_SIZE(__pyx_args); @@ -18731,7 +18300,7 @@ PyObject *__pyx_args, PyObject *__pyx_kwds #endif __pyx_kwvalues = __Pyx_KwValues_FASTCALL(__pyx_args, __pyx_nargs); { - PyObject **__pyx_pyargnames[] = {&__pyx_n_s_self,&__pyx_n_s_domains,&__pyx_n_s_constraints,&__pyx_n_s_vconstraints,0}; + PyObject **__pyx_pyargnames[] = {&__pyx_n_s_assignment,&__pyx_n_s_unassigned_vars,&__pyx_n_s_domains,&__pyx_n_s_constraint_lookup,0}; if (__pyx_kwds) { Py_ssize_t kw_args; switch (__pyx_nargs) { @@ -18749,46 +18318,46 @@ PyObject *__pyx_args, PyObject *__pyx_kwds kw_args = __Pyx_NumKwargs_FASTCALL(__pyx_kwds); switch (__pyx_nargs) { case 0: - if (likely((values[0] = __Pyx_GetKwValue_FASTCALL(__pyx_kwds, __pyx_kwvalues, __pyx_n_s_self)) != 0)) { + if (likely((values[0] = __Pyx_GetKwValue_FASTCALL(__pyx_kwds, __pyx_kwvalues, __pyx_n_s_assignment)) != 0)) { (void)__Pyx_Arg_NewRef_FASTCALL(values[0]); kw_args--; } - else if (unlikely(PyErr_Occurred())) __PYX_ERR(0, 748, __pyx_L3_error) + else if (unlikely(PyErr_Occurred())) __PYX_ERR(0, 708, __pyx_L3_error) else goto __pyx_L5_argtuple_error; CYTHON_FALLTHROUGH; case 1: - if (likely((values[1] = __Pyx_GetKwValue_FASTCALL(__pyx_kwds, __pyx_kwvalues, __pyx_n_s_domains)) != 0)) { + if (likely((values[1] = __Pyx_GetKwValue_FASTCALL(__pyx_kwds, __pyx_kwvalues, __pyx_n_s_unassigned_vars)) != 0)) { (void)__Pyx_Arg_NewRef_FASTCALL(values[1]); kw_args--; } - else if (unlikely(PyErr_Occurred())) __PYX_ERR(0, 748, __pyx_L3_error) + else if (unlikely(PyErr_Occurred())) __PYX_ERR(0, 708, __pyx_L3_error) else { - __Pyx_RaiseArgtupleInvalid("getSolution", 1, 4, 4, 1); __PYX_ERR(0, 748, __pyx_L3_error) + __Pyx_RaiseArgtupleInvalid("sequential_recursive_backtrack", 1, 4, 4, 1); __PYX_ERR(0, 708, __pyx_L3_error) } CYTHON_FALLTHROUGH; case 2: - if (likely((values[2] = __Pyx_GetKwValue_FASTCALL(__pyx_kwds, __pyx_kwvalues, __pyx_n_s_constraints)) != 0)) { + if (likely((values[2] = __Pyx_GetKwValue_FASTCALL(__pyx_kwds, __pyx_kwvalues, __pyx_n_s_domains)) != 0)) { (void)__Pyx_Arg_NewRef_FASTCALL(values[2]); kw_args--; } - else if (unlikely(PyErr_Occurred())) __PYX_ERR(0, 748, __pyx_L3_error) + else if (unlikely(PyErr_Occurred())) __PYX_ERR(0, 708, __pyx_L3_error) else { - __Pyx_RaiseArgtupleInvalid("getSolution", 1, 4, 4, 2); __PYX_ERR(0, 748, __pyx_L3_error) + __Pyx_RaiseArgtupleInvalid("sequential_recursive_backtrack", 1, 4, 4, 2); __PYX_ERR(0, 708, __pyx_L3_error) } CYTHON_FALLTHROUGH; case 3: - if (likely((values[3] = __Pyx_GetKwValue_FASTCALL(__pyx_kwds, __pyx_kwvalues, __pyx_n_s_vconstraints)) != 0)) { + if (likely((values[3] = __Pyx_GetKwValue_FASTCALL(__pyx_kwds, __pyx_kwvalues, __pyx_n_s_constraint_lookup)) != 0)) { (void)__Pyx_Arg_NewRef_FASTCALL(values[3]); kw_args--; } - else if (unlikely(PyErr_Occurred())) __PYX_ERR(0, 748, __pyx_L3_error) + else if (unlikely(PyErr_Occurred())) __PYX_ERR(0, 708, __pyx_L3_error) else { - __Pyx_RaiseArgtupleInvalid("getSolution", 1, 4, 4, 3); __PYX_ERR(0, 748, __pyx_L3_error) + __Pyx_RaiseArgtupleInvalid("sequential_recursive_backtrack", 1, 4, 4, 3); __PYX_ERR(0, 708, __pyx_L3_error) } } if (unlikely(kw_args > 0)) { const Py_ssize_t kwd_pos_args = __pyx_nargs; - if (unlikely(__Pyx_ParseOptionalKeywords(__pyx_kwds, __pyx_kwvalues, __pyx_pyargnames, 0, values + 0, kwd_pos_args, "getSolution") < 0)) __PYX_ERR(0, 748, __pyx_L3_error) + if (unlikely(__Pyx_ParseOptionalKeywords(__pyx_kwds, __pyx_kwvalues, __pyx_pyargnames, 0, values + 0, kwd_pos_args, "sequential_recursive_backtrack") < 0)) __PYX_ERR(0, 708, __pyx_L3_error) } } else if (unlikely(__pyx_nargs != 4)) { goto __pyx_L5_argtuple_error; @@ -18798,14 +18367,14 @@ PyObject *__pyx_args, PyObject *__pyx_kwds values[2] = __Pyx_Arg_FASTCALL(__pyx_args, 2); values[3] = __Pyx_Arg_FASTCALL(__pyx_args, 3); } - __pyx_v_self = values[0]; - __pyx_v_domains = ((PyObject*)values[1]); - __pyx_v_constraints = ((PyObject*)values[2]); - __pyx_v_vconstraints = ((PyObject*)values[3]); + __pyx_v_assignment = ((PyObject*)values[0]); + __pyx_v_unassigned_vars = ((PyObject*)values[1]); + __pyx_v_domains = ((PyObject*)values[2]); + __pyx_v_constraint_lookup = ((PyObject*)values[3]); } goto __pyx_L6_skip; __pyx_L5_argtuple_error:; - __Pyx_RaiseArgtupleInvalid("getSolution", 1, 4, 4, __pyx_nargs); __PYX_ERR(0, 748, __pyx_L3_error) + __Pyx_RaiseArgtupleInvalid("sequential_recursive_backtrack", 1, 4, 4, __pyx_nargs); __PYX_ERR(0, 708, __pyx_L3_error) __pyx_L6_skip:; goto __pyx_L4_argument_unpacking_done; __pyx_L3_error:; @@ -18815,134 +18384,382 @@ PyObject *__pyx_args, PyObject *__pyx_kwds __Pyx_Arg_XDECREF_FASTCALL(values[__pyx_temp]); } } - __Pyx_AddTraceback("constraint.solvers.ParallelSolver.getSolution", __pyx_clineno, __pyx_lineno, __pyx_filename); + __Pyx_AddTraceback("constraint.solvers.sequential_recursive_backtrack", __pyx_clineno, __pyx_lineno, __pyx_filename); __Pyx_RefNannyFinishContext(); return NULL; __pyx_L4_argument_unpacking_done:; - if (unlikely(!__Pyx_ArgTypeTest(((PyObject *)__pyx_v_domains), (&PyDict_Type), 0, "domains", 1))) __PYX_ERR(0, 748, __pyx_L1_error) - if (unlikely(!__Pyx_ArgTypeTest(((PyObject *)__pyx_v_constraints), (&PyList_Type), 0, "constraints", 1))) __PYX_ERR(0, 748, __pyx_L1_error) - if (unlikely(!__Pyx_ArgTypeTest(((PyObject *)__pyx_v_vconstraints), (&PyDict_Type), 0, "vconstraints", 1))) __PYX_ERR(0, 748, __pyx_L1_error) - __pyx_r = __pyx_pf_10constraint_7solvers_14ParallelSolver_2getSolution(__pyx_self, __pyx_v_self, __pyx_v_domains, __pyx_v_constraints, __pyx_v_vconstraints); + if (unlikely(!__Pyx_ArgTypeTest(((PyObject *)__pyx_v_assignment), (&PyDict_Type), 0, "assignment", 1))) __PYX_ERR(0, 708, __pyx_L1_error) + if (unlikely(!__Pyx_ArgTypeTest(((PyObject *)__pyx_v_unassigned_vars), (&PyList_Type), 0, "unassigned_vars", 1))) __PYX_ERR(0, 708, __pyx_L1_error) + if (unlikely(!__Pyx_ArgTypeTest(((PyObject *)__pyx_v_domains), (&PyDict_Type), 0, "domains", 1))) __PYX_ERR(0, 708, __pyx_L1_error) + if (unlikely(!__Pyx_ArgTypeTest(((PyObject *)__pyx_v_constraint_lookup), (&PyDict_Type), 0, "constraint_lookup", 1))) __PYX_ERR(0, 708, __pyx_L1_error) + __pyx_r = __pyx_pf_10constraint_7solvers_8sequential_recursive_backtrack(__pyx_self, __pyx_v_assignment, __pyx_v_unassigned_vars, __pyx_v_domains, __pyx_v_constraint_lookup); + + /* function exit code */ + goto __pyx_L0; + __pyx_L1_error:; + __pyx_r = NULL; + __pyx_L0:; + { + Py_ssize_t __pyx_temp; + for (__pyx_temp=0; __pyx_temp < (Py_ssize_t)(sizeof(values)/sizeof(values[0])); ++__pyx_temp) { + __Pyx_Arg_XDECREF_FASTCALL(values[__pyx_temp]); + } + } + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +static PyObject *__pyx_pf_10constraint_7solvers_8sequential_recursive_backtrack(CYTHON_UNUSED PyObject *__pyx_self, PyObject *__pyx_v_assignment, PyObject *__pyx_v_unassigned_vars, PyObject *__pyx_v_domains, PyObject *__pyx_v_constraint_lookup) { + PyObject *__pyx_v_var = NULL; + PyObject *__pyx_v_remaining_vars = NULL; + PyObject *__pyx_v_solutions = 0; + PyObject *__pyx_v_value = NULL; + PyObject *__pyx_r = NULL; + __Pyx_RefNannyDeclarations + int __pyx_t_1; + int __pyx_t_2; + PyObject *__pyx_t_3 = NULL; + PyObject *__pyx_t_4 = NULL; + Py_ssize_t __pyx_t_5; + PyObject *(*__pyx_t_6)(PyObject *); + PyObject *__pyx_t_7 = NULL; + PyObject *__pyx_t_8 = NULL; + PyObject *__pyx_t_9 = NULL; + unsigned int __pyx_t_10; + int __pyx_t_11; + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + __Pyx_RefNannySetupContext("sequential_recursive_backtrack", 1); + + /* "constraint/solvers.py":710 + * def sequential_recursive_backtrack(assignment: dict[Hashable, any], unassigned_vars: list[Hashable], domains: dict[Hashable, Domain], constraint_lookup: dict[Hashable, list[tuple[Constraint, Hashable]]]) -> list[dict[Hashable, any]]: # noqa E501 + * """Sequential recursive backtracking function for subproblems.""" + * if not unassigned_vars: # <<<<<<<<<<<<<< + * return [assignment.copy()] + * + */ + __pyx_t_1 = (PyList_GET_SIZE(__pyx_v_unassigned_vars) != 0); + __pyx_t_2 = (!__pyx_t_1); + if (__pyx_t_2) { + + /* "constraint/solvers.py":711 + * """Sequential recursive backtracking function for subproblems.""" + * if not unassigned_vars: + * return [assignment.copy()] # <<<<<<<<<<<<<< + * + * var = unassigned_vars[-1] + */ + __Pyx_XDECREF(__pyx_r); + __pyx_t_3 = PyDict_Copy(__pyx_v_assignment); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 711, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_3); + __pyx_t_4 = PyList_New(1); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 711, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_4); + __Pyx_GIVEREF(__pyx_t_3); + if (__Pyx_PyList_SET_ITEM(__pyx_t_4, 0, __pyx_t_3)) __PYX_ERR(0, 711, __pyx_L1_error); + __pyx_t_3 = 0; + __pyx_r = ((PyObject*)__pyx_t_4); + __pyx_t_4 = 0; + goto __pyx_L0; + + /* "constraint/solvers.py":710 + * def sequential_recursive_backtrack(assignment: dict[Hashable, any], unassigned_vars: list[Hashable], domains: dict[Hashable, Domain], constraint_lookup: dict[Hashable, list[tuple[Constraint, Hashable]]]) -> list[dict[Hashable, any]]: # noqa E501 + * """Sequential recursive backtracking function for subproblems.""" + * if not unassigned_vars: # <<<<<<<<<<<<<< + * return [assignment.copy()] + * + */ + } + + /* "constraint/solvers.py":713 + * return [assignment.copy()] + * + * var = unassigned_vars[-1] # <<<<<<<<<<<<<< + * remaining_vars = unassigned_vars[:-1] + * + */ + __pyx_t_4 = __Pyx_GetItemInt_List(__pyx_v_unassigned_vars, -1L, long, 1, __Pyx_PyInt_From_long, 1, 1, 1); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 713, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_4); + __pyx_v_var = __pyx_t_4; + __pyx_t_4 = 0; + + /* "constraint/solvers.py":714 + * + * var = unassigned_vars[-1] + * remaining_vars = unassigned_vars[:-1] # <<<<<<<<<<<<<< + * + * solutions: list[dict[Hashable, any]] = [] + */ + __pyx_t_4 = __Pyx_PyList_GetSlice(__pyx_v_unassigned_vars, 0, -1L); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 714, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_4); + __pyx_v_remaining_vars = ((PyObject*)__pyx_t_4); + __pyx_t_4 = 0; + + /* "constraint/solvers.py":716 + * remaining_vars = unassigned_vars[:-1] + * + * solutions: list[dict[Hashable, any]] = [] # <<<<<<<<<<<<<< + * for value in domains[var]: + * assignment[var] = value + */ + __pyx_t_4 = PyList_New(0); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 716, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_4); + __pyx_v_solutions = ((PyObject*)__pyx_t_4); + __pyx_t_4 = 0; + + /* "constraint/solvers.py":717 + * + * solutions: list[dict[Hashable, any]] = [] + * for value in domains[var]: # <<<<<<<<<<<<<< + * assignment[var] = value + * if is_valid(assignment, constraint_lookup[var], domains): + */ + __pyx_t_4 = __Pyx_PyDict_GetItem(__pyx_v_domains, __pyx_v_var); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 717, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_4); + if (likely(PyList_CheckExact(__pyx_t_4)) || PyTuple_CheckExact(__pyx_t_4)) { + __pyx_t_3 = __pyx_t_4; __Pyx_INCREF(__pyx_t_3); + __pyx_t_5 = 0; + __pyx_t_6 = NULL; + } else { + __pyx_t_5 = -1; __pyx_t_3 = PyObject_GetIter(__pyx_t_4); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 717, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_3); + __pyx_t_6 = __Pyx_PyObject_GetIterNextFunc(__pyx_t_3); if (unlikely(!__pyx_t_6)) __PYX_ERR(0, 717, __pyx_L1_error) + } + __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; + for (;;) { + if (likely(!__pyx_t_6)) { + if (likely(PyList_CheckExact(__pyx_t_3))) { + { + Py_ssize_t __pyx_temp = __Pyx_PyList_GET_SIZE(__pyx_t_3); + #if !CYTHON_ASSUME_SAFE_MACROS + if (unlikely((__pyx_temp < 0))) __PYX_ERR(0, 717, __pyx_L1_error) + #endif + if (__pyx_t_5 >= __pyx_temp) break; + } + #if CYTHON_ASSUME_SAFE_MACROS && !CYTHON_AVOID_BORROWED_REFS + __pyx_t_4 = PyList_GET_ITEM(__pyx_t_3, __pyx_t_5); __Pyx_INCREF(__pyx_t_4); __pyx_t_5++; if (unlikely((0 < 0))) __PYX_ERR(0, 717, __pyx_L1_error) + #else + __pyx_t_4 = __Pyx_PySequence_ITEM(__pyx_t_3, __pyx_t_5); __pyx_t_5++; if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 717, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_4); + #endif + } else { + { + Py_ssize_t __pyx_temp = __Pyx_PyTuple_GET_SIZE(__pyx_t_3); + #if !CYTHON_ASSUME_SAFE_MACROS + if (unlikely((__pyx_temp < 0))) __PYX_ERR(0, 717, __pyx_L1_error) + #endif + if (__pyx_t_5 >= __pyx_temp) break; + } + #if CYTHON_ASSUME_SAFE_MACROS && !CYTHON_AVOID_BORROWED_REFS + __pyx_t_4 = PyTuple_GET_ITEM(__pyx_t_3, __pyx_t_5); __Pyx_INCREF(__pyx_t_4); __pyx_t_5++; if (unlikely((0 < 0))) __PYX_ERR(0, 717, __pyx_L1_error) + #else + __pyx_t_4 = __Pyx_PySequence_ITEM(__pyx_t_3, __pyx_t_5); __pyx_t_5++; if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 717, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_4); + #endif + } + } else { + __pyx_t_4 = __pyx_t_6(__pyx_t_3); + if (unlikely(!__pyx_t_4)) { + PyObject* exc_type = PyErr_Occurred(); + if (exc_type) { + if (likely(__Pyx_PyErr_GivenExceptionMatches(exc_type, PyExc_StopIteration))) PyErr_Clear(); + else __PYX_ERR(0, 717, __pyx_L1_error) + } + break; + } + __Pyx_GOTREF(__pyx_t_4); + } + __Pyx_XDECREF_SET(__pyx_v_value, __pyx_t_4); + __pyx_t_4 = 0; + + /* "constraint/solvers.py":718 + * solutions: list[dict[Hashable, any]] = [] + * for value in domains[var]: + * assignment[var] = value # <<<<<<<<<<<<<< + * if is_valid(assignment, constraint_lookup[var], domains): + * solutions.extend(sequential_recursive_backtrack(assignment, remaining_vars, domains, constraint_lookup)) + */ + if (unlikely((PyDict_SetItem(__pyx_v_assignment, __pyx_v_var, __pyx_v_value) < 0))) __PYX_ERR(0, 718, __pyx_L1_error) + + /* "constraint/solvers.py":719 + * for value in domains[var]: + * assignment[var] = value + * if is_valid(assignment, constraint_lookup[var], domains): # <<<<<<<<<<<<<< + * solutions.extend(sequential_recursive_backtrack(assignment, remaining_vars, domains, constraint_lookup)) + * del assignment[var] + */ + __Pyx_GetModuleGlobalName(__pyx_t_7, __pyx_n_s_is_valid); if (unlikely(!__pyx_t_7)) __PYX_ERR(0, 719, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_7); + __pyx_t_8 = __Pyx_PyDict_GetItem(__pyx_v_constraint_lookup, __pyx_v_var); if (unlikely(!__pyx_t_8)) __PYX_ERR(0, 719, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_8); + __pyx_t_9 = NULL; + __pyx_t_10 = 0; + #if CYTHON_UNPACK_METHODS + if (unlikely(PyMethod_Check(__pyx_t_7))) { + __pyx_t_9 = PyMethod_GET_SELF(__pyx_t_7); + if (likely(__pyx_t_9)) { + PyObject* function = PyMethod_GET_FUNCTION(__pyx_t_7); + __Pyx_INCREF(__pyx_t_9); + __Pyx_INCREF(function); + __Pyx_DECREF_SET(__pyx_t_7, function); + __pyx_t_10 = 1; + } + } + #endif + { + PyObject *__pyx_callargs[4] = {__pyx_t_9, __pyx_v_assignment, __pyx_t_8, __pyx_v_domains}; + __pyx_t_4 = __Pyx_PyObject_FastCall(__pyx_t_7, __pyx_callargs+1-__pyx_t_10, 3+__pyx_t_10); + __Pyx_XDECREF(__pyx_t_9); __pyx_t_9 = 0; + __Pyx_DECREF(__pyx_t_8); __pyx_t_8 = 0; + if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 719, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_4); + __Pyx_DECREF(__pyx_t_7); __pyx_t_7 = 0; + } + __pyx_t_2 = __Pyx_PyObject_IsTrue(__pyx_t_4); if (unlikely((__pyx_t_2 < 0))) __PYX_ERR(0, 719, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; + if (__pyx_t_2) { + + /* "constraint/solvers.py":720 + * assignment[var] = value + * if is_valid(assignment, constraint_lookup[var], domains): + * solutions.extend(sequential_recursive_backtrack(assignment, remaining_vars, domains, constraint_lookup)) # <<<<<<<<<<<<<< + * del assignment[var] + * return solutions + */ + __Pyx_GetModuleGlobalName(__pyx_t_7, __pyx_n_s_sequential_recursive_backtrack); if (unlikely(!__pyx_t_7)) __PYX_ERR(0, 720, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_7); + __pyx_t_8 = NULL; + __pyx_t_10 = 0; + #if CYTHON_UNPACK_METHODS + if (unlikely(PyMethod_Check(__pyx_t_7))) { + __pyx_t_8 = PyMethod_GET_SELF(__pyx_t_7); + if (likely(__pyx_t_8)) { + PyObject* function = PyMethod_GET_FUNCTION(__pyx_t_7); + __Pyx_INCREF(__pyx_t_8); + __Pyx_INCREF(function); + __Pyx_DECREF_SET(__pyx_t_7, function); + __pyx_t_10 = 1; + } + } + #endif + { + PyObject *__pyx_callargs[5] = {__pyx_t_8, __pyx_v_assignment, __pyx_v_remaining_vars, __pyx_v_domains, __pyx_v_constraint_lookup}; + __pyx_t_4 = __Pyx_PyObject_FastCall(__pyx_t_7, __pyx_callargs+1-__pyx_t_10, 4+__pyx_t_10); + __Pyx_XDECREF(__pyx_t_8); __pyx_t_8 = 0; + if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 720, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_4); + __Pyx_DECREF(__pyx_t_7); __pyx_t_7 = 0; + } + __pyx_t_11 = __Pyx_PyList_Extend(__pyx_v_solutions, __pyx_t_4); if (unlikely(__pyx_t_11 == ((int)-1))) __PYX_ERR(0, 720, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; - /* function exit code */ - goto __pyx_L0; - __pyx_L1_error:; - __pyx_r = NULL; - __pyx_L0:; - { - Py_ssize_t __pyx_temp; - for (__pyx_temp=0; __pyx_temp < (Py_ssize_t)(sizeof(values)/sizeof(values[0])); ++__pyx_temp) { - __Pyx_Arg_XDECREF_FASTCALL(values[__pyx_temp]); + /* "constraint/solvers.py":719 + * for value in domains[var]: + * assignment[var] = value + * if is_valid(assignment, constraint_lookup[var], domains): # <<<<<<<<<<<<<< + * solutions.extend(sequential_recursive_backtrack(assignment, remaining_vars, domains, constraint_lookup)) + * del assignment[var] + */ } - } - __Pyx_RefNannyFinishContext(); - return __pyx_r; -} -static PyObject *__pyx_pf_10constraint_7solvers_14ParallelSolver_2getSolution(CYTHON_UNUSED PyObject *__pyx_self, PyObject *__pyx_v_self, CYTHON_UNUSED PyObject *__pyx_v_domains, CYTHON_UNUSED PyObject *__pyx_v_constraints, CYTHON_UNUSED PyObject *__pyx_v_vconstraints) { - PyObject *__pyx_v_msg = NULL; - PyObject *__pyx_r = NULL; - __Pyx_RefNannyDeclarations - PyObject *__pyx_t_1 = NULL; - PyObject *__pyx_t_2 = NULL; - int __pyx_lineno = 0; - const char *__pyx_filename = NULL; - int __pyx_clineno = 0; - __Pyx_RefNannySetupContext("getSolution", 1); - - /* "constraint/solvers.py":757 - * of constraints affecting the given variables. - * """ - * msg = f"{self.__class__.__name__} only provides all solutions" # <<<<<<<<<<<<<< - * raise NotImplementedError(msg) + /* "constraint/solvers.py":721 + * if is_valid(assignment, constraint_lookup[var], domains): + * solutions.extend(sequential_recursive_backtrack(assignment, remaining_vars, domains, constraint_lookup)) + * del assignment[var] # <<<<<<<<<<<<<< + * return solutions * */ - __pyx_t_1 = __Pyx_PyObject_GetAttrStr(__pyx_v_self, __pyx_n_s_class); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 757, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_1); - __pyx_t_2 = __Pyx_PyObject_GetAttrStr(__pyx_t_1, __pyx_n_s_name); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 757, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_2); - __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; - __pyx_t_1 = __Pyx_PyObject_FormatSimple(__pyx_t_2, __pyx_empty_unicode); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 757, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_1); - __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; - __pyx_t_2 = __Pyx_PyUnicode_ConcatInPlace(__pyx_t_1, __pyx_kp_u_only_provides_all_solutions); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 757, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_2); - __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; - __pyx_v_msg = ((PyObject*)__pyx_t_2); - __pyx_t_2 = 0; + if (unlikely((PyDict_DelItem(__pyx_v_assignment, __pyx_v_var) < 0))) __PYX_ERR(0, 721, __pyx_L1_error) - /* "constraint/solvers.py":758 - * """ - * msg = f"{self.__class__.__name__} only provides all solutions" - * raise NotImplementedError(msg) # <<<<<<<<<<<<<< + /* "constraint/solvers.py":717 * - * def getSolutionsList(self, domains: dict[Hashable, Domain], vconstraints: dict[Hashable, list[tuple[Constraint, Hashable]]]) -> list[dict[Hashable, any]]: # noqa: D102, E501 + * solutions: list[dict[Hashable, any]] = [] + * for value in domains[var]: # <<<<<<<<<<<<<< + * assignment[var] = value + * if is_valid(assignment, constraint_lookup[var], domains): */ - __pyx_t_2 = __Pyx_PyObject_CallOneArg(__pyx_builtin_NotImplementedError, __pyx_v_msg); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 758, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_2); - __Pyx_Raise(__pyx_t_2, 0, 0, 0); - __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; - __PYX_ERR(0, 758, __pyx_L1_error) + } + __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; - /* "constraint/solvers.py":748 - * self.requires_pickling = process_mode + /* "constraint/solvers.py":722 + * solutions.extend(sequential_recursive_backtrack(assignment, remaining_vars, domains, constraint_lookup)) + * del assignment[var] + * return solutions # <<<<<<<<<<<<<< * - * def getSolution(self, domains: dict, constraints: list[tuple], vconstraints: dict): # <<<<<<<<<<<<<< - * """Return one solution for the given problem. + * def sequential_optimized_backtrack(assignment: dict[Hashable, any], unassigned_vars: list[Hashable], domains: dict[Hashable, Domain], constraint_lookup: dict[Hashable, list[tuple[Constraint, Hashable]]]) -> list[dict[Hashable, any]]: # noqa E501 + */ + __Pyx_XDECREF(__pyx_r); + __Pyx_INCREF(__pyx_v_solutions); + __pyx_r = __pyx_v_solutions; + goto __pyx_L0; + + /* "constraint/solvers.py":708 + * return FunctionConstraint(func) * + * def sequential_recursive_backtrack(assignment: dict[Hashable, any], unassigned_vars: list[Hashable], domains: dict[Hashable, Domain], constraint_lookup: dict[Hashable, list[tuple[Constraint, Hashable]]]) -> list[dict[Hashable, any]]: # noqa E501 # <<<<<<<<<<<<<< + * """Sequential recursive backtracking function for subproblems.""" + * if not unassigned_vars: */ /* function exit code */ __pyx_L1_error:; - __Pyx_XDECREF(__pyx_t_1); - __Pyx_XDECREF(__pyx_t_2); - __Pyx_AddTraceback("constraint.solvers.ParallelSolver.getSolution", __pyx_clineno, __pyx_lineno, __pyx_filename); + __Pyx_XDECREF(__pyx_t_3); + __Pyx_XDECREF(__pyx_t_4); + __Pyx_XDECREF(__pyx_t_7); + __Pyx_XDECREF(__pyx_t_8); + __Pyx_XDECREF(__pyx_t_9); + __Pyx_AddTraceback("constraint.solvers.sequential_recursive_backtrack", __pyx_clineno, __pyx_lineno, __pyx_filename); __pyx_r = NULL; - __Pyx_XDECREF(__pyx_v_msg); + __pyx_L0:; + __Pyx_XDECREF(__pyx_v_var); + __Pyx_XDECREF(__pyx_v_remaining_vars); + __Pyx_XDECREF(__pyx_v_solutions); + __Pyx_XDECREF(__pyx_v_value); __Pyx_XGIVEREF(__pyx_r); __Pyx_RefNannyFinishContext(); return __pyx_r; } -/* "constraint/solvers.py":760 - * raise NotImplementedError(msg) +/* "constraint/solvers.py":724 + * return solutions * - * def getSolutionsList(self, domains: dict[Hashable, Domain], vconstraints: dict[Hashable, list[tuple[Constraint, Hashable]]]) -> list[dict[Hashable, any]]: # noqa: D102, E501 # <<<<<<<<<<<<<< - * """Parallelized all-solutions finder using ProcessPoolExecutor for work-stealing.""" - * # Precompute constraints lookup per variable + * def sequential_optimized_backtrack(assignment: dict[Hashable, any], unassigned_vars: list[Hashable], domains: dict[Hashable, Domain], constraint_lookup: dict[Hashable, list[tuple[Constraint, Hashable]]]) -> list[dict[Hashable, any]]: # noqa E501 # <<<<<<<<<<<<<< + * """Sequential optimized backtracking (as in OptimizedBacktrackingSolver) function for subproblems.""" + * # Does not do forwardcheck for simplicity */ /* Python wrapper */ -static PyObject *__pyx_pw_10constraint_7solvers_14ParallelSolver_5getSolutionsList(PyObject *__pyx_self, +static PyObject *__pyx_pw_10constraint_7solvers_11sequential_optimized_backtrack(PyObject *__pyx_self, #if CYTHON_METH_FASTCALL PyObject *const *__pyx_args, Py_ssize_t __pyx_nargs, PyObject *__pyx_kwds #else PyObject *__pyx_args, PyObject *__pyx_kwds #endif ); /*proto*/ -PyDoc_STRVAR(__pyx_doc_10constraint_7solvers_14ParallelSolver_4getSolutionsList, "Parallelized all-solutions finder using ProcessPoolExecutor for work-stealing."); -static PyMethodDef __pyx_mdef_10constraint_7solvers_14ParallelSolver_5getSolutionsList = {"getSolutionsList", (PyCFunction)(void*)(__Pyx_PyCFunction_FastCallWithKeywords)__pyx_pw_10constraint_7solvers_14ParallelSolver_5getSolutionsList, __Pyx_METH_FASTCALL|METH_KEYWORDS, __pyx_doc_10constraint_7solvers_14ParallelSolver_4getSolutionsList}; -static PyObject *__pyx_pw_10constraint_7solvers_14ParallelSolver_5getSolutionsList(PyObject *__pyx_self, +PyDoc_STRVAR(__pyx_doc_10constraint_7solvers_10sequential_optimized_backtrack, "Sequential optimized backtracking (as in OptimizedBacktrackingSolver) function for subproblems."); +static PyMethodDef __pyx_mdef_10constraint_7solvers_11sequential_optimized_backtrack = {"sequential_optimized_backtrack", (PyCFunction)(void*)(__Pyx_PyCFunction_FastCallWithKeywords)__pyx_pw_10constraint_7solvers_11sequential_optimized_backtrack, __Pyx_METH_FASTCALL|METH_KEYWORDS, __pyx_doc_10constraint_7solvers_10sequential_optimized_backtrack}; +static PyObject *__pyx_pw_10constraint_7solvers_11sequential_optimized_backtrack(PyObject *__pyx_self, #if CYTHON_METH_FASTCALL PyObject *const *__pyx_args, Py_ssize_t __pyx_nargs, PyObject *__pyx_kwds #else PyObject *__pyx_args, PyObject *__pyx_kwds #endif ) { - PyObject *__pyx_v_self = 0; + PyObject *__pyx_v_assignment = 0; + PyObject *__pyx_v_unassigned_vars = 0; PyObject *__pyx_v_domains = 0; - PyObject *__pyx_v_vconstraints = 0; + PyObject *__pyx_v_constraint_lookup = 0; #if !CYTHON_METH_FASTCALL CYTHON_UNUSED Py_ssize_t __pyx_nargs; #endif CYTHON_UNUSED PyObject *const *__pyx_kwvalues; - PyObject* values[3] = {0,0,0}; + PyObject* values[4] = {0,0,0,0}; int __pyx_lineno = 0; const char *__pyx_filename = NULL; int __pyx_clineno = 0; PyObject *__pyx_r = 0; __Pyx_RefNannyDeclarations - __Pyx_RefNannySetupContext("getSolutionsList (wrapper)", 0); + __Pyx_RefNannySetupContext("sequential_optimized_backtrack (wrapper)", 0); #if !CYTHON_METH_FASTCALL #if CYTHON_ASSUME_SAFE_MACROS __pyx_nargs = PyTuple_GET_SIZE(__pyx_args); @@ -18952,10 +18769,12 @@ PyObject *__pyx_args, PyObject *__pyx_kwds #endif __pyx_kwvalues = __Pyx_KwValues_FASTCALL(__pyx_args, __pyx_nargs); { - PyObject **__pyx_pyargnames[] = {&__pyx_n_s_self,&__pyx_n_s_domains,&__pyx_n_s_vconstraints,0}; + PyObject **__pyx_pyargnames[] = {&__pyx_n_s_assignment,&__pyx_n_s_unassigned_vars,&__pyx_n_s_domains,&__pyx_n_s_constraint_lookup,0}; if (__pyx_kwds) { Py_ssize_t kw_args; switch (__pyx_nargs) { + case 4: values[3] = __Pyx_Arg_FASTCALL(__pyx_args, 3); + CYTHON_FALLTHROUGH; case 3: values[2] = __Pyx_Arg_FASTCALL(__pyx_args, 2); CYTHON_FALLTHROUGH; case 2: values[1] = __Pyx_Arg_FASTCALL(__pyx_args, 1); @@ -18968,161 +18787,63 @@ PyObject *__pyx_args, PyObject *__pyx_kwds kw_args = __Pyx_NumKwargs_FASTCALL(__pyx_kwds); switch (__pyx_nargs) { case 0: - if (likely((values[0] = __Pyx_GetKwValue_FASTCALL(__pyx_kwds, __pyx_kwvalues, __pyx_n_s_self)) != 0)) { - (void)__Pyx_Arg_NewRef_FASTCALL(values[0]); - kw_args--; - } - else if (unlikely(PyErr_Occurred())) __PYX_ERR(0, 760, __pyx_L3_error) - else goto __pyx_L5_argtuple_error; - CYTHON_FALLTHROUGH; - case 1: - if (likely((values[1] = __Pyx_GetKwValue_FASTCALL(__pyx_kwds, __pyx_kwvalues, __pyx_n_s_domains)) != 0)) { - (void)__Pyx_Arg_NewRef_FASTCALL(values[1]); - kw_args--; - } - else if (unlikely(PyErr_Occurred())) __PYX_ERR(0, 760, __pyx_L3_error) - else { - __Pyx_RaiseArgtupleInvalid("getSolutionsList", 1, 3, 3, 1); __PYX_ERR(0, 760, __pyx_L3_error) - } - CYTHON_FALLTHROUGH; - case 2: - if (likely((values[2] = __Pyx_GetKwValue_FASTCALL(__pyx_kwds, __pyx_kwvalues, __pyx_n_s_vconstraints)) != 0)) { - (void)__Pyx_Arg_NewRef_FASTCALL(values[2]); - kw_args--; - } - else if (unlikely(PyErr_Occurred())) __PYX_ERR(0, 760, __pyx_L3_error) - else { - __Pyx_RaiseArgtupleInvalid("getSolutionsList", 1, 3, 3, 2); __PYX_ERR(0, 760, __pyx_L3_error) - } - } - if (unlikely(kw_args > 0)) { - const Py_ssize_t kwd_pos_args = __pyx_nargs; - if (unlikely(__Pyx_ParseOptionalKeywords(__pyx_kwds, __pyx_kwvalues, __pyx_pyargnames, 0, values + 0, kwd_pos_args, "getSolutionsList") < 0)) __PYX_ERR(0, 760, __pyx_L3_error) - } - } else if (unlikely(__pyx_nargs != 3)) { - goto __pyx_L5_argtuple_error; - } else { - values[0] = __Pyx_Arg_FASTCALL(__pyx_args, 0); - values[1] = __Pyx_Arg_FASTCALL(__pyx_args, 1); - values[2] = __Pyx_Arg_FASTCALL(__pyx_args, 2); - } - __pyx_v_self = values[0]; - __pyx_v_domains = ((PyObject*)values[1]); - __pyx_v_vconstraints = ((PyObject*)values[2]); - } - goto __pyx_L6_skip; - __pyx_L5_argtuple_error:; - __Pyx_RaiseArgtupleInvalid("getSolutionsList", 1, 3, 3, __pyx_nargs); __PYX_ERR(0, 760, __pyx_L3_error) - __pyx_L6_skip:; - goto __pyx_L4_argument_unpacking_done; - __pyx_L3_error:; - { - Py_ssize_t __pyx_temp; - for (__pyx_temp=0; __pyx_temp < (Py_ssize_t)(sizeof(values)/sizeof(values[0])); ++__pyx_temp) { - __Pyx_Arg_XDECREF_FASTCALL(values[__pyx_temp]); - } - } - __Pyx_AddTraceback("constraint.solvers.ParallelSolver.getSolutionsList", __pyx_clineno, __pyx_lineno, __pyx_filename); - __Pyx_RefNannyFinishContext(); - return NULL; - __pyx_L4_argument_unpacking_done:; - if (unlikely(!__Pyx_ArgTypeTest(((PyObject *)__pyx_v_domains), (&PyDict_Type), 0, "domains", 1))) __PYX_ERR(0, 760, __pyx_L1_error) - if (unlikely(!__Pyx_ArgTypeTest(((PyObject *)__pyx_v_vconstraints), (&PyDict_Type), 0, "vconstraints", 1))) __PYX_ERR(0, 760, __pyx_L1_error) - __pyx_r = __pyx_pf_10constraint_7solvers_14ParallelSolver_4getSolutionsList(__pyx_self, __pyx_v_self, __pyx_v_domains, __pyx_v_vconstraints); - - /* function exit code */ - goto __pyx_L0; - __pyx_L1_error:; - __pyx_r = NULL; - __pyx_L0:; - { - Py_ssize_t __pyx_temp; - for (__pyx_temp=0; __pyx_temp < (Py_ssize_t)(sizeof(values)/sizeof(values[0])); ++__pyx_temp) { - __Pyx_Arg_XDECREF_FASTCALL(values[__pyx_temp]); - } - } - __Pyx_RefNannyFinishContext(); - return __pyx_r; -} - -/* "constraint/solvers.py":766 - * - * # Sort variables by domain size (heuristic) - * sorted_vars: list[Hashable] = sorted(domains.keys(), key=lambda v: len(domains[v])) # <<<<<<<<<<<<<< - * - * # Split parallel and sequential parts - */ - -/* Python wrapper */ -static PyObject *__pyx_pw_10constraint_7solvers_14ParallelSolver_16getSolutionsList_lambda2(PyObject *__pyx_self, -#if CYTHON_METH_FASTCALL -PyObject *const *__pyx_args, Py_ssize_t __pyx_nargs, PyObject *__pyx_kwds -#else -PyObject *__pyx_args, PyObject *__pyx_kwds -#endif -); /*proto*/ -static PyMethodDef __pyx_mdef_10constraint_7solvers_14ParallelSolver_16getSolutionsList_lambda2 = {"lambda2", (PyCFunction)(void*)(__Pyx_PyCFunction_FastCallWithKeywords)__pyx_pw_10constraint_7solvers_14ParallelSolver_16getSolutionsList_lambda2, __Pyx_METH_FASTCALL|METH_KEYWORDS, 0}; -static PyObject *__pyx_pw_10constraint_7solvers_14ParallelSolver_16getSolutionsList_lambda2(PyObject *__pyx_self, -#if CYTHON_METH_FASTCALL -PyObject *const *__pyx_args, Py_ssize_t __pyx_nargs, PyObject *__pyx_kwds -#else -PyObject *__pyx_args, PyObject *__pyx_kwds -#endif -) { - PyObject *__pyx_v_v = 0; - #if !CYTHON_METH_FASTCALL - CYTHON_UNUSED Py_ssize_t __pyx_nargs; - #endif - CYTHON_UNUSED PyObject *const *__pyx_kwvalues; - PyObject* values[1] = {0}; - int __pyx_lineno = 0; - const char *__pyx_filename = NULL; - int __pyx_clineno = 0; - PyObject *__pyx_r = 0; - __Pyx_RefNannyDeclarations - __Pyx_RefNannySetupContext("lambda2 (wrapper)", 0); - #if !CYTHON_METH_FASTCALL - #if CYTHON_ASSUME_SAFE_MACROS - __pyx_nargs = PyTuple_GET_SIZE(__pyx_args); - #else - __pyx_nargs = PyTuple_Size(__pyx_args); if (unlikely(__pyx_nargs < 0)) return NULL; - #endif - #endif - __pyx_kwvalues = __Pyx_KwValues_FASTCALL(__pyx_args, __pyx_nargs); - { - PyObject **__pyx_pyargnames[] = {&__pyx_n_s_v,0}; - if (__pyx_kwds) { - Py_ssize_t kw_args; - switch (__pyx_nargs) { - case 1: values[0] = __Pyx_Arg_FASTCALL(__pyx_args, 0); - CYTHON_FALLTHROUGH; - case 0: break; - default: goto __pyx_L5_argtuple_error; - } - kw_args = __Pyx_NumKwargs_FASTCALL(__pyx_kwds); - switch (__pyx_nargs) { - case 0: - if (likely((values[0] = __Pyx_GetKwValue_FASTCALL(__pyx_kwds, __pyx_kwvalues, __pyx_n_s_v)) != 0)) { + if (likely((values[0] = __Pyx_GetKwValue_FASTCALL(__pyx_kwds, __pyx_kwvalues, __pyx_n_s_assignment)) != 0)) { (void)__Pyx_Arg_NewRef_FASTCALL(values[0]); kw_args--; } - else if (unlikely(PyErr_Occurred())) __PYX_ERR(0, 766, __pyx_L3_error) + else if (unlikely(PyErr_Occurred())) __PYX_ERR(0, 724, __pyx_L3_error) else goto __pyx_L5_argtuple_error; + CYTHON_FALLTHROUGH; + case 1: + if (likely((values[1] = __Pyx_GetKwValue_FASTCALL(__pyx_kwds, __pyx_kwvalues, __pyx_n_s_unassigned_vars)) != 0)) { + (void)__Pyx_Arg_NewRef_FASTCALL(values[1]); + kw_args--; + } + else if (unlikely(PyErr_Occurred())) __PYX_ERR(0, 724, __pyx_L3_error) + else { + __Pyx_RaiseArgtupleInvalid("sequential_optimized_backtrack", 1, 4, 4, 1); __PYX_ERR(0, 724, __pyx_L3_error) + } + CYTHON_FALLTHROUGH; + case 2: + if (likely((values[2] = __Pyx_GetKwValue_FASTCALL(__pyx_kwds, __pyx_kwvalues, __pyx_n_s_domains)) != 0)) { + (void)__Pyx_Arg_NewRef_FASTCALL(values[2]); + kw_args--; + } + else if (unlikely(PyErr_Occurred())) __PYX_ERR(0, 724, __pyx_L3_error) + else { + __Pyx_RaiseArgtupleInvalid("sequential_optimized_backtrack", 1, 4, 4, 2); __PYX_ERR(0, 724, __pyx_L3_error) + } + CYTHON_FALLTHROUGH; + case 3: + if (likely((values[3] = __Pyx_GetKwValue_FASTCALL(__pyx_kwds, __pyx_kwvalues, __pyx_n_s_constraint_lookup)) != 0)) { + (void)__Pyx_Arg_NewRef_FASTCALL(values[3]); + kw_args--; + } + else if (unlikely(PyErr_Occurred())) __PYX_ERR(0, 724, __pyx_L3_error) + else { + __Pyx_RaiseArgtupleInvalid("sequential_optimized_backtrack", 1, 4, 4, 3); __PYX_ERR(0, 724, __pyx_L3_error) + } } if (unlikely(kw_args > 0)) { const Py_ssize_t kwd_pos_args = __pyx_nargs; - if (unlikely(__Pyx_ParseOptionalKeywords(__pyx_kwds, __pyx_kwvalues, __pyx_pyargnames, 0, values + 0, kwd_pos_args, "lambda2") < 0)) __PYX_ERR(0, 766, __pyx_L3_error) + if (unlikely(__Pyx_ParseOptionalKeywords(__pyx_kwds, __pyx_kwvalues, __pyx_pyargnames, 0, values + 0, kwd_pos_args, "sequential_optimized_backtrack") < 0)) __PYX_ERR(0, 724, __pyx_L3_error) } - } else if (unlikely(__pyx_nargs != 1)) { + } else if (unlikely(__pyx_nargs != 4)) { goto __pyx_L5_argtuple_error; } else { values[0] = __Pyx_Arg_FASTCALL(__pyx_args, 0); + values[1] = __Pyx_Arg_FASTCALL(__pyx_args, 1); + values[2] = __Pyx_Arg_FASTCALL(__pyx_args, 2); + values[3] = __Pyx_Arg_FASTCALL(__pyx_args, 3); } - __pyx_v_v = values[0]; + __pyx_v_assignment = ((PyObject*)values[0]); + __pyx_v_unassigned_vars = ((PyObject*)values[1]); + __pyx_v_domains = ((PyObject*)values[2]); + __pyx_v_constraint_lookup = ((PyObject*)values[3]); } goto __pyx_L6_skip; __pyx_L5_argtuple_error:; - __Pyx_RaiseArgtupleInvalid("lambda2", 1, 1, 1, __pyx_nargs); __PYX_ERR(0, 766, __pyx_L3_error) + __Pyx_RaiseArgtupleInvalid("sequential_optimized_backtrack", 1, 4, 4, __pyx_nargs); __PYX_ERR(0, 724, __pyx_L3_error) __pyx_L6_skip:; goto __pyx_L4_argument_unpacking_done; __pyx_L3_error:; @@ -19132,13 +18853,21 @@ PyObject *__pyx_args, PyObject *__pyx_kwds __Pyx_Arg_XDECREF_FASTCALL(values[__pyx_temp]); } } - __Pyx_AddTraceback("constraint.solvers.ParallelSolver.getSolutionsList.lambda2", __pyx_clineno, __pyx_lineno, __pyx_filename); + __Pyx_AddTraceback("constraint.solvers.sequential_optimized_backtrack", __pyx_clineno, __pyx_lineno, __pyx_filename); __Pyx_RefNannyFinishContext(); return NULL; __pyx_L4_argument_unpacking_done:; - __pyx_r = __pyx_lambda_funcdef_lambda2(__pyx_self, __pyx_v_v); + if (unlikely(!__Pyx_ArgTypeTest(((PyObject *)__pyx_v_assignment), (&PyDict_Type), 0, "assignment", 1))) __PYX_ERR(0, 724, __pyx_L1_error) + if (unlikely(!__Pyx_ArgTypeTest(((PyObject *)__pyx_v_unassigned_vars), (&PyList_Type), 0, "unassigned_vars", 1))) __PYX_ERR(0, 724, __pyx_L1_error) + if (unlikely(!__Pyx_ArgTypeTest(((PyObject *)__pyx_v_domains), (&PyDict_Type), 0, "domains", 1))) __PYX_ERR(0, 724, __pyx_L1_error) + if (unlikely(!__Pyx_ArgTypeTest(((PyObject *)__pyx_v_constraint_lookup), (&PyDict_Type), 0, "constraint_lookup", 1))) __PYX_ERR(0, 724, __pyx_L1_error) + __pyx_r = __pyx_pf_10constraint_7solvers_10sequential_optimized_backtrack(__pyx_self, __pyx_v_assignment, __pyx_v_unassigned_vars, __pyx_v_domains, __pyx_v_constraint_lookup); /* function exit code */ + goto __pyx_L0; + __pyx_L1_error:; + __pyx_r = NULL; + __pyx_L0:; { Py_ssize_t __pyx_temp; for (__pyx_temp=0; __pyx_temp < (Py_ssize_t)(sizeof(values)/sizeof(values[0])); ++__pyx_temp) { @@ -19149,980 +18878,1236 @@ PyObject *__pyx_args, PyObject *__pyx_kwds return __pyx_r; } -static PyObject *__pyx_lambda_funcdef_lambda2(PyObject *__pyx_self, PyObject *__pyx_v_v) { - struct __pyx_obj_10constraint_7solvers___pyx_scope_struct_5_getSolutionsList *__pyx_cur_scope; - struct __pyx_obj_10constraint_7solvers___pyx_scope_struct_5_getSolutionsList *__pyx_outer_scope; +static PyObject *__pyx_pf_10constraint_7solvers_10sequential_optimized_backtrack(CYTHON_UNUSED PyObject *__pyx_self, PyObject *__pyx_v_assignment, PyObject *__pyx_v_unassigned_vars, PyObject *__pyx_v_domains, PyObject *__pyx_v_constraint_lookup) { + PyObject *__pyx_v_assignments = NULL; + PyObject *__pyx_v_sorted_variables = NULL; + PyObject *__pyx_v_queue = 0; + PyObject *__pyx_v_solutions = 0; + PyObject *__pyx_v_variable = NULL; + PyObject *__pyx_v_values = NULL; + PyObject *__pyx_v_constraint = NULL; + PyObject *__pyx_v_variables = NULL; PyObject *__pyx_r = NULL; __Pyx_RefNannyDeclarations PyObject *__pyx_t_1 = NULL; Py_ssize_t __pyx_t_2; + PyObject *__pyx_t_3 = NULL; + int __pyx_t_4; + PyObject *__pyx_t_5 = NULL; + int __pyx_t_6; + int __pyx_t_7; + PyObject *__pyx_t_8 = NULL; + PyObject *(*__pyx_t_9)(PyObject *); + PyObject *(*__pyx_t_10)(PyObject *); + PyObject *__pyx_t_11 = NULL; + unsigned int __pyx_t_12; int __pyx_lineno = 0; const char *__pyx_filename = NULL; int __pyx_clineno = 0; - __Pyx_RefNannySetupContext("lambda2", 1); - __pyx_outer_scope = (struct __pyx_obj_10constraint_7solvers___pyx_scope_struct_5_getSolutionsList *) __Pyx_CyFunction_GetClosure(__pyx_self); - __pyx_cur_scope = __pyx_outer_scope; - __Pyx_XDECREF(__pyx_r); - if (unlikely(!__pyx_cur_scope->__pyx_v_domains)) { __Pyx_RaiseClosureNameError("domains"); __PYX_ERR(0, 766, __pyx_L1_error) } - if (unlikely(__pyx_cur_scope->__pyx_v_domains == Py_None)) { - PyErr_SetString(PyExc_TypeError, "'NoneType' object is not subscriptable"); - __PYX_ERR(0, 766, __pyx_L1_error) - } - __pyx_t_1 = __Pyx_PyDict_GetItem(__pyx_cur_scope->__pyx_v_domains, __pyx_v_v); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 766, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_1); - __pyx_t_2 = PyObject_Length(__pyx_t_1); if (unlikely(__pyx_t_2 == ((Py_ssize_t)-1))) __PYX_ERR(0, 766, __pyx_L1_error) - __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; - __pyx_t_1 = PyInt_FromSsize_t(__pyx_t_2); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 766, __pyx_L1_error) + __Pyx_RefNannySetupContext("sequential_optimized_backtrack", 1); + + /* "constraint/solvers.py":728 + * # Does not do forwardcheck for simplicity + * + * assignments = assignment # <<<<<<<<<<<<<< + * sorted_variables = unassigned_vars + * queue: list[tuple] = [] + */ + __Pyx_INCREF(__pyx_v_assignment); + __pyx_v_assignments = __pyx_v_assignment; + + /* "constraint/solvers.py":729 + * + * assignments = assignment + * sorted_variables = unassigned_vars # <<<<<<<<<<<<<< + * queue: list[tuple] = [] + * solutions: list[dict] = list() + */ + __Pyx_INCREF(__pyx_v_unassigned_vars); + __pyx_v_sorted_variables = __pyx_v_unassigned_vars; + + /* "constraint/solvers.py":730 + * assignments = assignment + * sorted_variables = unassigned_vars + * queue: list[tuple] = [] # <<<<<<<<<<<<<< + * solutions: list[dict] = list() + * + */ + __pyx_t_1 = PyList_New(0); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 730, __pyx_L1_error) __Pyx_GOTREF(__pyx_t_1); - __pyx_r = __pyx_t_1; + __pyx_v_queue = ((PyObject*)__pyx_t_1); __pyx_t_1 = 0; - goto __pyx_L0; - - /* function exit code */ - __pyx_L1_error:; - __Pyx_XDECREF(__pyx_t_1); - __Pyx_AddTraceback("constraint.solvers.ParallelSolver.getSolutionsList.lambda2", __pyx_clineno, __pyx_lineno, __pyx_filename); - __pyx_r = NULL; - __pyx_L0:; - __Pyx_XGIVEREF(__pyx_r); - __Pyx_RefNannyFinishContext(); - return __pyx_r; -} -static PyObject *__pyx_gb_10constraint_7solvers_14ParallelSolver_16getSolutionsList_3generator4(__pyx_CoroutineObject *__pyx_generator, CYTHON_UNUSED PyThreadState *__pyx_tstate, PyObject *__pyx_sent_value); /* proto */ -/* "constraint/solvers.py":773 + /* "constraint/solvers.py":731 + * sorted_variables = unassigned_vars + * queue: list[tuple] = [] + * solutions: list[dict] = list() # <<<<<<<<<<<<<< * - * # Create the parallel function arguments and solutions lists - * args = ((self.requires_pickling, domains, constraint_lookup, first_var, val, remaining_vars.copy()) for val in domains[first_var]) # noqa: E501 # <<<<<<<<<<<<<< - * solutions: list[dict[Hashable, any]] = [] + * while True: + */ + __pyx_t_1 = PyList_New(0); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 731, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __pyx_v_solutions = ((PyObject*)__pyx_t_1); + __pyx_t_1 = 0; + + /* "constraint/solvers.py":733 + * solutions: list[dict] = list() * + * while True: # <<<<<<<<<<<<<< + * # Mix the Degree and Minimum Remaing Values (MRV) heuristics + * for variable in sorted_variables: */ + while (1) { -static PyObject *__pyx_pf_10constraint_7solvers_14ParallelSolver_16getSolutionsList_1genexpr(PyObject *__pyx_self, PyObject *__pyx_genexpr_arg_0) { - struct __pyx_obj_10constraint_7solvers___pyx_scope_struct_6_genexpr *__pyx_cur_scope; - PyObject *__pyx_r = NULL; - __Pyx_RefNannyDeclarations - int __pyx_lineno = 0; - const char *__pyx_filename = NULL; - int __pyx_clineno = 0; - __Pyx_RefNannySetupContext("genexpr", 0); - __pyx_cur_scope = (struct __pyx_obj_10constraint_7solvers___pyx_scope_struct_6_genexpr *)__pyx_tp_new_10constraint_7solvers___pyx_scope_struct_6_genexpr(__pyx_ptype_10constraint_7solvers___pyx_scope_struct_6_genexpr, __pyx_empty_tuple, NULL); - if (unlikely(!__pyx_cur_scope)) { - __pyx_cur_scope = ((struct __pyx_obj_10constraint_7solvers___pyx_scope_struct_6_genexpr *)Py_None); - __Pyx_INCREF(Py_None); - __PYX_ERR(0, 773, __pyx_L1_error) - } else { - __Pyx_GOTREF((PyObject *)__pyx_cur_scope); - } - __pyx_cur_scope->__pyx_outer_scope = (struct __pyx_obj_10constraint_7solvers___pyx_scope_struct_5_getSolutionsList *) __pyx_self; - __Pyx_INCREF((PyObject *)__pyx_cur_scope->__pyx_outer_scope); - __Pyx_GIVEREF((PyObject *)__pyx_cur_scope->__pyx_outer_scope); - __pyx_cur_scope->__pyx_genexpr_arg_0 = __pyx_genexpr_arg_0; - __Pyx_INCREF(__pyx_cur_scope->__pyx_genexpr_arg_0); - __Pyx_GIVEREF(__pyx_cur_scope->__pyx_genexpr_arg_0); - { - __pyx_CoroutineObject *gen = __Pyx_Generator_New((__pyx_coroutine_body_t) __pyx_gb_10constraint_7solvers_14ParallelSolver_16getSolutionsList_3generator4, NULL, (PyObject *) __pyx_cur_scope, __pyx_n_s_genexpr, __pyx_n_s_ParallelSolver_getSolutionsList, __pyx_n_s_constraint_solvers); if (unlikely(!gen)) __PYX_ERR(0, 773, __pyx_L1_error) - __Pyx_DECREF(__pyx_cur_scope); - __Pyx_RefNannyFinishContext(); - return (PyObject *) gen; - } + /* "constraint/solvers.py":735 + * while True: + * # Mix the Degree and Minimum Remaing Values (MRV) heuristics + * for variable in sorted_variables: # <<<<<<<<<<<<<< + * if variable not in assignments: + * # Found unassigned variable + */ + __pyx_t_1 = __pyx_v_sorted_variables; __Pyx_INCREF(__pyx_t_1); + __pyx_t_2 = 0; + for (;;) { + { + Py_ssize_t __pyx_temp = __Pyx_PyList_GET_SIZE(__pyx_t_1); + #if !CYTHON_ASSUME_SAFE_MACROS + if (unlikely((__pyx_temp < 0))) __PYX_ERR(0, 735, __pyx_L1_error) + #endif + if (__pyx_t_2 >= __pyx_temp) break; + } + #if CYTHON_ASSUME_SAFE_MACROS && !CYTHON_AVOID_BORROWED_REFS + __pyx_t_3 = PyList_GET_ITEM(__pyx_t_1, __pyx_t_2); __Pyx_INCREF(__pyx_t_3); __pyx_t_2++; if (unlikely((0 < 0))) __PYX_ERR(0, 735, __pyx_L1_error) + #else + __pyx_t_3 = __Pyx_PySequence_ITEM(__pyx_t_1, __pyx_t_2); __pyx_t_2++; if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 735, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_3); + #endif + __Pyx_XDECREF_SET(__pyx_v_variable, __pyx_t_3); + __pyx_t_3 = 0; - /* function exit code */ - __pyx_L1_error:; - __Pyx_AddTraceback("constraint.solvers.ParallelSolver.getSolutionsList.genexpr", __pyx_clineno, __pyx_lineno, __pyx_filename); - __pyx_r = NULL; - __Pyx_DECREF((PyObject *)__pyx_cur_scope); - __Pyx_XGIVEREF(__pyx_r); - __Pyx_RefNannyFinishContext(); - return __pyx_r; -} + /* "constraint/solvers.py":736 + * # Mix the Degree and Minimum Remaing Values (MRV) heuristics + * for variable in sorted_variables: + * if variable not in assignments: # <<<<<<<<<<<<<< + * # Found unassigned variable + * values = domains[variable][:] + */ + __pyx_t_4 = (__Pyx_PyDict_ContainsTF(__pyx_v_variable, __pyx_v_assignments, Py_NE)); if (unlikely((__pyx_t_4 < 0))) __PYX_ERR(0, 736, __pyx_L1_error) + if (__pyx_t_4) { + + /* "constraint/solvers.py":738 + * if variable not in assignments: + * # Found unassigned variable + * values = domains[variable][:] # <<<<<<<<<<<<<< + * break + * else: + */ + __pyx_t_3 = __Pyx_PyDict_GetItem(__pyx_v_domains, __pyx_v_variable); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 738, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_3); + __pyx_t_5 = __Pyx_PyObject_GetSlice(__pyx_t_3, 0, 0, NULL, NULL, &__pyx_slice_, 0, 0, 1); if (unlikely(!__pyx_t_5)) __PYX_ERR(0, 738, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_5); + __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; + __Pyx_XDECREF_SET(__pyx_v_values, __pyx_t_5); + __pyx_t_5 = 0; + + /* "constraint/solvers.py":739 + * # Found unassigned variable + * values = domains[variable][:] + * break # <<<<<<<<<<<<<< + * else: + * # No unassigned variables. We've got a solution. Go back + */ + goto __pyx_L6_break; + + /* "constraint/solvers.py":736 + * # Mix the Degree and Minimum Remaing Values (MRV) heuristics + * for variable in sorted_variables: + * if variable not in assignments: # <<<<<<<<<<<<<< + * # Found unassigned variable + * values = domains[variable][:] + */ + } + + /* "constraint/solvers.py":735 + * while True: + * # Mix the Degree and Minimum Remaing Values (MRV) heuristics + * for variable in sorted_variables: # <<<<<<<<<<<<<< + * if variable not in assignments: + * # Found unassigned variable + */ + } + __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; + goto __pyx_L8_for_else; + __pyx_L6_break:; + __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; + goto __pyx_L9_for_end; + /*else*/ { + __pyx_L8_for_else:; + + /* "constraint/solvers.py":743 + * # No unassigned variables. We've got a solution. Go back + * # to last variable, if there's one. + * solutions.append(assignments.copy()) # <<<<<<<<<<<<<< + * if not queue: + * return solutions + */ + __pyx_t_1 = PyDict_Copy(__pyx_v_assignments); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 743, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __pyx_t_6 = __Pyx_PyList_Append(__pyx_v_solutions, __pyx_t_1); if (unlikely(__pyx_t_6 == ((int)-1))) __PYX_ERR(0, 743, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; + + /* "constraint/solvers.py":744 + * # to last variable, if there's one. + * solutions.append(assignments.copy()) + * if not queue: # <<<<<<<<<<<<<< + * return solutions + * variable, values = queue.pop() + */ + __pyx_t_4 = (PyList_GET_SIZE(__pyx_v_queue) != 0); + __pyx_t_7 = (!__pyx_t_4); + if (__pyx_t_7) { + + /* "constraint/solvers.py":745 + * solutions.append(assignments.copy()) + * if not queue: + * return solutions # <<<<<<<<<<<<<< + * variable, values = queue.pop() + * + */ + __Pyx_XDECREF(__pyx_r); + __Pyx_INCREF(__pyx_v_solutions); + __pyx_r = __pyx_v_solutions; + goto __pyx_L0; -static PyObject *__pyx_gb_10constraint_7solvers_14ParallelSolver_16getSolutionsList_3generator4(__pyx_CoroutineObject *__pyx_generator, CYTHON_UNUSED PyThreadState *__pyx_tstate, PyObject *__pyx_sent_value) /* generator body */ -{ - struct __pyx_obj_10constraint_7solvers___pyx_scope_struct_6_genexpr *__pyx_cur_scope = ((struct __pyx_obj_10constraint_7solvers___pyx_scope_struct_6_genexpr *)__pyx_generator->closure); - PyObject *__pyx_r = NULL; - PyObject *__pyx_t_1 = NULL; - Py_ssize_t __pyx_t_2; - PyObject *(*__pyx_t_3)(PyObject *); - PyObject *__pyx_t_4 = NULL; - PyObject *__pyx_t_5 = NULL; - PyObject *__pyx_t_6 = NULL; - int __pyx_lineno = 0; - const char *__pyx_filename = NULL; - int __pyx_clineno = 0; - __Pyx_RefNannyDeclarations - __Pyx_RefNannySetupContext("genexpr", 0); - switch (__pyx_generator->resume_label) { - case 0: goto __pyx_L3_first_run; - case 1: goto __pyx_L6_resume_from_yield; - default: /* CPython raises the right error here */ - __Pyx_RefNannyFinishContext(); - return NULL; - } - __pyx_L3_first_run:; - if (unlikely(!__pyx_sent_value)) __PYX_ERR(0, 773, __pyx_L1_error) - if (unlikely(!__pyx_cur_scope->__pyx_genexpr_arg_0)) { __Pyx_RaiseUnboundLocalError(".0"); __PYX_ERR(0, 773, __pyx_L1_error) } - if (likely(PyList_CheckExact(__pyx_cur_scope->__pyx_genexpr_arg_0)) || PyTuple_CheckExact(__pyx_cur_scope->__pyx_genexpr_arg_0)) { - __pyx_t_1 = __pyx_cur_scope->__pyx_genexpr_arg_0; __Pyx_INCREF(__pyx_t_1); - __pyx_t_2 = 0; - __pyx_t_3 = NULL; - } else { - __pyx_t_2 = -1; __pyx_t_1 = PyObject_GetIter(__pyx_cur_scope->__pyx_genexpr_arg_0); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 773, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_1); - __pyx_t_3 = __Pyx_PyObject_GetIterNextFunc(__pyx_t_1); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 773, __pyx_L1_error) - } - for (;;) { - if (likely(!__pyx_t_3)) { - if (likely(PyList_CheckExact(__pyx_t_1))) { - { - Py_ssize_t __pyx_temp = __Pyx_PyList_GET_SIZE(__pyx_t_1); - #if !CYTHON_ASSUME_SAFE_MACROS - if (unlikely((__pyx_temp < 0))) __PYX_ERR(0, 773, __pyx_L1_error) - #endif - if (__pyx_t_2 >= __pyx_temp) break; + /* "constraint/solvers.py":744 + * # to last variable, if there's one. + * solutions.append(assignments.copy()) + * if not queue: # <<<<<<<<<<<<<< + * return solutions + * variable, values = queue.pop() + */ + } + + /* "constraint/solvers.py":746 + * if not queue: + * return solutions + * variable, values = queue.pop() # <<<<<<<<<<<<<< + * + * while True: + */ + __pyx_t_1 = __Pyx_PyList_Pop(__pyx_v_queue); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 746, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + if ((likely(PyTuple_CheckExact(__pyx_t_1))) || (PyList_CheckExact(__pyx_t_1))) { + PyObject* sequence = __pyx_t_1; + Py_ssize_t size = __Pyx_PySequence_SIZE(sequence); + if (unlikely(size != 2)) { + if (size > 2) __Pyx_RaiseTooManyValuesError(2); + else if (size >= 0) __Pyx_RaiseNeedMoreValuesError(size); + __PYX_ERR(0, 746, __pyx_L1_error) } #if CYTHON_ASSUME_SAFE_MACROS && !CYTHON_AVOID_BORROWED_REFS - __pyx_t_4 = PyList_GET_ITEM(__pyx_t_1, __pyx_t_2); __Pyx_INCREF(__pyx_t_4); __pyx_t_2++; if (unlikely((0 < 0))) __PYX_ERR(0, 773, __pyx_L1_error) - #else - __pyx_t_4 = __Pyx_PySequence_ITEM(__pyx_t_1, __pyx_t_2); __pyx_t_2++; if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 773, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_4); - #endif - } else { - { - Py_ssize_t __pyx_temp = __Pyx_PyTuple_GET_SIZE(__pyx_t_1); - #if !CYTHON_ASSUME_SAFE_MACROS - if (unlikely((__pyx_temp < 0))) __PYX_ERR(0, 773, __pyx_L1_error) - #endif - if (__pyx_t_2 >= __pyx_temp) break; + if (likely(PyTuple_CheckExact(sequence))) { + __pyx_t_5 = PyTuple_GET_ITEM(sequence, 0); + __pyx_t_3 = PyTuple_GET_ITEM(sequence, 1); + } else { + __pyx_t_5 = PyList_GET_ITEM(sequence, 0); + __pyx_t_3 = PyList_GET_ITEM(sequence, 1); } - #if CYTHON_ASSUME_SAFE_MACROS && !CYTHON_AVOID_BORROWED_REFS - __pyx_t_4 = PyTuple_GET_ITEM(__pyx_t_1, __pyx_t_2); __Pyx_INCREF(__pyx_t_4); __pyx_t_2++; if (unlikely((0 < 0))) __PYX_ERR(0, 773, __pyx_L1_error) + __Pyx_INCREF(__pyx_t_5); + __Pyx_INCREF(__pyx_t_3); #else - __pyx_t_4 = __Pyx_PySequence_ITEM(__pyx_t_1, __pyx_t_2); __pyx_t_2++; if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 773, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_4); + __pyx_t_5 = PySequence_ITEM(sequence, 0); if (unlikely(!__pyx_t_5)) __PYX_ERR(0, 746, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_5); + __pyx_t_3 = PySequence_ITEM(sequence, 1); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 746, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_3); #endif + __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; + } else { + Py_ssize_t index = -1; + __pyx_t_8 = PyObject_GetIter(__pyx_t_1); if (unlikely(!__pyx_t_8)) __PYX_ERR(0, 746, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_8); + __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; + __pyx_t_9 = __Pyx_PyObject_GetIterNextFunc(__pyx_t_8); + index = 0; __pyx_t_5 = __pyx_t_9(__pyx_t_8); if (unlikely(!__pyx_t_5)) goto __pyx_L11_unpacking_failed; + __Pyx_GOTREF(__pyx_t_5); + index = 1; __pyx_t_3 = __pyx_t_9(__pyx_t_8); if (unlikely(!__pyx_t_3)) goto __pyx_L11_unpacking_failed; + __Pyx_GOTREF(__pyx_t_3); + if (__Pyx_IternextUnpackEndCheck(__pyx_t_9(__pyx_t_8), 2) < 0) __PYX_ERR(0, 746, __pyx_L1_error) + __pyx_t_9 = NULL; + __Pyx_DECREF(__pyx_t_8); __pyx_t_8 = 0; + goto __pyx_L12_unpacking_done; + __pyx_L11_unpacking_failed:; + __Pyx_DECREF(__pyx_t_8); __pyx_t_8 = 0; + __pyx_t_9 = NULL; + if (__Pyx_IterFinish() == 0) __Pyx_RaiseNeedMoreValuesError(index); + __PYX_ERR(0, 746, __pyx_L1_error) + __pyx_L12_unpacking_done:; } - } else { - __pyx_t_4 = __pyx_t_3(__pyx_t_1); - if (unlikely(!__pyx_t_4)) { - PyObject* exc_type = PyErr_Occurred(); - if (exc_type) { - if (likely(__Pyx_PyErr_GivenExceptionMatches(exc_type, PyExc_StopIteration))) PyErr_Clear(); - else __PYX_ERR(0, 773, __pyx_L1_error) - } - break; - } - __Pyx_GOTREF(__pyx_t_4); + __Pyx_XDECREF_SET(__pyx_v_variable, __pyx_t_5); + __pyx_t_5 = 0; + __Pyx_XDECREF_SET(__pyx_v_values, __pyx_t_3); + __pyx_t_3 = 0; } - __Pyx_XGOTREF(__pyx_cur_scope->__pyx_v_val); - __Pyx_XDECREF_SET(__pyx_cur_scope->__pyx_v_val, __pyx_t_4); - __Pyx_GIVEREF(__pyx_t_4); - __pyx_t_4 = 0; - if (unlikely(!__pyx_cur_scope->__pyx_outer_scope->__pyx_v_self)) { __Pyx_RaiseClosureNameError("self"); __PYX_ERR(0, 773, __pyx_L1_error) } - __pyx_t_4 = __Pyx_PyObject_GetAttrStr(__pyx_cur_scope->__pyx_outer_scope->__pyx_v_self, __pyx_n_s_requires_pickling); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 773, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_4); - if (unlikely(!__pyx_cur_scope->__pyx_outer_scope->__pyx_v_domains)) { __Pyx_RaiseClosureNameError("domains"); __PYX_ERR(0, 773, __pyx_L1_error) } - if (unlikely(!__pyx_cur_scope->__pyx_outer_scope->__pyx_v_constraint_lookup)) { __Pyx_RaiseClosureNameError("constraint_lookup"); __PYX_ERR(0, 773, __pyx_L1_error) } - if (unlikely(!__pyx_cur_scope->__pyx_outer_scope->__pyx_v_first_var)) { __Pyx_RaiseClosureNameError("first_var"); __PYX_ERR(0, 773, __pyx_L1_error) } - if (unlikely(!__pyx_cur_scope->__pyx_outer_scope->__pyx_v_remaining_vars)) { __Pyx_RaiseClosureNameError("remaining_vars"); __PYX_ERR(0, 773, __pyx_L1_error) } - __pyx_t_5 = __Pyx_CallUnboundCMethod0(&__pyx_umethod_PyList_Type_copy, __pyx_cur_scope->__pyx_outer_scope->__pyx_v_remaining_vars); if (unlikely(!__pyx_t_5)) __PYX_ERR(0, 773, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_5); - __pyx_t_6 = PyTuple_New(6); if (unlikely(!__pyx_t_6)) __PYX_ERR(0, 773, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_6); - __Pyx_GIVEREF(__pyx_t_4); - if (__Pyx_PyTuple_SET_ITEM(__pyx_t_6, 0, __pyx_t_4)) __PYX_ERR(0, 773, __pyx_L1_error); - __Pyx_INCREF(__pyx_cur_scope->__pyx_outer_scope->__pyx_v_domains); - __Pyx_GIVEREF(__pyx_cur_scope->__pyx_outer_scope->__pyx_v_domains); - if (__Pyx_PyTuple_SET_ITEM(__pyx_t_6, 1, __pyx_cur_scope->__pyx_outer_scope->__pyx_v_domains)) __PYX_ERR(0, 773, __pyx_L1_error); - __Pyx_INCREF(__pyx_cur_scope->__pyx_outer_scope->__pyx_v_constraint_lookup); - __Pyx_GIVEREF(__pyx_cur_scope->__pyx_outer_scope->__pyx_v_constraint_lookup); - if (__Pyx_PyTuple_SET_ITEM(__pyx_t_6, 2, __pyx_cur_scope->__pyx_outer_scope->__pyx_v_constraint_lookup)) __PYX_ERR(0, 773, __pyx_L1_error); - __Pyx_INCREF(__pyx_cur_scope->__pyx_outer_scope->__pyx_v_first_var); - __Pyx_GIVEREF(__pyx_cur_scope->__pyx_outer_scope->__pyx_v_first_var); - if (__Pyx_PyTuple_SET_ITEM(__pyx_t_6, 3, __pyx_cur_scope->__pyx_outer_scope->__pyx_v_first_var)) __PYX_ERR(0, 773, __pyx_L1_error); - __Pyx_INCREF(__pyx_cur_scope->__pyx_v_val); - __Pyx_GIVEREF(__pyx_cur_scope->__pyx_v_val); - if (__Pyx_PyTuple_SET_ITEM(__pyx_t_6, 4, __pyx_cur_scope->__pyx_v_val)) __PYX_ERR(0, 773, __pyx_L1_error); - __Pyx_GIVEREF(__pyx_t_5); - if (__Pyx_PyTuple_SET_ITEM(__pyx_t_6, 5, __pyx_t_5)) __PYX_ERR(0, 773, __pyx_L1_error); - __pyx_t_4 = 0; - __pyx_t_5 = 0; - __pyx_r = __pyx_t_6; - __pyx_t_6 = 0; - __Pyx_XGIVEREF(__pyx_t_1); - __pyx_cur_scope->__pyx_t_0 = __pyx_t_1; - __pyx_cur_scope->__pyx_t_1 = __pyx_t_2; - __pyx_cur_scope->__pyx_t_2 = __pyx_t_3; - __Pyx_XGIVEREF(__pyx_r); - __Pyx_RefNannyFinishContext(); - __Pyx_Coroutine_ResetAndClearException(__pyx_generator); - /* return from generator, yielding value */ - __pyx_generator->resume_label = 1; - return __pyx_r; - __pyx_L6_resume_from_yield:; - __pyx_t_1 = __pyx_cur_scope->__pyx_t_0; - __pyx_cur_scope->__pyx_t_0 = 0; - __Pyx_XGOTREF(__pyx_t_1); - __pyx_t_2 = __pyx_cur_scope->__pyx_t_1; - __pyx_t_3 = __pyx_cur_scope->__pyx_t_2; - if (unlikely(!__pyx_sent_value)) __PYX_ERR(0, 773, __pyx_L1_error) - } - __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; - CYTHON_MAYBE_UNUSED_VAR(__pyx_cur_scope); + __pyx_L9_for_end:; - /* function exit code */ - PyErr_SetNone(PyExc_StopIteration); - goto __pyx_L0; - __pyx_L1_error:; - __Pyx_Generator_Replace_StopIteration(0); - __Pyx_XDECREF(__pyx_t_1); - __Pyx_XDECREF(__pyx_t_4); - __Pyx_XDECREF(__pyx_t_5); - __Pyx_XDECREF(__pyx_t_6); - __Pyx_AddTraceback("genexpr", __pyx_clineno, __pyx_lineno, __pyx_filename); - __pyx_L0:; - __Pyx_XDECREF(__pyx_r); __pyx_r = 0; - #if !CYTHON_USE_EXC_INFO_STACK - __Pyx_Coroutine_ResetAndClearException(__pyx_generator); - #endif - __pyx_generator->resume_label = -1; - __Pyx_Coroutine_clear((PyObject*)__pyx_generator); - __Pyx_RefNannyFinishContext(); - return __pyx_r; -} + /* "constraint/solvers.py":748 + * variable, values = queue.pop() + * + * while True: # <<<<<<<<<<<<<< + * # We have a variable. Do we have any values left? + * if not values: + */ + while (1) { + + /* "constraint/solvers.py":750 + * while True: + * # We have a variable. Do we have any values left? + * if not values: # <<<<<<<<<<<<<< + * # No. Go back to last variable, if there's one. + * del assignments[variable] + */ + __pyx_t_7 = __Pyx_PyObject_IsTrue(__pyx_v_values); if (unlikely((__pyx_t_7 < 0))) __PYX_ERR(0, 750, __pyx_L1_error) + __pyx_t_4 = (!__pyx_t_7); + if (__pyx_t_4) { + + /* "constraint/solvers.py":752 + * if not values: + * # No. Go back to last variable, if there's one. + * del assignments[variable] # <<<<<<<<<<<<<< + * while queue: + * variable, values = queue.pop() + */ + if (unlikely((PyDict_DelItem(__pyx_v_assignments, __pyx_v_variable) < 0))) __PYX_ERR(0, 752, __pyx_L1_error) + + /* "constraint/solvers.py":753 + * # No. Go back to last variable, if there's one. + * del assignments[variable] + * while queue: # <<<<<<<<<<<<<< + * variable, values = queue.pop() + * if values: + */ + while (1) { + __pyx_t_4 = (PyList_GET_SIZE(__pyx_v_queue) != 0); + if (!__pyx_t_4) break; + + /* "constraint/solvers.py":754 + * del assignments[variable] + * while queue: + * variable, values = queue.pop() # <<<<<<<<<<<<<< + * if values: + * break + */ + __pyx_t_1 = __Pyx_PyList_Pop(__pyx_v_queue); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 754, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + if ((likely(PyTuple_CheckExact(__pyx_t_1))) || (PyList_CheckExact(__pyx_t_1))) { + PyObject* sequence = __pyx_t_1; + Py_ssize_t size = __Pyx_PySequence_SIZE(sequence); + if (unlikely(size != 2)) { + if (size > 2) __Pyx_RaiseTooManyValuesError(2); + else if (size >= 0) __Pyx_RaiseNeedMoreValuesError(size); + __PYX_ERR(0, 754, __pyx_L1_error) + } + #if CYTHON_ASSUME_SAFE_MACROS && !CYTHON_AVOID_BORROWED_REFS + if (likely(PyTuple_CheckExact(sequence))) { + __pyx_t_3 = PyTuple_GET_ITEM(sequence, 0); + __pyx_t_5 = PyTuple_GET_ITEM(sequence, 1); + } else { + __pyx_t_3 = PyList_GET_ITEM(sequence, 0); + __pyx_t_5 = PyList_GET_ITEM(sequence, 1); + } + __Pyx_INCREF(__pyx_t_3); + __Pyx_INCREF(__pyx_t_5); + #else + __pyx_t_3 = PySequence_ITEM(sequence, 0); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 754, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_3); + __pyx_t_5 = PySequence_ITEM(sequence, 1); if (unlikely(!__pyx_t_5)) __PYX_ERR(0, 754, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_5); + #endif + __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; + } else { + Py_ssize_t index = -1; + __pyx_t_8 = PyObject_GetIter(__pyx_t_1); if (unlikely(!__pyx_t_8)) __PYX_ERR(0, 754, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_8); + __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; + __pyx_t_9 = __Pyx_PyObject_GetIterNextFunc(__pyx_t_8); + index = 0; __pyx_t_3 = __pyx_t_9(__pyx_t_8); if (unlikely(!__pyx_t_3)) goto __pyx_L18_unpacking_failed; + __Pyx_GOTREF(__pyx_t_3); + index = 1; __pyx_t_5 = __pyx_t_9(__pyx_t_8); if (unlikely(!__pyx_t_5)) goto __pyx_L18_unpacking_failed; + __Pyx_GOTREF(__pyx_t_5); + if (__Pyx_IternextUnpackEndCheck(__pyx_t_9(__pyx_t_8), 2) < 0) __PYX_ERR(0, 754, __pyx_L1_error) + __pyx_t_9 = NULL; + __Pyx_DECREF(__pyx_t_8); __pyx_t_8 = 0; + goto __pyx_L19_unpacking_done; + __pyx_L18_unpacking_failed:; + __Pyx_DECREF(__pyx_t_8); __pyx_t_8 = 0; + __pyx_t_9 = NULL; + if (__Pyx_IterFinish() == 0) __Pyx_RaiseNeedMoreValuesError(index); + __PYX_ERR(0, 754, __pyx_L1_error) + __pyx_L19_unpacking_done:; + } + __Pyx_DECREF_SET(__pyx_v_variable, __pyx_t_3); + __pyx_t_3 = 0; + __Pyx_DECREF_SET(__pyx_v_values, __pyx_t_5); + __pyx_t_5 = 0; -/* "constraint/solvers.py":760 - * raise NotImplementedError(msg) - * - * def getSolutionsList(self, domains: dict[Hashable, Domain], vconstraints: dict[Hashable, list[tuple[Constraint, Hashable]]]) -> list[dict[Hashable, any]]: # noqa: D102, E501 # <<<<<<<<<<<<<< - * """Parallelized all-solutions finder using ProcessPoolExecutor for work-stealing.""" - * # Precompute constraints lookup per variable + /* "constraint/solvers.py":755 + * while queue: + * variable, values = queue.pop() + * if values: # <<<<<<<<<<<<<< + * break + * del assignments[variable] */ + __pyx_t_4 = __Pyx_PyObject_IsTrue(__pyx_v_values); if (unlikely((__pyx_t_4 < 0))) __PYX_ERR(0, 755, __pyx_L1_error) + if (__pyx_t_4) { -static PyObject *__pyx_pf_10constraint_7solvers_14ParallelSolver_4getSolutionsList(CYTHON_UNUSED PyObject *__pyx_self, PyObject *__pyx_v_self, PyObject *__pyx_v_domains, PyObject *__pyx_v_vconstraints) { - struct __pyx_obj_10constraint_7solvers___pyx_scope_struct_5_getSolutionsList *__pyx_cur_scope; - PyObject *__pyx_v_sorted_vars = 0; - PyObject *__pyx_v_args = NULL; - PyObject *__pyx_v_solutions = 0; - PyObject *__pyx_v_parallel_pool = NULL; - PyObject *__pyx_v_executor = NULL; - PyObject *__pyx_v_results = NULL; - PyObject *__pyx_v_result = NULL; - PyObject *__pyx_9genexpr10__pyx_v_var = NULL; - PyObject *__pyx_gb_10constraint_7solvers_14ParallelSolver_16getSolutionsList_3generator4 = 0; - PyObject *__pyx_r = NULL; - __Pyx_RefNannyDeclarations - PyObject *__pyx_t_1 = NULL; - PyObject *__pyx_t_2 = NULL; - Py_ssize_t __pyx_t_3; - Py_ssize_t __pyx_t_4; - int __pyx_t_5; - PyObject *__pyx_t_6 = NULL; - int __pyx_t_7; - PyObject *__pyx_t_8 = NULL; - int __pyx_t_9; - unsigned int __pyx_t_10; - PyObject *__pyx_t_11 = NULL; - PyObject *__pyx_t_12 = NULL; - PyObject *__pyx_t_13 = NULL; - PyObject *__pyx_t_14 = NULL; - PyObject *(*__pyx_t_15)(PyObject *); - int __pyx_t_16; - PyObject *__pyx_t_17 = NULL; - int __pyx_t_18; - int __pyx_lineno = 0; - const char *__pyx_filename = NULL; - int __pyx_clineno = 0; - __Pyx_RefNannySetupContext("getSolutionsList", 0); - __pyx_cur_scope = (struct __pyx_obj_10constraint_7solvers___pyx_scope_struct_5_getSolutionsList *)__pyx_tp_new_10constraint_7solvers___pyx_scope_struct_5_getSolutionsList(__pyx_ptype_10constraint_7solvers___pyx_scope_struct_5_getSolutionsList, __pyx_empty_tuple, NULL); - if (unlikely(!__pyx_cur_scope)) { - __pyx_cur_scope = ((struct __pyx_obj_10constraint_7solvers___pyx_scope_struct_5_getSolutionsList *)Py_None); - __Pyx_INCREF(Py_None); - __PYX_ERR(0, 760, __pyx_L1_error) - } else { - __Pyx_GOTREF((PyObject *)__pyx_cur_scope); - } - __pyx_cur_scope->__pyx_v_self = __pyx_v_self; - __Pyx_INCREF(__pyx_cur_scope->__pyx_v_self); - __Pyx_GIVEREF(__pyx_cur_scope->__pyx_v_self); - __pyx_cur_scope->__pyx_v_domains = __pyx_v_domains; - __Pyx_INCREF(__pyx_cur_scope->__pyx_v_domains); - __Pyx_GIVEREF(__pyx_cur_scope->__pyx_v_domains); + /* "constraint/solvers.py":756 + * variable, values = queue.pop() + * if values: + * break # <<<<<<<<<<<<<< + * del assignments[variable] + * else: + */ + goto __pyx_L17_break; - /* "constraint/solvers.py":763 - * """Parallelized all-solutions finder using ProcessPoolExecutor for work-stealing.""" - * # Precompute constraints lookup per variable - * constraint_lookup: dict[Hashable, list[tuple[Constraint, Hashable]]] = {var: vconstraints.get(var, []) for var in domains} # noqa: E501 # <<<<<<<<<<<<<< - * - * # Sort variables by domain size (heuristic) + /* "constraint/solvers.py":755 + * while queue: + * variable, values = queue.pop() + * if values: # <<<<<<<<<<<<<< + * break + * del assignments[variable] */ - { /* enter inner scope */ - __pyx_t_1 = PyDict_New(); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 763, __pyx_L5_error) - __Pyx_GOTREF(__pyx_t_1); - __pyx_t_3 = 0; - __pyx_t_6 = __Pyx_dict_iterator(__pyx_cur_scope->__pyx_v_domains, 1, ((PyObject *)NULL), (&__pyx_t_4), (&__pyx_t_5)); if (unlikely(!__pyx_t_6)) __PYX_ERR(0, 763, __pyx_L5_error) - __Pyx_GOTREF(__pyx_t_6); - __Pyx_XDECREF(__pyx_t_2); - __pyx_t_2 = __pyx_t_6; - __pyx_t_6 = 0; - while (1) { - __pyx_t_7 = __Pyx_dict_iter_next(__pyx_t_2, __pyx_t_4, &__pyx_t_3, &__pyx_t_6, NULL, NULL, __pyx_t_5); - if (unlikely(__pyx_t_7 == 0)) break; - if (unlikely(__pyx_t_7 == -1)) __PYX_ERR(0, 763, __pyx_L5_error) - __Pyx_GOTREF(__pyx_t_6); - __Pyx_XDECREF_SET(__pyx_9genexpr10__pyx_v_var, __pyx_t_6); - __pyx_t_6 = 0; - __pyx_t_6 = PyList_New(0); if (unlikely(!__pyx_t_6)) __PYX_ERR(0, 763, __pyx_L5_error) - __Pyx_GOTREF(__pyx_t_6); - __pyx_t_8 = __Pyx_PyDict_GetItemDefault(__pyx_v_vconstraints, __pyx_9genexpr10__pyx_v_var, __pyx_t_6); if (unlikely(!__pyx_t_8)) __PYX_ERR(0, 763, __pyx_L5_error) - __Pyx_GOTREF(__pyx_t_8); - __Pyx_DECREF(__pyx_t_6); __pyx_t_6 = 0; - if (unlikely(PyDict_SetItem(__pyx_t_1, (PyObject*)__pyx_9genexpr10__pyx_v_var, (PyObject*)__pyx_t_8))) __PYX_ERR(0, 763, __pyx_L5_error) - __Pyx_DECREF(__pyx_t_8); __pyx_t_8 = 0; - } - __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; - __Pyx_XDECREF(__pyx_9genexpr10__pyx_v_var); __pyx_9genexpr10__pyx_v_var = 0; - goto __pyx_L8_exit_scope; - __pyx_L5_error:; - __Pyx_XDECREF(__pyx_9genexpr10__pyx_v_var); __pyx_9genexpr10__pyx_v_var = 0; - goto __pyx_L1_error; - __pyx_L8_exit_scope:; - } /* exit inner scope */ - __Pyx_GIVEREF(__pyx_t_1); - __pyx_cur_scope->__pyx_v_constraint_lookup = ((PyObject*)__pyx_t_1); - __pyx_t_1 = 0; + } - /* "constraint/solvers.py":766 - * - * # Sort variables by domain size (heuristic) - * sorted_vars: list[Hashable] = sorted(domains.keys(), key=lambda v: len(domains[v])) # <<<<<<<<<<<<<< - * - * # Split parallel and sequential parts + /* "constraint/solvers.py":757 + * if values: + * break + * del assignments[variable] # <<<<<<<<<<<<<< + * else: + * return solutions */ - __pyx_t_1 = __Pyx_PyDict_Keys(__pyx_cur_scope->__pyx_v_domains); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 766, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_1); - __pyx_t_2 = PyTuple_New(1); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 766, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_2); - __Pyx_GIVEREF(__pyx_t_1); - if (__Pyx_PyTuple_SET_ITEM(__pyx_t_2, 0, __pyx_t_1)) __PYX_ERR(0, 766, __pyx_L1_error); - __pyx_t_1 = 0; - __pyx_t_1 = __Pyx_PyDict_NewPresized(1); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 766, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_1); - __pyx_t_8 = __Pyx_CyFunction_New(&__pyx_mdef_10constraint_7solvers_14ParallelSolver_16getSolutionsList_lambda2, 0, __pyx_n_s_ParallelSolver_getSolutionsList_2, ((PyObject*)__pyx_cur_scope), __pyx_n_s_constraint_solvers, __pyx_d, NULL); if (unlikely(!__pyx_t_8)) __PYX_ERR(0, 766, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_8); - if (PyDict_SetItem(__pyx_t_1, __pyx_n_s_key, __pyx_t_8) < 0) __PYX_ERR(0, 766, __pyx_L1_error) - __Pyx_DECREF(__pyx_t_8); __pyx_t_8 = 0; - __pyx_t_8 = __Pyx_PyObject_Call(__pyx_builtin_sorted, __pyx_t_2, __pyx_t_1); if (unlikely(!__pyx_t_8)) __PYX_ERR(0, 766, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_8); - __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; - __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; - if (!(likely(PyList_CheckExact(__pyx_t_8))||((__pyx_t_8) == Py_None) || __Pyx_RaiseUnexpectedTypeError("list", __pyx_t_8))) __PYX_ERR(0, 766, __pyx_L1_error) - __pyx_v_sorted_vars = ((PyObject*)__pyx_t_8); - __pyx_t_8 = 0; + if (unlikely((PyDict_DelItem(__pyx_v_assignments, __pyx_v_variable) < 0))) __PYX_ERR(0, 757, __pyx_L1_error) + } - /* "constraint/solvers.py":769 + /* "constraint/solvers.py":759 + * del assignments[variable] + * else: + * return solutions # <<<<<<<<<<<<<< * - * # Split parallel and sequential parts - * first_var = sorted_vars[0] # <<<<<<<<<<<<<< - * remaining_vars = sorted_vars[1:] + * # Got a value. Check it. + */ + /*else*/ { + __Pyx_XDECREF(__pyx_r); + __Pyx_INCREF(__pyx_v_solutions); + __pyx_r = __pyx_v_solutions; + goto __pyx_L0; + } + __pyx_L17_break:; + + /* "constraint/solvers.py":750 + * while True: + * # We have a variable. Do we have any values left? + * if not values: # <<<<<<<<<<<<<< + * # No. Go back to last variable, if there's one. + * del assignments[variable] + */ + } + + /* "constraint/solvers.py":762 * + * # Got a value. Check it. + * assignments[variable] = values.pop() # <<<<<<<<<<<<<< + * for constraint, variables in constraint_lookup[variable]: + * if not constraint(variables, domains, assignments, None): */ - if (unlikely(__pyx_v_sorted_vars == Py_None)) { - PyErr_SetString(PyExc_TypeError, "'NoneType' object is not subscriptable"); - __PYX_ERR(0, 769, __pyx_L1_error) - } - __pyx_t_8 = __Pyx_GetItemInt_List(__pyx_v_sorted_vars, 0, long, 1, __Pyx_PyInt_From_long, 1, 0, 1); if (unlikely(!__pyx_t_8)) __PYX_ERR(0, 769, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_8); - __Pyx_GIVEREF(__pyx_t_8); - __pyx_cur_scope->__pyx_v_first_var = __pyx_t_8; - __pyx_t_8 = 0; + __pyx_t_1 = __Pyx_PyObject_Pop(__pyx_v_values); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 762, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + if (unlikely((PyDict_SetItem(__pyx_v_assignments, __pyx_v_variable, __pyx_t_1) < 0))) __PYX_ERR(0, 762, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; + + /* "constraint/solvers.py":763 + * # Got a value. Check it. + * assignments[variable] = values.pop() + * for constraint, variables in constraint_lookup[variable]: # <<<<<<<<<<<<<< + * if not constraint(variables, domains, assignments, None): + * # Value is not good. + */ + __pyx_t_1 = __Pyx_PyDict_GetItem(__pyx_v_constraint_lookup, __pyx_v_variable); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 763, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + if (likely(PyList_CheckExact(__pyx_t_1)) || PyTuple_CheckExact(__pyx_t_1)) { + __pyx_t_5 = __pyx_t_1; __Pyx_INCREF(__pyx_t_5); + __pyx_t_2 = 0; + __pyx_t_10 = NULL; + } else { + __pyx_t_2 = -1; __pyx_t_5 = PyObject_GetIter(__pyx_t_1); if (unlikely(!__pyx_t_5)) __PYX_ERR(0, 763, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_5); + __pyx_t_10 = __Pyx_PyObject_GetIterNextFunc(__pyx_t_5); if (unlikely(!__pyx_t_10)) __PYX_ERR(0, 763, __pyx_L1_error) + } + __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; + for (;;) { + if (likely(!__pyx_t_10)) { + if (likely(PyList_CheckExact(__pyx_t_5))) { + { + Py_ssize_t __pyx_temp = __Pyx_PyList_GET_SIZE(__pyx_t_5); + #if !CYTHON_ASSUME_SAFE_MACROS + if (unlikely((__pyx_temp < 0))) __PYX_ERR(0, 763, __pyx_L1_error) + #endif + if (__pyx_t_2 >= __pyx_temp) break; + } + #if CYTHON_ASSUME_SAFE_MACROS && !CYTHON_AVOID_BORROWED_REFS + __pyx_t_1 = PyList_GET_ITEM(__pyx_t_5, __pyx_t_2); __Pyx_INCREF(__pyx_t_1); __pyx_t_2++; if (unlikely((0 < 0))) __PYX_ERR(0, 763, __pyx_L1_error) + #else + __pyx_t_1 = __Pyx_PySequence_ITEM(__pyx_t_5, __pyx_t_2); __pyx_t_2++; if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 763, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + #endif + } else { + { + Py_ssize_t __pyx_temp = __Pyx_PyTuple_GET_SIZE(__pyx_t_5); + #if !CYTHON_ASSUME_SAFE_MACROS + if (unlikely((__pyx_temp < 0))) __PYX_ERR(0, 763, __pyx_L1_error) + #endif + if (__pyx_t_2 >= __pyx_temp) break; + } + #if CYTHON_ASSUME_SAFE_MACROS && !CYTHON_AVOID_BORROWED_REFS + __pyx_t_1 = PyTuple_GET_ITEM(__pyx_t_5, __pyx_t_2); __Pyx_INCREF(__pyx_t_1); __pyx_t_2++; if (unlikely((0 < 0))) __PYX_ERR(0, 763, __pyx_L1_error) + #else + __pyx_t_1 = __Pyx_PySequence_ITEM(__pyx_t_5, __pyx_t_2); __pyx_t_2++; if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 763, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + #endif + } + } else { + __pyx_t_1 = __pyx_t_10(__pyx_t_5); + if (unlikely(!__pyx_t_1)) { + PyObject* exc_type = PyErr_Occurred(); + if (exc_type) { + if (likely(__Pyx_PyErr_GivenExceptionMatches(exc_type, PyExc_StopIteration))) PyErr_Clear(); + else __PYX_ERR(0, 763, __pyx_L1_error) + } + break; + } + __Pyx_GOTREF(__pyx_t_1); + } + if ((likely(PyTuple_CheckExact(__pyx_t_1))) || (PyList_CheckExact(__pyx_t_1))) { + PyObject* sequence = __pyx_t_1; + Py_ssize_t size = __Pyx_PySequence_SIZE(sequence); + if (unlikely(size != 2)) { + if (size > 2) __Pyx_RaiseTooManyValuesError(2); + else if (size >= 0) __Pyx_RaiseNeedMoreValuesError(size); + __PYX_ERR(0, 763, __pyx_L1_error) + } + #if CYTHON_ASSUME_SAFE_MACROS && !CYTHON_AVOID_BORROWED_REFS + if (likely(PyTuple_CheckExact(sequence))) { + __pyx_t_3 = PyTuple_GET_ITEM(sequence, 0); + __pyx_t_8 = PyTuple_GET_ITEM(sequence, 1); + } else { + __pyx_t_3 = PyList_GET_ITEM(sequence, 0); + __pyx_t_8 = PyList_GET_ITEM(sequence, 1); + } + __Pyx_INCREF(__pyx_t_3); + __Pyx_INCREF(__pyx_t_8); + #else + __pyx_t_3 = PySequence_ITEM(sequence, 0); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 763, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_3); + __pyx_t_8 = PySequence_ITEM(sequence, 1); if (unlikely(!__pyx_t_8)) __PYX_ERR(0, 763, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_8); + #endif + __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; + } else { + Py_ssize_t index = -1; + __pyx_t_11 = PyObject_GetIter(__pyx_t_1); if (unlikely(!__pyx_t_11)) __PYX_ERR(0, 763, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_11); + __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; + __pyx_t_9 = __Pyx_PyObject_GetIterNextFunc(__pyx_t_11); + index = 0; __pyx_t_3 = __pyx_t_9(__pyx_t_11); if (unlikely(!__pyx_t_3)) goto __pyx_L23_unpacking_failed; + __Pyx_GOTREF(__pyx_t_3); + index = 1; __pyx_t_8 = __pyx_t_9(__pyx_t_11); if (unlikely(!__pyx_t_8)) goto __pyx_L23_unpacking_failed; + __Pyx_GOTREF(__pyx_t_8); + if (__Pyx_IternextUnpackEndCheck(__pyx_t_9(__pyx_t_11), 2) < 0) __PYX_ERR(0, 763, __pyx_L1_error) + __pyx_t_9 = NULL; + __Pyx_DECREF(__pyx_t_11); __pyx_t_11 = 0; + goto __pyx_L24_unpacking_done; + __pyx_L23_unpacking_failed:; + __Pyx_DECREF(__pyx_t_11); __pyx_t_11 = 0; + __pyx_t_9 = NULL; + if (__Pyx_IterFinish() == 0) __Pyx_RaiseNeedMoreValuesError(index); + __PYX_ERR(0, 763, __pyx_L1_error) + __pyx_L24_unpacking_done:; + } + __Pyx_XDECREF_SET(__pyx_v_constraint, __pyx_t_3); + __pyx_t_3 = 0; + __Pyx_XDECREF_SET(__pyx_v_variables, __pyx_t_8); + __pyx_t_8 = 0; - /* "constraint/solvers.py":770 - * # Split parallel and sequential parts - * first_var = sorted_vars[0] - * remaining_vars = sorted_vars[1:] # <<<<<<<<<<<<<< - * - * # Create the parallel function arguments and solutions lists + /* "constraint/solvers.py":764 + * assignments[variable] = values.pop() + * for constraint, variables in constraint_lookup[variable]: + * if not constraint(variables, domains, assignments, None): # <<<<<<<<<<<<<< + * # Value is not good. + * break */ - if (unlikely(__pyx_v_sorted_vars == Py_None)) { - PyErr_SetString(PyExc_TypeError, "'NoneType' object is not subscriptable"); - __PYX_ERR(0, 770, __pyx_L1_error) - } - __pyx_t_8 = __Pyx_PyList_GetSlice(__pyx_v_sorted_vars, 1, PY_SSIZE_T_MAX); if (unlikely(!__pyx_t_8)) __PYX_ERR(0, 770, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_8); - __Pyx_GIVEREF(__pyx_t_8); - __pyx_cur_scope->__pyx_v_remaining_vars = ((PyObject*)__pyx_t_8); - __pyx_t_8 = 0; + __Pyx_INCREF(__pyx_v_constraint); + __pyx_t_8 = __pyx_v_constraint; __pyx_t_3 = NULL; + __pyx_t_12 = 0; + #if CYTHON_UNPACK_METHODS + if (unlikely(PyMethod_Check(__pyx_t_8))) { + __pyx_t_3 = PyMethod_GET_SELF(__pyx_t_8); + if (likely(__pyx_t_3)) { + PyObject* function = PyMethod_GET_FUNCTION(__pyx_t_8); + __Pyx_INCREF(__pyx_t_3); + __Pyx_INCREF(function); + __Pyx_DECREF_SET(__pyx_t_8, function); + __pyx_t_12 = 1; + } + } + #endif + { + PyObject *__pyx_callargs[5] = {__pyx_t_3, __pyx_v_variables, __pyx_v_domains, __pyx_v_assignments, Py_None}; + __pyx_t_1 = __Pyx_PyObject_FastCall(__pyx_t_8, __pyx_callargs+1-__pyx_t_12, 4+__pyx_t_12); + __Pyx_XDECREF(__pyx_t_3); __pyx_t_3 = 0; + if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 764, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __Pyx_DECREF(__pyx_t_8); __pyx_t_8 = 0; + } + __pyx_t_4 = __Pyx_PyObject_IsTrue(__pyx_t_1); if (unlikely((__pyx_t_4 < 0))) __PYX_ERR(0, 764, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; + __pyx_t_7 = (!__pyx_t_4); + if (__pyx_t_7) { - /* "constraint/solvers.py":773 - * - * # Create the parallel function arguments and solutions lists - * args = ((self.requires_pickling, domains, constraint_lookup, first_var, val, remaining_vars.copy()) for val in domains[first_var]) # noqa: E501 # <<<<<<<<<<<<<< - * solutions: list[dict[Hashable, any]] = [] - * + /* "constraint/solvers.py":766 + * if not constraint(variables, domains, assignments, None): + * # Value is not good. + * break # <<<<<<<<<<<<<< + * else: + * break */ - __pyx_t_8 = __Pyx_PyDict_GetItem(__pyx_cur_scope->__pyx_v_domains, __pyx_cur_scope->__pyx_v_first_var); if (unlikely(!__pyx_t_8)) __PYX_ERR(0, 773, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_8); - __pyx_t_1 = __pyx_pf_10constraint_7solvers_14ParallelSolver_16getSolutionsList_1genexpr(((PyObject*)__pyx_cur_scope), __pyx_t_8); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 773, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_1); - __Pyx_DECREF(__pyx_t_8); __pyx_t_8 = 0; - __pyx_v_args = __pyx_t_1; - __pyx_t_1 = 0; + goto __pyx_L22_break; - /* "constraint/solvers.py":774 - * # Create the parallel function arguments and solutions lists - * args = ((self.requires_pickling, domains, constraint_lookup, first_var, val, remaining_vars.copy()) for val in domains[first_var]) # noqa: E501 - * solutions: list[dict[Hashable, any]] = [] # <<<<<<<<<<<<<< - * - * # execute in parallel + /* "constraint/solvers.py":764 + * assignments[variable] = values.pop() + * for constraint, variables in constraint_lookup[variable]: + * if not constraint(variables, domains, assignments, None): # <<<<<<<<<<<<<< + * # Value is not good. + * break */ - __pyx_t_1 = PyList_New(0); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 774, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_1); - __pyx_v_solutions = ((PyObject*)__pyx_t_1); - __pyx_t_1 = 0; + } - /* "constraint/solvers.py":777 - * - * # execute in parallel - * parallel_pool = ProcessPoolExecutor if self._process_mode else ThreadPoolExecutor # <<<<<<<<<<<<<< - * with parallel_pool() as executor: - * # results = map(parallel_worker, args) # sequential + /* "constraint/solvers.py":763 + * # Got a value. Check it. + * assignments[variable] = values.pop() + * for constraint, variables in constraint_lookup[variable]: # <<<<<<<<<<<<<< + * if not constraint(variables, domains, assignments, None): + * # Value is not good. */ - __pyx_t_8 = __Pyx_PyObject_GetAttrStr(__pyx_cur_scope->__pyx_v_self, __pyx_n_s_process_mode_2); if (unlikely(!__pyx_t_8)) __PYX_ERR(0, 777, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_8); - __pyx_t_9 = __Pyx_PyObject_IsTrue(__pyx_t_8); if (unlikely((__pyx_t_9 < 0))) __PYX_ERR(0, 777, __pyx_L1_error) - __Pyx_DECREF(__pyx_t_8); __pyx_t_8 = 0; - if (__pyx_t_9) { - __Pyx_GetModuleGlobalName(__pyx_t_8, __pyx_n_s_ProcessPoolExecutor); if (unlikely(!__pyx_t_8)) __PYX_ERR(0, 777, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_8); - __pyx_t_1 = __pyx_t_8; - __pyx_t_8 = 0; - } else { - __Pyx_GetModuleGlobalName(__pyx_t_8, __pyx_n_s_ThreadPoolExecutor); if (unlikely(!__pyx_t_8)) __PYX_ERR(0, 777, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_8); - __pyx_t_1 = __pyx_t_8; - __pyx_t_8 = 0; - } - __pyx_v_parallel_pool = __pyx_t_1; - __pyx_t_1 = 0; + } + __Pyx_DECREF(__pyx_t_5); __pyx_t_5 = 0; + goto __pyx_L26_for_else; + __pyx_L22_break:; + __Pyx_DECREF(__pyx_t_5); __pyx_t_5 = 0; + goto __pyx_L27_for_end; + /*else*/ { + __pyx_L26_for_else:; - /* "constraint/solvers.py":778 - * # execute in parallel - * parallel_pool = ProcessPoolExecutor if self._process_mode else ThreadPoolExecutor - * with parallel_pool() as executor: # <<<<<<<<<<<<<< - * # results = map(parallel_worker, args) # sequential - * results = executor.map(parallel_worker, args, chunksize=1) # parallel + /* "constraint/solvers.py":768 + * break + * else: + * break # <<<<<<<<<<<<<< + * + * # Push state before looking for next variable. */ - /*with:*/ { - __Pyx_INCREF(__pyx_v_parallel_pool); - __pyx_t_8 = __pyx_v_parallel_pool; __pyx_t_2 = NULL; - __pyx_t_10 = 0; - #if CYTHON_UNPACK_METHODS - if (unlikely(PyMethod_Check(__pyx_t_8))) { - __pyx_t_2 = PyMethod_GET_SELF(__pyx_t_8); - if (likely(__pyx_t_2)) { - PyObject* function = PyMethod_GET_FUNCTION(__pyx_t_8); - __Pyx_INCREF(__pyx_t_2); - __Pyx_INCREF(function); - __Pyx_DECREF_SET(__pyx_t_8, function); - __pyx_t_10 = 1; - } - } - #endif - { - PyObject *__pyx_callargs[2] = {__pyx_t_2, NULL}; - __pyx_t_1 = __Pyx_PyObject_FastCall(__pyx_t_8, __pyx_callargs+1-__pyx_t_10, 0+__pyx_t_10); - __Pyx_XDECREF(__pyx_t_2); __pyx_t_2 = 0; - if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 778, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_1); - __Pyx_DECREF(__pyx_t_8); __pyx_t_8 = 0; - } - __pyx_t_11 = __Pyx_PyObject_LookupSpecial(__pyx_t_1, __pyx_n_s_exit); if (unlikely(!__pyx_t_11)) __PYX_ERR(0, 778, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_11); - __pyx_t_2 = __Pyx_PyObject_LookupSpecial(__pyx_t_1, __pyx_n_s_enter); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 778, __pyx_L9_error) - __Pyx_GOTREF(__pyx_t_2); - __pyx_t_6 = NULL; - __pyx_t_10 = 0; - #if CYTHON_UNPACK_METHODS - if (likely(PyMethod_Check(__pyx_t_2))) { - __pyx_t_6 = PyMethod_GET_SELF(__pyx_t_2); - if (likely(__pyx_t_6)) { - PyObject* function = PyMethod_GET_FUNCTION(__pyx_t_2); - __Pyx_INCREF(__pyx_t_6); - __Pyx_INCREF(function); - __Pyx_DECREF_SET(__pyx_t_2, function); - __pyx_t_10 = 1; + goto __pyx_L14_break; } + __pyx_L27_for_end:; } - #endif - { - PyObject *__pyx_callargs[2] = {__pyx_t_6, NULL}; - __pyx_t_8 = __Pyx_PyObject_FastCall(__pyx_t_2, __pyx_callargs+1-__pyx_t_10, 0+__pyx_t_10); - __Pyx_XDECREF(__pyx_t_6); __pyx_t_6 = 0; - if (unlikely(!__pyx_t_8)) __PYX_ERR(0, 778, __pyx_L9_error) - __Pyx_GOTREF(__pyx_t_8); - __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; - } - __pyx_t_2 = __pyx_t_8; - __pyx_t_8 = 0; - __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; - /*try:*/ { - { - __Pyx_PyThreadState_declare - __Pyx_PyThreadState_assign - __Pyx_ExceptionSave(&__pyx_t_12, &__pyx_t_13, &__pyx_t_14); - __Pyx_XGOTREF(__pyx_t_12); - __Pyx_XGOTREF(__pyx_t_13); - __Pyx_XGOTREF(__pyx_t_14); - /*try:*/ { - __pyx_v_executor = __pyx_t_2; - __pyx_t_2 = 0; - - /* "constraint/solvers.py":780 - * with parallel_pool() as executor: - * # results = map(parallel_worker, args) # sequential - * results = executor.map(parallel_worker, args, chunksize=1) # parallel # <<<<<<<<<<<<<< - * for result in results: - * solutions.extend(result) - */ - __pyx_t_2 = __Pyx_PyObject_GetAttrStr(__pyx_v_executor, __pyx_n_s_map); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 780, __pyx_L13_error) - __Pyx_GOTREF(__pyx_t_2); - __Pyx_GetModuleGlobalName(__pyx_t_1, __pyx_n_s_parallel_worker); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 780, __pyx_L13_error) - __Pyx_GOTREF(__pyx_t_1); - __pyx_t_8 = PyTuple_New(2); if (unlikely(!__pyx_t_8)) __PYX_ERR(0, 780, __pyx_L13_error) - __Pyx_GOTREF(__pyx_t_8); - __Pyx_GIVEREF(__pyx_t_1); - if (__Pyx_PyTuple_SET_ITEM(__pyx_t_8, 0, __pyx_t_1)) __PYX_ERR(0, 780, __pyx_L13_error); - __Pyx_INCREF(__pyx_v_args); - __Pyx_GIVEREF(__pyx_v_args); - if (__Pyx_PyTuple_SET_ITEM(__pyx_t_8, 1, __pyx_v_args)) __PYX_ERR(0, 780, __pyx_L13_error); - __pyx_t_1 = 0; - __pyx_t_1 = __Pyx_PyDict_NewPresized(1); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 780, __pyx_L13_error) - __Pyx_GOTREF(__pyx_t_1); - if (PyDict_SetItem(__pyx_t_1, __pyx_n_s_chunksize, __pyx_int_1) < 0) __PYX_ERR(0, 780, __pyx_L13_error) - __pyx_t_6 = __Pyx_PyObject_Call(__pyx_t_2, __pyx_t_8, __pyx_t_1); if (unlikely(!__pyx_t_6)) __PYX_ERR(0, 780, __pyx_L13_error) - __Pyx_GOTREF(__pyx_t_6); - __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; - __Pyx_DECREF(__pyx_t_8); __pyx_t_8 = 0; - __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; - __pyx_v_results = __pyx_t_6; - __pyx_t_6 = 0; + __pyx_L14_break:; - /* "constraint/solvers.py":781 - * # results = map(parallel_worker, args) # sequential - * results = executor.map(parallel_worker, args, chunksize=1) # parallel - * for result in results: # <<<<<<<<<<<<<< - * solutions.extend(result) + /* "constraint/solvers.py":771 + * + * # Push state before looking for next variable. + * queue.append((variable, values)) # <<<<<<<<<<<<<< + * * */ - if (likely(PyList_CheckExact(__pyx_v_results)) || PyTuple_CheckExact(__pyx_v_results)) { - __pyx_t_6 = __pyx_v_results; __Pyx_INCREF(__pyx_t_6); - __pyx_t_4 = 0; - __pyx_t_15 = NULL; - } else { - __pyx_t_4 = -1; __pyx_t_6 = PyObject_GetIter(__pyx_v_results); if (unlikely(!__pyx_t_6)) __PYX_ERR(0, 781, __pyx_L13_error) - __Pyx_GOTREF(__pyx_t_6); - __pyx_t_15 = __Pyx_PyObject_GetIterNextFunc(__pyx_t_6); if (unlikely(!__pyx_t_15)) __PYX_ERR(0, 781, __pyx_L13_error) - } - for (;;) { - if (likely(!__pyx_t_15)) { - if (likely(PyList_CheckExact(__pyx_t_6))) { - { - Py_ssize_t __pyx_temp = __Pyx_PyList_GET_SIZE(__pyx_t_6); - #if !CYTHON_ASSUME_SAFE_MACROS - if (unlikely((__pyx_temp < 0))) __PYX_ERR(0, 781, __pyx_L13_error) - #endif - if (__pyx_t_4 >= __pyx_temp) break; - } - #if CYTHON_ASSUME_SAFE_MACROS && !CYTHON_AVOID_BORROWED_REFS - __pyx_t_1 = PyList_GET_ITEM(__pyx_t_6, __pyx_t_4); __Pyx_INCREF(__pyx_t_1); __pyx_t_4++; if (unlikely((0 < 0))) __PYX_ERR(0, 781, __pyx_L13_error) - #else - __pyx_t_1 = __Pyx_PySequence_ITEM(__pyx_t_6, __pyx_t_4); __pyx_t_4++; if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 781, __pyx_L13_error) - __Pyx_GOTREF(__pyx_t_1); - #endif - } else { - { - Py_ssize_t __pyx_temp = __Pyx_PyTuple_GET_SIZE(__pyx_t_6); - #if !CYTHON_ASSUME_SAFE_MACROS - if (unlikely((__pyx_temp < 0))) __PYX_ERR(0, 781, __pyx_L13_error) - #endif - if (__pyx_t_4 >= __pyx_temp) break; - } - #if CYTHON_ASSUME_SAFE_MACROS && !CYTHON_AVOID_BORROWED_REFS - __pyx_t_1 = PyTuple_GET_ITEM(__pyx_t_6, __pyx_t_4); __Pyx_INCREF(__pyx_t_1); __pyx_t_4++; if (unlikely((0 < 0))) __PYX_ERR(0, 781, __pyx_L13_error) - #else - __pyx_t_1 = __Pyx_PySequence_ITEM(__pyx_t_6, __pyx_t_4); __pyx_t_4++; if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 781, __pyx_L13_error) - __Pyx_GOTREF(__pyx_t_1); - #endif - } - } else { - __pyx_t_1 = __pyx_t_15(__pyx_t_6); - if (unlikely(!__pyx_t_1)) { - PyObject* exc_type = PyErr_Occurred(); - if (exc_type) { - if (likely(__Pyx_PyErr_GivenExceptionMatches(exc_type, PyExc_StopIteration))) PyErr_Clear(); - else __PYX_ERR(0, 781, __pyx_L13_error) - } - break; - } - __Pyx_GOTREF(__pyx_t_1); - } - __Pyx_XDECREF_SET(__pyx_v_result, __pyx_t_1); - __pyx_t_1 = 0; + __pyx_t_5 = PyTuple_New(2); if (unlikely(!__pyx_t_5)) __PYX_ERR(0, 771, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_5); + __Pyx_INCREF(__pyx_v_variable); + __Pyx_GIVEREF(__pyx_v_variable); + if (__Pyx_PyTuple_SET_ITEM(__pyx_t_5, 0, __pyx_v_variable)) __PYX_ERR(0, 771, __pyx_L1_error); + __Pyx_INCREF(__pyx_v_values); + __Pyx_GIVEREF(__pyx_v_values); + if (__Pyx_PyTuple_SET_ITEM(__pyx_t_5, 1, __pyx_v_values)) __PYX_ERR(0, 771, __pyx_L1_error); + __pyx_t_6 = __Pyx_PyList_Append(__pyx_v_queue, __pyx_t_5); if (unlikely(__pyx_t_6 == ((int)-1))) __PYX_ERR(0, 771, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_5); __pyx_t_5 = 0; + } - /* "constraint/solvers.py":782 - * results = executor.map(parallel_worker, args, chunksize=1) # parallel - * for result in results: - * solutions.extend(result) # <<<<<<<<<<<<<< + /* "constraint/solvers.py":724 + * return solutions * - * return solutions + * def sequential_optimized_backtrack(assignment: dict[Hashable, any], unassigned_vars: list[Hashable], domains: dict[Hashable, Domain], constraint_lookup: dict[Hashable, list[tuple[Constraint, Hashable]]]) -> list[dict[Hashable, any]]: # noqa E501 # <<<<<<<<<<<<<< + * """Sequential optimized backtracking (as in OptimizedBacktrackingSolver) function for subproblems.""" + * # Does not do forwardcheck for simplicity */ - __pyx_t_16 = __Pyx_PyList_Extend(__pyx_v_solutions, __pyx_v_result); if (unlikely(__pyx_t_16 == ((int)-1))) __PYX_ERR(0, 782, __pyx_L13_error) - /* "constraint/solvers.py":781 - * # results = map(parallel_worker, args) # sequential - * results = executor.map(parallel_worker, args, chunksize=1) # parallel - * for result in results: # <<<<<<<<<<<<<< - * solutions.extend(result) + /* function exit code */ + __pyx_r = ((PyObject*)Py_None); __Pyx_INCREF(Py_None); + goto __pyx_L0; + __pyx_L1_error:; + __Pyx_XDECREF(__pyx_t_1); + __Pyx_XDECREF(__pyx_t_3); + __Pyx_XDECREF(__pyx_t_5); + __Pyx_XDECREF(__pyx_t_8); + __Pyx_XDECREF(__pyx_t_11); + __Pyx_AddTraceback("constraint.solvers.sequential_optimized_backtrack", __pyx_clineno, __pyx_lineno, __pyx_filename); + __pyx_r = NULL; + __pyx_L0:; + __Pyx_XDECREF(__pyx_v_assignments); + __Pyx_XDECREF(__pyx_v_sorted_variables); + __Pyx_XDECREF(__pyx_v_queue); + __Pyx_XDECREF(__pyx_v_solutions); + __Pyx_XDECREF(__pyx_v_variable); + __Pyx_XDECREF(__pyx_v_values); + __Pyx_XDECREF(__pyx_v_constraint); + __Pyx_XDECREF(__pyx_v_variables); + __Pyx_XGIVEREF(__pyx_r); + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +/* "constraint/solvers.py":774 * + * + * def parallel_worker(args: tuple[bool, dict[Hashable, Domain], dict[Hashable, list[tuple[Constraint, Hashable]]], Hashable, any, list[Hashable]]) -> list[dict[Hashable, any]]: # noqa E501 # <<<<<<<<<<<<<< + * """Worker function for parallel execution on first variable.""" + * process_mode, domains, constraint_lookup, first_var, first_value, remaining_vars = args */ - } - __Pyx_DECREF(__pyx_t_6); __pyx_t_6 = 0; - /* "constraint/solvers.py":778 - * # execute in parallel - * parallel_pool = ProcessPoolExecutor if self._process_mode else ThreadPoolExecutor - * with parallel_pool() as executor: # <<<<<<<<<<<<<< - * # results = map(parallel_worker, args) # sequential - * results = executor.map(parallel_worker, args, chunksize=1) # parallel - */ - } - __Pyx_XDECREF(__pyx_t_12); __pyx_t_12 = 0; - __Pyx_XDECREF(__pyx_t_13); __pyx_t_13 = 0; - __Pyx_XDECREF(__pyx_t_14); __pyx_t_14 = 0; - goto __pyx_L18_try_end; - __pyx_L13_error:; - __Pyx_XDECREF(__pyx_t_1); __pyx_t_1 = 0; - __Pyx_XDECREF(__pyx_t_2); __pyx_t_2 = 0; - __Pyx_XDECREF(__pyx_t_6); __pyx_t_6 = 0; - __Pyx_XDECREF(__pyx_t_8); __pyx_t_8 = 0; - /*except:*/ { - __Pyx_AddTraceback("constraint.solvers.ParallelSolver.getSolutionsList", __pyx_clineno, __pyx_lineno, __pyx_filename); - if (__Pyx_GetException(&__pyx_t_6, &__pyx_t_1, &__pyx_t_8) < 0) __PYX_ERR(0, 778, __pyx_L15_except_error) - __Pyx_XGOTREF(__pyx_t_6); - __Pyx_XGOTREF(__pyx_t_1); - __Pyx_XGOTREF(__pyx_t_8); - __pyx_t_2 = PyTuple_Pack(3, __pyx_t_6, __pyx_t_1, __pyx_t_8); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 778, __pyx_L15_except_error) - __Pyx_GOTREF(__pyx_t_2); - __pyx_t_17 = __Pyx_PyObject_Call(__pyx_t_11, __pyx_t_2, NULL); - __Pyx_DECREF(__pyx_t_11); __pyx_t_11 = 0; - __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; - if (unlikely(!__pyx_t_17)) __PYX_ERR(0, 778, __pyx_L15_except_error) - __Pyx_GOTREF(__pyx_t_17); - __pyx_t_9 = __Pyx_PyObject_IsTrue(__pyx_t_17); - __Pyx_DECREF(__pyx_t_17); __pyx_t_17 = 0; - if (__pyx_t_9 < 0) __PYX_ERR(0, 778, __pyx_L15_except_error) - __pyx_t_18 = (!__pyx_t_9); - if (unlikely(__pyx_t_18)) { - __Pyx_GIVEREF(__pyx_t_6); - __Pyx_GIVEREF(__pyx_t_1); - __Pyx_XGIVEREF(__pyx_t_8); - __Pyx_ErrRestoreWithState(__pyx_t_6, __pyx_t_1, __pyx_t_8); - __pyx_t_6 = 0; __pyx_t_1 = 0; __pyx_t_8 = 0; - __PYX_ERR(0, 778, __pyx_L15_except_error) - } - __Pyx_XDECREF(__pyx_t_6); __pyx_t_6 = 0; - __Pyx_XDECREF(__pyx_t_1); __pyx_t_1 = 0; - __Pyx_XDECREF(__pyx_t_8); __pyx_t_8 = 0; - goto __pyx_L14_exception_handled; +/* Python wrapper */ +static PyObject *__pyx_pw_10constraint_7solvers_13parallel_worker(PyObject *__pyx_self, +#if CYTHON_METH_FASTCALL +PyObject *const *__pyx_args, Py_ssize_t __pyx_nargs, PyObject *__pyx_kwds +#else +PyObject *__pyx_args, PyObject *__pyx_kwds +#endif +); /*proto*/ +PyDoc_STRVAR(__pyx_doc_10constraint_7solvers_12parallel_worker, "Worker function for parallel execution on first variable."); +static PyMethodDef __pyx_mdef_10constraint_7solvers_13parallel_worker = {"parallel_worker", (PyCFunction)(void*)(__Pyx_PyCFunction_FastCallWithKeywords)__pyx_pw_10constraint_7solvers_13parallel_worker, __Pyx_METH_FASTCALL|METH_KEYWORDS, __pyx_doc_10constraint_7solvers_12parallel_worker}; +static PyObject *__pyx_pw_10constraint_7solvers_13parallel_worker(PyObject *__pyx_self, +#if CYTHON_METH_FASTCALL +PyObject *const *__pyx_args, Py_ssize_t __pyx_nargs, PyObject *__pyx_kwds +#else +PyObject *__pyx_args, PyObject *__pyx_kwds +#endif +) { + PyObject *__pyx_v_args = 0; + #if !CYTHON_METH_FASTCALL + CYTHON_UNUSED Py_ssize_t __pyx_nargs; + #endif + CYTHON_UNUSED PyObject *const *__pyx_kwvalues; + PyObject* values[1] = {0}; + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + PyObject *__pyx_r = 0; + __Pyx_RefNannyDeclarations + __Pyx_RefNannySetupContext("parallel_worker (wrapper)", 0); + #if !CYTHON_METH_FASTCALL + #if CYTHON_ASSUME_SAFE_MACROS + __pyx_nargs = PyTuple_GET_SIZE(__pyx_args); + #else + __pyx_nargs = PyTuple_Size(__pyx_args); if (unlikely(__pyx_nargs < 0)) return NULL; + #endif + #endif + __pyx_kwvalues = __Pyx_KwValues_FASTCALL(__pyx_args, __pyx_nargs); + { + PyObject **__pyx_pyargnames[] = {&__pyx_n_s_args,0}; + if (__pyx_kwds) { + Py_ssize_t kw_args; + switch (__pyx_nargs) { + case 1: values[0] = __Pyx_Arg_FASTCALL(__pyx_args, 0); + CYTHON_FALLTHROUGH; + case 0: break; + default: goto __pyx_L5_argtuple_error; + } + kw_args = __Pyx_NumKwargs_FASTCALL(__pyx_kwds); + switch (__pyx_nargs) { + case 0: + if (likely((values[0] = __Pyx_GetKwValue_FASTCALL(__pyx_kwds, __pyx_kwvalues, __pyx_n_s_args)) != 0)) { + (void)__Pyx_Arg_NewRef_FASTCALL(values[0]); + kw_args--; } - __pyx_L15_except_error:; - __Pyx_XGIVEREF(__pyx_t_12); - __Pyx_XGIVEREF(__pyx_t_13); - __Pyx_XGIVEREF(__pyx_t_14); - __Pyx_ExceptionReset(__pyx_t_12, __pyx_t_13, __pyx_t_14); - goto __pyx_L1_error; - __pyx_L14_exception_handled:; - __Pyx_XGIVEREF(__pyx_t_12); - __Pyx_XGIVEREF(__pyx_t_13); - __Pyx_XGIVEREF(__pyx_t_14); - __Pyx_ExceptionReset(__pyx_t_12, __pyx_t_13, __pyx_t_14); - __pyx_L18_try_end:; + else if (unlikely(PyErr_Occurred())) __PYX_ERR(0, 774, __pyx_L3_error) + else goto __pyx_L5_argtuple_error; + } + if (unlikely(kw_args > 0)) { + const Py_ssize_t kwd_pos_args = __pyx_nargs; + if (unlikely(__Pyx_ParseOptionalKeywords(__pyx_kwds, __pyx_kwvalues, __pyx_pyargnames, 0, values + 0, kwd_pos_args, "parallel_worker") < 0)) __PYX_ERR(0, 774, __pyx_L3_error) } + } else if (unlikely(__pyx_nargs != 1)) { + goto __pyx_L5_argtuple_error; + } else { + values[0] = __Pyx_Arg_FASTCALL(__pyx_args, 0); } - /*finally:*/ { - /*normal exit:*/{ - if (__pyx_t_11) { - __pyx_t_14 = __Pyx_PyObject_Call(__pyx_t_11, __pyx_tuple__5, NULL); - __Pyx_DECREF(__pyx_t_11); __pyx_t_11 = 0; - if (unlikely(!__pyx_t_14)) __PYX_ERR(0, 778, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_14); - __Pyx_DECREF(__pyx_t_14); __pyx_t_14 = 0; - } - goto __pyx_L12; + __pyx_v_args = ((PyObject*)values[0]); + } + goto __pyx_L6_skip; + __pyx_L5_argtuple_error:; + __Pyx_RaiseArgtupleInvalid("parallel_worker", 1, 1, 1, __pyx_nargs); __PYX_ERR(0, 774, __pyx_L3_error) + __pyx_L6_skip:; + goto __pyx_L4_argument_unpacking_done; + __pyx_L3_error:; + { + Py_ssize_t __pyx_temp; + for (__pyx_temp=0; __pyx_temp < (Py_ssize_t)(sizeof(values)/sizeof(values[0])); ++__pyx_temp) { + __Pyx_Arg_XDECREF_FASTCALL(values[__pyx_temp]); + } + } + __Pyx_AddTraceback("constraint.solvers.parallel_worker", __pyx_clineno, __pyx_lineno, __pyx_filename); + __Pyx_RefNannyFinishContext(); + return NULL; + __pyx_L4_argument_unpacking_done:; + if (unlikely(!__Pyx_ArgTypeTest(((PyObject *)__pyx_v_args), (&PyTuple_Type), 0, "args", 1))) __PYX_ERR(0, 774, __pyx_L1_error) + __pyx_r = __pyx_pf_10constraint_7solvers_12parallel_worker(__pyx_self, __pyx_v_args); + + /* function exit code */ + goto __pyx_L0; + __pyx_L1_error:; + __pyx_r = NULL; + __pyx_L0:; + { + Py_ssize_t __pyx_temp; + for (__pyx_temp=0; __pyx_temp < (Py_ssize_t)(sizeof(values)/sizeof(values[0])); ++__pyx_temp) { + __Pyx_Arg_XDECREF_FASTCALL(values[__pyx_temp]); + } + } + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +static PyObject *__pyx_pf_10constraint_7solvers_12parallel_worker(CYTHON_UNUSED PyObject *__pyx_self, PyObject *__pyx_v_args) { + PyObject *__pyx_v_process_mode = NULL; + PyObject *__pyx_v_domains = NULL; + PyObject *__pyx_v_constraint_lookup = NULL; + PyObject *__pyx_v_first_var = NULL; + PyObject *__pyx_v_first_value = NULL; + PyObject *__pyx_v_remaining_vars = NULL; + PyObject *__pyx_v_local_assignment = NULL; + PyObject *__pyx_v_var = NULL; + PyObject *__pyx_v_constraints = NULL; + PyObject *__pyx_9genexpr11__pyx_v_constraint = NULL; + PyObject *__pyx_9genexpr11__pyx_v_vals = NULL; + PyObject *__pyx_r = NULL; + __Pyx_RefNannyDeclarations + PyObject *__pyx_t_1 = NULL; + PyObject *__pyx_t_2 = NULL; + PyObject *__pyx_t_3 = NULL; + PyObject *__pyx_t_4 = NULL; + PyObject *__pyx_t_5 = NULL; + PyObject *__pyx_t_6 = NULL; + int __pyx_t_7; + Py_ssize_t __pyx_t_8; + Py_ssize_t __pyx_t_9; + int __pyx_t_10; + int __pyx_t_11; + Py_ssize_t __pyx_t_12; + PyObject *(*__pyx_t_13)(PyObject *); + PyObject *__pyx_t_14 = NULL; + PyObject *(*__pyx_t_15)(PyObject *); + unsigned int __pyx_t_16; + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + __Pyx_RefNannySetupContext("parallel_worker", 1); + + /* "constraint/solvers.py":776 + * def parallel_worker(args: tuple[bool, dict[Hashable, Domain], dict[Hashable, list[tuple[Constraint, Hashable]]], Hashable, any, list[Hashable]]) -> list[dict[Hashable, any]]: # noqa E501 + * """Worker function for parallel execution on first variable.""" + * process_mode, domains, constraint_lookup, first_var, first_value, remaining_vars = args # <<<<<<<<<<<<<< + * local_assignment = {first_var: first_value} + * + */ + if (1) { + PyObject* sequence = __pyx_v_args; + Py_ssize_t size = __Pyx_PySequence_SIZE(sequence); + if (unlikely(size != 6)) { + if (size > 6) __Pyx_RaiseTooManyValuesError(6); + else if (size >= 0) __Pyx_RaiseNeedMoreValuesError(size); + __PYX_ERR(0, 776, __pyx_L1_error) + } + #if CYTHON_ASSUME_SAFE_MACROS && !CYTHON_AVOID_BORROWED_REFS + __pyx_t_1 = PyTuple_GET_ITEM(sequence, 0); + __pyx_t_2 = PyTuple_GET_ITEM(sequence, 1); + __pyx_t_3 = PyTuple_GET_ITEM(sequence, 2); + __pyx_t_4 = PyTuple_GET_ITEM(sequence, 3); + __pyx_t_5 = PyTuple_GET_ITEM(sequence, 4); + __pyx_t_6 = PyTuple_GET_ITEM(sequence, 5); + __Pyx_INCREF(__pyx_t_1); + __Pyx_INCREF(__pyx_t_2); + __Pyx_INCREF(__pyx_t_3); + __Pyx_INCREF(__pyx_t_4); + __Pyx_INCREF(__pyx_t_5); + __Pyx_INCREF(__pyx_t_6); + #else + { + Py_ssize_t i; + PyObject** temps[6] = {&__pyx_t_1,&__pyx_t_2,&__pyx_t_3,&__pyx_t_4,&__pyx_t_5,&__pyx_t_6}; + for (i=0; i < 6; i++) { + PyObject* item = PySequence_ITEM(sequence, i); if (unlikely(!item)) __PYX_ERR(0, 776, __pyx_L1_error) + __Pyx_GOTREF(item); + *(temps[i]) = item; } - __pyx_L12:; } - goto __pyx_L25; - __pyx_L9_error:; - __Pyx_DECREF(__pyx_t_11); __pyx_t_11 = 0; - goto __pyx_L1_error; - __pyx_L25:; + #endif } + __pyx_v_process_mode = __pyx_t_1; + __pyx_t_1 = 0; + __pyx_v_domains = __pyx_t_2; + __pyx_t_2 = 0; + __pyx_v_constraint_lookup = __pyx_t_3; + __pyx_t_3 = 0; + __pyx_v_first_var = __pyx_t_4; + __pyx_t_4 = 0; + __pyx_v_first_value = __pyx_t_5; + __pyx_t_5 = 0; + __pyx_v_remaining_vars = __pyx_t_6; + __pyx_t_6 = 0; - /* "constraint/solvers.py":784 - * solutions.extend(result) - * - * return solutions # <<<<<<<<<<<<<< + /* "constraint/solvers.py":777 + * """Worker function for parallel execution on first variable.""" + * process_mode, domains, constraint_lookup, first_var, first_value, remaining_vars = args + * local_assignment = {first_var: first_value} # <<<<<<<<<<<<<< * - * def getSolutions(self, domains: dict, constraints: list[tuple], vconstraints: dict): # noqa: D102 + * if process_mode: */ - __Pyx_XDECREF(__pyx_r); - __Pyx_INCREF(__pyx_v_solutions); - __pyx_r = __pyx_v_solutions; - goto __pyx_L0; + __pyx_t_6 = __Pyx_PyDict_NewPresized(1); if (unlikely(!__pyx_t_6)) __PYX_ERR(0, 777, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_6); + if (PyDict_SetItem(__pyx_t_6, __pyx_v_first_var, __pyx_v_first_value) < 0) __PYX_ERR(0, 777, __pyx_L1_error) + __pyx_v_local_assignment = ((PyObject*)__pyx_t_6); + __pyx_t_6 = 0; - /* "constraint/solvers.py":760 - * raise NotImplementedError(msg) + /* "constraint/solvers.py":779 + * local_assignment = {first_var: first_value} * - * def getSolutionsList(self, domains: dict[Hashable, Domain], vconstraints: dict[Hashable, list[tuple[Constraint, Hashable]]]) -> list[dict[Hashable, any]]: # noqa: D102, E501 # <<<<<<<<<<<<<< - * """Parallelized all-solutions finder using ProcessPoolExecutor for work-stealing.""" - * # Precompute constraints lookup per variable + * if process_mode: # <<<<<<<<<<<<<< + * # if there are any CompilableFunctionConstraint, they must be compiled locally first + * for var, constraints in constraint_lookup.items(): */ + __pyx_t_7 = __Pyx_PyObject_IsTrue(__pyx_v_process_mode); if (unlikely((__pyx_t_7 < 0))) __PYX_ERR(0, 779, __pyx_L1_error) + if (__pyx_t_7) { - /* function exit code */ - __pyx_L1_error:; - __Pyx_XDECREF(__pyx_t_1); - __Pyx_XDECREF(__pyx_t_2); - __Pyx_XDECREF(__pyx_t_6); - __Pyx_XDECREF(__pyx_t_8); - __Pyx_AddTraceback("constraint.solvers.ParallelSolver.getSolutionsList", __pyx_clineno, __pyx_lineno, __pyx_filename); - __pyx_r = NULL; - __pyx_L0:; - __Pyx_XDECREF(__pyx_v_sorted_vars); - __Pyx_XDECREF(__pyx_v_args); - __Pyx_XDECREF(__pyx_v_solutions); - __Pyx_XDECREF(__pyx_v_parallel_pool); - __Pyx_XDECREF(__pyx_v_executor); - __Pyx_XDECREF(__pyx_v_results); - __Pyx_XDECREF(__pyx_v_result); - __Pyx_XDECREF(__pyx_9genexpr10__pyx_v_var); - __Pyx_XDECREF(__pyx_gb_10constraint_7solvers_14ParallelSolver_16getSolutionsList_3generator4); - __Pyx_DECREF((PyObject *)__pyx_cur_scope); - __Pyx_XGIVEREF(__pyx_r); - __Pyx_RefNannyFinishContext(); - return __pyx_r; -} - -/* "constraint/solvers.py":786 - * return solutions - * - * def getSolutions(self, domains: dict, constraints: list[tuple], vconstraints: dict): # noqa: D102 # <<<<<<<<<<<<<< - * return self.getSolutionsList(domains, vconstraints) + /* "constraint/solvers.py":781 + * if process_mode: + * # if there are any CompilableFunctionConstraint, they must be compiled locally first + * for var, constraints in constraint_lookup.items(): # <<<<<<<<<<<<<< + * constraint_lookup[var] = [tuple([compile_to_function(constraint) if isinstance(constraint, CompilableFunctionConstraint) else constraint, vals]) for constraint, vals in constraints] # noqa E501 * */ + __pyx_t_8 = 0; + if (unlikely(__pyx_v_constraint_lookup == Py_None)) { + PyErr_Format(PyExc_AttributeError, "'NoneType' object has no attribute '%.30s'", "items"); + __PYX_ERR(0, 781, __pyx_L1_error) + } + __pyx_t_5 = __Pyx_dict_iterator(__pyx_v_constraint_lookup, 0, __pyx_n_s_items, (&__pyx_t_9), (&__pyx_t_10)); if (unlikely(!__pyx_t_5)) __PYX_ERR(0, 781, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_5); + __Pyx_XDECREF(__pyx_t_6); + __pyx_t_6 = __pyx_t_5; + __pyx_t_5 = 0; + while (1) { + __pyx_t_11 = __Pyx_dict_iter_next(__pyx_t_6, __pyx_t_9, &__pyx_t_8, &__pyx_t_5, &__pyx_t_4, NULL, __pyx_t_10); + if (unlikely(__pyx_t_11 == 0)) break; + if (unlikely(__pyx_t_11 == -1)) __PYX_ERR(0, 781, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_5); + __Pyx_GOTREF(__pyx_t_4); + __Pyx_XDECREF_SET(__pyx_v_var, __pyx_t_5); + __pyx_t_5 = 0; + __Pyx_XDECREF_SET(__pyx_v_constraints, __pyx_t_4); + __pyx_t_4 = 0; -/* Python wrapper */ -static PyObject *__pyx_pw_10constraint_7solvers_14ParallelSolver_7getSolutions(PyObject *__pyx_self, -#if CYTHON_METH_FASTCALL -PyObject *const *__pyx_args, Py_ssize_t __pyx_nargs, PyObject *__pyx_kwds -#else -PyObject *__pyx_args, PyObject *__pyx_kwds -#endif -); /*proto*/ -static PyMethodDef __pyx_mdef_10constraint_7solvers_14ParallelSolver_7getSolutions = {"getSolutions", (PyCFunction)(void*)(__Pyx_PyCFunction_FastCallWithKeywords)__pyx_pw_10constraint_7solvers_14ParallelSolver_7getSolutions, __Pyx_METH_FASTCALL|METH_KEYWORDS, 0}; -static PyObject *__pyx_pw_10constraint_7solvers_14ParallelSolver_7getSolutions(PyObject *__pyx_self, -#if CYTHON_METH_FASTCALL -PyObject *const *__pyx_args, Py_ssize_t __pyx_nargs, PyObject *__pyx_kwds -#else -PyObject *__pyx_args, PyObject *__pyx_kwds -#endif -) { - PyObject *__pyx_v_self = 0; - PyObject *__pyx_v_domains = 0; - CYTHON_UNUSED PyObject *__pyx_v_constraints = 0; - PyObject *__pyx_v_vconstraints = 0; - #if !CYTHON_METH_FASTCALL - CYTHON_UNUSED Py_ssize_t __pyx_nargs; - #endif - CYTHON_UNUSED PyObject *const *__pyx_kwvalues; - PyObject* values[4] = {0,0,0,0}; - int __pyx_lineno = 0; - const char *__pyx_filename = NULL; - int __pyx_clineno = 0; - PyObject *__pyx_r = 0; - __Pyx_RefNannyDeclarations - __Pyx_RefNannySetupContext("getSolutions (wrapper)", 0); - #if !CYTHON_METH_FASTCALL - #if CYTHON_ASSUME_SAFE_MACROS - __pyx_nargs = PyTuple_GET_SIZE(__pyx_args); - #else - __pyx_nargs = PyTuple_Size(__pyx_args); if (unlikely(__pyx_nargs < 0)) return NULL; - #endif - #endif - __pyx_kwvalues = __Pyx_KwValues_FASTCALL(__pyx_args, __pyx_nargs); - { - PyObject **__pyx_pyargnames[] = {&__pyx_n_s_self,&__pyx_n_s_domains,&__pyx_n_s_constraints,&__pyx_n_s_vconstraints,0}; - if (__pyx_kwds) { - Py_ssize_t kw_args; - switch (__pyx_nargs) { - case 4: values[3] = __Pyx_Arg_FASTCALL(__pyx_args, 3); - CYTHON_FALLTHROUGH; - case 3: values[2] = __Pyx_Arg_FASTCALL(__pyx_args, 2); - CYTHON_FALLTHROUGH; - case 2: values[1] = __Pyx_Arg_FASTCALL(__pyx_args, 1); - CYTHON_FALLTHROUGH; - case 1: values[0] = __Pyx_Arg_FASTCALL(__pyx_args, 0); - CYTHON_FALLTHROUGH; - case 0: break; - default: goto __pyx_L5_argtuple_error; - } - kw_args = __Pyx_NumKwargs_FASTCALL(__pyx_kwds); - switch (__pyx_nargs) { - case 0: - if (likely((values[0] = __Pyx_GetKwValue_FASTCALL(__pyx_kwds, __pyx_kwvalues, __pyx_n_s_self)) != 0)) { - (void)__Pyx_Arg_NewRef_FASTCALL(values[0]); - kw_args--; - } - else if (unlikely(PyErr_Occurred())) __PYX_ERR(0, 786, __pyx_L3_error) - else goto __pyx_L5_argtuple_error; - CYTHON_FALLTHROUGH; - case 1: - if (likely((values[1] = __Pyx_GetKwValue_FASTCALL(__pyx_kwds, __pyx_kwvalues, __pyx_n_s_domains)) != 0)) { - (void)__Pyx_Arg_NewRef_FASTCALL(values[1]); - kw_args--; - } - else if (unlikely(PyErr_Occurred())) __PYX_ERR(0, 786, __pyx_L3_error) - else { - __Pyx_RaiseArgtupleInvalid("getSolutions", 1, 4, 4, 1); __PYX_ERR(0, 786, __pyx_L3_error) - } - CYTHON_FALLTHROUGH; - case 2: - if (likely((values[2] = __Pyx_GetKwValue_FASTCALL(__pyx_kwds, __pyx_kwvalues, __pyx_n_s_constraints)) != 0)) { - (void)__Pyx_Arg_NewRef_FASTCALL(values[2]); - kw_args--; - } - else if (unlikely(PyErr_Occurred())) __PYX_ERR(0, 786, __pyx_L3_error) - else { - __Pyx_RaiseArgtupleInvalid("getSolutions", 1, 4, 4, 2); __PYX_ERR(0, 786, __pyx_L3_error) - } - CYTHON_FALLTHROUGH; - case 3: - if (likely((values[3] = __Pyx_GetKwValue_FASTCALL(__pyx_kwds, __pyx_kwvalues, __pyx_n_s_vconstraints)) != 0)) { - (void)__Pyx_Arg_NewRef_FASTCALL(values[3]); - kw_args--; + /* "constraint/solvers.py":782 + * # if there are any CompilableFunctionConstraint, they must be compiled locally first + * for var, constraints in constraint_lookup.items(): + * constraint_lookup[var] = [tuple([compile_to_function(constraint) if isinstance(constraint, CompilableFunctionConstraint) else constraint, vals]) for constraint, vals in constraints] # noqa E501 # <<<<<<<<<<<<<< + * + * # continue solving sequentially on this process + */ + { /* enter inner scope */ + __pyx_t_4 = PyList_New(0); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 782, __pyx_L8_error) + __Pyx_GOTREF(__pyx_t_4); + if (likely(PyList_CheckExact(__pyx_v_constraints)) || PyTuple_CheckExact(__pyx_v_constraints)) { + __pyx_t_5 = __pyx_v_constraints; __Pyx_INCREF(__pyx_t_5); + __pyx_t_12 = 0; + __pyx_t_13 = NULL; + } else { + __pyx_t_12 = -1; __pyx_t_5 = PyObject_GetIter(__pyx_v_constraints); if (unlikely(!__pyx_t_5)) __PYX_ERR(0, 782, __pyx_L8_error) + __Pyx_GOTREF(__pyx_t_5); + __pyx_t_13 = __Pyx_PyObject_GetIterNextFunc(__pyx_t_5); if (unlikely(!__pyx_t_13)) __PYX_ERR(0, 782, __pyx_L8_error) } - else if (unlikely(PyErr_Occurred())) __PYX_ERR(0, 786, __pyx_L3_error) - else { - __Pyx_RaiseArgtupleInvalid("getSolutions", 1, 4, 4, 3); __PYX_ERR(0, 786, __pyx_L3_error) + for (;;) { + if (likely(!__pyx_t_13)) { + if (likely(PyList_CheckExact(__pyx_t_5))) { + { + Py_ssize_t __pyx_temp = __Pyx_PyList_GET_SIZE(__pyx_t_5); + #if !CYTHON_ASSUME_SAFE_MACROS + if (unlikely((__pyx_temp < 0))) __PYX_ERR(0, 782, __pyx_L8_error) + #endif + if (__pyx_t_12 >= __pyx_temp) break; + } + #if CYTHON_ASSUME_SAFE_MACROS && !CYTHON_AVOID_BORROWED_REFS + __pyx_t_3 = PyList_GET_ITEM(__pyx_t_5, __pyx_t_12); __Pyx_INCREF(__pyx_t_3); __pyx_t_12++; if (unlikely((0 < 0))) __PYX_ERR(0, 782, __pyx_L8_error) + #else + __pyx_t_3 = __Pyx_PySequence_ITEM(__pyx_t_5, __pyx_t_12); __pyx_t_12++; if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 782, __pyx_L8_error) + __Pyx_GOTREF(__pyx_t_3); + #endif + } else { + { + Py_ssize_t __pyx_temp = __Pyx_PyTuple_GET_SIZE(__pyx_t_5); + #if !CYTHON_ASSUME_SAFE_MACROS + if (unlikely((__pyx_temp < 0))) __PYX_ERR(0, 782, __pyx_L8_error) + #endif + if (__pyx_t_12 >= __pyx_temp) break; + } + #if CYTHON_ASSUME_SAFE_MACROS && !CYTHON_AVOID_BORROWED_REFS + __pyx_t_3 = PyTuple_GET_ITEM(__pyx_t_5, __pyx_t_12); __Pyx_INCREF(__pyx_t_3); __pyx_t_12++; if (unlikely((0 < 0))) __PYX_ERR(0, 782, __pyx_L8_error) + #else + __pyx_t_3 = __Pyx_PySequence_ITEM(__pyx_t_5, __pyx_t_12); __pyx_t_12++; if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 782, __pyx_L8_error) + __Pyx_GOTREF(__pyx_t_3); + #endif + } + } else { + __pyx_t_3 = __pyx_t_13(__pyx_t_5); + if (unlikely(!__pyx_t_3)) { + PyObject* exc_type = PyErr_Occurred(); + if (exc_type) { + if (likely(__Pyx_PyErr_GivenExceptionMatches(exc_type, PyExc_StopIteration))) PyErr_Clear(); + else __PYX_ERR(0, 782, __pyx_L8_error) + } + break; + } + __Pyx_GOTREF(__pyx_t_3); + } + if ((likely(PyTuple_CheckExact(__pyx_t_3))) || (PyList_CheckExact(__pyx_t_3))) { + PyObject* sequence = __pyx_t_3; + Py_ssize_t size = __Pyx_PySequence_SIZE(sequence); + if (unlikely(size != 2)) { + if (size > 2) __Pyx_RaiseTooManyValuesError(2); + else if (size >= 0) __Pyx_RaiseNeedMoreValuesError(size); + __PYX_ERR(0, 782, __pyx_L8_error) + } + #if CYTHON_ASSUME_SAFE_MACROS && !CYTHON_AVOID_BORROWED_REFS + if (likely(PyTuple_CheckExact(sequence))) { + __pyx_t_2 = PyTuple_GET_ITEM(sequence, 0); + __pyx_t_1 = PyTuple_GET_ITEM(sequence, 1); + } else { + __pyx_t_2 = PyList_GET_ITEM(sequence, 0); + __pyx_t_1 = PyList_GET_ITEM(sequence, 1); + } + __Pyx_INCREF(__pyx_t_2); + __Pyx_INCREF(__pyx_t_1); + #else + __pyx_t_2 = PySequence_ITEM(sequence, 0); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 782, __pyx_L8_error) + __Pyx_GOTREF(__pyx_t_2); + __pyx_t_1 = PySequence_ITEM(sequence, 1); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 782, __pyx_L8_error) + __Pyx_GOTREF(__pyx_t_1); + #endif + __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; + } else { + Py_ssize_t index = -1; + __pyx_t_14 = PyObject_GetIter(__pyx_t_3); if (unlikely(!__pyx_t_14)) __PYX_ERR(0, 782, __pyx_L8_error) + __Pyx_GOTREF(__pyx_t_14); + __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; + __pyx_t_15 = __Pyx_PyObject_GetIterNextFunc(__pyx_t_14); + index = 0; __pyx_t_2 = __pyx_t_15(__pyx_t_14); if (unlikely(!__pyx_t_2)) goto __pyx_L11_unpacking_failed; + __Pyx_GOTREF(__pyx_t_2); + index = 1; __pyx_t_1 = __pyx_t_15(__pyx_t_14); if (unlikely(!__pyx_t_1)) goto __pyx_L11_unpacking_failed; + __Pyx_GOTREF(__pyx_t_1); + if (__Pyx_IternextUnpackEndCheck(__pyx_t_15(__pyx_t_14), 2) < 0) __PYX_ERR(0, 782, __pyx_L8_error) + __pyx_t_15 = NULL; + __Pyx_DECREF(__pyx_t_14); __pyx_t_14 = 0; + goto __pyx_L12_unpacking_done; + __pyx_L11_unpacking_failed:; + __Pyx_DECREF(__pyx_t_14); __pyx_t_14 = 0; + __pyx_t_15 = NULL; + if (__Pyx_IterFinish() == 0) __Pyx_RaiseNeedMoreValuesError(index); + __PYX_ERR(0, 782, __pyx_L8_error) + __pyx_L12_unpacking_done:; + } + __Pyx_XDECREF_SET(__pyx_9genexpr11__pyx_v_constraint, __pyx_t_2); + __pyx_t_2 = 0; + __Pyx_XDECREF_SET(__pyx_9genexpr11__pyx_v_vals, __pyx_t_1); + __pyx_t_1 = 0; + __Pyx_GetModuleGlobalName(__pyx_t_1, __pyx_n_s_CompilableFunctionConstraint); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 782, __pyx_L8_error) + __Pyx_GOTREF(__pyx_t_1); + __pyx_t_7 = PyObject_IsInstance(__pyx_9genexpr11__pyx_v_constraint, __pyx_t_1); if (unlikely(__pyx_t_7 == ((int)-1))) __PYX_ERR(0, 782, __pyx_L8_error) + __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; + if (__pyx_t_7) { + __Pyx_GetModuleGlobalName(__pyx_t_2, __pyx_n_s_compile_to_function); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 782, __pyx_L8_error) + __Pyx_GOTREF(__pyx_t_2); + __pyx_t_14 = NULL; + __pyx_t_16 = 0; + #if CYTHON_UNPACK_METHODS + if (unlikely(PyMethod_Check(__pyx_t_2))) { + __pyx_t_14 = PyMethod_GET_SELF(__pyx_t_2); + if (likely(__pyx_t_14)) { + PyObject* function = PyMethod_GET_FUNCTION(__pyx_t_2); + __Pyx_INCREF(__pyx_t_14); + __Pyx_INCREF(function); + __Pyx_DECREF_SET(__pyx_t_2, function); + __pyx_t_16 = 1; + } + } + #endif + { + PyObject *__pyx_callargs[2] = {__pyx_t_14, __pyx_9genexpr11__pyx_v_constraint}; + __pyx_t_1 = __Pyx_PyObject_FastCall(__pyx_t_2, __pyx_callargs+1-__pyx_t_16, 1+__pyx_t_16); + __Pyx_XDECREF(__pyx_t_14); __pyx_t_14 = 0; + if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 782, __pyx_L8_error) + __Pyx_GOTREF(__pyx_t_1); + __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; + } + __pyx_t_3 = __pyx_t_1; + __pyx_t_1 = 0; + } else { + __Pyx_INCREF(__pyx_9genexpr11__pyx_v_constraint); + __pyx_t_3 = __pyx_9genexpr11__pyx_v_constraint; + } + __pyx_t_1 = PyList_New(2); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 782, __pyx_L8_error) + __Pyx_GOTREF(__pyx_t_1); + __Pyx_GIVEREF(__pyx_t_3); + if (__Pyx_PyList_SET_ITEM(__pyx_t_1, 0, __pyx_t_3)) __PYX_ERR(0, 782, __pyx_L8_error); + __Pyx_INCREF(__pyx_9genexpr11__pyx_v_vals); + __Pyx_GIVEREF(__pyx_9genexpr11__pyx_v_vals); + if (__Pyx_PyList_SET_ITEM(__pyx_t_1, 1, __pyx_9genexpr11__pyx_v_vals)) __PYX_ERR(0, 782, __pyx_L8_error); + __pyx_t_3 = 0; + __pyx_t_3 = PyList_AsTuple(((PyObject*)__pyx_t_1)); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 782, __pyx_L8_error) + __Pyx_GOTREF(__pyx_t_3); + __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; + if (unlikely(__Pyx_ListComp_Append(__pyx_t_4, (PyObject*)__pyx_t_3))) __PYX_ERR(0, 782, __pyx_L8_error) + __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; } - } - if (unlikely(kw_args > 0)) { - const Py_ssize_t kwd_pos_args = __pyx_nargs; - if (unlikely(__Pyx_ParseOptionalKeywords(__pyx_kwds, __pyx_kwvalues, __pyx_pyargnames, 0, values + 0, kwd_pos_args, "getSolutions") < 0)) __PYX_ERR(0, 786, __pyx_L3_error) - } - } else if (unlikely(__pyx_nargs != 4)) { - goto __pyx_L5_argtuple_error; - } else { - values[0] = __Pyx_Arg_FASTCALL(__pyx_args, 0); - values[1] = __Pyx_Arg_FASTCALL(__pyx_args, 1); - values[2] = __Pyx_Arg_FASTCALL(__pyx_args, 2); - values[3] = __Pyx_Arg_FASTCALL(__pyx_args, 3); - } - __pyx_v_self = values[0]; - __pyx_v_domains = ((PyObject*)values[1]); - __pyx_v_constraints = ((PyObject*)values[2]); - __pyx_v_vconstraints = ((PyObject*)values[3]); - } - goto __pyx_L6_skip; - __pyx_L5_argtuple_error:; - __Pyx_RaiseArgtupleInvalid("getSolutions", 1, 4, 4, __pyx_nargs); __PYX_ERR(0, 786, __pyx_L3_error) - __pyx_L6_skip:; - goto __pyx_L4_argument_unpacking_done; - __pyx_L3_error:; - { - Py_ssize_t __pyx_temp; - for (__pyx_temp=0; __pyx_temp < (Py_ssize_t)(sizeof(values)/sizeof(values[0])); ++__pyx_temp) { - __Pyx_Arg_XDECREF_FASTCALL(values[__pyx_temp]); + __Pyx_DECREF(__pyx_t_5); __pyx_t_5 = 0; + __Pyx_XDECREF(__pyx_9genexpr11__pyx_v_constraint); __pyx_9genexpr11__pyx_v_constraint = 0; + __Pyx_XDECREF(__pyx_9genexpr11__pyx_v_vals); __pyx_9genexpr11__pyx_v_vals = 0; + goto __pyx_L14_exit_scope; + __pyx_L8_error:; + __Pyx_XDECREF(__pyx_9genexpr11__pyx_v_constraint); __pyx_9genexpr11__pyx_v_constraint = 0; + __Pyx_XDECREF(__pyx_9genexpr11__pyx_v_vals); __pyx_9genexpr11__pyx_v_vals = 0; + goto __pyx_L1_error; + __pyx_L14_exit_scope:; + } /* exit inner scope */ + if (unlikely((PyObject_SetItem(__pyx_v_constraint_lookup, __pyx_v_var, __pyx_t_4) < 0))) __PYX_ERR(0, 782, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; } - } - __Pyx_AddTraceback("constraint.solvers.ParallelSolver.getSolutions", __pyx_clineno, __pyx_lineno, __pyx_filename); - __Pyx_RefNannyFinishContext(); - return NULL; - __pyx_L4_argument_unpacking_done:; - if (unlikely(!__Pyx_ArgTypeTest(((PyObject *)__pyx_v_domains), (&PyDict_Type), 0, "domains", 1))) __PYX_ERR(0, 786, __pyx_L1_error) - if (unlikely(!__Pyx_ArgTypeTest(((PyObject *)__pyx_v_constraints), (&PyList_Type), 0, "constraints", 1))) __PYX_ERR(0, 786, __pyx_L1_error) - if (unlikely(!__Pyx_ArgTypeTest(((PyObject *)__pyx_v_vconstraints), (&PyDict_Type), 0, "vconstraints", 1))) __PYX_ERR(0, 786, __pyx_L1_error) - __pyx_r = __pyx_pf_10constraint_7solvers_14ParallelSolver_6getSolutions(__pyx_self, __pyx_v_self, __pyx_v_domains, __pyx_v_constraints, __pyx_v_vconstraints); + __Pyx_DECREF(__pyx_t_6); __pyx_t_6 = 0; - /* function exit code */ - goto __pyx_L0; - __pyx_L1_error:; - __pyx_r = NULL; - __pyx_L0:; - { - Py_ssize_t __pyx_temp; - for (__pyx_temp=0; __pyx_temp < (Py_ssize_t)(sizeof(values)/sizeof(values[0])); ++__pyx_temp) { - __Pyx_Arg_XDECREF_FASTCALL(values[__pyx_temp]); - } + /* "constraint/solvers.py":779 + * local_assignment = {first_var: first_value} + * + * if process_mode: # <<<<<<<<<<<<<< + * # if there are any CompilableFunctionConstraint, they must be compiled locally first + * for var, constraints in constraint_lookup.items(): + */ } - __Pyx_RefNannyFinishContext(); - return __pyx_r; -} - -static PyObject *__pyx_pf_10constraint_7solvers_14ParallelSolver_6getSolutions(CYTHON_UNUSED PyObject *__pyx_self, PyObject *__pyx_v_self, PyObject *__pyx_v_domains, CYTHON_UNUSED PyObject *__pyx_v_constraints, PyObject *__pyx_v_vconstraints) { - PyObject *__pyx_r = NULL; - __Pyx_RefNannyDeclarations - PyObject *__pyx_t_1 = NULL; - PyObject *__pyx_t_2 = NULL; - PyObject *__pyx_t_3 = NULL; - unsigned int __pyx_t_4; - int __pyx_lineno = 0; - const char *__pyx_filename = NULL; - int __pyx_clineno = 0; - __Pyx_RefNannySetupContext("getSolutions", 1); - /* "constraint/solvers.py":787 - * - * def getSolutions(self, domains: dict, constraints: list[tuple], vconstraints: dict): # noqa: D102 - * return self.getSolutionsList(domains, vconstraints) # <<<<<<<<<<<<<< + /* "constraint/solvers.py":785 * + * # continue solving sequentially on this process + * if is_valid(local_assignment, constraint_lookup[first_var], domains): # <<<<<<<<<<<<<< + * return sequential_optimized_backtrack(local_assignment, remaining_vars, domains, constraint_lookup) + * return [] */ - __Pyx_XDECREF(__pyx_r); - __pyx_t_2 = __Pyx_PyObject_GetAttrStr(__pyx_v_self, __pyx_n_s_getSolutionsList); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 787, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_2); + __Pyx_GetModuleGlobalName(__pyx_t_4, __pyx_n_s_is_valid); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 785, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_4); + __pyx_t_5 = __Pyx_PyObject_GetItem(__pyx_v_constraint_lookup, __pyx_v_first_var); if (unlikely(!__pyx_t_5)) __PYX_ERR(0, 785, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_5); __pyx_t_3 = NULL; - __pyx_t_4 = 0; + __pyx_t_16 = 0; #if CYTHON_UNPACK_METHODS - if (likely(PyMethod_Check(__pyx_t_2))) { - __pyx_t_3 = PyMethod_GET_SELF(__pyx_t_2); + if (unlikely(PyMethod_Check(__pyx_t_4))) { + __pyx_t_3 = PyMethod_GET_SELF(__pyx_t_4); if (likely(__pyx_t_3)) { - PyObject* function = PyMethod_GET_FUNCTION(__pyx_t_2); + PyObject* function = PyMethod_GET_FUNCTION(__pyx_t_4); __Pyx_INCREF(__pyx_t_3); __Pyx_INCREF(function); - __Pyx_DECREF_SET(__pyx_t_2, function); - __pyx_t_4 = 1; + __Pyx_DECREF_SET(__pyx_t_4, function); + __pyx_t_16 = 1; } } #endif { - PyObject *__pyx_callargs[3] = {__pyx_t_3, __pyx_v_domains, __pyx_v_vconstraints}; - __pyx_t_1 = __Pyx_PyObject_FastCall(__pyx_t_2, __pyx_callargs+1-__pyx_t_4, 2+__pyx_t_4); + PyObject *__pyx_callargs[4] = {__pyx_t_3, __pyx_v_local_assignment, __pyx_t_5, __pyx_v_domains}; + __pyx_t_6 = __Pyx_PyObject_FastCall(__pyx_t_4, __pyx_callargs+1-__pyx_t_16, 3+__pyx_t_16); __Pyx_XDECREF(__pyx_t_3); __pyx_t_3 = 0; - if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 787, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_1); - __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; + __Pyx_DECREF(__pyx_t_5); __pyx_t_5 = 0; + if (unlikely(!__pyx_t_6)) __PYX_ERR(0, 785, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_6); + __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; } - __pyx_r = __pyx_t_1; - __pyx_t_1 = 0; + __pyx_t_7 = __Pyx_PyObject_IsTrue(__pyx_t_6); if (unlikely((__pyx_t_7 < 0))) __PYX_ERR(0, 785, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_6); __pyx_t_6 = 0; + if (__pyx_t_7) { + + /* "constraint/solvers.py":786 + * # continue solving sequentially on this process + * if is_valid(local_assignment, constraint_lookup[first_var], domains): + * return sequential_optimized_backtrack(local_assignment, remaining_vars, domains, constraint_lookup) # <<<<<<<<<<<<<< + * return [] + * + */ + __Pyx_XDECREF(__pyx_r); + __Pyx_GetModuleGlobalName(__pyx_t_4, __pyx_n_s_sequential_optimized_backtrack); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 786, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_4); + __pyx_t_5 = NULL; + __pyx_t_16 = 0; + #if CYTHON_UNPACK_METHODS + if (unlikely(PyMethod_Check(__pyx_t_4))) { + __pyx_t_5 = PyMethod_GET_SELF(__pyx_t_4); + if (likely(__pyx_t_5)) { + PyObject* function = PyMethod_GET_FUNCTION(__pyx_t_4); + __Pyx_INCREF(__pyx_t_5); + __Pyx_INCREF(function); + __Pyx_DECREF_SET(__pyx_t_4, function); + __pyx_t_16 = 1; + } + } + #endif + { + PyObject *__pyx_callargs[5] = {__pyx_t_5, __pyx_v_local_assignment, __pyx_v_remaining_vars, __pyx_v_domains, __pyx_v_constraint_lookup}; + __pyx_t_6 = __Pyx_PyObject_FastCall(__pyx_t_4, __pyx_callargs+1-__pyx_t_16, 4+__pyx_t_16); + __Pyx_XDECREF(__pyx_t_5); __pyx_t_5 = 0; + if (unlikely(!__pyx_t_6)) __PYX_ERR(0, 786, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_6); + __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; + } + if (!(likely(PyList_CheckExact(__pyx_t_6))||((__pyx_t_6) == Py_None) || __Pyx_RaiseUnexpectedTypeError("list", __pyx_t_6))) __PYX_ERR(0, 786, __pyx_L1_error) + __pyx_r = ((PyObject*)__pyx_t_6); + __pyx_t_6 = 0; + goto __pyx_L0; + + /* "constraint/solvers.py":785 + * + * # continue solving sequentially on this process + * if is_valid(local_assignment, constraint_lookup[first_var], domains): # <<<<<<<<<<<<<< + * return sequential_optimized_backtrack(local_assignment, remaining_vars, domains, constraint_lookup) + * return [] + */ + } + + /* "constraint/solvers.py":787 + * if is_valid(local_assignment, constraint_lookup[first_var], domains): + * return sequential_optimized_backtrack(local_assignment, remaining_vars, domains, constraint_lookup) + * return [] # <<<<<<<<<<<<<< + * + */ + __Pyx_XDECREF(__pyx_r); + __pyx_t_6 = PyList_New(0); if (unlikely(!__pyx_t_6)) __PYX_ERR(0, 787, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_6); + __pyx_r = ((PyObject*)__pyx_t_6); + __pyx_t_6 = 0; goto __pyx_L0; - /* "constraint/solvers.py":786 - * return solutions + /* "constraint/solvers.py":774 * - * def getSolutions(self, domains: dict, constraints: list[tuple], vconstraints: dict): # noqa: D102 # <<<<<<<<<<<<<< - * return self.getSolutionsList(domains, vconstraints) * + * def parallel_worker(args: tuple[bool, dict[Hashable, Domain], dict[Hashable, list[tuple[Constraint, Hashable]]], Hashable, any, list[Hashable]]) -> list[dict[Hashable, any]]: # noqa E501 # <<<<<<<<<<<<<< + * """Worker function for parallel execution on first variable.""" + * process_mode, domains, constraint_lookup, first_var, first_value, remaining_vars = args */ /* function exit code */ @@ -20130,9 +20115,24 @@ static PyObject *__pyx_pf_10constraint_7solvers_14ParallelSolver_6getSolutions(C __Pyx_XDECREF(__pyx_t_1); __Pyx_XDECREF(__pyx_t_2); __Pyx_XDECREF(__pyx_t_3); - __Pyx_AddTraceback("constraint.solvers.ParallelSolver.getSolutions", __pyx_clineno, __pyx_lineno, __pyx_filename); + __Pyx_XDECREF(__pyx_t_4); + __Pyx_XDECREF(__pyx_t_5); + __Pyx_XDECREF(__pyx_t_6); + __Pyx_XDECREF(__pyx_t_14); + __Pyx_AddTraceback("constraint.solvers.parallel_worker", __pyx_clineno, __pyx_lineno, __pyx_filename); __pyx_r = NULL; __pyx_L0:; + __Pyx_XDECREF(__pyx_v_process_mode); + __Pyx_XDECREF(__pyx_v_domains); + __Pyx_XDECREF(__pyx_v_constraint_lookup); + __Pyx_XDECREF(__pyx_v_first_var); + __Pyx_XDECREF(__pyx_v_first_value); + __Pyx_XDECREF(__pyx_v_remaining_vars); + __Pyx_XDECREF(__pyx_v_local_assignment); + __Pyx_XDECREF(__pyx_v_var); + __Pyx_XDECREF(__pyx_v_constraints); + __Pyx_XDECREF(__pyx_9genexpr11__pyx_v_constraint); + __Pyx_XDECREF(__pyx_9genexpr11__pyx_v_vals); __Pyx_XGIVEREF(__pyx_r); __Pyx_RefNannyFinishContext(); return __pyx_r; @@ -20587,20 +20587,20 @@ static PyTypeObject __pyx_type_10constraint_7solvers___pyx_scope_struct_1_getSol #endif #if CYTHON_USE_FREELISTS -static struct __pyx_obj_10constraint_7solvers___pyx_scope_struct_2_is_valid *__pyx_freelist_10constraint_7solvers___pyx_scope_struct_2_is_valid[8]; -static int __pyx_freecount_10constraint_7solvers___pyx_scope_struct_2_is_valid = 0; +static struct __pyx_obj_10constraint_7solvers___pyx_scope_struct_2_getSolutionsList *__pyx_freelist_10constraint_7solvers___pyx_scope_struct_2_getSolutionsList[8]; +static int __pyx_freecount_10constraint_7solvers___pyx_scope_struct_2_getSolutionsList = 0; #endif -static PyObject *__pyx_tp_new_10constraint_7solvers___pyx_scope_struct_2_is_valid(PyTypeObject *t, CYTHON_UNUSED PyObject *a, CYTHON_UNUSED PyObject *k) { +static PyObject *__pyx_tp_new_10constraint_7solvers___pyx_scope_struct_2_getSolutionsList(PyTypeObject *t, CYTHON_UNUSED PyObject *a, CYTHON_UNUSED PyObject *k) { PyObject *o; #if CYTHON_COMPILING_IN_LIMITED_API allocfunc alloc_func = (allocfunc)PyType_GetSlot(t, Py_tp_alloc); o = alloc_func(t, 0); #else #if CYTHON_USE_FREELISTS - if (likely((int)(__pyx_freecount_10constraint_7solvers___pyx_scope_struct_2_is_valid > 0) & (int)(t->tp_basicsize == sizeof(struct __pyx_obj_10constraint_7solvers___pyx_scope_struct_2_is_valid)))) { - o = (PyObject*)__pyx_freelist_10constraint_7solvers___pyx_scope_struct_2_is_valid[--__pyx_freecount_10constraint_7solvers___pyx_scope_struct_2_is_valid]; - memset(o, 0, sizeof(struct __pyx_obj_10constraint_7solvers___pyx_scope_struct_2_is_valid)); + if (likely((int)(__pyx_freecount_10constraint_7solvers___pyx_scope_struct_2_getSolutionsList > 0) & (int)(t->tp_basicsize == sizeof(struct __pyx_obj_10constraint_7solvers___pyx_scope_struct_2_getSolutionsList)))) { + o = (PyObject*)__pyx_freelist_10constraint_7solvers___pyx_scope_struct_2_getSolutionsList[--__pyx_freecount_10constraint_7solvers___pyx_scope_struct_2_getSolutionsList]; + memset(o, 0, sizeof(struct __pyx_obj_10constraint_7solvers___pyx_scope_struct_2_getSolutionsList)); (void) PyObject_INIT(o, t); PyObject_GC_Track(o); } else @@ -20613,21 +20613,24 @@ static PyObject *__pyx_tp_new_10constraint_7solvers___pyx_scope_struct_2_is_vali return o; } -static void __pyx_tp_dealloc_10constraint_7solvers___pyx_scope_struct_2_is_valid(PyObject *o) { - struct __pyx_obj_10constraint_7solvers___pyx_scope_struct_2_is_valid *p = (struct __pyx_obj_10constraint_7solvers___pyx_scope_struct_2_is_valid *)o; +static void __pyx_tp_dealloc_10constraint_7solvers___pyx_scope_struct_2_getSolutionsList(PyObject *o) { + struct __pyx_obj_10constraint_7solvers___pyx_scope_struct_2_getSolutionsList *p = (struct __pyx_obj_10constraint_7solvers___pyx_scope_struct_2_getSolutionsList *)o; #if CYTHON_USE_TP_FINALIZE if (unlikely((PY_VERSION_HEX >= 0x03080000 || __Pyx_PyType_HasFeature(Py_TYPE(o), Py_TPFLAGS_HAVE_FINALIZE)) && __Pyx_PyObject_GetSlot(o, tp_finalize, destructor)) && !__Pyx_PyObject_GC_IsFinalized(o)) { - if (__Pyx_PyObject_GetSlot(o, tp_dealloc, destructor) == __pyx_tp_dealloc_10constraint_7solvers___pyx_scope_struct_2_is_valid) { + if (__Pyx_PyObject_GetSlot(o, tp_dealloc, destructor) == __pyx_tp_dealloc_10constraint_7solvers___pyx_scope_struct_2_getSolutionsList) { if (PyObject_CallFinalizerFromDealloc(o)) return; } } #endif PyObject_GC_UnTrack(o); - Py_CLEAR(p->__pyx_v_assignment); + Py_CLEAR(p->__pyx_v_constraint_lookup); Py_CLEAR(p->__pyx_v_domains); + Py_CLEAR(p->__pyx_v_first_var); + Py_CLEAR(p->__pyx_v_remaining_vars); + Py_CLEAR(p->__pyx_v_self); #if CYTHON_USE_FREELISTS - if (((int)(__pyx_freecount_10constraint_7solvers___pyx_scope_struct_2_is_valid < 8) & (int)(Py_TYPE(o)->tp_basicsize == sizeof(struct __pyx_obj_10constraint_7solvers___pyx_scope_struct_2_is_valid)))) { - __pyx_freelist_10constraint_7solvers___pyx_scope_struct_2_is_valid[__pyx_freecount_10constraint_7solvers___pyx_scope_struct_2_is_valid++] = ((struct __pyx_obj_10constraint_7solvers___pyx_scope_struct_2_is_valid *)o); + if (((int)(__pyx_freecount_10constraint_7solvers___pyx_scope_struct_2_getSolutionsList < 8) & (int)(Py_TYPE(o)->tp_basicsize == sizeof(struct __pyx_obj_10constraint_7solvers___pyx_scope_struct_2_getSolutionsList)))) { + __pyx_freelist_10constraint_7solvers___pyx_scope_struct_2_getSolutionsList[__pyx_freecount_10constraint_7solvers___pyx_scope_struct_2_getSolutionsList++] = ((struct __pyx_obj_10constraint_7solvers___pyx_scope_struct_2_getSolutionsList *)o); } else #endif { @@ -20642,52 +20645,70 @@ static void __pyx_tp_dealloc_10constraint_7solvers___pyx_scope_struct_2_is_valid } } -static int __pyx_tp_traverse_10constraint_7solvers___pyx_scope_struct_2_is_valid(PyObject *o, visitproc v, void *a) { +static int __pyx_tp_traverse_10constraint_7solvers___pyx_scope_struct_2_getSolutionsList(PyObject *o, visitproc v, void *a) { int e; - struct __pyx_obj_10constraint_7solvers___pyx_scope_struct_2_is_valid *p = (struct __pyx_obj_10constraint_7solvers___pyx_scope_struct_2_is_valid *)o; - if (p->__pyx_v_assignment) { - e = (*v)(p->__pyx_v_assignment, a); if (e) return e; + struct __pyx_obj_10constraint_7solvers___pyx_scope_struct_2_getSolutionsList *p = (struct __pyx_obj_10constraint_7solvers___pyx_scope_struct_2_getSolutionsList *)o; + if (p->__pyx_v_constraint_lookup) { + e = (*v)(p->__pyx_v_constraint_lookup, a); if (e) return e; } if (p->__pyx_v_domains) { e = (*v)(p->__pyx_v_domains, a); if (e) return e; } + if (p->__pyx_v_first_var) { + e = (*v)(p->__pyx_v_first_var, a); if (e) return e; + } + if (p->__pyx_v_remaining_vars) { + e = (*v)(p->__pyx_v_remaining_vars, a); if (e) return e; + } + if (p->__pyx_v_self) { + e = (*v)(p->__pyx_v_self, a); if (e) return e; + } return 0; } -static int __pyx_tp_clear_10constraint_7solvers___pyx_scope_struct_2_is_valid(PyObject *o) { +static int __pyx_tp_clear_10constraint_7solvers___pyx_scope_struct_2_getSolutionsList(PyObject *o) { PyObject* tmp; - struct __pyx_obj_10constraint_7solvers___pyx_scope_struct_2_is_valid *p = (struct __pyx_obj_10constraint_7solvers___pyx_scope_struct_2_is_valid *)o; - tmp = ((PyObject*)p->__pyx_v_assignment); - p->__pyx_v_assignment = ((PyObject*)Py_None); Py_INCREF(Py_None); + struct __pyx_obj_10constraint_7solvers___pyx_scope_struct_2_getSolutionsList *p = (struct __pyx_obj_10constraint_7solvers___pyx_scope_struct_2_getSolutionsList *)o; + tmp = ((PyObject*)p->__pyx_v_constraint_lookup); + p->__pyx_v_constraint_lookup = ((PyObject*)Py_None); Py_INCREF(Py_None); Py_XDECREF(tmp); tmp = ((PyObject*)p->__pyx_v_domains); p->__pyx_v_domains = ((PyObject*)Py_None); Py_INCREF(Py_None); Py_XDECREF(tmp); + tmp = ((PyObject*)p->__pyx_v_first_var); + p->__pyx_v_first_var = Py_None; Py_INCREF(Py_None); + Py_XDECREF(tmp); + tmp = ((PyObject*)p->__pyx_v_remaining_vars); + p->__pyx_v_remaining_vars = ((PyObject*)Py_None); Py_INCREF(Py_None); + Py_XDECREF(tmp); + tmp = ((PyObject*)p->__pyx_v_self); + p->__pyx_v_self = Py_None; Py_INCREF(Py_None); + Py_XDECREF(tmp); return 0; } #if CYTHON_USE_TYPE_SPECS -static PyType_Slot __pyx_type_10constraint_7solvers___pyx_scope_struct_2_is_valid_slots[] = { - {Py_tp_dealloc, (void *)__pyx_tp_dealloc_10constraint_7solvers___pyx_scope_struct_2_is_valid}, - {Py_tp_traverse, (void *)__pyx_tp_traverse_10constraint_7solvers___pyx_scope_struct_2_is_valid}, - {Py_tp_clear, (void *)__pyx_tp_clear_10constraint_7solvers___pyx_scope_struct_2_is_valid}, - {Py_tp_new, (void *)__pyx_tp_new_10constraint_7solvers___pyx_scope_struct_2_is_valid}, +static PyType_Slot __pyx_type_10constraint_7solvers___pyx_scope_struct_2_getSolutionsList_slots[] = { + {Py_tp_dealloc, (void *)__pyx_tp_dealloc_10constraint_7solvers___pyx_scope_struct_2_getSolutionsList}, + {Py_tp_traverse, (void *)__pyx_tp_traverse_10constraint_7solvers___pyx_scope_struct_2_getSolutionsList}, + {Py_tp_clear, (void *)__pyx_tp_clear_10constraint_7solvers___pyx_scope_struct_2_getSolutionsList}, + {Py_tp_new, (void *)__pyx_tp_new_10constraint_7solvers___pyx_scope_struct_2_getSolutionsList}, {0, 0}, }; -static PyType_Spec __pyx_type_10constraint_7solvers___pyx_scope_struct_2_is_valid_spec = { - "constraint.solvers.__pyx_scope_struct_2_is_valid", - sizeof(struct __pyx_obj_10constraint_7solvers___pyx_scope_struct_2_is_valid), +static PyType_Spec __pyx_type_10constraint_7solvers___pyx_scope_struct_2_getSolutionsList_spec = { + "constraint.solvers.__pyx_scope_struct_2_getSolutionsList", + sizeof(struct __pyx_obj_10constraint_7solvers___pyx_scope_struct_2_getSolutionsList), 0, Py_TPFLAGS_DEFAULT|Py_TPFLAGS_HAVE_VERSION_TAG|Py_TPFLAGS_CHECKTYPES|Py_TPFLAGS_HAVE_NEWBUFFER|Py_TPFLAGS_HAVE_GC|Py_TPFLAGS_HAVE_FINALIZE, - __pyx_type_10constraint_7solvers___pyx_scope_struct_2_is_valid_slots, + __pyx_type_10constraint_7solvers___pyx_scope_struct_2_getSolutionsList_slots, }; #else -static PyTypeObject __pyx_type_10constraint_7solvers___pyx_scope_struct_2_is_valid = { +static PyTypeObject __pyx_type_10constraint_7solvers___pyx_scope_struct_2_getSolutionsList = { PyVarObject_HEAD_INIT(0, 0) - "constraint.solvers.""__pyx_scope_struct_2_is_valid", /*tp_name*/ - sizeof(struct __pyx_obj_10constraint_7solvers___pyx_scope_struct_2_is_valid), /*tp_basicsize*/ + "constraint.solvers.""__pyx_scope_struct_2_getSolutionsList", /*tp_name*/ + sizeof(struct __pyx_obj_10constraint_7solvers___pyx_scope_struct_2_getSolutionsList), /*tp_basicsize*/ 0, /*tp_itemsize*/ - __pyx_tp_dealloc_10constraint_7solvers___pyx_scope_struct_2_is_valid, /*tp_dealloc*/ + __pyx_tp_dealloc_10constraint_7solvers___pyx_scope_struct_2_getSolutionsList, /*tp_dealloc*/ #if PY_VERSION_HEX < 0x030800b4 0, /*tp_print*/ #endif @@ -20714,8 +20735,8 @@ static PyTypeObject __pyx_type_10constraint_7solvers___pyx_scope_struct_2_is_val 0, /*tp_as_buffer*/ Py_TPFLAGS_DEFAULT|Py_TPFLAGS_HAVE_VERSION_TAG|Py_TPFLAGS_CHECKTYPES|Py_TPFLAGS_HAVE_NEWBUFFER|Py_TPFLAGS_HAVE_GC|Py_TPFLAGS_HAVE_FINALIZE, /*tp_flags*/ 0, /*tp_doc*/ - __pyx_tp_traverse_10constraint_7solvers___pyx_scope_struct_2_is_valid, /*tp_traverse*/ - __pyx_tp_clear_10constraint_7solvers___pyx_scope_struct_2_is_valid, /*tp_clear*/ + __pyx_tp_traverse_10constraint_7solvers___pyx_scope_struct_2_getSolutionsList, /*tp_traverse*/ + __pyx_tp_clear_10constraint_7solvers___pyx_scope_struct_2_getSolutionsList, /*tp_clear*/ 0, /*tp_richcompare*/ 0, /*tp_weaklistoffset*/ 0, /*tp_iter*/ @@ -20732,7 +20753,7 @@ static PyTypeObject __pyx_type_10constraint_7solvers___pyx_scope_struct_2_is_val #endif 0, /*tp_init*/ 0, /*tp_alloc*/ - __pyx_tp_new_10constraint_7solvers___pyx_scope_struct_2_is_valid, /*tp_new*/ + __pyx_tp_new_10constraint_7solvers___pyx_scope_struct_2_getSolutionsList, /*tp_new*/ 0, /*tp_free*/ 0, /*tp_is_gc*/ 0, /*tp_bases*/ @@ -20806,9 +20827,8 @@ static void __pyx_tp_dealloc_10constraint_7solvers___pyx_scope_struct_3_genexpr( PyObject_GC_UnTrack(o); Py_CLEAR(p->__pyx_outer_scope); Py_CLEAR(p->__pyx_genexpr_arg_0); - Py_CLEAR(p->__pyx_v_constraint); - Py_CLEAR(p->__pyx_v_genexpr); - Py_CLEAR(p->__pyx_v_vars_involved); + Py_CLEAR(p->__pyx_v_val); + Py_CLEAR(p->__pyx_t_0); #if CYTHON_USE_FREELISTS if (((int)(__pyx_freecount_10constraint_7solvers___pyx_scope_struct_3_genexpr < 8) & (int)(Py_TYPE(o)->tp_basicsize == sizeof(struct __pyx_obj_10constraint_7solvers___pyx_scope_struct_3_genexpr)))) { __pyx_freelist_10constraint_7solvers___pyx_scope_struct_3_genexpr[__pyx_freecount_10constraint_7solvers___pyx_scope_struct_3_genexpr++] = ((struct __pyx_obj_10constraint_7solvers___pyx_scope_struct_3_genexpr *)o); @@ -20835,14 +20855,11 @@ static int __pyx_tp_traverse_10constraint_7solvers___pyx_scope_struct_3_genexpr( if (p->__pyx_genexpr_arg_0) { e = (*v)(p->__pyx_genexpr_arg_0, a); if (e) return e; } - if (p->__pyx_v_constraint) { - e = (*v)(p->__pyx_v_constraint, a); if (e) return e; - } - if (p->__pyx_v_genexpr) { - e = (*v)(p->__pyx_v_genexpr, a); if (e) return e; + if (p->__pyx_v_val) { + e = (*v)(p->__pyx_v_val, a); if (e) return e; } - if (p->__pyx_v_vars_involved) { - e = (*v)(p->__pyx_v_vars_involved, a); if (e) return e; + if (p->__pyx_t_0) { + e = (*v)(p->__pyx_t_0, a); if (e) return e; } return 0; } @@ -20948,20 +20965,20 @@ static PyTypeObject __pyx_type_10constraint_7solvers___pyx_scope_struct_3_genexp #endif #if CYTHON_USE_FREELISTS -static struct __pyx_obj_10constraint_7solvers___pyx_scope_struct_4_genexpr *__pyx_freelist_10constraint_7solvers___pyx_scope_struct_4_genexpr[8]; -static int __pyx_freecount_10constraint_7solvers___pyx_scope_struct_4_genexpr = 0; +static struct __pyx_obj_10constraint_7solvers___pyx_scope_struct_4_is_valid *__pyx_freelist_10constraint_7solvers___pyx_scope_struct_4_is_valid[8]; +static int __pyx_freecount_10constraint_7solvers___pyx_scope_struct_4_is_valid = 0; #endif -static PyObject *__pyx_tp_new_10constraint_7solvers___pyx_scope_struct_4_genexpr(PyTypeObject *t, CYTHON_UNUSED PyObject *a, CYTHON_UNUSED PyObject *k) { +static PyObject *__pyx_tp_new_10constraint_7solvers___pyx_scope_struct_4_is_valid(PyTypeObject *t, CYTHON_UNUSED PyObject *a, CYTHON_UNUSED PyObject *k) { PyObject *o; #if CYTHON_COMPILING_IN_LIMITED_API allocfunc alloc_func = (allocfunc)PyType_GetSlot(t, Py_tp_alloc); o = alloc_func(t, 0); #else #if CYTHON_USE_FREELISTS - if (likely((int)(__pyx_freecount_10constraint_7solvers___pyx_scope_struct_4_genexpr > 0) & (int)(t->tp_basicsize == sizeof(struct __pyx_obj_10constraint_7solvers___pyx_scope_struct_4_genexpr)))) { - o = (PyObject*)__pyx_freelist_10constraint_7solvers___pyx_scope_struct_4_genexpr[--__pyx_freecount_10constraint_7solvers___pyx_scope_struct_4_genexpr]; - memset(o, 0, sizeof(struct __pyx_obj_10constraint_7solvers___pyx_scope_struct_4_genexpr)); + if (likely((int)(__pyx_freecount_10constraint_7solvers___pyx_scope_struct_4_is_valid > 0) & (int)(t->tp_basicsize == sizeof(struct __pyx_obj_10constraint_7solvers___pyx_scope_struct_4_is_valid)))) { + o = (PyObject*)__pyx_freelist_10constraint_7solvers___pyx_scope_struct_4_is_valid[--__pyx_freecount_10constraint_7solvers___pyx_scope_struct_4_is_valid]; + memset(o, 0, sizeof(struct __pyx_obj_10constraint_7solvers___pyx_scope_struct_4_is_valid)); (void) PyObject_INIT(o, t); PyObject_GC_Track(o); } else @@ -20974,22 +20991,21 @@ static PyObject *__pyx_tp_new_10constraint_7solvers___pyx_scope_struct_4_genexpr return o; } -static void __pyx_tp_dealloc_10constraint_7solvers___pyx_scope_struct_4_genexpr(PyObject *o) { - struct __pyx_obj_10constraint_7solvers___pyx_scope_struct_4_genexpr *p = (struct __pyx_obj_10constraint_7solvers___pyx_scope_struct_4_genexpr *)o; +static void __pyx_tp_dealloc_10constraint_7solvers___pyx_scope_struct_4_is_valid(PyObject *o) { + struct __pyx_obj_10constraint_7solvers___pyx_scope_struct_4_is_valid *p = (struct __pyx_obj_10constraint_7solvers___pyx_scope_struct_4_is_valid *)o; #if CYTHON_USE_TP_FINALIZE if (unlikely((PY_VERSION_HEX >= 0x03080000 || __Pyx_PyType_HasFeature(Py_TYPE(o), Py_TPFLAGS_HAVE_FINALIZE)) && __Pyx_PyObject_GetSlot(o, tp_finalize, destructor)) && !__Pyx_PyObject_GC_IsFinalized(o)) { - if (__Pyx_PyObject_GetSlot(o, tp_dealloc, destructor) == __pyx_tp_dealloc_10constraint_7solvers___pyx_scope_struct_4_genexpr) { + if (__Pyx_PyObject_GetSlot(o, tp_dealloc, destructor) == __pyx_tp_dealloc_10constraint_7solvers___pyx_scope_struct_4_is_valid) { if (PyObject_CallFinalizerFromDealloc(o)) return; } } #endif PyObject_GC_UnTrack(o); - Py_CLEAR(p->__pyx_outer_scope); - Py_CLEAR(p->__pyx_genexpr_arg_0); - Py_CLEAR(p->__pyx_v_v); + Py_CLEAR(p->__pyx_v_assignment); + Py_CLEAR(p->__pyx_v_domains); #if CYTHON_USE_FREELISTS - if (((int)(__pyx_freecount_10constraint_7solvers___pyx_scope_struct_4_genexpr < 8) & (int)(Py_TYPE(o)->tp_basicsize == sizeof(struct __pyx_obj_10constraint_7solvers___pyx_scope_struct_4_genexpr)))) { - __pyx_freelist_10constraint_7solvers___pyx_scope_struct_4_genexpr[__pyx_freecount_10constraint_7solvers___pyx_scope_struct_4_genexpr++] = ((struct __pyx_obj_10constraint_7solvers___pyx_scope_struct_4_genexpr *)o); + if (((int)(__pyx_freecount_10constraint_7solvers___pyx_scope_struct_4_is_valid < 8) & (int)(Py_TYPE(o)->tp_basicsize == sizeof(struct __pyx_obj_10constraint_7solvers___pyx_scope_struct_4_is_valid)))) { + __pyx_freelist_10constraint_7solvers___pyx_scope_struct_4_is_valid[__pyx_freecount_10constraint_7solvers___pyx_scope_struct_4_is_valid++] = ((struct __pyx_obj_10constraint_7solvers___pyx_scope_struct_4_is_valid *)o); } else #endif { @@ -21004,42 +21020,52 @@ static void __pyx_tp_dealloc_10constraint_7solvers___pyx_scope_struct_4_genexpr( } } -static int __pyx_tp_traverse_10constraint_7solvers___pyx_scope_struct_4_genexpr(PyObject *o, visitproc v, void *a) { +static int __pyx_tp_traverse_10constraint_7solvers___pyx_scope_struct_4_is_valid(PyObject *o, visitproc v, void *a) { int e; - struct __pyx_obj_10constraint_7solvers___pyx_scope_struct_4_genexpr *p = (struct __pyx_obj_10constraint_7solvers___pyx_scope_struct_4_genexpr *)o; - if (p->__pyx_outer_scope) { - e = (*v)(((PyObject *)p->__pyx_outer_scope), a); if (e) return e; - } - if (p->__pyx_genexpr_arg_0) { - e = (*v)(p->__pyx_genexpr_arg_0, a); if (e) return e; + struct __pyx_obj_10constraint_7solvers___pyx_scope_struct_4_is_valid *p = (struct __pyx_obj_10constraint_7solvers___pyx_scope_struct_4_is_valid *)o; + if (p->__pyx_v_assignment) { + e = (*v)(p->__pyx_v_assignment, a); if (e) return e; } - if (p->__pyx_v_v) { - e = (*v)(p->__pyx_v_v, a); if (e) return e; + if (p->__pyx_v_domains) { + e = (*v)(p->__pyx_v_domains, a); if (e) return e; } return 0; } + +static int __pyx_tp_clear_10constraint_7solvers___pyx_scope_struct_4_is_valid(PyObject *o) { + PyObject* tmp; + struct __pyx_obj_10constraint_7solvers___pyx_scope_struct_4_is_valid *p = (struct __pyx_obj_10constraint_7solvers___pyx_scope_struct_4_is_valid *)o; + tmp = ((PyObject*)p->__pyx_v_assignment); + p->__pyx_v_assignment = ((PyObject*)Py_None); Py_INCREF(Py_None); + Py_XDECREF(tmp); + tmp = ((PyObject*)p->__pyx_v_domains); + p->__pyx_v_domains = ((PyObject*)Py_None); Py_INCREF(Py_None); + Py_XDECREF(tmp); + return 0; +} #if CYTHON_USE_TYPE_SPECS -static PyType_Slot __pyx_type_10constraint_7solvers___pyx_scope_struct_4_genexpr_slots[] = { - {Py_tp_dealloc, (void *)__pyx_tp_dealloc_10constraint_7solvers___pyx_scope_struct_4_genexpr}, - {Py_tp_traverse, (void *)__pyx_tp_traverse_10constraint_7solvers___pyx_scope_struct_4_genexpr}, - {Py_tp_new, (void *)__pyx_tp_new_10constraint_7solvers___pyx_scope_struct_4_genexpr}, +static PyType_Slot __pyx_type_10constraint_7solvers___pyx_scope_struct_4_is_valid_slots[] = { + {Py_tp_dealloc, (void *)__pyx_tp_dealloc_10constraint_7solvers___pyx_scope_struct_4_is_valid}, + {Py_tp_traverse, (void *)__pyx_tp_traverse_10constraint_7solvers___pyx_scope_struct_4_is_valid}, + {Py_tp_clear, (void *)__pyx_tp_clear_10constraint_7solvers___pyx_scope_struct_4_is_valid}, + {Py_tp_new, (void *)__pyx_tp_new_10constraint_7solvers___pyx_scope_struct_4_is_valid}, {0, 0}, }; -static PyType_Spec __pyx_type_10constraint_7solvers___pyx_scope_struct_4_genexpr_spec = { - "constraint.solvers.__pyx_scope_struct_4_genexpr", - sizeof(struct __pyx_obj_10constraint_7solvers___pyx_scope_struct_4_genexpr), +static PyType_Spec __pyx_type_10constraint_7solvers___pyx_scope_struct_4_is_valid_spec = { + "constraint.solvers.__pyx_scope_struct_4_is_valid", + sizeof(struct __pyx_obj_10constraint_7solvers___pyx_scope_struct_4_is_valid), 0, Py_TPFLAGS_DEFAULT|Py_TPFLAGS_HAVE_VERSION_TAG|Py_TPFLAGS_CHECKTYPES|Py_TPFLAGS_HAVE_NEWBUFFER|Py_TPFLAGS_HAVE_GC|Py_TPFLAGS_HAVE_FINALIZE, - __pyx_type_10constraint_7solvers___pyx_scope_struct_4_genexpr_slots, + __pyx_type_10constraint_7solvers___pyx_scope_struct_4_is_valid_slots, }; #else -static PyTypeObject __pyx_type_10constraint_7solvers___pyx_scope_struct_4_genexpr = { +static PyTypeObject __pyx_type_10constraint_7solvers___pyx_scope_struct_4_is_valid = { PyVarObject_HEAD_INIT(0, 0) - "constraint.solvers.""__pyx_scope_struct_4_genexpr", /*tp_name*/ - sizeof(struct __pyx_obj_10constraint_7solvers___pyx_scope_struct_4_genexpr), /*tp_basicsize*/ + "constraint.solvers.""__pyx_scope_struct_4_is_valid", /*tp_name*/ + sizeof(struct __pyx_obj_10constraint_7solvers___pyx_scope_struct_4_is_valid), /*tp_basicsize*/ 0, /*tp_itemsize*/ - __pyx_tp_dealloc_10constraint_7solvers___pyx_scope_struct_4_genexpr, /*tp_dealloc*/ + __pyx_tp_dealloc_10constraint_7solvers___pyx_scope_struct_4_is_valid, /*tp_dealloc*/ #if PY_VERSION_HEX < 0x030800b4 0, /*tp_print*/ #endif @@ -21066,8 +21092,8 @@ static PyTypeObject __pyx_type_10constraint_7solvers___pyx_scope_struct_4_genexp 0, /*tp_as_buffer*/ Py_TPFLAGS_DEFAULT|Py_TPFLAGS_HAVE_VERSION_TAG|Py_TPFLAGS_CHECKTYPES|Py_TPFLAGS_HAVE_NEWBUFFER|Py_TPFLAGS_HAVE_GC|Py_TPFLAGS_HAVE_FINALIZE, /*tp_flags*/ 0, /*tp_doc*/ - __pyx_tp_traverse_10constraint_7solvers___pyx_scope_struct_4_genexpr, /*tp_traverse*/ - 0, /*tp_clear*/ + __pyx_tp_traverse_10constraint_7solvers___pyx_scope_struct_4_is_valid, /*tp_traverse*/ + __pyx_tp_clear_10constraint_7solvers___pyx_scope_struct_4_is_valid, /*tp_clear*/ 0, /*tp_richcompare*/ 0, /*tp_weaklistoffset*/ 0, /*tp_iter*/ @@ -21084,7 +21110,7 @@ static PyTypeObject __pyx_type_10constraint_7solvers___pyx_scope_struct_4_genexp #endif 0, /*tp_init*/ 0, /*tp_alloc*/ - __pyx_tp_new_10constraint_7solvers___pyx_scope_struct_4_genexpr, /*tp_new*/ + __pyx_tp_new_10constraint_7solvers___pyx_scope_struct_4_is_valid, /*tp_new*/ 0, /*tp_free*/ 0, /*tp_is_gc*/ 0, /*tp_bases*/ @@ -21120,20 +21146,20 @@ static PyTypeObject __pyx_type_10constraint_7solvers___pyx_scope_struct_4_genexp #endif #if CYTHON_USE_FREELISTS -static struct __pyx_obj_10constraint_7solvers___pyx_scope_struct_5_getSolutionsList *__pyx_freelist_10constraint_7solvers___pyx_scope_struct_5_getSolutionsList[8]; -static int __pyx_freecount_10constraint_7solvers___pyx_scope_struct_5_getSolutionsList = 0; +static struct __pyx_obj_10constraint_7solvers___pyx_scope_struct_5_genexpr *__pyx_freelist_10constraint_7solvers___pyx_scope_struct_5_genexpr[8]; +static int __pyx_freecount_10constraint_7solvers___pyx_scope_struct_5_genexpr = 0; #endif -static PyObject *__pyx_tp_new_10constraint_7solvers___pyx_scope_struct_5_getSolutionsList(PyTypeObject *t, CYTHON_UNUSED PyObject *a, CYTHON_UNUSED PyObject *k) { +static PyObject *__pyx_tp_new_10constraint_7solvers___pyx_scope_struct_5_genexpr(PyTypeObject *t, CYTHON_UNUSED PyObject *a, CYTHON_UNUSED PyObject *k) { PyObject *o; #if CYTHON_COMPILING_IN_LIMITED_API allocfunc alloc_func = (allocfunc)PyType_GetSlot(t, Py_tp_alloc); o = alloc_func(t, 0); #else #if CYTHON_USE_FREELISTS - if (likely((int)(__pyx_freecount_10constraint_7solvers___pyx_scope_struct_5_getSolutionsList > 0) & (int)(t->tp_basicsize == sizeof(struct __pyx_obj_10constraint_7solvers___pyx_scope_struct_5_getSolutionsList)))) { - o = (PyObject*)__pyx_freelist_10constraint_7solvers___pyx_scope_struct_5_getSolutionsList[--__pyx_freecount_10constraint_7solvers___pyx_scope_struct_5_getSolutionsList]; - memset(o, 0, sizeof(struct __pyx_obj_10constraint_7solvers___pyx_scope_struct_5_getSolutionsList)); + if (likely((int)(__pyx_freecount_10constraint_7solvers___pyx_scope_struct_5_genexpr > 0) & (int)(t->tp_basicsize == sizeof(struct __pyx_obj_10constraint_7solvers___pyx_scope_struct_5_genexpr)))) { + o = (PyObject*)__pyx_freelist_10constraint_7solvers___pyx_scope_struct_5_genexpr[--__pyx_freecount_10constraint_7solvers___pyx_scope_struct_5_genexpr]; + memset(o, 0, sizeof(struct __pyx_obj_10constraint_7solvers___pyx_scope_struct_5_genexpr)); (void) PyObject_INIT(o, t); PyObject_GC_Track(o); } else @@ -21146,24 +21172,24 @@ static PyObject *__pyx_tp_new_10constraint_7solvers___pyx_scope_struct_5_getSolu return o; } -static void __pyx_tp_dealloc_10constraint_7solvers___pyx_scope_struct_5_getSolutionsList(PyObject *o) { - struct __pyx_obj_10constraint_7solvers___pyx_scope_struct_5_getSolutionsList *p = (struct __pyx_obj_10constraint_7solvers___pyx_scope_struct_5_getSolutionsList *)o; +static void __pyx_tp_dealloc_10constraint_7solvers___pyx_scope_struct_5_genexpr(PyObject *o) { + struct __pyx_obj_10constraint_7solvers___pyx_scope_struct_5_genexpr *p = (struct __pyx_obj_10constraint_7solvers___pyx_scope_struct_5_genexpr *)o; #if CYTHON_USE_TP_FINALIZE if (unlikely((PY_VERSION_HEX >= 0x03080000 || __Pyx_PyType_HasFeature(Py_TYPE(o), Py_TPFLAGS_HAVE_FINALIZE)) && __Pyx_PyObject_GetSlot(o, tp_finalize, destructor)) && !__Pyx_PyObject_GC_IsFinalized(o)) { - if (__Pyx_PyObject_GetSlot(o, tp_dealloc, destructor) == __pyx_tp_dealloc_10constraint_7solvers___pyx_scope_struct_5_getSolutionsList) { + if (__Pyx_PyObject_GetSlot(o, tp_dealloc, destructor) == __pyx_tp_dealloc_10constraint_7solvers___pyx_scope_struct_5_genexpr) { if (PyObject_CallFinalizerFromDealloc(o)) return; } } #endif PyObject_GC_UnTrack(o); - Py_CLEAR(p->__pyx_v_constraint_lookup); - Py_CLEAR(p->__pyx_v_domains); - Py_CLEAR(p->__pyx_v_first_var); - Py_CLEAR(p->__pyx_v_remaining_vars); - Py_CLEAR(p->__pyx_v_self); + Py_CLEAR(p->__pyx_outer_scope); + Py_CLEAR(p->__pyx_genexpr_arg_0); + Py_CLEAR(p->__pyx_v_constraint); + Py_CLEAR(p->__pyx_v_genexpr); + Py_CLEAR(p->__pyx_v_vars_involved); #if CYTHON_USE_FREELISTS - if (((int)(__pyx_freecount_10constraint_7solvers___pyx_scope_struct_5_getSolutionsList < 8) & (int)(Py_TYPE(o)->tp_basicsize == sizeof(struct __pyx_obj_10constraint_7solvers___pyx_scope_struct_5_getSolutionsList)))) { - __pyx_freelist_10constraint_7solvers___pyx_scope_struct_5_getSolutionsList[__pyx_freecount_10constraint_7solvers___pyx_scope_struct_5_getSolutionsList++] = ((struct __pyx_obj_10constraint_7solvers___pyx_scope_struct_5_getSolutionsList *)o); + if (((int)(__pyx_freecount_10constraint_7solvers___pyx_scope_struct_5_genexpr < 8) & (int)(Py_TYPE(o)->tp_basicsize == sizeof(struct __pyx_obj_10constraint_7solvers___pyx_scope_struct_5_genexpr)))) { + __pyx_freelist_10constraint_7solvers___pyx_scope_struct_5_genexpr[__pyx_freecount_10constraint_7solvers___pyx_scope_struct_5_genexpr++] = ((struct __pyx_obj_10constraint_7solvers___pyx_scope_struct_5_genexpr *)o); } else #endif { @@ -21178,70 +21204,48 @@ static void __pyx_tp_dealloc_10constraint_7solvers___pyx_scope_struct_5_getSolut } } -static int __pyx_tp_traverse_10constraint_7solvers___pyx_scope_struct_5_getSolutionsList(PyObject *o, visitproc v, void *a) { +static int __pyx_tp_traverse_10constraint_7solvers___pyx_scope_struct_5_genexpr(PyObject *o, visitproc v, void *a) { int e; - struct __pyx_obj_10constraint_7solvers___pyx_scope_struct_5_getSolutionsList *p = (struct __pyx_obj_10constraint_7solvers___pyx_scope_struct_5_getSolutionsList *)o; - if (p->__pyx_v_constraint_lookup) { - e = (*v)(p->__pyx_v_constraint_lookup, a); if (e) return e; + struct __pyx_obj_10constraint_7solvers___pyx_scope_struct_5_genexpr *p = (struct __pyx_obj_10constraint_7solvers___pyx_scope_struct_5_genexpr *)o; + if (p->__pyx_outer_scope) { + e = (*v)(((PyObject *)p->__pyx_outer_scope), a); if (e) return e; } - if (p->__pyx_v_domains) { - e = (*v)(p->__pyx_v_domains, a); if (e) return e; + if (p->__pyx_genexpr_arg_0) { + e = (*v)(p->__pyx_genexpr_arg_0, a); if (e) return e; } - if (p->__pyx_v_first_var) { - e = (*v)(p->__pyx_v_first_var, a); if (e) return e; + if (p->__pyx_v_constraint) { + e = (*v)(p->__pyx_v_constraint, a); if (e) return e; } - if (p->__pyx_v_remaining_vars) { - e = (*v)(p->__pyx_v_remaining_vars, a); if (e) return e; + if (p->__pyx_v_genexpr) { + e = (*v)(p->__pyx_v_genexpr, a); if (e) return e; } - if (p->__pyx_v_self) { - e = (*v)(p->__pyx_v_self, a); if (e) return e; + if (p->__pyx_v_vars_involved) { + e = (*v)(p->__pyx_v_vars_involved, a); if (e) return e; } return 0; } - -static int __pyx_tp_clear_10constraint_7solvers___pyx_scope_struct_5_getSolutionsList(PyObject *o) { - PyObject* tmp; - struct __pyx_obj_10constraint_7solvers___pyx_scope_struct_5_getSolutionsList *p = (struct __pyx_obj_10constraint_7solvers___pyx_scope_struct_5_getSolutionsList *)o; - tmp = ((PyObject*)p->__pyx_v_constraint_lookup); - p->__pyx_v_constraint_lookup = ((PyObject*)Py_None); Py_INCREF(Py_None); - Py_XDECREF(tmp); - tmp = ((PyObject*)p->__pyx_v_domains); - p->__pyx_v_domains = ((PyObject*)Py_None); Py_INCREF(Py_None); - Py_XDECREF(tmp); - tmp = ((PyObject*)p->__pyx_v_first_var); - p->__pyx_v_first_var = Py_None; Py_INCREF(Py_None); - Py_XDECREF(tmp); - tmp = ((PyObject*)p->__pyx_v_remaining_vars); - p->__pyx_v_remaining_vars = ((PyObject*)Py_None); Py_INCREF(Py_None); - Py_XDECREF(tmp); - tmp = ((PyObject*)p->__pyx_v_self); - p->__pyx_v_self = Py_None; Py_INCREF(Py_None); - Py_XDECREF(tmp); - return 0; -} #if CYTHON_USE_TYPE_SPECS -static PyType_Slot __pyx_type_10constraint_7solvers___pyx_scope_struct_5_getSolutionsList_slots[] = { - {Py_tp_dealloc, (void *)__pyx_tp_dealloc_10constraint_7solvers___pyx_scope_struct_5_getSolutionsList}, - {Py_tp_traverse, (void *)__pyx_tp_traverse_10constraint_7solvers___pyx_scope_struct_5_getSolutionsList}, - {Py_tp_clear, (void *)__pyx_tp_clear_10constraint_7solvers___pyx_scope_struct_5_getSolutionsList}, - {Py_tp_new, (void *)__pyx_tp_new_10constraint_7solvers___pyx_scope_struct_5_getSolutionsList}, +static PyType_Slot __pyx_type_10constraint_7solvers___pyx_scope_struct_5_genexpr_slots[] = { + {Py_tp_dealloc, (void *)__pyx_tp_dealloc_10constraint_7solvers___pyx_scope_struct_5_genexpr}, + {Py_tp_traverse, (void *)__pyx_tp_traverse_10constraint_7solvers___pyx_scope_struct_5_genexpr}, + {Py_tp_new, (void *)__pyx_tp_new_10constraint_7solvers___pyx_scope_struct_5_genexpr}, {0, 0}, }; -static PyType_Spec __pyx_type_10constraint_7solvers___pyx_scope_struct_5_getSolutionsList_spec = { - "constraint.solvers.__pyx_scope_struct_5_getSolutionsList", - sizeof(struct __pyx_obj_10constraint_7solvers___pyx_scope_struct_5_getSolutionsList), +static PyType_Spec __pyx_type_10constraint_7solvers___pyx_scope_struct_5_genexpr_spec = { + "constraint.solvers.__pyx_scope_struct_5_genexpr", + sizeof(struct __pyx_obj_10constraint_7solvers___pyx_scope_struct_5_genexpr), 0, Py_TPFLAGS_DEFAULT|Py_TPFLAGS_HAVE_VERSION_TAG|Py_TPFLAGS_CHECKTYPES|Py_TPFLAGS_HAVE_NEWBUFFER|Py_TPFLAGS_HAVE_GC|Py_TPFLAGS_HAVE_FINALIZE, - __pyx_type_10constraint_7solvers___pyx_scope_struct_5_getSolutionsList_slots, + __pyx_type_10constraint_7solvers___pyx_scope_struct_5_genexpr_slots, }; #else -static PyTypeObject __pyx_type_10constraint_7solvers___pyx_scope_struct_5_getSolutionsList = { +static PyTypeObject __pyx_type_10constraint_7solvers___pyx_scope_struct_5_genexpr = { PyVarObject_HEAD_INIT(0, 0) - "constraint.solvers.""__pyx_scope_struct_5_getSolutionsList", /*tp_name*/ - sizeof(struct __pyx_obj_10constraint_7solvers___pyx_scope_struct_5_getSolutionsList), /*tp_basicsize*/ + "constraint.solvers.""__pyx_scope_struct_5_genexpr", /*tp_name*/ + sizeof(struct __pyx_obj_10constraint_7solvers___pyx_scope_struct_5_genexpr), /*tp_basicsize*/ 0, /*tp_itemsize*/ - __pyx_tp_dealloc_10constraint_7solvers___pyx_scope_struct_5_getSolutionsList, /*tp_dealloc*/ + __pyx_tp_dealloc_10constraint_7solvers___pyx_scope_struct_5_genexpr, /*tp_dealloc*/ #if PY_VERSION_HEX < 0x030800b4 0, /*tp_print*/ #endif @@ -21268,8 +21272,8 @@ static PyTypeObject __pyx_type_10constraint_7solvers___pyx_scope_struct_5_getSol 0, /*tp_as_buffer*/ Py_TPFLAGS_DEFAULT|Py_TPFLAGS_HAVE_VERSION_TAG|Py_TPFLAGS_CHECKTYPES|Py_TPFLAGS_HAVE_NEWBUFFER|Py_TPFLAGS_HAVE_GC|Py_TPFLAGS_HAVE_FINALIZE, /*tp_flags*/ 0, /*tp_doc*/ - __pyx_tp_traverse_10constraint_7solvers___pyx_scope_struct_5_getSolutionsList, /*tp_traverse*/ - __pyx_tp_clear_10constraint_7solvers___pyx_scope_struct_5_getSolutionsList, /*tp_clear*/ + __pyx_tp_traverse_10constraint_7solvers___pyx_scope_struct_5_genexpr, /*tp_traverse*/ + 0, /*tp_clear*/ 0, /*tp_richcompare*/ 0, /*tp_weaklistoffset*/ 0, /*tp_iter*/ @@ -21286,7 +21290,7 @@ static PyTypeObject __pyx_type_10constraint_7solvers___pyx_scope_struct_5_getSol #endif 0, /*tp_init*/ 0, /*tp_alloc*/ - __pyx_tp_new_10constraint_7solvers___pyx_scope_struct_5_getSolutionsList, /*tp_new*/ + __pyx_tp_new_10constraint_7solvers___pyx_scope_struct_5_genexpr, /*tp_new*/ 0, /*tp_free*/ 0, /*tp_is_gc*/ 0, /*tp_bases*/ @@ -21360,8 +21364,7 @@ static void __pyx_tp_dealloc_10constraint_7solvers___pyx_scope_struct_6_genexpr( PyObject_GC_UnTrack(o); Py_CLEAR(p->__pyx_outer_scope); Py_CLEAR(p->__pyx_genexpr_arg_0); - Py_CLEAR(p->__pyx_v_val); - Py_CLEAR(p->__pyx_t_0); + Py_CLEAR(p->__pyx_v_v); #if CYTHON_USE_FREELISTS if (((int)(__pyx_freecount_10constraint_7solvers___pyx_scope_struct_6_genexpr < 8) & (int)(Py_TYPE(o)->tp_basicsize == sizeof(struct __pyx_obj_10constraint_7solvers___pyx_scope_struct_6_genexpr)))) { __pyx_freelist_10constraint_7solvers___pyx_scope_struct_6_genexpr[__pyx_freecount_10constraint_7solvers___pyx_scope_struct_6_genexpr++] = ((struct __pyx_obj_10constraint_7solvers___pyx_scope_struct_6_genexpr *)o); @@ -21388,11 +21391,8 @@ static int __pyx_tp_traverse_10constraint_7solvers___pyx_scope_struct_6_genexpr( if (p->__pyx_genexpr_arg_0) { e = (*v)(p->__pyx_genexpr_arg_0, a); if (e) return e; } - if (p->__pyx_v_val) { - e = (*v)(p->__pyx_v_val, a); if (e) return e; - } - if (p->__pyx_t_0) { - e = (*v)(p->__pyx_t_0, a); if (e) return e; + if (p->__pyx_v_v) { + e = (*v)(p->__pyx_v_v, a); if (e) return e; } return 0; } @@ -21735,9 +21735,9 @@ static CYTHON_SMALL_CODE int __Pyx_InitCachedBuiltins(void) { __pyx_builtin_RuntimeError = __Pyx_GetBuiltinName(__pyx_n_s_RuntimeError); if (!__pyx_builtin_RuntimeError) __PYX_ERR(0, 221, __pyx_L1_error) __pyx_builtin_StopIteration = __Pyx_GetBuiltinName(__pyx_n_s_StopIteration); if (!__pyx_builtin_StopIteration) __PYX_ERR(0, 227, __pyx_L1_error) __pyx_builtin_range = __Pyx_GetBuiltinName(__pyx_n_s_range); if (!__pyx_builtin_range) __PYX_ERR(0, 573, __pyx_L1_error) - __pyx_builtin_compile = __Pyx_GetBuiltinName(__pyx_n_s_compile); if (!__pyx_builtin_compile) __PYX_ERR(0, 620, __pyx_L1_error) - __pyx_builtin_super = __Pyx_GetBuiltinName(__pyx_n_s_super); if (!__pyx_builtin_super) __PYX_ERR(0, 744, __pyx_L1_error) - __pyx_builtin_sorted = __Pyx_GetBuiltinName(__pyx_n_s_sorted); if (!__pyx_builtin_sorted) __PYX_ERR(0, 766, __pyx_L1_error) + __pyx_builtin_super = __Pyx_GetBuiltinName(__pyx_n_s_super); if (!__pyx_builtin_super) __PYX_ERR(0, 646, __pyx_L1_error) + __pyx_builtin_sorted = __Pyx_GetBuiltinName(__pyx_n_s_sorted); if (!__pyx_builtin_sorted) __PYX_ERR(0, 668, __pyx_L1_error) + __pyx_builtin_compile = __Pyx_GetBuiltinName(__pyx_n_s_compile); if (!__pyx_builtin_compile) __PYX_ERR(0, 704, __pyx_L1_error) return 0; __pyx_L1_error:; return -1; @@ -21770,14 +21770,14 @@ static CYTHON_SMALL_CODE int __Pyx_InitCachedConstants(void) { __Pyx_GOTREF(__pyx_tuple__3); __Pyx_GIVEREF(__pyx_tuple__3); - /* "constraint/solvers.py":778 + /* "constraint/solvers.py":680 * # execute in parallel * parallel_pool = ProcessPoolExecutor if self._process_mode else ThreadPoolExecutor * with parallel_pool() as executor: # <<<<<<<<<<<<<< * # results = map(parallel_worker, args) # sequential * results = executor.map(parallel_worker, args, chunksize=1) # parallel */ - __pyx_tuple__5 = PyTuple_Pack(3, Py_None, Py_None, Py_None); if (unlikely(!__pyx_tuple__5)) __PYX_ERR(0, 778, __pyx_L1_error) + __pyx_tuple__5 = PyTuple_Pack(3, Py_None, Py_None, Py_None); if (unlikely(!__pyx_tuple__5)) __PYX_ERR(0, 680, __pyx_L1_error) __Pyx_GOTREF(__pyx_tuple__5); __Pyx_GIVEREF(__pyx_tuple__5); @@ -22018,110 +22018,110 @@ static CYTHON_SMALL_CODE int __Pyx_InitCachedConstants(void) { __Pyx_GIVEREF(__pyx_tuple__42); __pyx_codeobj__43 = (PyObject*)__Pyx_PyCode_New(4, 0, 0, 17, 0, CO_OPTIMIZED|CO_NEWLOCALS, __pyx_empty_bytes, __pyx_empty_tuple, __pyx_empty_tuple, __pyx_tuple__42, __pyx_empty_tuple, __pyx_empty_tuple, __pyx_kp_s_constraint_solvers_py, __pyx_n_s_getSolution, 566, __pyx_empty_bytes); if (unlikely(!__pyx_codeobj__43)) __PYX_ERR(0, 566, __pyx_L1_error) - /* "constraint/solvers.py":609 + /* "constraint/solvers.py":644 + * """ # noqa E501 + * + * def __init__(self, process_mode=False): # <<<<<<<<<<<<<< + * """Initialization method. Set `process_mode` to True for using ProcessPool, otherwise uses ThreadPool.""" + * super().__init__() + */ + __pyx_tuple__44 = PyTuple_Pack(2, __pyx_n_s_self, __pyx_n_s_process_mode); if (unlikely(!__pyx_tuple__44)) __PYX_ERR(0, 644, __pyx_L1_error) + __Pyx_GOTREF(__pyx_tuple__44); + __Pyx_GIVEREF(__pyx_tuple__44); + __pyx_codeobj__45 = (PyObject*)__Pyx_PyCode_New(2, 0, 0, 2, 0, CO_OPTIMIZED|CO_NEWLOCALS, __pyx_empty_bytes, __pyx_empty_tuple, __pyx_empty_tuple, __pyx_tuple__44, __pyx_empty_tuple, __pyx_empty_tuple, __pyx_kp_s_constraint_solvers_py, __pyx_n_s_init, 644, __pyx_empty_bytes); if (unlikely(!__pyx_codeobj__45)) __PYX_ERR(0, 644, __pyx_L1_error) + __pyx_tuple__46 = PyTuple_Pack(1, ((PyObject *)Py_False)); if (unlikely(!__pyx_tuple__46)) __PYX_ERR(0, 644, __pyx_L1_error) + __Pyx_GOTREF(__pyx_tuple__46); + __Pyx_GIVEREF(__pyx_tuple__46); + + /* "constraint/solvers.py":650 + * self.requires_pickling = process_mode + * + * def getSolution(self, domains: dict, constraints: list[tuple], vconstraints: dict): # <<<<<<<<<<<<<< + * """Return one solution for the given problem. + * + */ + __pyx_codeobj__47 = (PyObject*)__Pyx_PyCode_New(4, 0, 0, 5, 0, CO_OPTIMIZED|CO_NEWLOCALS, __pyx_empty_bytes, __pyx_empty_tuple, __pyx_empty_tuple, __pyx_tuple__13, __pyx_empty_tuple, __pyx_empty_tuple, __pyx_kp_s_constraint_solvers_py, __pyx_n_s_getSolution, 650, __pyx_empty_bytes); if (unlikely(!__pyx_codeobj__47)) __PYX_ERR(0, 650, __pyx_L1_error) + + /* "constraint/solvers.py":662 + * raise NotImplementedError(msg) + * + * def getSolutionsList(self, domains: dict[Hashable, Domain], vconstraints: dict[Hashable, list[tuple[Constraint, Hashable]]]) -> list[dict[Hashable, any]]: # noqa: D102, E501 # <<<<<<<<<<<<<< + * """Parallelized all-solutions finder using ProcessPoolExecutor for work-stealing.""" + * # Precompute constraints lookup per variable + */ + __pyx_tuple__48 = PyTuple_Pack(16, __pyx_n_s_self, __pyx_n_s_domains, __pyx_n_s_vconstraints, __pyx_n_s_constraint_lookup, __pyx_n_s_sorted_vars, __pyx_n_s_first_var, __pyx_n_s_remaining_vars, __pyx_n_s_args, __pyx_n_s_solutions, __pyx_n_s_parallel_pool, __pyx_n_s_executor, __pyx_n_s_results, __pyx_n_s_result, __pyx_n_s_var, __pyx_n_s_genexpr, __pyx_n_s_genexpr); if (unlikely(!__pyx_tuple__48)) __PYX_ERR(0, 662, __pyx_L1_error) + __Pyx_GOTREF(__pyx_tuple__48); + __Pyx_GIVEREF(__pyx_tuple__48); + __pyx_codeobj__49 = (PyObject*)__Pyx_PyCode_New(3, 0, 0, 16, 0, CO_OPTIMIZED|CO_NEWLOCALS, __pyx_empty_bytes, __pyx_empty_tuple, __pyx_empty_tuple, __pyx_tuple__48, __pyx_empty_tuple, __pyx_empty_tuple, __pyx_kp_s_constraint_solvers_py, __pyx_n_s_getSolutionsList, 662, __pyx_empty_bytes); if (unlikely(!__pyx_codeobj__49)) __PYX_ERR(0, 662, __pyx_L1_error) + + /* "constraint/solvers.py":688 + * return solutions + * + * def getSolutions(self, domains: dict, constraints: list[tuple], vconstraints: dict): # noqa: D102 # <<<<<<<<<<<<<< + * return self.getSolutionsList(domains, vconstraints) + * + */ + __pyx_codeobj__50 = (PyObject*)__Pyx_PyCode_New(4, 0, 0, 4, 0, CO_OPTIMIZED|CO_NEWLOCALS, __pyx_empty_bytes, __pyx_empty_tuple, __pyx_empty_tuple, __pyx_tuple__23, __pyx_empty_tuple, __pyx_empty_tuple, __pyx_kp_s_constraint_solvers_py, __pyx_n_s_getSolutions, 688, __pyx_empty_bytes); if (unlikely(!__pyx_codeobj__50)) __PYX_ERR(0, 688, __pyx_L1_error) + + /* "constraint/solvers.py":693 * ### Helper functions for parallel solver * * def is_valid(assignment: dict[Hashable, any], constraints_lookup: list[tuple[Constraint, Hashable]], domains: dict[Hashable, Domain]) -> bool: # noqa E501 # <<<<<<<<<<<<<< * """Check if all constraints are satisfied given the current assignment.""" * return all( */ - __pyx_tuple__44 = PyTuple_Pack(5, __pyx_n_s_assignment, __pyx_n_s_constraints_lookup, __pyx_n_s_domains, __pyx_n_s_genexpr, __pyx_n_s_genexpr); if (unlikely(!__pyx_tuple__44)) __PYX_ERR(0, 609, __pyx_L1_error) - __Pyx_GOTREF(__pyx_tuple__44); - __Pyx_GIVEREF(__pyx_tuple__44); - __pyx_codeobj__45 = (PyObject*)__Pyx_PyCode_New(3, 0, 0, 5, 0, CO_OPTIMIZED|CO_NEWLOCALS, __pyx_empty_bytes, __pyx_empty_tuple, __pyx_empty_tuple, __pyx_tuple__44, __pyx_empty_tuple, __pyx_empty_tuple, __pyx_kp_s_constraint_solvers_py, __pyx_n_s_is_valid, 609, __pyx_empty_bytes); if (unlikely(!__pyx_codeobj__45)) __PYX_ERR(0, 609, __pyx_L1_error) + __pyx_tuple__51 = PyTuple_Pack(5, __pyx_n_s_assignment, __pyx_n_s_constraints_lookup, __pyx_n_s_domains, __pyx_n_s_genexpr, __pyx_n_s_genexpr); if (unlikely(!__pyx_tuple__51)) __PYX_ERR(0, 693, __pyx_L1_error) + __Pyx_GOTREF(__pyx_tuple__51); + __Pyx_GIVEREF(__pyx_tuple__51); + __pyx_codeobj__52 = (PyObject*)__Pyx_PyCode_New(3, 0, 0, 5, 0, CO_OPTIMIZED|CO_NEWLOCALS, __pyx_empty_bytes, __pyx_empty_tuple, __pyx_empty_tuple, __pyx_tuple__51, __pyx_empty_tuple, __pyx_empty_tuple, __pyx_kp_s_constraint_solvers_py, __pyx_n_s_is_valid, 693, __pyx_empty_bytes); if (unlikely(!__pyx_codeobj__52)) __PYX_ERR(0, 693, __pyx_L1_error) - /* "constraint/solvers.py":617 + /* "constraint/solvers.py":701 * ) * * def compile_to_function(constraint: CompilableFunctionConstraint) -> FunctionConstraint: # <<<<<<<<<<<<<< * """Compile a CompilableFunctionConstraint to a function, wrapped by a FunctionConstraint.""" * func_string = constraint._func */ - __pyx_tuple__46 = PyTuple_Pack(4, __pyx_n_s_constraint, __pyx_n_s_func_string, __pyx_n_s_code_object, __pyx_n_s_func_2); if (unlikely(!__pyx_tuple__46)) __PYX_ERR(0, 617, __pyx_L1_error) - __Pyx_GOTREF(__pyx_tuple__46); - __Pyx_GIVEREF(__pyx_tuple__46); - __pyx_codeobj__47 = (PyObject*)__Pyx_PyCode_New(1, 0, 0, 4, 0, CO_OPTIMIZED|CO_NEWLOCALS, __pyx_empty_bytes, __pyx_empty_tuple, __pyx_empty_tuple, __pyx_tuple__46, __pyx_empty_tuple, __pyx_empty_tuple, __pyx_kp_s_constraint_solvers_py, __pyx_n_s_compile_to_function, 617, __pyx_empty_bytes); if (unlikely(!__pyx_codeobj__47)) __PYX_ERR(0, 617, __pyx_L1_error) + __pyx_tuple__53 = PyTuple_Pack(4, __pyx_n_s_constraint, __pyx_n_s_func_string, __pyx_n_s_code_object, __pyx_n_s_func_2); if (unlikely(!__pyx_tuple__53)) __PYX_ERR(0, 701, __pyx_L1_error) + __Pyx_GOTREF(__pyx_tuple__53); + __Pyx_GIVEREF(__pyx_tuple__53); + __pyx_codeobj__54 = (PyObject*)__Pyx_PyCode_New(1, 0, 0, 4, 0, CO_OPTIMIZED|CO_NEWLOCALS, __pyx_empty_bytes, __pyx_empty_tuple, __pyx_empty_tuple, __pyx_tuple__53, __pyx_empty_tuple, __pyx_empty_tuple, __pyx_kp_s_constraint_solvers_py, __pyx_n_s_compile_to_function, 701, __pyx_empty_bytes); if (unlikely(!__pyx_codeobj__54)) __PYX_ERR(0, 701, __pyx_L1_error) - /* "constraint/solvers.py":624 + /* "constraint/solvers.py":708 * return FunctionConstraint(func) * * def sequential_recursive_backtrack(assignment: dict[Hashable, any], unassigned_vars: list[Hashable], domains: dict[Hashable, Domain], constraint_lookup: dict[Hashable, list[tuple[Constraint, Hashable]]]) -> list[dict[Hashable, any]]: # noqa E501 # <<<<<<<<<<<<<< * """Sequential recursive backtracking function for subproblems.""" * if not unassigned_vars: */ - __pyx_tuple__48 = PyTuple_Pack(8, __pyx_n_s_assignment, __pyx_n_s_unassigned_vars, __pyx_n_s_domains, __pyx_n_s_constraint_lookup, __pyx_n_s_var, __pyx_n_s_remaining_vars, __pyx_n_s_solutions, __pyx_n_s_value); if (unlikely(!__pyx_tuple__48)) __PYX_ERR(0, 624, __pyx_L1_error) - __Pyx_GOTREF(__pyx_tuple__48); - __Pyx_GIVEREF(__pyx_tuple__48); - __pyx_codeobj__49 = (PyObject*)__Pyx_PyCode_New(4, 0, 0, 8, 0, CO_OPTIMIZED|CO_NEWLOCALS, __pyx_empty_bytes, __pyx_empty_tuple, __pyx_empty_tuple, __pyx_tuple__48, __pyx_empty_tuple, __pyx_empty_tuple, __pyx_kp_s_constraint_solvers_py, __pyx_n_s_sequential_recursive_backtrack, 624, __pyx_empty_bytes); if (unlikely(!__pyx_codeobj__49)) __PYX_ERR(0, 624, __pyx_L1_error) + __pyx_tuple__55 = PyTuple_Pack(8, __pyx_n_s_assignment, __pyx_n_s_unassigned_vars, __pyx_n_s_domains, __pyx_n_s_constraint_lookup, __pyx_n_s_var, __pyx_n_s_remaining_vars, __pyx_n_s_solutions, __pyx_n_s_value); if (unlikely(!__pyx_tuple__55)) __PYX_ERR(0, 708, __pyx_L1_error) + __Pyx_GOTREF(__pyx_tuple__55); + __Pyx_GIVEREF(__pyx_tuple__55); + __pyx_codeobj__56 = (PyObject*)__Pyx_PyCode_New(4, 0, 0, 8, 0, CO_OPTIMIZED|CO_NEWLOCALS, __pyx_empty_bytes, __pyx_empty_tuple, __pyx_empty_tuple, __pyx_tuple__55, __pyx_empty_tuple, __pyx_empty_tuple, __pyx_kp_s_constraint_solvers_py, __pyx_n_s_sequential_recursive_backtrack, 708, __pyx_empty_bytes); if (unlikely(!__pyx_codeobj__56)) __PYX_ERR(0, 708, __pyx_L1_error) - /* "constraint/solvers.py":640 + /* "constraint/solvers.py":724 * return solutions * * def sequential_optimized_backtrack(assignment: dict[Hashable, any], unassigned_vars: list[Hashable], domains: dict[Hashable, Domain], constraint_lookup: dict[Hashable, list[tuple[Constraint, Hashable]]]) -> list[dict[Hashable, any]]: # noqa E501 # <<<<<<<<<<<<<< * """Sequential optimized backtracking (as in OptimizedBacktrackingSolver) function for subproblems.""" * # Does not do forwardcheck for simplicity */ - __pyx_tuple__50 = PyTuple_Pack(12, __pyx_n_s_assignment, __pyx_n_s_unassigned_vars, __pyx_n_s_domains, __pyx_n_s_constraint_lookup, __pyx_n_s_assignments, __pyx_n_s_sorted_variables, __pyx_n_s_queue, __pyx_n_s_solutions, __pyx_n_s_variable, __pyx_n_s_values, __pyx_n_s_constraint, __pyx_n_s_variables); if (unlikely(!__pyx_tuple__50)) __PYX_ERR(0, 640, __pyx_L1_error) - __Pyx_GOTREF(__pyx_tuple__50); - __Pyx_GIVEREF(__pyx_tuple__50); - __pyx_codeobj__51 = (PyObject*)__Pyx_PyCode_New(4, 0, 0, 12, 0, CO_OPTIMIZED|CO_NEWLOCALS, __pyx_empty_bytes, __pyx_empty_tuple, __pyx_empty_tuple, __pyx_tuple__50, __pyx_empty_tuple, __pyx_empty_tuple, __pyx_kp_s_constraint_solvers_py, __pyx_n_s_sequential_optimized_backtrack, 640, __pyx_empty_bytes); if (unlikely(!__pyx_codeobj__51)) __PYX_ERR(0, 640, __pyx_L1_error) + __pyx_tuple__57 = PyTuple_Pack(12, __pyx_n_s_assignment, __pyx_n_s_unassigned_vars, __pyx_n_s_domains, __pyx_n_s_constraint_lookup, __pyx_n_s_assignments, __pyx_n_s_sorted_variables, __pyx_n_s_queue, __pyx_n_s_solutions, __pyx_n_s_variable, __pyx_n_s_values, __pyx_n_s_constraint, __pyx_n_s_variables); if (unlikely(!__pyx_tuple__57)) __PYX_ERR(0, 724, __pyx_L1_error) + __Pyx_GOTREF(__pyx_tuple__57); + __Pyx_GIVEREF(__pyx_tuple__57); + __pyx_codeobj__58 = (PyObject*)__Pyx_PyCode_New(4, 0, 0, 12, 0, CO_OPTIMIZED|CO_NEWLOCALS, __pyx_empty_bytes, __pyx_empty_tuple, __pyx_empty_tuple, __pyx_tuple__57, __pyx_empty_tuple, __pyx_empty_tuple, __pyx_kp_s_constraint_solvers_py, __pyx_n_s_sequential_optimized_backtrack, 724, __pyx_empty_bytes); if (unlikely(!__pyx_codeobj__58)) __PYX_ERR(0, 724, __pyx_L1_error) - /* "constraint/solvers.py":690 + /* "constraint/solvers.py":774 * * * def parallel_worker(args: tuple[bool, dict[Hashable, Domain], dict[Hashable, list[tuple[Constraint, Hashable]]], Hashable, any, list[Hashable]]) -> list[dict[Hashable, any]]: # noqa E501 # <<<<<<<<<<<<<< * """Worker function for parallel execution on first variable.""" * process_mode, domains, constraint_lookup, first_var, first_value, remaining_vars = args */ - __pyx_tuple__52 = PyTuple_Pack(12, __pyx_n_s_args, __pyx_n_s_process_mode, __pyx_n_s_domains, __pyx_n_s_constraint_lookup, __pyx_n_s_first_var, __pyx_n_s_first_value, __pyx_n_s_remaining_vars, __pyx_n_s_local_assignment, __pyx_n_s_var, __pyx_n_s_constraints, __pyx_n_s_constraint, __pyx_n_s_vals); if (unlikely(!__pyx_tuple__52)) __PYX_ERR(0, 690, __pyx_L1_error) - __Pyx_GOTREF(__pyx_tuple__52); - __Pyx_GIVEREF(__pyx_tuple__52); - __pyx_codeobj__53 = (PyObject*)__Pyx_PyCode_New(1, 0, 0, 12, 0, CO_OPTIMIZED|CO_NEWLOCALS, __pyx_empty_bytes, __pyx_empty_tuple, __pyx_empty_tuple, __pyx_tuple__52, __pyx_empty_tuple, __pyx_empty_tuple, __pyx_kp_s_constraint_solvers_py, __pyx_n_s_parallel_worker, 690, __pyx_empty_bytes); if (unlikely(!__pyx_codeobj__53)) __PYX_ERR(0, 690, __pyx_L1_error) - - /* "constraint/solvers.py":742 - * """ # noqa E501 - * - * def __init__(self, process_mode=False): # <<<<<<<<<<<<<< - * """Initialization method. Set `process_mode` to True for using ProcessPool, otherwise uses ThreadPool.""" - * super().__init__() - */ - __pyx_tuple__54 = PyTuple_Pack(2, __pyx_n_s_self, __pyx_n_s_process_mode); if (unlikely(!__pyx_tuple__54)) __PYX_ERR(0, 742, __pyx_L1_error) - __Pyx_GOTREF(__pyx_tuple__54); - __Pyx_GIVEREF(__pyx_tuple__54); - __pyx_codeobj__55 = (PyObject*)__Pyx_PyCode_New(2, 0, 0, 2, 0, CO_OPTIMIZED|CO_NEWLOCALS, __pyx_empty_bytes, __pyx_empty_tuple, __pyx_empty_tuple, __pyx_tuple__54, __pyx_empty_tuple, __pyx_empty_tuple, __pyx_kp_s_constraint_solvers_py, __pyx_n_s_init, 742, __pyx_empty_bytes); if (unlikely(!__pyx_codeobj__55)) __PYX_ERR(0, 742, __pyx_L1_error) - __pyx_tuple__56 = PyTuple_Pack(1, ((PyObject *)Py_False)); if (unlikely(!__pyx_tuple__56)) __PYX_ERR(0, 742, __pyx_L1_error) - __Pyx_GOTREF(__pyx_tuple__56); - __Pyx_GIVEREF(__pyx_tuple__56); - - /* "constraint/solvers.py":748 - * self.requires_pickling = process_mode - * - * def getSolution(self, domains: dict, constraints: list[tuple], vconstraints: dict): # <<<<<<<<<<<<<< - * """Return one solution for the given problem. - * - */ - __pyx_codeobj__57 = (PyObject*)__Pyx_PyCode_New(4, 0, 0, 5, 0, CO_OPTIMIZED|CO_NEWLOCALS, __pyx_empty_bytes, __pyx_empty_tuple, __pyx_empty_tuple, __pyx_tuple__13, __pyx_empty_tuple, __pyx_empty_tuple, __pyx_kp_s_constraint_solvers_py, __pyx_n_s_getSolution, 748, __pyx_empty_bytes); if (unlikely(!__pyx_codeobj__57)) __PYX_ERR(0, 748, __pyx_L1_error) - - /* "constraint/solvers.py":760 - * raise NotImplementedError(msg) - * - * def getSolutionsList(self, domains: dict[Hashable, Domain], vconstraints: dict[Hashable, list[tuple[Constraint, Hashable]]]) -> list[dict[Hashable, any]]: # noqa: D102, E501 # <<<<<<<<<<<<<< - * """Parallelized all-solutions finder using ProcessPoolExecutor for work-stealing.""" - * # Precompute constraints lookup per variable - */ - __pyx_tuple__58 = PyTuple_Pack(16, __pyx_n_s_self, __pyx_n_s_domains, __pyx_n_s_vconstraints, __pyx_n_s_constraint_lookup, __pyx_n_s_sorted_vars, __pyx_n_s_first_var, __pyx_n_s_remaining_vars, __pyx_n_s_args, __pyx_n_s_solutions, __pyx_n_s_parallel_pool, __pyx_n_s_executor, __pyx_n_s_results, __pyx_n_s_result, __pyx_n_s_var, __pyx_n_s_genexpr, __pyx_n_s_genexpr); if (unlikely(!__pyx_tuple__58)) __PYX_ERR(0, 760, __pyx_L1_error) - __Pyx_GOTREF(__pyx_tuple__58); - __Pyx_GIVEREF(__pyx_tuple__58); - __pyx_codeobj__59 = (PyObject*)__Pyx_PyCode_New(3, 0, 0, 16, 0, CO_OPTIMIZED|CO_NEWLOCALS, __pyx_empty_bytes, __pyx_empty_tuple, __pyx_empty_tuple, __pyx_tuple__58, __pyx_empty_tuple, __pyx_empty_tuple, __pyx_kp_s_constraint_solvers_py, __pyx_n_s_getSolutionsList, 760, __pyx_empty_bytes); if (unlikely(!__pyx_codeobj__59)) __PYX_ERR(0, 760, __pyx_L1_error) - - /* "constraint/solvers.py":786 - * return solutions - * - * def getSolutions(self, domains: dict, constraints: list[tuple], vconstraints: dict): # noqa: D102 # <<<<<<<<<<<<<< - * return self.getSolutionsList(domains, vconstraints) - * - */ - __pyx_codeobj__60 = (PyObject*)__Pyx_PyCode_New(4, 0, 0, 4, 0, CO_OPTIMIZED|CO_NEWLOCALS, __pyx_empty_bytes, __pyx_empty_tuple, __pyx_empty_tuple, __pyx_tuple__23, __pyx_empty_tuple, __pyx_empty_tuple, __pyx_kp_s_constraint_solvers_py, __pyx_n_s_getSolutions, 786, __pyx_empty_bytes); if (unlikely(!__pyx_codeobj__60)) __PYX_ERR(0, 786, __pyx_L1_error) + __pyx_tuple__59 = PyTuple_Pack(12, __pyx_n_s_args, __pyx_n_s_process_mode, __pyx_n_s_domains, __pyx_n_s_constraint_lookup, __pyx_n_s_first_var, __pyx_n_s_first_value, __pyx_n_s_remaining_vars, __pyx_n_s_local_assignment, __pyx_n_s_var, __pyx_n_s_constraints, __pyx_n_s_constraint, __pyx_n_s_vals); if (unlikely(!__pyx_tuple__59)) __PYX_ERR(0, 774, __pyx_L1_error) + __Pyx_GOTREF(__pyx_tuple__59); + __Pyx_GIVEREF(__pyx_tuple__59); + __pyx_codeobj__60 = (PyObject*)__Pyx_PyCode_New(1, 0, 0, 12, 0, CO_OPTIMIZED|CO_NEWLOCALS, __pyx_empty_bytes, __pyx_empty_tuple, __pyx_empty_tuple, __pyx_tuple__59, __pyx_empty_tuple, __pyx_empty_tuple, __pyx_kp_s_constraint_solvers_py, __pyx_n_s_parallel_worker, 774, __pyx_empty_bytes); if (unlikely(!__pyx_codeobj__60)) __PYX_ERR(0, 774, __pyx_L1_error) __Pyx_RefNannyFinishContext(); return 0; __pyx_L1_error:; @@ -22234,34 +22234,34 @@ static int __Pyx_modinit_type_init_code(void) { } #endif #if CYTHON_USE_TYPE_SPECS - __pyx_ptype_10constraint_7solvers___pyx_scope_struct_2_is_valid = (PyTypeObject *) __Pyx_PyType_FromModuleAndSpec(__pyx_m, &__pyx_type_10constraint_7solvers___pyx_scope_struct_2_is_valid_spec, NULL); if (unlikely(!__pyx_ptype_10constraint_7solvers___pyx_scope_struct_2_is_valid)) __PYX_ERR(0, 609, __pyx_L1_error) - if (__Pyx_fix_up_extension_type_from_spec(&__pyx_type_10constraint_7solvers___pyx_scope_struct_2_is_valid_spec, __pyx_ptype_10constraint_7solvers___pyx_scope_struct_2_is_valid) < 0) __PYX_ERR(0, 609, __pyx_L1_error) + __pyx_ptype_10constraint_7solvers___pyx_scope_struct_2_getSolutionsList = (PyTypeObject *) __Pyx_PyType_FromModuleAndSpec(__pyx_m, &__pyx_type_10constraint_7solvers___pyx_scope_struct_2_getSolutionsList_spec, NULL); if (unlikely(!__pyx_ptype_10constraint_7solvers___pyx_scope_struct_2_getSolutionsList)) __PYX_ERR(0, 662, __pyx_L1_error) + if (__Pyx_fix_up_extension_type_from_spec(&__pyx_type_10constraint_7solvers___pyx_scope_struct_2_getSolutionsList_spec, __pyx_ptype_10constraint_7solvers___pyx_scope_struct_2_getSolutionsList) < 0) __PYX_ERR(0, 662, __pyx_L1_error) #else - __pyx_ptype_10constraint_7solvers___pyx_scope_struct_2_is_valid = &__pyx_type_10constraint_7solvers___pyx_scope_struct_2_is_valid; + __pyx_ptype_10constraint_7solvers___pyx_scope_struct_2_getSolutionsList = &__pyx_type_10constraint_7solvers___pyx_scope_struct_2_getSolutionsList; #endif #if !CYTHON_COMPILING_IN_LIMITED_API #endif #if !CYTHON_USE_TYPE_SPECS - if (__Pyx_PyType_Ready(__pyx_ptype_10constraint_7solvers___pyx_scope_struct_2_is_valid) < 0) __PYX_ERR(0, 609, __pyx_L1_error) + if (__Pyx_PyType_Ready(__pyx_ptype_10constraint_7solvers___pyx_scope_struct_2_getSolutionsList) < 0) __PYX_ERR(0, 662, __pyx_L1_error) #endif #if PY_MAJOR_VERSION < 3 - __pyx_ptype_10constraint_7solvers___pyx_scope_struct_2_is_valid->tp_print = 0; + __pyx_ptype_10constraint_7solvers___pyx_scope_struct_2_getSolutionsList->tp_print = 0; #endif #if !CYTHON_COMPILING_IN_LIMITED_API - if ((CYTHON_USE_TYPE_SLOTS && CYTHON_USE_PYTYPE_LOOKUP) && likely(!__pyx_ptype_10constraint_7solvers___pyx_scope_struct_2_is_valid->tp_dictoffset && __pyx_ptype_10constraint_7solvers___pyx_scope_struct_2_is_valid->tp_getattro == PyObject_GenericGetAttr)) { - __pyx_ptype_10constraint_7solvers___pyx_scope_struct_2_is_valid->tp_getattro = __Pyx_PyObject_GenericGetAttrNoDict; + if ((CYTHON_USE_TYPE_SLOTS && CYTHON_USE_PYTYPE_LOOKUP) && likely(!__pyx_ptype_10constraint_7solvers___pyx_scope_struct_2_getSolutionsList->tp_dictoffset && __pyx_ptype_10constraint_7solvers___pyx_scope_struct_2_getSolutionsList->tp_getattro == PyObject_GenericGetAttr)) { + __pyx_ptype_10constraint_7solvers___pyx_scope_struct_2_getSolutionsList->tp_getattro = __Pyx_PyObject_GenericGetAttrNoDict; } #endif #if CYTHON_USE_TYPE_SPECS - __pyx_ptype_10constraint_7solvers___pyx_scope_struct_3_genexpr = (PyTypeObject *) __Pyx_PyType_FromModuleAndSpec(__pyx_m, &__pyx_type_10constraint_7solvers___pyx_scope_struct_3_genexpr_spec, NULL); if (unlikely(!__pyx_ptype_10constraint_7solvers___pyx_scope_struct_3_genexpr)) __PYX_ERR(0, 612, __pyx_L1_error) - if (__Pyx_fix_up_extension_type_from_spec(&__pyx_type_10constraint_7solvers___pyx_scope_struct_3_genexpr_spec, __pyx_ptype_10constraint_7solvers___pyx_scope_struct_3_genexpr) < 0) __PYX_ERR(0, 612, __pyx_L1_error) + __pyx_ptype_10constraint_7solvers___pyx_scope_struct_3_genexpr = (PyTypeObject *) __Pyx_PyType_FromModuleAndSpec(__pyx_m, &__pyx_type_10constraint_7solvers___pyx_scope_struct_3_genexpr_spec, NULL); if (unlikely(!__pyx_ptype_10constraint_7solvers___pyx_scope_struct_3_genexpr)) __PYX_ERR(0, 675, __pyx_L1_error) + if (__Pyx_fix_up_extension_type_from_spec(&__pyx_type_10constraint_7solvers___pyx_scope_struct_3_genexpr_spec, __pyx_ptype_10constraint_7solvers___pyx_scope_struct_3_genexpr) < 0) __PYX_ERR(0, 675, __pyx_L1_error) #else __pyx_ptype_10constraint_7solvers___pyx_scope_struct_3_genexpr = &__pyx_type_10constraint_7solvers___pyx_scope_struct_3_genexpr; #endif #if !CYTHON_COMPILING_IN_LIMITED_API #endif #if !CYTHON_USE_TYPE_SPECS - if (__Pyx_PyType_Ready(__pyx_ptype_10constraint_7solvers___pyx_scope_struct_3_genexpr) < 0) __PYX_ERR(0, 612, __pyx_L1_error) + if (__Pyx_PyType_Ready(__pyx_ptype_10constraint_7solvers___pyx_scope_struct_3_genexpr) < 0) __PYX_ERR(0, 675, __pyx_L1_error) #endif #if PY_MAJOR_VERSION < 3 __pyx_ptype_10constraint_7solvers___pyx_scope_struct_3_genexpr->tp_print = 0; @@ -22272,53 +22272,53 @@ static int __Pyx_modinit_type_init_code(void) { } #endif #if CYTHON_USE_TYPE_SPECS - __pyx_ptype_10constraint_7solvers___pyx_scope_struct_4_genexpr = (PyTypeObject *) __Pyx_PyType_FromModuleAndSpec(__pyx_m, &__pyx_type_10constraint_7solvers___pyx_scope_struct_4_genexpr_spec, NULL); if (unlikely(!__pyx_ptype_10constraint_7solvers___pyx_scope_struct_4_genexpr)) __PYX_ERR(0, 614, __pyx_L1_error) - if (__Pyx_fix_up_extension_type_from_spec(&__pyx_type_10constraint_7solvers___pyx_scope_struct_4_genexpr_spec, __pyx_ptype_10constraint_7solvers___pyx_scope_struct_4_genexpr) < 0) __PYX_ERR(0, 614, __pyx_L1_error) + __pyx_ptype_10constraint_7solvers___pyx_scope_struct_4_is_valid = (PyTypeObject *) __Pyx_PyType_FromModuleAndSpec(__pyx_m, &__pyx_type_10constraint_7solvers___pyx_scope_struct_4_is_valid_spec, NULL); if (unlikely(!__pyx_ptype_10constraint_7solvers___pyx_scope_struct_4_is_valid)) __PYX_ERR(0, 693, __pyx_L1_error) + if (__Pyx_fix_up_extension_type_from_spec(&__pyx_type_10constraint_7solvers___pyx_scope_struct_4_is_valid_spec, __pyx_ptype_10constraint_7solvers___pyx_scope_struct_4_is_valid) < 0) __PYX_ERR(0, 693, __pyx_L1_error) #else - __pyx_ptype_10constraint_7solvers___pyx_scope_struct_4_genexpr = &__pyx_type_10constraint_7solvers___pyx_scope_struct_4_genexpr; + __pyx_ptype_10constraint_7solvers___pyx_scope_struct_4_is_valid = &__pyx_type_10constraint_7solvers___pyx_scope_struct_4_is_valid; #endif #if !CYTHON_COMPILING_IN_LIMITED_API #endif #if !CYTHON_USE_TYPE_SPECS - if (__Pyx_PyType_Ready(__pyx_ptype_10constraint_7solvers___pyx_scope_struct_4_genexpr) < 0) __PYX_ERR(0, 614, __pyx_L1_error) + if (__Pyx_PyType_Ready(__pyx_ptype_10constraint_7solvers___pyx_scope_struct_4_is_valid) < 0) __PYX_ERR(0, 693, __pyx_L1_error) #endif #if PY_MAJOR_VERSION < 3 - __pyx_ptype_10constraint_7solvers___pyx_scope_struct_4_genexpr->tp_print = 0; + __pyx_ptype_10constraint_7solvers___pyx_scope_struct_4_is_valid->tp_print = 0; #endif #if !CYTHON_COMPILING_IN_LIMITED_API - if ((CYTHON_USE_TYPE_SLOTS && CYTHON_USE_PYTYPE_LOOKUP) && likely(!__pyx_ptype_10constraint_7solvers___pyx_scope_struct_4_genexpr->tp_dictoffset && __pyx_ptype_10constraint_7solvers___pyx_scope_struct_4_genexpr->tp_getattro == PyObject_GenericGetAttr)) { - __pyx_ptype_10constraint_7solvers___pyx_scope_struct_4_genexpr->tp_getattro = __Pyx_PyObject_GenericGetAttrNoDict; + if ((CYTHON_USE_TYPE_SLOTS && CYTHON_USE_PYTYPE_LOOKUP) && likely(!__pyx_ptype_10constraint_7solvers___pyx_scope_struct_4_is_valid->tp_dictoffset && __pyx_ptype_10constraint_7solvers___pyx_scope_struct_4_is_valid->tp_getattro == PyObject_GenericGetAttr)) { + __pyx_ptype_10constraint_7solvers___pyx_scope_struct_4_is_valid->tp_getattro = __Pyx_PyObject_GenericGetAttrNoDict; } #endif #if CYTHON_USE_TYPE_SPECS - __pyx_ptype_10constraint_7solvers___pyx_scope_struct_5_getSolutionsList = (PyTypeObject *) __Pyx_PyType_FromModuleAndSpec(__pyx_m, &__pyx_type_10constraint_7solvers___pyx_scope_struct_5_getSolutionsList_spec, NULL); if (unlikely(!__pyx_ptype_10constraint_7solvers___pyx_scope_struct_5_getSolutionsList)) __PYX_ERR(0, 760, __pyx_L1_error) - if (__Pyx_fix_up_extension_type_from_spec(&__pyx_type_10constraint_7solvers___pyx_scope_struct_5_getSolutionsList_spec, __pyx_ptype_10constraint_7solvers___pyx_scope_struct_5_getSolutionsList) < 0) __PYX_ERR(0, 760, __pyx_L1_error) + __pyx_ptype_10constraint_7solvers___pyx_scope_struct_5_genexpr = (PyTypeObject *) __Pyx_PyType_FromModuleAndSpec(__pyx_m, &__pyx_type_10constraint_7solvers___pyx_scope_struct_5_genexpr_spec, NULL); if (unlikely(!__pyx_ptype_10constraint_7solvers___pyx_scope_struct_5_genexpr)) __PYX_ERR(0, 696, __pyx_L1_error) + if (__Pyx_fix_up_extension_type_from_spec(&__pyx_type_10constraint_7solvers___pyx_scope_struct_5_genexpr_spec, __pyx_ptype_10constraint_7solvers___pyx_scope_struct_5_genexpr) < 0) __PYX_ERR(0, 696, __pyx_L1_error) #else - __pyx_ptype_10constraint_7solvers___pyx_scope_struct_5_getSolutionsList = &__pyx_type_10constraint_7solvers___pyx_scope_struct_5_getSolutionsList; + __pyx_ptype_10constraint_7solvers___pyx_scope_struct_5_genexpr = &__pyx_type_10constraint_7solvers___pyx_scope_struct_5_genexpr; #endif #if !CYTHON_COMPILING_IN_LIMITED_API #endif #if !CYTHON_USE_TYPE_SPECS - if (__Pyx_PyType_Ready(__pyx_ptype_10constraint_7solvers___pyx_scope_struct_5_getSolutionsList) < 0) __PYX_ERR(0, 760, __pyx_L1_error) + if (__Pyx_PyType_Ready(__pyx_ptype_10constraint_7solvers___pyx_scope_struct_5_genexpr) < 0) __PYX_ERR(0, 696, __pyx_L1_error) #endif #if PY_MAJOR_VERSION < 3 - __pyx_ptype_10constraint_7solvers___pyx_scope_struct_5_getSolutionsList->tp_print = 0; + __pyx_ptype_10constraint_7solvers___pyx_scope_struct_5_genexpr->tp_print = 0; #endif #if !CYTHON_COMPILING_IN_LIMITED_API - if ((CYTHON_USE_TYPE_SLOTS && CYTHON_USE_PYTYPE_LOOKUP) && likely(!__pyx_ptype_10constraint_7solvers___pyx_scope_struct_5_getSolutionsList->tp_dictoffset && __pyx_ptype_10constraint_7solvers___pyx_scope_struct_5_getSolutionsList->tp_getattro == PyObject_GenericGetAttr)) { - __pyx_ptype_10constraint_7solvers___pyx_scope_struct_5_getSolutionsList->tp_getattro = __Pyx_PyObject_GenericGetAttrNoDict; + if ((CYTHON_USE_TYPE_SLOTS && CYTHON_USE_PYTYPE_LOOKUP) && likely(!__pyx_ptype_10constraint_7solvers___pyx_scope_struct_5_genexpr->tp_dictoffset && __pyx_ptype_10constraint_7solvers___pyx_scope_struct_5_genexpr->tp_getattro == PyObject_GenericGetAttr)) { + __pyx_ptype_10constraint_7solvers___pyx_scope_struct_5_genexpr->tp_getattro = __Pyx_PyObject_GenericGetAttrNoDict; } #endif #if CYTHON_USE_TYPE_SPECS - __pyx_ptype_10constraint_7solvers___pyx_scope_struct_6_genexpr = (PyTypeObject *) __Pyx_PyType_FromModuleAndSpec(__pyx_m, &__pyx_type_10constraint_7solvers___pyx_scope_struct_6_genexpr_spec, NULL); if (unlikely(!__pyx_ptype_10constraint_7solvers___pyx_scope_struct_6_genexpr)) __PYX_ERR(0, 773, __pyx_L1_error) - if (__Pyx_fix_up_extension_type_from_spec(&__pyx_type_10constraint_7solvers___pyx_scope_struct_6_genexpr_spec, __pyx_ptype_10constraint_7solvers___pyx_scope_struct_6_genexpr) < 0) __PYX_ERR(0, 773, __pyx_L1_error) + __pyx_ptype_10constraint_7solvers___pyx_scope_struct_6_genexpr = (PyTypeObject *) __Pyx_PyType_FromModuleAndSpec(__pyx_m, &__pyx_type_10constraint_7solvers___pyx_scope_struct_6_genexpr_spec, NULL); if (unlikely(!__pyx_ptype_10constraint_7solvers___pyx_scope_struct_6_genexpr)) __PYX_ERR(0, 698, __pyx_L1_error) + if (__Pyx_fix_up_extension_type_from_spec(&__pyx_type_10constraint_7solvers___pyx_scope_struct_6_genexpr_spec, __pyx_ptype_10constraint_7solvers___pyx_scope_struct_6_genexpr) < 0) __PYX_ERR(0, 698, __pyx_L1_error) #else __pyx_ptype_10constraint_7solvers___pyx_scope_struct_6_genexpr = &__pyx_type_10constraint_7solvers___pyx_scope_struct_6_genexpr; #endif #if !CYTHON_COMPILING_IN_LIMITED_API #endif #if !CYTHON_USE_TYPE_SPECS - if (__Pyx_PyType_Ready(__pyx_ptype_10constraint_7solvers___pyx_scope_struct_6_genexpr) < 0) __PYX_ERR(0, 773, __pyx_L1_error) + if (__Pyx_PyType_Ready(__pyx_ptype_10constraint_7solvers___pyx_scope_struct_6_genexpr) < 0) __PYX_ERR(0, 698, __pyx_L1_error) #endif #if PY_MAJOR_VERSION < 3 __pyx_ptype_10constraint_7solvers___pyx_scope_struct_6_genexpr->tp_print = 0; @@ -23305,266 +23305,266 @@ if (!__Pyx_RefNanny) { __Pyx_GOTREF(__pyx_t_6); __Pyx_CyFunction_SetDefaultsTuple(__pyx_t_6, __pyx_tuple__41); if (__Pyx_SetNameInClass(__pyx_t_5, __pyx_n_s_init, __pyx_t_6) < 0) __PYX_ERR(0, 554, __pyx_L1_error) - __Pyx_DECREF(__pyx_t_6); __pyx_t_6 = 0; - - /* "constraint/solvers.py":566 - * self._rand = rand - * - * def getSolution(self, domains: dict, constraints: list[tuple], vconstraints: dict): # noqa: D102 # <<<<<<<<<<<<<< - * choice = self._rand.choice if self._rand is not None else random.choice - * shuffle = self._rand.shuffle if self._rand is not None else random.shuffle - */ - __pyx_t_6 = __Pyx_PyDict_NewPresized(3); if (unlikely(!__pyx_t_6)) __PYX_ERR(0, 566, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_6); - if (PyDict_SetItem(__pyx_t_6, __pyx_n_s_domains, __pyx_n_s_dict) < 0) __PYX_ERR(0, 566, __pyx_L1_error) - if (PyDict_SetItem(__pyx_t_6, __pyx_n_s_constraints, __pyx_kp_s_list_tuple) < 0) __PYX_ERR(0, 566, __pyx_L1_error) - if (PyDict_SetItem(__pyx_t_6, __pyx_n_s_vconstraints, __pyx_n_s_dict) < 0) __PYX_ERR(0, 566, __pyx_L1_error) - __pyx_t_2 = __Pyx_CyFunction_New(&__pyx_mdef_10constraint_7solvers_18MinConflictsSolver_3getSolution, 0, __pyx_n_s_MinConflictsSolver_getSolution, NULL, __pyx_n_s_constraint_solvers, __pyx_d, ((PyObject *)__pyx_codeobj__43)); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 566, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_2); - __Pyx_CyFunction_SetAnnotationsDict(__pyx_t_2, __pyx_t_6); - __Pyx_DECREF(__pyx_t_6); __pyx_t_6 = 0; - if (__Pyx_SetNameInClass(__pyx_t_5, __pyx_n_s_getSolution, __pyx_t_2) < 0) __PYX_ERR(0, 566, __pyx_L1_error) - __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; - - /* "constraint/solvers.py":527 - * - * - * class MinConflictsSolver(Solver): # <<<<<<<<<<<<<< - * """Problem solver based on the minimum conflicts theory. - * - */ - __pyx_t_2 = __Pyx_Py3ClassCreate(__pyx_t_4, __pyx_n_s_MinConflictsSolver, __pyx_t_3, __pyx_t_5, NULL, 0, 0); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 527, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_2); - if (PyDict_SetItem(__pyx_d, __pyx_n_s_MinConflictsSolver, __pyx_t_2) < 0) __PYX_ERR(0, 527, __pyx_L1_error) - __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; - __Pyx_DECREF(__pyx_t_5); __pyx_t_5 = 0; - __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; - __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; - - /* "constraint/solvers.py":609 - * ### Helper functions for parallel solver - * - * def is_valid(assignment: dict[Hashable, any], constraints_lookup: list[tuple[Constraint, Hashable]], domains: dict[Hashable, Domain]) -> bool: # noqa E501 # <<<<<<<<<<<<<< - * """Check if all constraints are satisfied given the current assignment.""" - * return all( - */ - __pyx_t_3 = __Pyx_PyDict_NewPresized(4); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 609, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_3); - if (PyDict_SetItem(__pyx_t_3, __pyx_n_s_assignment, __pyx_kp_s_dict_Hashable_any) < 0) __PYX_ERR(0, 609, __pyx_L1_error) - if (PyDict_SetItem(__pyx_t_3, __pyx_n_s_constraints_lookup, __pyx_kp_s_list_tuple_Constraint_Hashable) < 0) __PYX_ERR(0, 609, __pyx_L1_error) - if (PyDict_SetItem(__pyx_t_3, __pyx_n_s_domains, __pyx_kp_s_dict_Hashable_Domain) < 0) __PYX_ERR(0, 609, __pyx_L1_error) - if (PyDict_SetItem(__pyx_t_3, __pyx_n_s_return, __pyx_n_s_bool) < 0) __PYX_ERR(0, 609, __pyx_L1_error) - __pyx_t_4 = __Pyx_CyFunction_New(&__pyx_mdef_10constraint_7solvers_5is_valid, 0, __pyx_n_s_is_valid, NULL, __pyx_n_s_constraint_solvers, __pyx_d, ((PyObject *)__pyx_codeobj__45)); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 609, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_4); - __Pyx_CyFunction_SetAnnotationsDict(__pyx_t_4, __pyx_t_3); - __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; - if (PyDict_SetItem(__pyx_d, __pyx_n_s_is_valid, __pyx_t_4) < 0) __PYX_ERR(0, 609, __pyx_L1_error) - __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; - - /* "constraint/solvers.py":617 - * ) - * - * def compile_to_function(constraint: CompilableFunctionConstraint) -> FunctionConstraint: # <<<<<<<<<<<<<< - * """Compile a CompilableFunctionConstraint to a function, wrapped by a FunctionConstraint.""" - * func_string = constraint._func - */ - __pyx_t_4 = __Pyx_PyDict_NewPresized(2); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 617, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_4); - if (PyDict_SetItem(__pyx_t_4, __pyx_n_s_constraint, __pyx_n_s_CompilableFunctionConstraint) < 0) __PYX_ERR(0, 617, __pyx_L1_error) - if (PyDict_SetItem(__pyx_t_4, __pyx_n_s_return, __pyx_n_s_FunctionConstraint) < 0) __PYX_ERR(0, 617, __pyx_L1_error) - __pyx_t_3 = __Pyx_CyFunction_New(&__pyx_mdef_10constraint_7solvers_7compile_to_function, 0, __pyx_n_s_compile_to_function, NULL, __pyx_n_s_constraint_solvers, __pyx_d, ((PyObject *)__pyx_codeobj__47)); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 617, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_3); - __Pyx_CyFunction_SetAnnotationsDict(__pyx_t_3, __pyx_t_4); - __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; - if (PyDict_SetItem(__pyx_d, __pyx_n_s_compile_to_function, __pyx_t_3) < 0) __PYX_ERR(0, 617, __pyx_L1_error) - __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; - - /* "constraint/solvers.py":624 - * return FunctionConstraint(func) - * - * def sequential_recursive_backtrack(assignment: dict[Hashable, any], unassigned_vars: list[Hashable], domains: dict[Hashable, Domain], constraint_lookup: dict[Hashable, list[tuple[Constraint, Hashable]]]) -> list[dict[Hashable, any]]: # noqa E501 # <<<<<<<<<<<<<< - * """Sequential recursive backtracking function for subproblems.""" - * if not unassigned_vars: - */ - __pyx_t_3 = __Pyx_PyDict_NewPresized(5); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 624, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_3); - if (PyDict_SetItem(__pyx_t_3, __pyx_n_s_assignment, __pyx_kp_s_dict_Hashable_any) < 0) __PYX_ERR(0, 624, __pyx_L1_error) - if (PyDict_SetItem(__pyx_t_3, __pyx_n_s_unassigned_vars, __pyx_kp_s_list_Hashable) < 0) __PYX_ERR(0, 624, __pyx_L1_error) - if (PyDict_SetItem(__pyx_t_3, __pyx_n_s_domains, __pyx_kp_s_dict_Hashable_Domain) < 0) __PYX_ERR(0, 624, __pyx_L1_error) - if (PyDict_SetItem(__pyx_t_3, __pyx_n_s_constraint_lookup, __pyx_kp_s_dict_Hashable_list_tuple_Constra) < 0) __PYX_ERR(0, 624, __pyx_L1_error) - if (PyDict_SetItem(__pyx_t_3, __pyx_n_s_return, __pyx_kp_s_list_dict_Hashable_any) < 0) __PYX_ERR(0, 624, __pyx_L1_error) - __pyx_t_4 = __Pyx_CyFunction_New(&__pyx_mdef_10constraint_7solvers_9sequential_recursive_backtrack, 0, __pyx_n_s_sequential_recursive_backtrack, NULL, __pyx_n_s_constraint_solvers, __pyx_d, ((PyObject *)__pyx_codeobj__49)); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 624, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_4); - __Pyx_CyFunction_SetAnnotationsDict(__pyx_t_4, __pyx_t_3); - __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; - if (PyDict_SetItem(__pyx_d, __pyx_n_s_sequential_recursive_backtrack, __pyx_t_4) < 0) __PYX_ERR(0, 624, __pyx_L1_error) - __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; + __Pyx_DECREF(__pyx_t_6); __pyx_t_6 = 0; - /* "constraint/solvers.py":640 - * return solutions + /* "constraint/solvers.py":566 + * self._rand = rand * - * def sequential_optimized_backtrack(assignment: dict[Hashable, any], unassigned_vars: list[Hashable], domains: dict[Hashable, Domain], constraint_lookup: dict[Hashable, list[tuple[Constraint, Hashable]]]) -> list[dict[Hashable, any]]: # noqa E501 # <<<<<<<<<<<<<< - * """Sequential optimized backtracking (as in OptimizedBacktrackingSolver) function for subproblems.""" - * # Does not do forwardcheck for simplicity + * def getSolution(self, domains: dict, constraints: list[tuple], vconstraints: dict): # noqa: D102 # <<<<<<<<<<<<<< + * choice = self._rand.choice if self._rand is not None else random.choice + * shuffle = self._rand.shuffle if self._rand is not None else random.shuffle */ - __pyx_t_4 = __Pyx_PyDict_NewPresized(5); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 640, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_4); - if (PyDict_SetItem(__pyx_t_4, __pyx_n_s_assignment, __pyx_kp_s_dict_Hashable_any) < 0) __PYX_ERR(0, 640, __pyx_L1_error) - if (PyDict_SetItem(__pyx_t_4, __pyx_n_s_unassigned_vars, __pyx_kp_s_list_Hashable) < 0) __PYX_ERR(0, 640, __pyx_L1_error) - if (PyDict_SetItem(__pyx_t_4, __pyx_n_s_domains, __pyx_kp_s_dict_Hashable_Domain) < 0) __PYX_ERR(0, 640, __pyx_L1_error) - if (PyDict_SetItem(__pyx_t_4, __pyx_n_s_constraint_lookup, __pyx_kp_s_dict_Hashable_list_tuple_Constra) < 0) __PYX_ERR(0, 640, __pyx_L1_error) - if (PyDict_SetItem(__pyx_t_4, __pyx_n_s_return, __pyx_kp_s_list_dict_Hashable_any) < 0) __PYX_ERR(0, 640, __pyx_L1_error) - __pyx_t_3 = __Pyx_CyFunction_New(&__pyx_mdef_10constraint_7solvers_11sequential_optimized_backtrack, 0, __pyx_n_s_sequential_optimized_backtrack, NULL, __pyx_n_s_constraint_solvers, __pyx_d, ((PyObject *)__pyx_codeobj__51)); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 640, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_3); - __Pyx_CyFunction_SetAnnotationsDict(__pyx_t_3, __pyx_t_4); - __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; - if (PyDict_SetItem(__pyx_d, __pyx_n_s_sequential_optimized_backtrack, __pyx_t_3) < 0) __PYX_ERR(0, 640, __pyx_L1_error) - __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; + __pyx_t_6 = __Pyx_PyDict_NewPresized(3); if (unlikely(!__pyx_t_6)) __PYX_ERR(0, 566, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_6); + if (PyDict_SetItem(__pyx_t_6, __pyx_n_s_domains, __pyx_n_s_dict) < 0) __PYX_ERR(0, 566, __pyx_L1_error) + if (PyDict_SetItem(__pyx_t_6, __pyx_n_s_constraints, __pyx_kp_s_list_tuple) < 0) __PYX_ERR(0, 566, __pyx_L1_error) + if (PyDict_SetItem(__pyx_t_6, __pyx_n_s_vconstraints, __pyx_n_s_dict) < 0) __PYX_ERR(0, 566, __pyx_L1_error) + __pyx_t_2 = __Pyx_CyFunction_New(&__pyx_mdef_10constraint_7solvers_18MinConflictsSolver_3getSolution, 0, __pyx_n_s_MinConflictsSolver_getSolution, NULL, __pyx_n_s_constraint_solvers, __pyx_d, ((PyObject *)__pyx_codeobj__43)); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 566, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_2); + __Pyx_CyFunction_SetAnnotationsDict(__pyx_t_2, __pyx_t_6); + __Pyx_DECREF(__pyx_t_6); __pyx_t_6 = 0; + if (__Pyx_SetNameInClass(__pyx_t_5, __pyx_n_s_getSolution, __pyx_t_2) < 0) __PYX_ERR(0, 566, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; - /* "constraint/solvers.py":690 + /* "constraint/solvers.py":527 * * - * def parallel_worker(args: tuple[bool, dict[Hashable, Domain], dict[Hashable, list[tuple[Constraint, Hashable]]], Hashable, any, list[Hashable]]) -> list[dict[Hashable, any]]: # noqa E501 # <<<<<<<<<<<<<< - * """Worker function for parallel execution on first variable.""" - * process_mode, domains, constraint_lookup, first_var, first_value, remaining_vars = args + * class MinConflictsSolver(Solver): # <<<<<<<<<<<<<< + * """Problem solver based on the minimum conflicts theory. + * */ - __pyx_t_3 = __Pyx_PyDict_NewPresized(2); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 690, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_3); - if (PyDict_SetItem(__pyx_t_3, __pyx_n_s_args, __pyx_kp_s_tuple_bool_dict_Hashable_Domain) < 0) __PYX_ERR(0, 690, __pyx_L1_error) - if (PyDict_SetItem(__pyx_t_3, __pyx_n_s_return, __pyx_kp_s_list_dict_Hashable_any) < 0) __PYX_ERR(0, 690, __pyx_L1_error) - __pyx_t_4 = __Pyx_CyFunction_New(&__pyx_mdef_10constraint_7solvers_13parallel_worker, 0, __pyx_n_s_parallel_worker, NULL, __pyx_n_s_constraint_solvers, __pyx_d, ((PyObject *)__pyx_codeobj__53)); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 690, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_4); - __Pyx_CyFunction_SetAnnotationsDict(__pyx_t_4, __pyx_t_3); - __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; - if (PyDict_SetItem(__pyx_d, __pyx_n_s_parallel_worker, __pyx_t_4) < 0) __PYX_ERR(0, 690, __pyx_L1_error) + __pyx_t_2 = __Pyx_Py3ClassCreate(__pyx_t_4, __pyx_n_s_MinConflictsSolver, __pyx_t_3, __pyx_t_5, NULL, 0, 0); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 527, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_2); + if (PyDict_SetItem(__pyx_d, __pyx_n_s_MinConflictsSolver, __pyx_t_2) < 0) __PYX_ERR(0, 527, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; + __Pyx_DECREF(__pyx_t_5); __pyx_t_5 = 0; __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; + __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; - /* "constraint/solvers.py":705 - * return [] + /* "constraint/solvers.py":607 + * * * class ParallelSolver(Solver): # <<<<<<<<<<<<<< * """Problem solver that executes all-solution solve in parallel (ProcessPool or ThreadPool mode). * */ - __Pyx_GetModuleGlobalName(__pyx_t_4, __pyx_n_s_Solver); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 705, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_4); - __pyx_t_3 = PyTuple_New(1); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 705, __pyx_L1_error) + __Pyx_GetModuleGlobalName(__pyx_t_3, __pyx_n_s_Solver); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 607, __pyx_L1_error) __Pyx_GOTREF(__pyx_t_3); - __Pyx_GIVEREF(__pyx_t_4); - if (__Pyx_PyTuple_SET_ITEM(__pyx_t_3, 0, __pyx_t_4)) __PYX_ERR(0, 705, __pyx_L1_error); - __pyx_t_4 = 0; - __pyx_t_4 = __Pyx_PEP560_update_bases(__pyx_t_3); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 705, __pyx_L1_error) + __pyx_t_4 = PyTuple_New(1); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 607, __pyx_L1_error) __Pyx_GOTREF(__pyx_t_4); - __pyx_t_5 = __Pyx_CalculateMetaclass(NULL, __pyx_t_4); if (unlikely(!__pyx_t_5)) __PYX_ERR(0, 705, __pyx_L1_error) + __Pyx_GIVEREF(__pyx_t_3); + if (__Pyx_PyTuple_SET_ITEM(__pyx_t_4, 0, __pyx_t_3)) __PYX_ERR(0, 607, __pyx_L1_error); + __pyx_t_3 = 0; + __pyx_t_3 = __Pyx_PEP560_update_bases(__pyx_t_4); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 607, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_3); + __pyx_t_5 = __Pyx_CalculateMetaclass(NULL, __pyx_t_3); if (unlikely(!__pyx_t_5)) __PYX_ERR(0, 607, __pyx_L1_error) __Pyx_GOTREF(__pyx_t_5); - __pyx_t_2 = __Pyx_Py3MetaclassPrepare(__pyx_t_5, __pyx_t_4, __pyx_n_s_ParallelSolver, __pyx_n_s_ParallelSolver, (PyObject *) NULL, __pyx_n_s_constraint_solvers, __pyx_kp_s_Problem_solver_that_executes_all); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 705, __pyx_L1_error) + __pyx_t_2 = __Pyx_Py3MetaclassPrepare(__pyx_t_5, __pyx_t_3, __pyx_n_s_ParallelSolver, __pyx_n_s_ParallelSolver, (PyObject *) NULL, __pyx_n_s_constraint_solvers, __pyx_kp_s_Problem_solver_that_executes_all); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 607, __pyx_L1_error) __Pyx_GOTREF(__pyx_t_2); - if (__pyx_t_4 != __pyx_t_3) { - if (unlikely((PyDict_SetItemString(__pyx_t_2, "__orig_bases__", __pyx_t_3) < 0))) __PYX_ERR(0, 705, __pyx_L1_error) + if (__pyx_t_3 != __pyx_t_4) { + if (unlikely((PyDict_SetItemString(__pyx_t_2, "__orig_bases__", __pyx_t_4) < 0))) __PYX_ERR(0, 607, __pyx_L1_error) } - __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; - __pyx_t_3 = PyList_New(0); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 705, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_3); + __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; + __pyx_t_4 = PyList_New(0); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 607, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_4); - /* "constraint/solvers.py":742 + /* "constraint/solvers.py":644 * """ # noqa E501 * * def __init__(self, process_mode=False): # <<<<<<<<<<<<<< * """Initialization method. Set `process_mode` to True for using ProcessPool, otherwise uses ThreadPool.""" * super().__init__() */ - __pyx_t_6 = __Pyx_CyFunction_New(&__pyx_mdef_10constraint_7solvers_14ParallelSolver_1__init__, 0, __pyx_n_s_ParallelSolver___init, NULL, __pyx_n_s_constraint_solvers, __pyx_d, ((PyObject *)__pyx_codeobj__55)); if (unlikely(!__pyx_t_6)) __PYX_ERR(0, 742, __pyx_L1_error) + __pyx_t_6 = __Pyx_CyFunction_New(&__pyx_mdef_10constraint_7solvers_14ParallelSolver_1__init__, 0, __pyx_n_s_ParallelSolver___init, NULL, __pyx_n_s_constraint_solvers, __pyx_d, ((PyObject *)__pyx_codeobj__45)); if (unlikely(!__pyx_t_6)) __PYX_ERR(0, 644, __pyx_L1_error) __Pyx_GOTREF(__pyx_t_6); __Pyx_INCREF(__pyx_t_6); - PyList_Append(__pyx_t_3, __pyx_t_6); + PyList_Append(__pyx_t_4, __pyx_t_6); __Pyx_GIVEREF(__pyx_t_6); - __Pyx_CyFunction_SetDefaultsTuple(__pyx_t_6, __pyx_tuple__56); - if (__Pyx_SetNameInClass(__pyx_t_2, __pyx_n_s_init, __pyx_t_6) < 0) __PYX_ERR(0, 742, __pyx_L1_error) + __Pyx_CyFunction_SetDefaultsTuple(__pyx_t_6, __pyx_tuple__46); + if (__Pyx_SetNameInClass(__pyx_t_2, __pyx_n_s_init, __pyx_t_6) < 0) __PYX_ERR(0, 644, __pyx_L1_error) __Pyx_DECREF(__pyx_t_6); __pyx_t_6 = 0; - /* "constraint/solvers.py":748 + /* "constraint/solvers.py":650 * self.requires_pickling = process_mode * * def getSolution(self, domains: dict, constraints: list[tuple], vconstraints: dict): # <<<<<<<<<<<<<< * """Return one solution for the given problem. * */ - __pyx_t_6 = __Pyx_PyDict_NewPresized(3); if (unlikely(!__pyx_t_6)) __PYX_ERR(0, 748, __pyx_L1_error) + __pyx_t_6 = __Pyx_PyDict_NewPresized(3); if (unlikely(!__pyx_t_6)) __PYX_ERR(0, 650, __pyx_L1_error) __Pyx_GOTREF(__pyx_t_6); - if (PyDict_SetItem(__pyx_t_6, __pyx_n_s_domains, __pyx_n_s_dict) < 0) __PYX_ERR(0, 748, __pyx_L1_error) - if (PyDict_SetItem(__pyx_t_6, __pyx_n_s_constraints, __pyx_kp_s_list_tuple) < 0) __PYX_ERR(0, 748, __pyx_L1_error) - if (PyDict_SetItem(__pyx_t_6, __pyx_n_s_vconstraints, __pyx_n_s_dict) < 0) __PYX_ERR(0, 748, __pyx_L1_error) - __pyx_t_7 = __Pyx_CyFunction_New(&__pyx_mdef_10constraint_7solvers_14ParallelSolver_3getSolution, 0, __pyx_n_s_ParallelSolver_getSolution, NULL, __pyx_n_s_constraint_solvers, __pyx_d, ((PyObject *)__pyx_codeobj__57)); if (unlikely(!__pyx_t_7)) __PYX_ERR(0, 748, __pyx_L1_error) + if (PyDict_SetItem(__pyx_t_6, __pyx_n_s_domains, __pyx_n_s_dict) < 0) __PYX_ERR(0, 650, __pyx_L1_error) + if (PyDict_SetItem(__pyx_t_6, __pyx_n_s_constraints, __pyx_kp_s_list_tuple) < 0) __PYX_ERR(0, 650, __pyx_L1_error) + if (PyDict_SetItem(__pyx_t_6, __pyx_n_s_vconstraints, __pyx_n_s_dict) < 0) __PYX_ERR(0, 650, __pyx_L1_error) + __pyx_t_7 = __Pyx_CyFunction_New(&__pyx_mdef_10constraint_7solvers_14ParallelSolver_3getSolution, 0, __pyx_n_s_ParallelSolver_getSolution, NULL, __pyx_n_s_constraint_solvers, __pyx_d, ((PyObject *)__pyx_codeobj__47)); if (unlikely(!__pyx_t_7)) __PYX_ERR(0, 650, __pyx_L1_error) __Pyx_GOTREF(__pyx_t_7); __Pyx_CyFunction_SetAnnotationsDict(__pyx_t_7, __pyx_t_6); __Pyx_DECREF(__pyx_t_6); __pyx_t_6 = 0; - if (__Pyx_SetNameInClass(__pyx_t_2, __pyx_n_s_getSolution, __pyx_t_7) < 0) __PYX_ERR(0, 748, __pyx_L1_error) + if (__Pyx_SetNameInClass(__pyx_t_2, __pyx_n_s_getSolution, __pyx_t_7) < 0) __PYX_ERR(0, 650, __pyx_L1_error) __Pyx_DECREF(__pyx_t_7); __pyx_t_7 = 0; - /* "constraint/solvers.py":760 + /* "constraint/solvers.py":662 * raise NotImplementedError(msg) * * def getSolutionsList(self, domains: dict[Hashable, Domain], vconstraints: dict[Hashable, list[tuple[Constraint, Hashable]]]) -> list[dict[Hashable, any]]: # noqa: D102, E501 # <<<<<<<<<<<<<< * """Parallelized all-solutions finder using ProcessPoolExecutor for work-stealing.""" * # Precompute constraints lookup per variable */ - __pyx_t_7 = __Pyx_PyDict_NewPresized(3); if (unlikely(!__pyx_t_7)) __PYX_ERR(0, 760, __pyx_L1_error) + __pyx_t_7 = __Pyx_PyDict_NewPresized(3); if (unlikely(!__pyx_t_7)) __PYX_ERR(0, 662, __pyx_L1_error) __Pyx_GOTREF(__pyx_t_7); - if (PyDict_SetItem(__pyx_t_7, __pyx_n_s_domains, __pyx_kp_s_dict_Hashable_Domain) < 0) __PYX_ERR(0, 760, __pyx_L1_error) - if (PyDict_SetItem(__pyx_t_7, __pyx_n_s_vconstraints, __pyx_kp_s_dict_Hashable_list_tuple_Constra) < 0) __PYX_ERR(0, 760, __pyx_L1_error) - if (PyDict_SetItem(__pyx_t_7, __pyx_n_s_return, __pyx_kp_s_list_dict_Hashable_any) < 0) __PYX_ERR(0, 760, __pyx_L1_error) - __pyx_t_6 = __Pyx_CyFunction_New(&__pyx_mdef_10constraint_7solvers_14ParallelSolver_5getSolutionsList, 0, __pyx_n_s_ParallelSolver_getSolutionsList_3, NULL, __pyx_n_s_constraint_solvers, __pyx_d, ((PyObject *)__pyx_codeobj__59)); if (unlikely(!__pyx_t_6)) __PYX_ERR(0, 760, __pyx_L1_error) + if (PyDict_SetItem(__pyx_t_7, __pyx_n_s_domains, __pyx_kp_s_dict_Hashable_Domain) < 0) __PYX_ERR(0, 662, __pyx_L1_error) + if (PyDict_SetItem(__pyx_t_7, __pyx_n_s_vconstraints, __pyx_kp_s_dict_Hashable_list_tuple_Constra) < 0) __PYX_ERR(0, 662, __pyx_L1_error) + if (PyDict_SetItem(__pyx_t_7, __pyx_n_s_return, __pyx_kp_s_list_dict_Hashable_any) < 0) __PYX_ERR(0, 662, __pyx_L1_error) + __pyx_t_6 = __Pyx_CyFunction_New(&__pyx_mdef_10constraint_7solvers_14ParallelSolver_5getSolutionsList, 0, __pyx_n_s_ParallelSolver_getSolutionsList_3, NULL, __pyx_n_s_constraint_solvers, __pyx_d, ((PyObject *)__pyx_codeobj__49)); if (unlikely(!__pyx_t_6)) __PYX_ERR(0, 662, __pyx_L1_error) __Pyx_GOTREF(__pyx_t_6); __Pyx_CyFunction_SetAnnotationsDict(__pyx_t_6, __pyx_t_7); __Pyx_DECREF(__pyx_t_7); __pyx_t_7 = 0; - if (__Pyx_SetNameInClass(__pyx_t_2, __pyx_n_s_getSolutionsList, __pyx_t_6) < 0) __PYX_ERR(0, 760, __pyx_L1_error) + if (__Pyx_SetNameInClass(__pyx_t_2, __pyx_n_s_getSolutionsList, __pyx_t_6) < 0) __PYX_ERR(0, 662, __pyx_L1_error) __Pyx_DECREF(__pyx_t_6); __pyx_t_6 = 0; - /* "constraint/solvers.py":786 + /* "constraint/solvers.py":688 * return solutions * * def getSolutions(self, domains: dict, constraints: list[tuple], vconstraints: dict): # noqa: D102 # <<<<<<<<<<<<<< * return self.getSolutionsList(domains, vconstraints) * */ - __pyx_t_6 = __Pyx_PyDict_NewPresized(3); if (unlikely(!__pyx_t_6)) __PYX_ERR(0, 786, __pyx_L1_error) + __pyx_t_6 = __Pyx_PyDict_NewPresized(3); if (unlikely(!__pyx_t_6)) __PYX_ERR(0, 688, __pyx_L1_error) __Pyx_GOTREF(__pyx_t_6); - if (PyDict_SetItem(__pyx_t_6, __pyx_n_s_domains, __pyx_n_s_dict) < 0) __PYX_ERR(0, 786, __pyx_L1_error) - if (PyDict_SetItem(__pyx_t_6, __pyx_n_s_constraints, __pyx_kp_s_list_tuple) < 0) __PYX_ERR(0, 786, __pyx_L1_error) - if (PyDict_SetItem(__pyx_t_6, __pyx_n_s_vconstraints, __pyx_n_s_dict) < 0) __PYX_ERR(0, 786, __pyx_L1_error) - __pyx_t_7 = __Pyx_CyFunction_New(&__pyx_mdef_10constraint_7solvers_14ParallelSolver_7getSolutions, 0, __pyx_n_s_ParallelSolver_getSolutions, NULL, __pyx_n_s_constraint_solvers, __pyx_d, ((PyObject *)__pyx_codeobj__60)); if (unlikely(!__pyx_t_7)) __PYX_ERR(0, 786, __pyx_L1_error) + if (PyDict_SetItem(__pyx_t_6, __pyx_n_s_domains, __pyx_n_s_dict) < 0) __PYX_ERR(0, 688, __pyx_L1_error) + if (PyDict_SetItem(__pyx_t_6, __pyx_n_s_constraints, __pyx_kp_s_list_tuple) < 0) __PYX_ERR(0, 688, __pyx_L1_error) + if (PyDict_SetItem(__pyx_t_6, __pyx_n_s_vconstraints, __pyx_n_s_dict) < 0) __PYX_ERR(0, 688, __pyx_L1_error) + __pyx_t_7 = __Pyx_CyFunction_New(&__pyx_mdef_10constraint_7solvers_14ParallelSolver_7getSolutions, 0, __pyx_n_s_ParallelSolver_getSolutions, NULL, __pyx_n_s_constraint_solvers, __pyx_d, ((PyObject *)__pyx_codeobj__50)); if (unlikely(!__pyx_t_7)) __PYX_ERR(0, 688, __pyx_L1_error) __Pyx_GOTREF(__pyx_t_7); __Pyx_CyFunction_SetAnnotationsDict(__pyx_t_7, __pyx_t_6); __Pyx_DECREF(__pyx_t_6); __pyx_t_6 = 0; - if (__Pyx_SetNameInClass(__pyx_t_2, __pyx_n_s_getSolutions, __pyx_t_7) < 0) __PYX_ERR(0, 786, __pyx_L1_error) + if (__Pyx_SetNameInClass(__pyx_t_2, __pyx_n_s_getSolutions, __pyx_t_7) < 0) __PYX_ERR(0, 688, __pyx_L1_error) __Pyx_DECREF(__pyx_t_7); __pyx_t_7 = 0; - /* "constraint/solvers.py":705 - * return [] + /* "constraint/solvers.py":607 + * * * class ParallelSolver(Solver): # <<<<<<<<<<<<<< * """Problem solver that executes all-solution solve in parallel (ProcessPool or ThreadPool mode). * */ - __pyx_t_7 = __Pyx_Py3ClassCreate(__pyx_t_5, __pyx_n_s_ParallelSolver, __pyx_t_4, __pyx_t_2, NULL, 0, 0); if (unlikely(!__pyx_t_7)) __PYX_ERR(0, 705, __pyx_L1_error) + __pyx_t_7 = __Pyx_Py3ClassCreate(__pyx_t_5, __pyx_n_s_ParallelSolver, __pyx_t_3, __pyx_t_2, NULL, 0, 0); if (unlikely(!__pyx_t_7)) __PYX_ERR(0, 607, __pyx_L1_error) __Pyx_GOTREF(__pyx_t_7); - if (__Pyx_CyFunction_InitClassCell(__pyx_t_3, __pyx_t_7) < 0) __PYX_ERR(0, 705, __pyx_L1_error) - __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; - if (PyDict_SetItem(__pyx_d, __pyx_n_s_ParallelSolver, __pyx_t_7) < 0) __PYX_ERR(0, 705, __pyx_L1_error) + if (__Pyx_CyFunction_InitClassCell(__pyx_t_4, __pyx_t_7) < 0) __PYX_ERR(0, 607, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; + if (PyDict_SetItem(__pyx_d, __pyx_n_s_ParallelSolver, __pyx_t_7) < 0) __PYX_ERR(0, 607, __pyx_L1_error) __Pyx_DECREF(__pyx_t_7); __pyx_t_7 = 0; __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; __Pyx_DECREF(__pyx_t_5); __pyx_t_5 = 0; - __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; + __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; + + /* "constraint/solvers.py":693 + * ### Helper functions for parallel solver + * + * def is_valid(assignment: dict[Hashable, any], constraints_lookup: list[tuple[Constraint, Hashable]], domains: dict[Hashable, Domain]) -> bool: # noqa E501 # <<<<<<<<<<<<<< + * """Check if all constraints are satisfied given the current assignment.""" + * return all( + */ + __pyx_t_3 = __Pyx_PyDict_NewPresized(4); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 693, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_3); + if (PyDict_SetItem(__pyx_t_3, __pyx_n_s_assignment, __pyx_kp_s_dict_Hashable_any) < 0) __PYX_ERR(0, 693, __pyx_L1_error) + if (PyDict_SetItem(__pyx_t_3, __pyx_n_s_constraints_lookup, __pyx_kp_s_list_tuple_Constraint_Hashable) < 0) __PYX_ERR(0, 693, __pyx_L1_error) + if (PyDict_SetItem(__pyx_t_3, __pyx_n_s_domains, __pyx_kp_s_dict_Hashable_Domain) < 0) __PYX_ERR(0, 693, __pyx_L1_error) + if (PyDict_SetItem(__pyx_t_3, __pyx_n_s_return, __pyx_n_s_bool) < 0) __PYX_ERR(0, 693, __pyx_L1_error) + __pyx_t_5 = __Pyx_CyFunction_New(&__pyx_mdef_10constraint_7solvers_5is_valid, 0, __pyx_n_s_is_valid, NULL, __pyx_n_s_constraint_solvers, __pyx_d, ((PyObject *)__pyx_codeobj__52)); if (unlikely(!__pyx_t_5)) __PYX_ERR(0, 693, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_5); + __Pyx_CyFunction_SetAnnotationsDict(__pyx_t_5, __pyx_t_3); + __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; + if (PyDict_SetItem(__pyx_d, __pyx_n_s_is_valid, __pyx_t_5) < 0) __PYX_ERR(0, 693, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_5); __pyx_t_5 = 0; + + /* "constraint/solvers.py":701 + * ) + * + * def compile_to_function(constraint: CompilableFunctionConstraint) -> FunctionConstraint: # <<<<<<<<<<<<<< + * """Compile a CompilableFunctionConstraint to a function, wrapped by a FunctionConstraint.""" + * func_string = constraint._func + */ + __pyx_t_5 = __Pyx_PyDict_NewPresized(2); if (unlikely(!__pyx_t_5)) __PYX_ERR(0, 701, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_5); + if (PyDict_SetItem(__pyx_t_5, __pyx_n_s_constraint, __pyx_n_s_CompilableFunctionConstraint) < 0) __PYX_ERR(0, 701, __pyx_L1_error) + if (PyDict_SetItem(__pyx_t_5, __pyx_n_s_return, __pyx_n_s_FunctionConstraint) < 0) __PYX_ERR(0, 701, __pyx_L1_error) + __pyx_t_3 = __Pyx_CyFunction_New(&__pyx_mdef_10constraint_7solvers_7compile_to_function, 0, __pyx_n_s_compile_to_function, NULL, __pyx_n_s_constraint_solvers, __pyx_d, ((PyObject *)__pyx_codeobj__54)); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 701, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_3); + __Pyx_CyFunction_SetAnnotationsDict(__pyx_t_3, __pyx_t_5); + __Pyx_DECREF(__pyx_t_5); __pyx_t_5 = 0; + if (PyDict_SetItem(__pyx_d, __pyx_n_s_compile_to_function, __pyx_t_3) < 0) __PYX_ERR(0, 701, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; + + /* "constraint/solvers.py":708 + * return FunctionConstraint(func) + * + * def sequential_recursive_backtrack(assignment: dict[Hashable, any], unassigned_vars: list[Hashable], domains: dict[Hashable, Domain], constraint_lookup: dict[Hashable, list[tuple[Constraint, Hashable]]]) -> list[dict[Hashable, any]]: # noqa E501 # <<<<<<<<<<<<<< + * """Sequential recursive backtracking function for subproblems.""" + * if not unassigned_vars: + */ + __pyx_t_3 = __Pyx_PyDict_NewPresized(5); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 708, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_3); + if (PyDict_SetItem(__pyx_t_3, __pyx_n_s_assignment, __pyx_kp_s_dict_Hashable_any) < 0) __PYX_ERR(0, 708, __pyx_L1_error) + if (PyDict_SetItem(__pyx_t_3, __pyx_n_s_unassigned_vars, __pyx_kp_s_list_Hashable) < 0) __PYX_ERR(0, 708, __pyx_L1_error) + if (PyDict_SetItem(__pyx_t_3, __pyx_n_s_domains, __pyx_kp_s_dict_Hashable_Domain) < 0) __PYX_ERR(0, 708, __pyx_L1_error) + if (PyDict_SetItem(__pyx_t_3, __pyx_n_s_constraint_lookup, __pyx_kp_s_dict_Hashable_list_tuple_Constra) < 0) __PYX_ERR(0, 708, __pyx_L1_error) + if (PyDict_SetItem(__pyx_t_3, __pyx_n_s_return, __pyx_kp_s_list_dict_Hashable_any) < 0) __PYX_ERR(0, 708, __pyx_L1_error) + __pyx_t_5 = __Pyx_CyFunction_New(&__pyx_mdef_10constraint_7solvers_9sequential_recursive_backtrack, 0, __pyx_n_s_sequential_recursive_backtrack, NULL, __pyx_n_s_constraint_solvers, __pyx_d, ((PyObject *)__pyx_codeobj__56)); if (unlikely(!__pyx_t_5)) __PYX_ERR(0, 708, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_5); + __Pyx_CyFunction_SetAnnotationsDict(__pyx_t_5, __pyx_t_3); + __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; + if (PyDict_SetItem(__pyx_d, __pyx_n_s_sequential_recursive_backtrack, __pyx_t_5) < 0) __PYX_ERR(0, 708, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_5); __pyx_t_5 = 0; + + /* "constraint/solvers.py":724 + * return solutions + * + * def sequential_optimized_backtrack(assignment: dict[Hashable, any], unassigned_vars: list[Hashable], domains: dict[Hashable, Domain], constraint_lookup: dict[Hashable, list[tuple[Constraint, Hashable]]]) -> list[dict[Hashable, any]]: # noqa E501 # <<<<<<<<<<<<<< + * """Sequential optimized backtracking (as in OptimizedBacktrackingSolver) function for subproblems.""" + * # Does not do forwardcheck for simplicity + */ + __pyx_t_5 = __Pyx_PyDict_NewPresized(5); if (unlikely(!__pyx_t_5)) __PYX_ERR(0, 724, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_5); + if (PyDict_SetItem(__pyx_t_5, __pyx_n_s_assignment, __pyx_kp_s_dict_Hashable_any) < 0) __PYX_ERR(0, 724, __pyx_L1_error) + if (PyDict_SetItem(__pyx_t_5, __pyx_n_s_unassigned_vars, __pyx_kp_s_list_Hashable) < 0) __PYX_ERR(0, 724, __pyx_L1_error) + if (PyDict_SetItem(__pyx_t_5, __pyx_n_s_domains, __pyx_kp_s_dict_Hashable_Domain) < 0) __PYX_ERR(0, 724, __pyx_L1_error) + if (PyDict_SetItem(__pyx_t_5, __pyx_n_s_constraint_lookup, __pyx_kp_s_dict_Hashable_list_tuple_Constra) < 0) __PYX_ERR(0, 724, __pyx_L1_error) + if (PyDict_SetItem(__pyx_t_5, __pyx_n_s_return, __pyx_kp_s_list_dict_Hashable_any) < 0) __PYX_ERR(0, 724, __pyx_L1_error) + __pyx_t_3 = __Pyx_CyFunction_New(&__pyx_mdef_10constraint_7solvers_11sequential_optimized_backtrack, 0, __pyx_n_s_sequential_optimized_backtrack, NULL, __pyx_n_s_constraint_solvers, __pyx_d, ((PyObject *)__pyx_codeobj__58)); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 724, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_3); + __Pyx_CyFunction_SetAnnotationsDict(__pyx_t_3, __pyx_t_5); + __Pyx_DECREF(__pyx_t_5); __pyx_t_5 = 0; + if (PyDict_SetItem(__pyx_d, __pyx_n_s_sequential_optimized_backtrack, __pyx_t_3) < 0) __PYX_ERR(0, 724, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; + + /* "constraint/solvers.py":774 + * + * + * def parallel_worker(args: tuple[bool, dict[Hashable, Domain], dict[Hashable, list[tuple[Constraint, Hashable]]], Hashable, any, list[Hashable]]) -> list[dict[Hashable, any]]: # noqa E501 # <<<<<<<<<<<<<< + * """Worker function for parallel execution on first variable.""" + * process_mode, domains, constraint_lookup, first_var, first_value, remaining_vars = args + */ + __pyx_t_3 = __Pyx_PyDict_NewPresized(2); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 774, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_3); + if (PyDict_SetItem(__pyx_t_3, __pyx_n_s_args, __pyx_kp_s_tuple_bool_dict_Hashable_Domain) < 0) __PYX_ERR(0, 774, __pyx_L1_error) + if (PyDict_SetItem(__pyx_t_3, __pyx_n_s_return, __pyx_kp_s_list_dict_Hashable_any) < 0) __PYX_ERR(0, 774, __pyx_L1_error) + __pyx_t_5 = __Pyx_CyFunction_New(&__pyx_mdef_10constraint_7solvers_13parallel_worker, 0, __pyx_n_s_parallel_worker, NULL, __pyx_n_s_constraint_solvers, __pyx_d, ((PyObject *)__pyx_codeobj__60)); if (unlikely(!__pyx_t_5)) __PYX_ERR(0, 774, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_5); + __Pyx_CyFunction_SetAnnotationsDict(__pyx_t_5, __pyx_t_3); + __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; + if (PyDict_SetItem(__pyx_d, __pyx_n_s_parallel_worker, __pyx_t_5) < 0) __PYX_ERR(0, 774, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_5); __pyx_t_5 = 0; /* "constraint/solvers.py":1 * """Module containing the code for the problem solvers.""" # <<<<<<<<<<<<<< * * import random */ - __pyx_t_4 = __Pyx_PyDict_NewPresized(0); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 1, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_4); - if (PyDict_SetItem(__pyx_d, __pyx_n_s_test, __pyx_t_4) < 0) __PYX_ERR(0, 1, __pyx_L1_error) - __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; + __pyx_t_5 = __Pyx_PyDict_NewPresized(0); if (unlikely(!__pyx_t_5)) __PYX_ERR(0, 1, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_5); + if (PyDict_SetItem(__pyx_d, __pyx_n_s_test, __pyx_t_5) < 0) __PYX_ERR(0, 1, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_5); __pyx_t_5 = 0; /*--- Wrapped vars code ---*/ @@ -26180,77 +26180,14 @@ static PyObject* __Pyx_PyInt_AddObjC(PyObject *op1, PyObject *op2, long intval, return -1; } -/* RaiseUnboundLocalError */ - static CYTHON_INLINE void __Pyx_RaiseUnboundLocalError(const char *varname) { - PyErr_Format(PyExc_UnboundLocalError, "local variable '%s' referenced before assignment", varname); -} - /* RaiseClosureNameError */ static CYTHON_INLINE void __Pyx_RaiseClosureNameError(const char *varname) { PyErr_Format(PyExc_NameError, "free variable '%s' referenced before assignment in enclosing scope", varname); } -/* GetAttr */ - static CYTHON_INLINE PyObject *__Pyx_GetAttr(PyObject *o, PyObject *n) { -#if CYTHON_USE_TYPE_SLOTS -#if PY_MAJOR_VERSION >= 3 - if (likely(PyUnicode_Check(n))) -#else - if (likely(PyString_Check(n))) -#endif - return __Pyx_PyObject_GetAttrStr(o, n); -#endif - return PyObject_GetAttr(o, n); -} - -/* Globals */ - static PyObject* __Pyx_Globals(void) { - return __Pyx_NewRef(__pyx_d); -} - -/* SliceTupleAndList */ - #if CYTHON_COMPILING_IN_CPYTHON -static CYTHON_INLINE void __Pyx_crop_slice(Py_ssize_t* _start, Py_ssize_t* _stop, Py_ssize_t* _length) { - Py_ssize_t start = *_start, stop = *_stop, length = *_length; - if (start < 0) { - start += length; - if (start < 0) - start = 0; - } - if (stop < 0) - stop += length; - else if (stop > length) - stop = length; - *_length = stop - start; - *_start = start; - *_stop = stop; -} -static CYTHON_INLINE PyObject* __Pyx_PyList_GetSlice( - PyObject* src, Py_ssize_t start, Py_ssize_t stop) { - Py_ssize_t length = PyList_GET_SIZE(src); - __Pyx_crop_slice(&start, &stop, &length); - if (length <= 0) { - return PyList_New(0); - } - return __Pyx_PyList_FromArray(((PyListObject*)src)->ob_item + start, length); -} -static CYTHON_INLINE PyObject* __Pyx_PyTuple_GetSlice( - PyObject* src, Py_ssize_t start, Py_ssize_t stop) { - Py_ssize_t length = PyTuple_GET_SIZE(src); - __Pyx_crop_slice(&start, &stop, &length); - return __Pyx_PyTuple_FromArray(((PyTupleObject*)src)->ob_item + start, length); -} -#endif - -/* RaiseUnexpectedTypeError */ - static int -__Pyx_RaiseUnexpectedTypeError(const char *expected, PyObject *obj) -{ - __Pyx_TypeName obj_type_name = __Pyx_PyType_GetName(Py_TYPE(obj)); - PyErr_Format(PyExc_TypeError, "Expected %s, got " __Pyx_FMT_TYPENAME, - expected, obj_type_name); - __Pyx_DECREF_TypeName(obj_type_name); - return 0; +/* RaiseUnboundLocalError */ + static CYTHON_INLINE void __Pyx_RaiseUnboundLocalError(const char *varname) { + PyErr_Format(PyExc_UnboundLocalError, "local variable '%s' referenced before assignment", varname); } /* CallUnboundCMethod1 */ @@ -27588,6 +27525,51 @@ static CYTHON_INLINE void __Pyx_CyFunction_SetAnnotationsDict(PyObject *func, Py return op; } +/* RaiseUnexpectedTypeError */ + static int +__Pyx_RaiseUnexpectedTypeError(const char *expected, PyObject *obj) +{ + __Pyx_TypeName obj_type_name = __Pyx_PyType_GetName(Py_TYPE(obj)); + PyErr_Format(PyExc_TypeError, "Expected %s, got " __Pyx_FMT_TYPENAME, + expected, obj_type_name); + __Pyx_DECREF_TypeName(obj_type_name); + return 0; +} + +/* SliceTupleAndList */ + #if CYTHON_COMPILING_IN_CPYTHON +static CYTHON_INLINE void __Pyx_crop_slice(Py_ssize_t* _start, Py_ssize_t* _stop, Py_ssize_t* _length) { + Py_ssize_t start = *_start, stop = *_stop, length = *_length; + if (start < 0) { + start += length; + if (start < 0) + start = 0; + } + if (stop < 0) + stop += length; + else if (stop > length) + stop = length; + *_length = stop - start; + *_start = start; + *_stop = stop; +} +static CYTHON_INLINE PyObject* __Pyx_PyList_GetSlice( + PyObject* src, Py_ssize_t start, Py_ssize_t stop) { + Py_ssize_t length = PyList_GET_SIZE(src); + __Pyx_crop_slice(&start, &stop, &length); + if (length <= 0) { + return PyList_New(0); + } + return __Pyx_PyList_FromArray(((PyListObject*)src)->ob_item + start, length); +} +static CYTHON_INLINE PyObject* __Pyx_PyTuple_GetSlice( + PyObject* src, Py_ssize_t start, Py_ssize_t stop) { + Py_ssize_t length = PyTuple_GET_SIZE(src); + __Pyx_crop_slice(&start, &stop, &length); + return __Pyx_PyTuple_FromArray(((PyTupleObject*)src)->ob_item + start, length); +} +#endif + /* PyObjectLookupSpecial */ #if CYTHON_USE_PYTYPE_LOOKUP && CYTHON_USE_TYPE_SLOTS static CYTHON_INLINE PyObject* __Pyx__PyObject_LookupSpecial(PyObject* obj, PyObject* attr_name, int with_error) { @@ -27612,6 +27594,24 @@ static CYTHON_INLINE PyObject* __Pyx__PyObject_LookupSpecial(PyObject* obj, PyOb } #endif +/* GetAttr */ + static CYTHON_INLINE PyObject *__Pyx_GetAttr(PyObject *o, PyObject *n) { +#if CYTHON_USE_TYPE_SLOTS +#if PY_MAJOR_VERSION >= 3 + if (likely(PyUnicode_Check(n))) +#else + if (likely(PyString_Check(n))) +#endif + return __Pyx_PyObject_GetAttrStr(o, n); +#endif + return PyObject_GetAttr(o, n); +} + +/* Globals */ + static PyObject* __Pyx_Globals(void) { + return __Pyx_NewRef(__pyx_d); +} + /* ValidateBasesTuple */ #if CYTHON_COMPILING_IN_CPYTHON || CYTHON_COMPILING_IN_LIMITED_API || CYTHON_USE_TYPE_SPECS static int __Pyx_validate_bases_tuple(const char *type_name, Py_ssize_t dictoffset, PyObject *bases) { diff --git a/constraint/solvers.py b/constraint/solvers.py index 2f6916d..6a7b6ae 100644 --- a/constraint/solvers.py +++ b/constraint/solvers.py @@ -602,7 +602,91 @@ def getSolution(self, domains: dict, constraints: list[tuple], vconstraints: dic if not conflicted: return assignments return None + + +class ParallelSolver(Solver): + """Problem solver that executes all-solution solve in parallel (ProcessPool or ThreadPool mode). + + Sorts the domains on size, creating jobs for each value in the domain with the most variables. + Each leaf job is solved locally with either optimized backtracking or recursion. + Whether this is actually faster than non-parallel solving depends on your problem, and hardware and software environment. + + Uses ThreadPool by default. Instantiate with process_mode=True to use ProcessPool. + In ProcessPool mode, the jobs do not share memory. + In ProcessPool mode, precompiled FunctionConstraints are not allowed due to pickling, use string constraints instead. + + Examples: + >>> result = [[('a', 1), ('b', 2)], + ... [('a', 1), ('b', 3)], + ... [('a', 2), ('b', 3)]] + + >>> problem = Problem(ParallelSolver()) + >>> problem.addVariables(["a", "b"], [1, 2, 3]) + >>> problem.addConstraint("b > a", ["a", "b"]) + + >>> for solution in problem.getSolutions(): + ... sorted(solution.items()) in result + True + True + True + + >>> problem.getSolution() + Traceback (most recent call last): + ... + NotImplementedError: ParallelSolver only provides all solutions + + >>> problem.getSolutionIter() + Traceback (most recent call last): + ... + NotImplementedError: ParallelSolver doesn't provide iteration + """ # noqa E501 + + def __init__(self, process_mode=False): + """Initialization method. Set `process_mode` to True for using ProcessPool, otherwise uses ThreadPool.""" + super().__init__() + self._process_mode = process_mode + self.requires_pickling = process_mode + + def getSolution(self, domains: dict, constraints: list[tuple], vconstraints: dict): + """Return one solution for the given problem. + + Args: + domains (dict): Dictionary mapping variables to their domains + constraints (list): List of pairs of (constraint, variables) + vconstraints (dict): Dictionary mapping variables to a list + of constraints affecting the given variables. + """ + msg = f"{self.__class__.__name__} only provides all solutions" + raise NotImplementedError(msg) + + def getSolutionsList(self, domains: dict[Hashable, Domain], vconstraints: dict[Hashable, list[tuple[Constraint, Hashable]]]) -> list[dict[Hashable, any]]: # noqa: D102, E501 + """Parallelized all-solutions finder using ProcessPoolExecutor for work-stealing.""" + # Precompute constraints lookup per variable + constraint_lookup: dict[Hashable, list[tuple[Constraint, Hashable]]] = {var: vconstraints.get(var, []) for var in domains} # noqa: E501 + # Sort variables by domain size (heuristic) + sorted_vars: list[Hashable] = sorted(domains.keys(), key=lambda v: len(domains[v])) + + # Split parallel and sequential parts + first_var = sorted_vars[0] + remaining_vars = sorted_vars[1:] + + # Create the parallel function arguments and solutions lists + args = ((self.requires_pickling, domains, constraint_lookup, first_var, val, remaining_vars.copy()) for val in domains[first_var]) # noqa: E501 + solutions: list[dict[Hashable, any]] = [] + + # execute in parallel + parallel_pool = ProcessPoolExecutor if self._process_mode else ThreadPoolExecutor + with parallel_pool() as executor: + # results = map(parallel_worker, args) # sequential + results = executor.map(parallel_worker, args, chunksize=1) # parallel + for result in results: + solutions.extend(result) + + return solutions + + def getSolutions(self, domains: dict, constraints: list[tuple], vconstraints: dict): # noqa: D102 + return self.getSolutionsList(domains, vconstraints) ### Helper functions for parallel solver @@ -701,88 +785,4 @@ def parallel_worker(args: tuple[bool, dict[Hashable, Domain], dict[Hashable, lis if is_valid(local_assignment, constraint_lookup[first_var], domains): return sequential_optimized_backtrack(local_assignment, remaining_vars, domains, constraint_lookup) return [] - -class ParallelSolver(Solver): - """Problem solver that executes all-solution solve in parallel (ProcessPool or ThreadPool mode). - - Sorts the domains on size, creating jobs for each value in the domain with the most variables. - Each leaf job is solved locally with either optimized backtracking or recursion. - Whether this is actually faster than non-parallel solving depends on your problem, and hardware and software environment. - - Uses ThreadPool by default. Instantiate with process_mode=True to use ProcessPool. - In ProcessPool mode, the jobs do not share memory. - In ProcessPool mode, precompiled FunctionConstraints are not allowed due to pickling, use string constraints instead. - - Examples: - >>> result = [[('a', 1), ('b', 2)], - ... [('a', 1), ('b', 3)], - ... [('a', 2), ('b', 3)]] - - >>> problem = Problem(ParallelSolver()) - >>> problem.addVariables(["a", "b"], [1, 2, 3]) - >>> problem.addConstraint("b > a", ["a", "b"]) - - >>> for solution in problem.getSolutions(): - ... sorted(solution.items()) in result - True - True - True - - >>> problem.getSolution() - Traceback (most recent call last): - ... - NotImplementedError: ParallelSolver only provides all solutions - - >>> problem.getSolutionIter() - Traceback (most recent call last): - ... - NotImplementedError: ParallelSolver doesn't provide iteration - """ # noqa E501 - - def __init__(self, process_mode=False): - """Initialization method. Set `process_mode` to True for using ProcessPool, otherwise uses ThreadPool.""" - super().__init__() - self._process_mode = process_mode - self.requires_pickling = process_mode - - def getSolution(self, domains: dict, constraints: list[tuple], vconstraints: dict): - """Return one solution for the given problem. - - Args: - domains (dict): Dictionary mapping variables to their domains - constraints (list): List of pairs of (constraint, variables) - vconstraints (dict): Dictionary mapping variables to a list - of constraints affecting the given variables. - """ - msg = f"{self.__class__.__name__} only provides all solutions" - raise NotImplementedError(msg) - - def getSolutionsList(self, domains: dict[Hashable, Domain], vconstraints: dict[Hashable, list[tuple[Constraint, Hashable]]]) -> list[dict[Hashable, any]]: # noqa: D102, E501 - """Parallelized all-solutions finder using ProcessPoolExecutor for work-stealing.""" - # Precompute constraints lookup per variable - constraint_lookup: dict[Hashable, list[tuple[Constraint, Hashable]]] = {var: vconstraints.get(var, []) for var in domains} # noqa: E501 - - # Sort variables by domain size (heuristic) - sorted_vars: list[Hashable] = sorted(domains.keys(), key=lambda v: len(domains[v])) - - # Split parallel and sequential parts - first_var = sorted_vars[0] - remaining_vars = sorted_vars[1:] - - # Create the parallel function arguments and solutions lists - args = ((self.requires_pickling, domains, constraint_lookup, first_var, val, remaining_vars.copy()) for val in domains[first_var]) # noqa: E501 - solutions: list[dict[Hashable, any]] = [] - - # execute in parallel - parallel_pool = ProcessPoolExecutor if self._process_mode else ThreadPoolExecutor - with parallel_pool() as executor: - # results = map(parallel_worker, args) # sequential - results = executor.map(parallel_worker, args, chunksize=1) # parallel - for result in results: - solutions.extend(result) - - return solutions - - def getSolutions(self, domains: dict, constraints: list[tuple], vconstraints: dict): # noqa: D102 - return self.getSolutionsList(domains, vconstraints) \ No newline at end of file diff --git a/docs/benchmarks/.gitkeep b/docs/benchmarks/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/docs/conf.py b/docs/conf.py index 788297c..aa47a4a 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -24,7 +24,7 @@ # import data from pyproject.toml using https://github.com/sphinx-toolbox/sphinx-pyproject # additional data can be added with `[tool.sphinx-pyproject]` and retrieved with `config['']`. -config = SphinxConfig("../pyproject.toml", style="poetry") # add `, globalns=globals()` to directly insert in namespace +config = SphinxConfig("../pyproject.toml") # add `, globalns=globals()` to directly insert in namespace year = time.strftime("%Y") project = "python-constraint" diff --git a/docs/requirements.txt b/docs/requirements.txt index 8ce6cf6..687ef51 100644 --- a/docs/requirements.txt +++ b/docs/requirements.txt @@ -1,33 +1,33 @@ -alabaster==0.7.16 ; python_version >= "3.9" and python_version < "3.15" -babel==2.17.0 ; python_version >= "3.9" and python_version < "3.15" -certifi==2025.1.31 ; python_version >= "3.9" and python_version < "3.15" -charset-normalizer==3.4.1 ; python_version >= "3.9" and python_version < "3.15" -colorama==0.4.6 ; python_version >= "3.9" and python_version < "3.15" and sys_platform == "win32" -docutils==0.18.1 ; python_version >= "3.9" and python_version < "3.15" -dom-toml==2.0.1 ; python_version >= "3.9" and python_version < "3.15" -domdf-python-tools==3.9.0 ; python_version >= "3.9" and python_version < "3.15" -idna==3.10 ; python_version >= "3.9" and python_version < "3.15" -imagesize==1.4.1 ; python_version >= "3.9" and python_version < "3.15" +alabaster==0.7.16 ; python_version >= "3.9" +babel==2.17.0 ; python_version >= "3.9" +certifi==2025.1.31 ; python_version >= "3.9" +charset-normalizer==3.4.1 ; python_version >= "3.9" +colorama==0.4.6 ; python_version >= "3.9" and sys_platform == "win32" +docutils==0.21.2 ; python_version >= "3.9" +dom-toml==2.0.1 ; python_version >= "3.9" +domdf-python-tools==3.10.0 ; python_version >= "3.9" +idna==3.10 ; python_version >= "3.9" +imagesize==1.4.1 ; python_version >= "3.9" importlib-metadata==8.6.1 ; python_version >= "3.9" and python_version < "3.10" -jinja2==3.1.5 ; python_version >= "3.9" and python_version < "3.15" -markupsafe==3.0.2 ; python_version >= "3.9" and python_version < "3.15" -natsort==8.4.0 ; python_version >= "3.9" and python_version < "3.15" -packaging==24.2 ; python_version >= "3.9" and python_version < "3.15" -pygments==2.19.1 ; python_version >= "3.9" and python_version < "3.15" -requests==2.32.3 ; python_version >= "3.9" and python_version < "3.15" -snowballstemmer==2.2.0 ; python_version >= "3.9" and python_version < "3.15" -sphinx-autodoc-typehints==1.25.3 ; python_version >= "3.9" and python_version < "3.15" -sphinx-pyproject==0.3.0 ; python_version >= "3.9" and python_version < "3.15" -sphinx-rtd-theme==1.3.0 ; python_version >= "3.9" and python_version < "3.15" -sphinx==7.3.7 ; python_version >= "3.9" and python_version < "3.15" -sphinxcontrib-applehelp==2.0.0 ; python_version >= "3.9" and python_version < "3.15" -sphinxcontrib-devhelp==2.0.0 ; python_version >= "3.9" and python_version < "3.15" -sphinxcontrib-htmlhelp==2.1.0 ; python_version >= "3.9" and python_version < "3.15" -sphinxcontrib-jquery==4.1 ; python_version >= "3.9" and python_version < "3.15" -sphinxcontrib-jsmath==1.0.1 ; python_version >= "3.9" and python_version < "3.15" -sphinxcontrib-qthelp==2.0.0 ; python_version >= "3.9" and python_version < "3.15" -sphinxcontrib-serializinghtml==2.0.0 ; python_version >= "3.9" and python_version < "3.15" -tomli==2.2.1 ; python_version >= "3.9" and python_version < "3.15" -typing-extensions==4.12.2 ; python_version >= "3.9" and python_version < "3.15" -urllib3==2.3.0 ; python_version >= "3.9" and python_version < "3.15" +jinja2==3.1.5 ; python_version >= "3.9" +markupsafe==3.0.2 ; python_version >= "3.9" +natsort==8.4.0 ; python_version >= "3.9" +packaging==24.2 ; python_version >= "3.9" +pygments==2.19.1 ; python_version >= "3.9" +requests==2.32.3 ; python_version >= "3.9" +snowballstemmer==2.2.0 ; python_version >= "3.9" +sphinx-autodoc-typehints==2.3.0 ; python_version >= "3.9" +sphinx-pyproject==0.3.0 ; python_version >= "3.9" +sphinx-rtd-theme==3.0.2 ; python_version >= "3.9" +sphinx==7.4.7 ; python_version >= "3.9" +sphinxcontrib-applehelp==2.0.0 ; python_version >= "3.9" +sphinxcontrib-devhelp==2.0.0 ; python_version >= "3.9" +sphinxcontrib-htmlhelp==2.1.0 ; python_version >= "3.9" +sphinxcontrib-jquery==4.1 ; python_version >= "3.9" +sphinxcontrib-jsmath==1.0.1 ; python_version >= "3.9" +sphinxcontrib-qthelp==2.0.0 ; python_version >= "3.9" +sphinxcontrib-serializinghtml==2.0.0 ; python_version >= "3.9" +tomli==2.2.1 ; python_version >= "3.9" +typing-extensions==4.12.2 ; python_version >= "3.9" +urllib3==2.3.0 ; python_version >= "3.9" zipp==3.21.0 ; python_version >= "3.9" and python_version < "3.10" diff --git a/noxfile.py b/noxfile.py index 0cab3a0..6faa52c 100644 --- a/noxfile.py +++ b/noxfile.py @@ -7,6 +7,7 @@ import nox from nox import Session, session +from pathlib import Path # from nox_poetry import Session, session # nox_poetry is a better option, but <=1.0.3 has a bug with filename-URLs @@ -21,6 +22,9 @@ nox.options.stop_on_first_error = True nox.options.error_on_missing_interpreters = True +# create the benchmark folder +Path(".benchmarks").mkdir(exist_ok=True) + # Test code quality: linting @session @@ -35,13 +39,19 @@ def lint(session: Session) -> None: # do not forget check / set the versions with `pyenv global`, or `pyenv local` in case of virtual environment def tests(session: Session) -> None: """Run the tests for the specified Python versions.""" + # get command line arguments + if session.posargs: + os_name = session.posargs[0] + else: + os_name = 'local' + # install the dev-dependencies and build the package session.install("poetry") session.run("poetry", "install", "--with", "dev,test", external=True) # session.poetry.installroot(distribution_format="sdist") # run pytest on the package with C-extensions, disable required coverage percentage - session.run("pytest", "--no-cov") + session.run("pytest", "--no-cov", "--benchmark-json", f".benchmarks/benchmark_{os_name}_{session.python}.json") # for the last Python version session: if session.python == python_versions_to_test[-1]: diff --git a/poetry.lock b/poetry.lock index f4d5a42..bcd104c 100644 --- a/poetry.lock +++ b/poetry.lock @@ -1,4 +1,4 @@ -# This file is automatically @generated by Poetry 1.7.1 and should not be changed by hand. +# This file is automatically @generated by Poetry 2.1.1 and should not be changed by hand. [[package]] name = "alabaster" @@ -6,6 +6,7 @@ version = "0.7.16" description = "A light, configurable Sphinx theme" optional = false python-versions = ">=3.9" +groups = ["docs"] files = [ {file = "alabaster-0.7.16-py3-none-any.whl", hash = "sha256:b46733c07dce03ae4e150330b975c75737fa60f0a7c591b6c8bf4928a28e2c92"}, {file = "alabaster-0.7.16.tar.gz", hash = "sha256:75a8b99c28a5dad50dd7f8ccdd447a121ddb3892da9e53d1ca5cca3106d58d65"}, @@ -13,31 +14,53 @@ files = [ [[package]] name = "argcomplete" -version = "3.5.3" +version = "3.6.1" description = "Bash tab completion for argparse" optional = false python-versions = ">=3.8" +groups = ["test"] files = [ - {file = "argcomplete-3.5.3-py3-none-any.whl", hash = "sha256:2ab2c4a215c59fd6caaff41a869480a23e8f6a5f910b266c1808037f4e375b61"}, - {file = "argcomplete-3.5.3.tar.gz", hash = "sha256:c12bf50eded8aebb298c7b7da7a5ff3ee24dffd9f5281867dfe1424b58c55392"}, + {file = "argcomplete-3.6.1-py3-none-any.whl", hash = "sha256:cef54d7f752560570291214f0f1c48c3b8ef09aca63d65de7747612666725dbc"}, + {file = "argcomplete-3.6.1.tar.gz", hash = "sha256:927531c2fbaa004979f18c2316f6ffadcfc5cc2de15ae2624dfe65deaf60e14f"}, ] [package.extras] test = ["coverage", "mypy", "pexpect", "ruff", "wheel"] +[[package]] +name = "attrs" +version = "25.3.0" +description = "Classes Without Boilerplate" +optional = false +python-versions = ">=3.8" +groups = ["test"] +files = [ + {file = "attrs-25.3.0-py3-none-any.whl", hash = "sha256:427318ce031701fea540783410126f03899a97ffc6f61596ad581ac2e40e3bc3"}, + {file = "attrs-25.3.0.tar.gz", hash = "sha256:75d7cefc7fb576747b2c81b4442d4d4a1ce0900973527c011d1030fd3bf4af1b"}, +] + +[package.extras] +benchmark = ["cloudpickle ; platform_python_implementation == \"CPython\"", "hypothesis", "mypy (>=1.11.1) ; platform_python_implementation == \"CPython\" and python_version >= \"3.10\"", "pympler", "pytest (>=4.3.0)", "pytest-codspeed", "pytest-mypy-plugins ; platform_python_implementation == \"CPython\" and python_version >= \"3.10\"", "pytest-xdist[psutil]"] +cov = ["cloudpickle ; platform_python_implementation == \"CPython\"", "coverage[toml] (>=5.3)", "hypothesis", "mypy (>=1.11.1) ; platform_python_implementation == \"CPython\" and python_version >= \"3.10\"", "pympler", "pytest (>=4.3.0)", "pytest-mypy-plugins ; platform_python_implementation == \"CPython\" and python_version >= \"3.10\"", "pytest-xdist[psutil]"] +dev = ["cloudpickle ; platform_python_implementation == \"CPython\"", "hypothesis", "mypy (>=1.11.1) ; platform_python_implementation == \"CPython\" and python_version >= \"3.10\"", "pre-commit-uv", "pympler", "pytest (>=4.3.0)", "pytest-mypy-plugins ; platform_python_implementation == \"CPython\" and python_version >= \"3.10\"", "pytest-xdist[psutil]"] +docs = ["cogapp", "furo", "myst-parser", "sphinx", "sphinx-notfound-page", "sphinxcontrib-towncrier", "towncrier"] +tests = ["cloudpickle ; platform_python_implementation == \"CPython\"", "hypothesis", "mypy (>=1.11.1) ; platform_python_implementation == \"CPython\" and python_version >= \"3.10\"", "pympler", "pytest (>=4.3.0)", "pytest-mypy-plugins ; platform_python_implementation == \"CPython\" and python_version >= \"3.10\"", "pytest-xdist[psutil]"] +tests-mypy = ["mypy (>=1.11.1) ; platform_python_implementation == \"CPython\" and python_version >= \"3.10\"", "pytest-mypy-plugins ; platform_python_implementation == \"CPython\" and python_version >= \"3.10\""] + [[package]] name = "babel" version = "2.17.0" description = "Internationalization utilities" optional = false python-versions = ">=3.8" +groups = ["docs"] files = [ {file = "babel-2.17.0-py3-none-any.whl", hash = "sha256:4d0b53093fdfb4b21c92b5213dba5a1b23885afa8383709427046b21c366e5f2"}, {file = "babel-2.17.0.tar.gz", hash = "sha256:0c54cffb19f690cdcc52a3b50bcbf71e07a808d1c80d549f2459b9d2cf0afb9d"}, ] [package.extras] -dev = ["backports.zoneinfo", "freezegun (>=1.0,<2.0)", "jinja2 (>=3.0)", "pytest (>=6.0)", "pytest-cov", "pytz", "setuptools", "tzdata"] +dev = ["backports.zoneinfo ; python_version < \"3.9\"", "freezegun (>=1.0,<2.0)", "jinja2 (>=3.0)", "pytest (>=6.0)", "pytest-cov", "pytz", "setuptools", "tzdata ; sys_platform == \"win32\""] [[package]] name = "certifi" @@ -45,6 +68,7 @@ version = "2025.1.31" description = "Python package for providing Mozilla's CA Bundle." optional = false python-versions = ">=3.6" +groups = ["docs"] files = [ {file = "certifi-2025.1.31-py3-none-any.whl", hash = "sha256:ca78db4565a652026a4db2bcdf68f2fb589ea80d0be70e03929ed730746b84fe"}, {file = "certifi-2025.1.31.tar.gz", hash = "sha256:3d5da6925056f6f18f119200434a4780a94263f10d1c21d032a6f6b2baa20651"}, @@ -56,6 +80,7 @@ version = "3.4.1" description = "The Real First Universal Charset Detector. Open, modern and actively maintained alternative to Chardet." optional = false python-versions = ">=3.7" +groups = ["docs"] files = [ {file = "charset_normalizer-3.4.1-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:91b36a978b5ae0ee86c394f5a54d6ef44db1de0815eb43de826d41d21e4af3de"}, {file = "charset_normalizer-3.4.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7461baadb4dc00fd9e0acbe254e3d7d2112e7f92ced2adc96e54ef6501c5f176"}, @@ -157,6 +182,8 @@ version = "0.4.6" description = "Cross-platform colored terminal text." optional = false python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*,!=3.6.*,>=2.7" +groups = ["docs", "test"] +markers = "sys_platform == \"win32\"" files = [ {file = "colorama-0.4.6-py2.py3-none-any.whl", hash = "sha256:4f1d9991f5acc0ca119f9d443620b77f9d6b33703e51011c16baf57afb285fc6"}, {file = "colorama-0.4.6.tar.gz", hash = "sha256:08695f5cb7ed6e0531a20572697297273c47b8cae5a63ffc6d6ed5c201be6e44"}, @@ -168,6 +195,7 @@ version = "6.9.0" description = "Add colours to the output of Python's logging module." optional = false python-versions = ">=3.6" +groups = ["test"] files = [ {file = "colorlog-6.9.0-py3-none-any.whl", hash = "sha256:5906e71acd67cb07a71e779c47c4bcb45fb8c2993eebe9e5adcd6a6f1b283eff"}, {file = "colorlog-6.9.0.tar.gz", hash = "sha256:bfba54a1b93b94f54e1f4fe48395725a3d92fd2a4af702f6bd70946bdc0c6ac2"}, @@ -181,75 +209,82 @@ development = ["black", "flake8", "mypy", "pytest", "types-colorama"] [[package]] name = "coverage" -version = "7.6.11" +version = "7.7.1" description = "Code coverage measurement for Python" optional = false python-versions = ">=3.9" +groups = ["test"] files = [ - {file = "coverage-7.6.11-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:eafea49da254a8289bed3fab960f808b322eda5577cb17a3733014928bbfbebd"}, - {file = "coverage-7.6.11-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:5a3f7cbbcb4ad95067a6525f83a6fc78d9cbc1e70f8abaeeaeaa72ef34f48fc3"}, - {file = "coverage-7.6.11-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:de6b079b39246a7da9a40cfa62d5766bd52b4b7a88cf5a82ec4c45bf6e152306"}, - {file = "coverage-7.6.11-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:60d4ad09dfc8c36c4910685faafcb8044c84e4dae302e86c585b3e2e7778726c"}, - {file = "coverage-7.6.11-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8e433b6e3a834a43dae2889adc125f3fa4c66668df420d8e49bc4ee817dd7a70"}, - {file = "coverage-7.6.11-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:ac5d92e2cc121a13270697e4cb37e1eb4511ac01d23fe1b6c097facc3b46489e"}, - {file = "coverage-7.6.11-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:5128f3ba694c0a1bde55fc480090392c336236c3e1a10dad40dc1ab17c7675ff"}, - {file = "coverage-7.6.11-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:397489c611b76302dfa1d9ea079e138dddc4af80fc6819d5f5119ec8ca6c0e47"}, - {file = "coverage-7.6.11-cp310-cp310-win32.whl", hash = "sha256:c7719a5e1dc93883a6b319bc0374ecd46fb6091ed659f3fbe281ab991634b9b0"}, - {file = "coverage-7.6.11-cp310-cp310-win_amd64.whl", hash = "sha256:c27df03730059118b8a923cfc8b84b7e9976742560af528242f201880879c1da"}, - {file = "coverage-7.6.11-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:532fe139691af134aa8b54ed60dd3c806aa81312d93693bd2883c7b61592c840"}, - {file = "coverage-7.6.11-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:e0b0f272901a5172090c0802053fbc503cdc3fa2612720d2669a98a7384a7bec"}, - {file = "coverage-7.6.11-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:4bda710139ea646890d1c000feb533caff86904a0e0638f85e967c28cb8eec50"}, - {file = "coverage-7.6.11-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a165b09e7d5f685bf659063334a9a7b1a2d57b531753d3e04bd442b3cfe5845b"}, - {file = "coverage-7.6.11-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:ff136607689c1c87f43d24203b6d2055b42030f352d5176f9c8b204d4235ef27"}, - {file = "coverage-7.6.11-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:050172741de03525290e67f0161ae5f7f387c88fca50d47fceb4724ceaa591d2"}, - {file = "coverage-7.6.11-cp311-cp311-win32.whl", hash = "sha256:27700d859be68e4fb2e7bf774cf49933dcac6f81a9bc4c13bd41735b8d26a53b"}, - {file = "coverage-7.6.11-cp311-cp311-win_amd64.whl", hash = "sha256:cd4839813b09ab1dd1be1bbc74f9a7787615f931f83952b6a9af1b2d3f708bf7"}, - {file = "coverage-7.6.11-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:dbb1a822fd858d9853333a7c95d4e70dde9a79e65893138ce32c2ec6457d7a36"}, - {file = "coverage-7.6.11-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:61c834cbb80946d6ebfddd9b393a4c46bec92fcc0fa069321fcb8049117f76ea"}, - {file = "coverage-7.6.11-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a46d56e99a31d858d6912d31ffa4ede6a325c86af13139539beefca10a1234ce"}, - {file = "coverage-7.6.11-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5b48db06f53d1864fea6dbd855e6d51d41c0f06c212c3004511c0bdc6847b297"}, - {file = "coverage-7.6.11-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:b6ff5be3b1853e0862da9d349fe87f869f68e63a25f7c37ce1130b321140f963"}, - {file = "coverage-7.6.11-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:be05bde21d5e6eefbc3a6de6b9bee2b47894b8945342e8663192809c4d1f08ce"}, - {file = "coverage-7.6.11-cp312-cp312-win32.whl", hash = "sha256:e3b746fa0ffc5b6b8856529de487da8b9aeb4fb394bb58de6502ef45f3434f12"}, - {file = "coverage-7.6.11-cp312-cp312-win_amd64.whl", hash = "sha256:ac476e6d0128fb7919b3fae726de72b28b5c9644cb4b579e4a523d693187c551"}, - {file = "coverage-7.6.11-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:c86f4c7a6d1a54a24d804d9684d96e36a62d3ef7c0d7745ae2ea39e3e0293251"}, - {file = "coverage-7.6.11-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:7eb0504bb307401fd08bc5163a351df301438b3beb88a4fa044681295bbefc67"}, - {file = "coverage-7.6.11-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ca95d40900cf614e07f00cee8c2fad0371df03ca4d7a80161d84be2ec132b7a4"}, - {file = "coverage-7.6.11-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:db4b1a69976b1b02acda15937538a1d3fe10b185f9d99920b17a740a0a102e06"}, - {file = "coverage-7.6.11-cp313-cp313-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4cf96beb05d004e4c51cd846fcdf9eee9eb2681518524b66b2e7610507944c2f"}, - {file = "coverage-7.6.11-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:08e5fb93576a6b054d3d326242af5ef93daaac9bb52bc25f12ccbc3fa94227cd"}, - {file = "coverage-7.6.11-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:25575cd5a7d2acc46b42711e8aff826027c0e4f80fb38028a74f31ac22aae69d"}, - {file = "coverage-7.6.11-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:8fa4fffd90ee92f62ff7404b4801b59e8ea8502e19c9bf2d3241ce745b52926c"}, - {file = "coverage-7.6.11-cp313-cp313-win32.whl", hash = "sha256:0d03c9452d9d1ccfe5d3a5df0427705022a49b356ac212d529762eaea5ef97b4"}, - {file = "coverage-7.6.11-cp313-cp313-win_amd64.whl", hash = "sha256:fd2fffc8ce8692ce540103dff26279d2af22d424516ddebe2d7e4d6dbb3816b2"}, - {file = "coverage-7.6.11-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:5e7ac966ab110bd94ee844f2643f196d78fde1cd2450399116d3efdd706e19f5"}, - {file = "coverage-7.6.11-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:6ba27a0375c5ef4d2a7712f829265102decd5ff78b96d342ac2fa555742c4f4f"}, - {file = "coverage-7.6.11-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e2778be4f574b39ec9dcd9e5e13644f770351ee0990a0ecd27e364aba95af89b"}, - {file = "coverage-7.6.11-cp313-cp313t-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:5edc16712187139ab635a2e644cc41fc239bc6d245b16124045743130455c652"}, - {file = "coverage-7.6.11-cp313-cp313t-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:df6ff122a0a10a30121d9f0cb3fbd03a6fe05861e4ec47adb9f25e9245aabc19"}, - {file = "coverage-7.6.11-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:ff562952f15eff27247a4c4b03e45ce8a82e3fb197de6a7c54080f9d4ba07845"}, - {file = "coverage-7.6.11-cp313-cp313t-musllinux_1_2_i686.whl", hash = "sha256:4f21e3617f48d683f30cf2a6c8b739c838e600cb1454fe6b2eb486ac2bce8fbd"}, - {file = "coverage-7.6.11-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:6d60577673ba48d8ae8e362e61fd4ad1a640293ffe8991d11c86f195479100b7"}, - {file = "coverage-7.6.11-cp313-cp313t-win32.whl", hash = "sha256:13100f98497086b359bf56fc035a762c674de8ef526daa389ac8932cb9bff1e0"}, - {file = "coverage-7.6.11-cp313-cp313t-win_amd64.whl", hash = "sha256:2c81e53782043b323bd34c7de711ed9b4673414eb517eaf35af92185b873839c"}, - {file = "coverage-7.6.11-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:ff52b4e2ac0080c96e506819586c4b16cdbf46724bda90d308a7330a73cc8521"}, - {file = "coverage-7.6.11-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:f4679fcc9eb9004fdd1b00231ef1ec7167168071bebc4d66327e28c1979b4449"}, - {file = "coverage-7.6.11-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:90de4e9ca4489e823138bd13098af9ac8028cc029f33f60098b5c08c675c7bda"}, - {file = "coverage-7.6.11-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6c96a142057d83ee993eaf71629ca3fb952cda8afa9a70af4132950c2bd3deb9"}, - {file = "coverage-7.6.11-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:476f29a258b9cd153f2be5bf5f119d670d2806363595263917bddc167d6e5cce"}, - {file = "coverage-7.6.11-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:09d03f48d9025b8a6a116cddcb6c7b8ce80e4fb4c31dd2e124a7c377036ad58e"}, - {file = "coverage-7.6.11-cp39-cp39-win32.whl", hash = "sha256:bb35ae9f134fbd9cf7302a9654d5a1e597c974202678082dcc569eb39a8cde03"}, - {file = "coverage-7.6.11-cp39-cp39-win_amd64.whl", hash = "sha256:f382004fa4c93c01016d9226b9d696a08c53f6818b7ad59b4e96cb67e863353a"}, - {file = "coverage-7.6.11-pp39.pp310-none-any.whl", hash = "sha256:adc2d941c0381edfcf3897f94b9f41b1e504902fab78a04b1677f2f72afead4b"}, - {file = "coverage-7.6.11-py3-none-any.whl", hash = "sha256:f0f334ae844675420164175bf32b04e18a81fe57ad8eb7e0cfd4689d681ffed7"}, - {file = "coverage-7.6.11.tar.gz", hash = "sha256:e642e6a46a04e992ebfdabed79e46f478ec60e2c528e1e1a074d63800eda4286"}, + {file = "coverage-7.7.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:553ba93f8e3c70e1b0031e4dfea36aba4e2b51fe5770db35e99af8dc5c5a9dfe"}, + {file = "coverage-7.7.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:44683f2556a56c9a6e673b583763096b8efbd2df022b02995609cf8e64fc8ae0"}, + {file = "coverage-7.7.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:02fad4f8faa4153db76f9246bc95c1d99f054f4e0a884175bff9155cf4f856cb"}, + {file = "coverage-7.7.1-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:4c181ceba2e6808ede1e964f7bdc77bd8c7eb62f202c63a48cc541e5ffffccb6"}, + {file = "coverage-7.7.1-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:80b5b207a8b08c6a934b214e364cab2fa82663d4af18981a6c0a9e95f8df7602"}, + {file = "coverage-7.7.1-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:25fe40967717bad0ce628a0223f08a10d54c9d739e88c9cbb0f77b5959367542"}, + {file = "coverage-7.7.1-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:881cae0f9cbd928c9c001487bb3dcbfd0b0af3ef53ae92180878591053be0cb3"}, + {file = "coverage-7.7.1-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:c90e9141e9221dd6fbc16a2727a5703c19443a8d9bf7d634c792fa0287cee1ab"}, + {file = "coverage-7.7.1-cp310-cp310-win32.whl", hash = "sha256:ae13ed5bf5542d7d4a0a42ff5160e07e84adc44eda65ddaa635c484ff8e55917"}, + {file = "coverage-7.7.1-cp310-cp310-win_amd64.whl", hash = "sha256:171e9977c6a5d2b2be9efc7df1126fd525ce7cad0eb9904fe692da007ba90d81"}, + {file = "coverage-7.7.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:1165490be0069e34e4f99d08e9c5209c463de11b471709dfae31e2a98cbd49fd"}, + {file = "coverage-7.7.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:44af11c00fd3b19b8809487630f8a0039130d32363239dfd15238e6d37e41a48"}, + {file = "coverage-7.7.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:fbba59022e7c20124d2f520842b75904c7b9f16c854233fa46575c69949fb5b9"}, + {file = "coverage-7.7.1-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:af94fb80e4f159f4d93fb411800448ad87b6039b0500849a403b73a0d36bb5ae"}, + {file = "coverage-7.7.1-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:eae79f8e3501133aa0e220bbc29573910d096795882a70e6f6e6637b09522133"}, + {file = "coverage-7.7.1-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:e33426a5e1dc7743dd54dfd11d3a6c02c5d127abfaa2edd80a6e352b58347d1a"}, + {file = "coverage-7.7.1-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:b559adc22486937786731dac69e57296cb9aede7e2687dfc0d2696dbd3b1eb6b"}, + {file = "coverage-7.7.1-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:b838a91e84e1773c3436f6cc6996e000ed3ca5721799e7789be18830fad009a2"}, + {file = "coverage-7.7.1-cp311-cp311-win32.whl", hash = "sha256:2c492401bdb3a85824669d6a03f57b3dfadef0941b8541f035f83bbfc39d4282"}, + {file = "coverage-7.7.1-cp311-cp311-win_amd64.whl", hash = "sha256:1e6f867379fd033a0eeabb1be0cffa2bd660582b8b0c9478895c509d875a9d9e"}, + {file = "coverage-7.7.1-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:eff187177d8016ff6addf789dcc421c3db0d014e4946c1cc3fbf697f7852459d"}, + {file = "coverage-7.7.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:2444fbe1ba1889e0b29eb4d11931afa88f92dc507b7248f45be372775b3cef4f"}, + {file = "coverage-7.7.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:177d837339883c541f8524683e227adcaea581eca6bb33823a2a1fdae4c988e1"}, + {file = "coverage-7.7.1-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:15d54ecef1582b1d3ec6049b20d3c1a07d5e7f85335d8a3b617c9960b4f807e0"}, + {file = "coverage-7.7.1-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:75c82b27c56478d5e1391f2e7b2e7f588d093157fa40d53fd9453a471b1191f2"}, + {file = "coverage-7.7.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:315ff74b585110ac3b7ab631e89e769d294f303c6d21302a816b3554ed4c81af"}, + {file = "coverage-7.7.1-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:4dd532dac197d68c478480edde74fd4476c6823355987fd31d01ad9aa1e5fb59"}, + {file = "coverage-7.7.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:385618003e3d608001676bb35dc67ae3ad44c75c0395d8de5780af7bb35be6b2"}, + {file = "coverage-7.7.1-cp312-cp312-win32.whl", hash = "sha256:63306486fcb5a827449464f6211d2991f01dfa2965976018c9bab9d5e45a35c8"}, + {file = "coverage-7.7.1-cp312-cp312-win_amd64.whl", hash = "sha256:37351dc8123c154fa05b7579fdb126b9f8b1cf42fd6f79ddf19121b7bdd4aa04"}, + {file = "coverage-7.7.1-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:eebd927b86761a7068a06d3699fd6c20129becf15bb44282db085921ea0f1585"}, + {file = "coverage-7.7.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:2a79c4a09765d18311c35975ad2eb1ac613c0401afdd9cb1ca4110aeb5dd3c4c"}, + {file = "coverage-7.7.1-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8b1c65a739447c5ddce5b96c0a388fd82e4bbdff7251396a70182b1d83631019"}, + {file = "coverage-7.7.1-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:392cc8fd2b1b010ca36840735e2a526fcbd76795a5d44006065e79868cc76ccf"}, + {file = "coverage-7.7.1-cp313-cp313-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9bb47cc9f07a59a451361a850cb06d20633e77a9118d05fd0f77b1864439461b"}, + {file = "coverage-7.7.1-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:b4c144c129343416a49378e05c9451c34aae5ccf00221e4fa4f487db0816ee2f"}, + {file = "coverage-7.7.1-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:bc96441c9d9ca12a790b5ae17d2fa6654da4b3962ea15e0eabb1b1caed094777"}, + {file = "coverage-7.7.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:3d03287eb03186256999539d98818c425c33546ab4901028c8fa933b62c35c3a"}, + {file = "coverage-7.7.1-cp313-cp313-win32.whl", hash = "sha256:8fed429c26b99641dc1f3a79179860122b22745dd9af36f29b141e178925070a"}, + {file = "coverage-7.7.1-cp313-cp313-win_amd64.whl", hash = "sha256:092b134129a8bb940c08b2d9ceb4459af5fb3faea77888af63182e17d89e1cf1"}, + {file = "coverage-7.7.1-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:d3154b369141c3169b8133973ac00f63fcf8d6dbcc297d788d36afbb7811e511"}, + {file = "coverage-7.7.1-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:264ff2bcce27a7f455b64ac0dfe097680b65d9a1a293ef902675fa8158d20b24"}, + {file = "coverage-7.7.1-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ba8480ebe401c2f094d10a8c4209b800a9b77215b6c796d16b6ecdf665048950"}, + {file = "coverage-7.7.1-cp313-cp313t-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:520af84febb6bb54453e7fbb730afa58c7178fd018c398a8fcd8e269a79bf96d"}, + {file = "coverage-7.7.1-cp313-cp313t-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:88d96127ae01ff571d465d4b0be25c123789cef88ba0879194d673fdea52f54e"}, + {file = "coverage-7.7.1-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:0ce92c5a9d7007d838456f4b77ea159cb628187a137e1895331e530973dcf862"}, + {file = "coverage-7.7.1-cp313-cp313t-musllinux_1_2_i686.whl", hash = "sha256:0dab4ef76d7b14f432057fdb7a0477e8bffca0ad39ace308be6e74864e632271"}, + {file = "coverage-7.7.1-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:7e688010581dbac9cab72800e9076e16f7cccd0d89af5785b70daa11174e94de"}, + {file = "coverage-7.7.1-cp313-cp313t-win32.whl", hash = "sha256:e52eb31ae3afacdacfe50705a15b75ded67935770c460d88c215a9c0c40d0e9c"}, + {file = "coverage-7.7.1-cp313-cp313t-win_amd64.whl", hash = "sha256:a6b6b3bd121ee2ec4bd35039319f3423d0be282b9752a5ae9f18724bc93ebe7c"}, + {file = "coverage-7.7.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:34a3bf6b92e6621fc4dcdaab353e173ccb0ca9e4bfbcf7e49a0134c86c9cd303"}, + {file = "coverage-7.7.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:d6874929d624d3a670f676efafbbc747f519a6121b581dd41d012109e70a5ebd"}, + {file = "coverage-7.7.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7ba5ff236c87a7b7aa1441a216caf44baee14cbfbd2256d306f926d16b026578"}, + {file = "coverage-7.7.1-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:452735fafe8ff5918236d5fe1feac322b359e57692269c75151f9b4ee4b7e1bc"}, + {file = "coverage-7.7.1-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f5f99a93cecf799738e211f9746dc83749b5693538fbfac279a61682ba309387"}, + {file = "coverage-7.7.1-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:11dd6f52c2a7ce8bf0a5f3b6e4a8eb60e157ffedc3c4b4314a41c1dfbd26ce58"}, + {file = "coverage-7.7.1-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:b52edb940d087e2a96e73c1523284a2e94a4e66fa2ea1e2e64dddc67173bad94"}, + {file = "coverage-7.7.1-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:d2e73e2ac468536197e6b3ab79bc4a5c9da0f078cd78cfcc7fe27cf5d1195ef0"}, + {file = "coverage-7.7.1-cp39-cp39-win32.whl", hash = "sha256:18f544356bceef17cc55fcf859e5664f06946c1b68efcea6acdc50f8f6a6e776"}, + {file = "coverage-7.7.1-cp39-cp39-win_amd64.whl", hash = "sha256:d66ff48ab3bb6f762a153e29c0fc1eb5a62a260217bc64470d7ba602f5886d20"}, + {file = "coverage-7.7.1-pp39.pp310.pp311-none-any.whl", hash = "sha256:5b7b02e50d54be6114cc4f6a3222fec83164f7c42772ba03b520138859b5fde1"}, + {file = "coverage-7.7.1-py3-none-any.whl", hash = "sha256:822fa99dd1ac686061e1219b67868e25d9757989cf2259f735a4802497d6da31"}, + {file = "coverage-7.7.1.tar.gz", hash = "sha256:199a1272e642266b90c9f40dec7fd3d307b51bf639fa0d15980dc0b3246c1393"}, ] [package.dependencies] tomli = {version = "*", optional = true, markers = "python_full_version <= \"3.11.0a6\" and extra == \"toml\""} [package.extras] -toml = ["tomli"] +toml = ["tomli ; python_full_version <= \"3.11.0a6\""] [[package]] name = "cython" @@ -257,6 +292,7 @@ version = "3.0.12" description = "The Cython compiler for writing C extensions in the Python language." optional = false python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,>=2.7" +groups = ["dev"] files = [ {file = "Cython-3.0.12-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:ba67eee9413b66dd9fbacd33f0bc2e028a2a120991d77b5fd4b19d0b1e4039b9"}, {file = "Cython-3.0.12-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bee2717e5b5f7d966d0c6e27d2efe3698c357aa4d61bb3201997c7a4f9fe485a"}, @@ -324,12 +360,32 @@ files = [ {file = "cython-3.0.12.tar.gz", hash = "sha256:b988bb297ce76c671e28c97d017b95411010f7c77fa6623dd0bb47eed1aee1bc"}, ] +[[package]] +name = "dependency-groups" +version = "1.3.0" +description = "A tool for resolving PEP 735 Dependency Group data" +optional = false +python-versions = ">=3.8" +groups = ["test"] +files = [ + {file = "dependency_groups-1.3.0-py3-none-any.whl", hash = "sha256:1abf34d712deda5581e80d507512664d52b35d1c2d7caf16c85e58ca508547e0"}, + {file = "dependency_groups-1.3.0.tar.gz", hash = "sha256:5b9751d5d98fbd6dfd038a560a69c8382e41afcbf7ffdbcc28a2a3f85498830f"}, +] + +[package.dependencies] +packaging = "*" +tomli = {version = "*", markers = "python_version < \"3.11\""} + +[package.extras] +cli = ["tomli ; python_version < \"3.11\""] + [[package]] name = "distlib" version = "0.3.9" description = "Distribution utilities" optional = false python-versions = "*" +groups = ["test"] files = [ {file = "distlib-0.3.9-py2.py3-none-any.whl", hash = "sha256:47f8c22fd27c27e25a65601af709b38e4f0a45ea4fc2e710f65755fa8caaaf87"}, {file = "distlib-0.3.9.tar.gz", hash = "sha256:a60f20dea646b8a33f3e7772f74dc0b2d0772d2837ee1342a00645c81edf9403"}, @@ -337,13 +393,14 @@ files = [ [[package]] name = "docutils" -version = "0.18.1" +version = "0.21.2" description = "Docutils -- Python Documentation Utilities" optional = false -python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" +python-versions = ">=3.9" +groups = ["docs"] files = [ - {file = "docutils-0.18.1-py2.py3-none-any.whl", hash = "sha256:23010f129180089fbcd3bc08cfefccb3b890b0050e1ca00c867036e9d161b98c"}, - {file = "docutils-0.18.1.tar.gz", hash = "sha256:679987caf361a7539d76e584cbeddc311e3aee937877c87346f31debc63e9d06"}, + {file = "docutils-0.21.2-py3-none-any.whl", hash = "sha256:dafca5b9e384f0e419294eb4d2ff9fa826435bf15f15b7bd45723e8ad76811b2"}, + {file = "docutils-0.21.2.tar.gz", hash = "sha256:3a6b18732edf182daa3cd12775bbb338cf5691468f91eeeb109deff6ebfa986f"}, ] [[package]] @@ -352,6 +409,7 @@ version = "2.0.1" description = "Dom's tools for Tom's Obvious, Minimal Language." optional = false python-versions = ">=3.6.1" +groups = ["docs"] files = [ {file = "dom_toml-2.0.1-py3-none-any.whl", hash = "sha256:6681a793c94a5d1fb7b59690009cc3b1dfb1bcaae108fb8054c712a8f128efc7"}, {file = "dom_toml-2.0.1.tar.gz", hash = "sha256:31c5874595c777f41cc191c34c66dbea215c8289a7b148b425fb7a10c3f4fbc8"}, @@ -363,13 +421,14 @@ tomli = ">=1.2.3" [[package]] name = "domdf-python-tools" -version = "3.9.0" +version = "3.10.0" description = "Helpful functions for Python 🐍 🛠️" optional = false python-versions = ">=3.6" +groups = ["docs"] files = [ - {file = "domdf_python_tools-3.9.0-py3-none-any.whl", hash = "sha256:4e1ef365cbc24627d6d1e90cf7d46d8ab8df967e1237f4a26885f6986c78872e"}, - {file = "domdf_python_tools-3.9.0.tar.gz", hash = "sha256:1f8a96971178333a55e083e35610d7688cd7620ad2b99790164e1fc1a3614c18"}, + {file = "domdf_python_tools-3.10.0-py3-none-any.whl", hash = "sha256:5e71c1be71bbcc1f881d690c8984b60e64298ec256903b3147f068bc33090c36"}, + {file = "domdf_python_tools-3.10.0.tar.gz", hash = "sha256:2ae308d2f4f1e9145f5f4ba57f840fbfd1c2983ee26e4824347789649d3ae298"}, ] [package.dependencies] @@ -386,6 +445,8 @@ version = "1.2.2" description = "Backport of PEP 654 (exception groups)" optional = false python-versions = ">=3.7" +groups = ["test"] +markers = "python_version < \"3.11\"" files = [ {file = "exceptiongroup-1.2.2-py3-none-any.whl", hash = "sha256:3111b9d131c238bec2f8f516e123e14ba243563fb135d3fe885990585aa7795b"}, {file = "exceptiongroup-1.2.2.tar.gz", hash = "sha256:47c2edf7c6738fafb49fd34290706d1a1a2f4d1c6df275526b62cbb4aa5393cc"}, @@ -396,19 +457,20 @@ test = ["pytest (>=6)"] [[package]] name = "filelock" -version = "3.17.0" +version = "3.18.0" description = "A platform independent file lock." optional = false python-versions = ">=3.9" +groups = ["test"] files = [ - {file = "filelock-3.17.0-py3-none-any.whl", hash = "sha256:533dc2f7ba78dc2f0f531fc6c4940addf7b70a481e269a5a3b93be94ffbe8338"}, - {file = "filelock-3.17.0.tar.gz", hash = "sha256:ee4e77401ef576ebb38cd7f13b9b28893194acc20a8e68e18730ba9c0e54660e"}, + {file = "filelock-3.18.0-py3-none-any.whl", hash = "sha256:c401f4f8377c4464e6db25fff06205fd89bdd83b65eb0488ed1b160f780e21de"}, + {file = "filelock-3.18.0.tar.gz", hash = "sha256:adbc88eabb99d2fec8c9c1b229b171f18afa655400173ddc653d5d01501fb9f2"}, ] [package.extras] docs = ["furo (>=2024.8.6)", "sphinx (>=8.1.3)", "sphinx-autodoc-typehints (>=3)"] testing = ["covdefaults (>=2.3)", "coverage (>=7.6.10)", "diff-cover (>=9.2.1)", "pytest (>=8.3.4)", "pytest-asyncio (>=0.25.2)", "pytest-cov (>=6)", "pytest-mock (>=3.14)", "pytest-timeout (>=2.3.1)", "virtualenv (>=20.28.1)"] -typing = ["typing-extensions (>=4.12.2)"] +typing = ["typing-extensions (>=4.12.2) ; python_version < \"3.11\""] [[package]] name = "idna" @@ -416,6 +478,7 @@ version = "3.10" description = "Internationalized Domain Names in Applications (IDNA)" optional = false python-versions = ">=3.6" +groups = ["docs"] files = [ {file = "idna-3.10-py3-none-any.whl", hash = "sha256:946d195a0d259cbba61165e88e65941f16e9b36ea6ddb97f00452bae8b1287d3"}, {file = "idna-3.10.tar.gz", hash = "sha256:12f65c9b470abda6dc35cf8e63cc574b1c52b11df2c86030af0ac09b01b13ea9"}, @@ -430,6 +493,7 @@ version = "1.4.1" description = "Getting image size from png/jpeg/jpeg2000/gif file" optional = false python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" +groups = ["docs"] files = [ {file = "imagesize-1.4.1-py2.py3-none-any.whl", hash = "sha256:0d8d18d08f840c19d0ee7ca1fd82490fdc3729b7ac93f49870406ddde8ef8d8b"}, {file = "imagesize-1.4.1.tar.gz", hash = "sha256:69150444affb9cb0d5cc5a92b3676f0b2fb7cd9ae39e947a5e11a36b4497cd4a"}, @@ -441,6 +505,8 @@ version = "8.6.1" description = "Read metadata from Python packages" optional = false python-versions = ">=3.9" +groups = ["docs"] +markers = "python_version < \"3.10\"" files = [ {file = "importlib_metadata-8.6.1-py3-none-any.whl", hash = "sha256:02a89390c1e15fdfdc0d7c6b25cb3e62650d0494005c97d6f148bf5b9787525e"}, {file = "importlib_metadata-8.6.1.tar.gz", hash = "sha256:310b41d755445d74569f993ccfc22838295d9fe005425094fad953d7f15c8580"}, @@ -450,34 +516,36 @@ files = [ zipp = ">=3.20" [package.extras] -check = ["pytest-checkdocs (>=2.4)", "pytest-ruff (>=0.2.1)"] +check = ["pytest-checkdocs (>=2.4)", "pytest-ruff (>=0.2.1) ; sys_platform != \"cygwin\""] cover = ["pytest-cov"] doc = ["furo", "jaraco.packaging (>=9.3)", "jaraco.tidelift (>=1.4)", "rst.linker (>=1.9)", "sphinx (>=3.5)", "sphinx-lint"] enabler = ["pytest-enabler (>=2.2)"] perf = ["ipython"] -test = ["flufl.flake8", "importlib_resources (>=1.3)", "jaraco.test (>=5.4)", "packaging", "pyfakefs", "pytest (>=6,!=8.1.*)", "pytest-perf (>=0.9.2)"] +test = ["flufl.flake8", "importlib_resources (>=1.3) ; python_version < \"3.9\"", "jaraco.test (>=5.4)", "packaging", "pyfakefs", "pytest (>=6,!=8.1.*)", "pytest-perf (>=0.9.2)"] type = ["pytest-mypy"] [[package]] name = "iniconfig" -version = "2.0.0" +version = "2.1.0" description = "brain-dead simple config-ini parsing" optional = false -python-versions = ">=3.7" +python-versions = ">=3.8" +groups = ["test"] files = [ - {file = "iniconfig-2.0.0-py3-none-any.whl", hash = "sha256:b6a85871a79d2e3b22d2d1b94ac2824226a63c6b741c88f7ae975f18b6778374"}, - {file = "iniconfig-2.0.0.tar.gz", hash = "sha256:2d91e135bf72d31a410b17c16da610a82cb55f6b0477d1a902134b24a455b8b3"}, + {file = "iniconfig-2.1.0-py3-none-any.whl", hash = "sha256:9deba5723312380e77435581c6bf4935c94cbfab9b1ed33ef8d238ea168eb760"}, + {file = "iniconfig-2.1.0.tar.gz", hash = "sha256:3abbd2e30b36733fee78f9c7f7308f2d0050e88f0087fd25c2645f63c773e1c7"}, ] [[package]] name = "jinja2" -version = "3.1.5" +version = "3.1.6" description = "A very fast and expressive template engine." optional = false python-versions = ">=3.7" +groups = ["docs"] files = [ - {file = "jinja2-3.1.5-py3-none-any.whl", hash = "sha256:aba0f4dc9ed8013c424088f68a5c226f7d6097ed89b246d7749c2ec4175c6adb"}, - {file = "jinja2-3.1.5.tar.gz", hash = "sha256:8fefff8dc3034e27bb80d67c671eb8a9bc424c0ef4c0826edbff304cceff43bb"}, + {file = "jinja2-3.1.6-py3-none-any.whl", hash = "sha256:85ece4451f492d0c13c5dd7c13a64681a86afae63a5f347908daf103ce6d2f67"}, + {file = "jinja2-3.1.6.tar.gz", hash = "sha256:0137fb05990d35f1275a587e9aee6d56da821fc83491a0fb838183be43f66d6d"}, ] [package.dependencies] @@ -492,6 +560,7 @@ version = "3.0.2" description = "Safely add untrusted strings to HTML/XML markup." optional = false python-versions = ">=3.9" +groups = ["docs"] files = [ {file = "MarkupSafe-3.0.2-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:7e94c425039cde14257288fd61dcfb01963e658efbc0ff54f5306b06054700f8"}, {file = "MarkupSafe-3.0.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:9e2d922824181480953426608b81967de705c3cef4d1af983af849d7bd619158"}, @@ -562,6 +631,7 @@ version = "8.4.0" description = "Simple yet flexible natural sorting in Python." optional = false python-versions = ">=3.7" +groups = ["docs"] files = [ {file = "natsort-8.4.0-py3-none-any.whl", hash = "sha256:4732914fb471f56b5cce04d7bae6f164a592c7712e1c85f9ef585e197299521c"}, {file = "natsort-8.4.0.tar.gz", hash = "sha256:45312c4a0e5507593da193dedd04abb1469253b601ecaf63445ad80f0a1ea581"}, @@ -573,24 +643,27 @@ icu = ["PyICU (>=1.0.0)"] [[package]] name = "nox" -version = "2024.10.9" +version = "2025.2.9" description = "Flexible test automation." optional = false python-versions = ">=3.8" +groups = ["test"] files = [ - {file = "nox-2024.10.9-py3-none-any.whl", hash = "sha256:1d36f309a0a2a853e9bccb76bbef6bb118ba92fa92674d15604ca99adeb29eab"}, - {file = "nox-2024.10.9.tar.gz", hash = "sha256:7aa9dc8d1c27e9f45ab046ffd1c3b2c4f7c91755304769df231308849ebded95"}, + {file = "nox-2025.2.9-py3-none-any.whl", hash = "sha256:7d1e92d1918c6980d70aee9cf1c1d19d16faa71c4afe338fffd39e8a460e2067"}, + {file = "nox-2025.2.9.tar.gz", hash = "sha256:d50cd4ca568bd7621c2e6cbbc4845b3b7f7697f25d5fb0190ce8f4600be79768"}, ] [package.dependencies] argcomplete = ">=1.9.4,<4" +attrs = ">=23.1" colorlog = ">=2.6.1,<7" +dependency-groups = ">=1.1" packaging = ">=20.9" tomli = {version = ">=1", markers = "python_version < \"3.11\""} virtualenv = ">=20.14.1" [package.extras] -tox-to-nox = ["jinja2", "tox"] +tox-to-nox = ["importlib-resources ; python_version < \"3.9\"", "jinja2", "tox (>=4)"] uv = ["uv (>=0.1.6)"] [[package]] @@ -599,6 +672,7 @@ version = "24.2" description = "Core utilities for Python packages" optional = false python-versions = ">=3.8" +groups = ["docs", "test"] files = [ {file = "packaging-24.2-py3-none-any.whl", hash = "sha256:09abb1bccd265c01f4a3aa3f7a7db064b36514d2cba19a2f694fe6150451a759"}, {file = "packaging-24.2.tar.gz", hash = "sha256:c228a6dc5e932d346bc5739379109d49e8853dd8223571c7c5b55260edc0b97f"}, @@ -610,6 +684,7 @@ version = "0.1.2" description = "A simple package with utils to check whether versions number match PEP 440." optional = false python-versions = ">=3.7" +groups = ["test"] files = [ {file = "pep440-0.1.2-py3-none-any.whl", hash = "sha256:36d6ad73f2b5d07769294cafe183500ac89d848c922a3d3f521b968481880d51"}, {file = "pep440-0.1.2.tar.gz", hash = "sha256:58b37246cc2b13fee1ca2a3c092cb3704d21ecf621a5bdbb168e44e697f6d04d"}, @@ -621,19 +696,20 @@ test = ["pytest", "pytest-console-scripts", "pytest-cov"] [[package]] name = "platformdirs" -version = "4.3.6" +version = "4.3.7" description = "A small Python package for determining appropriate platform-specific dirs, e.g. a `user data dir`." optional = false -python-versions = ">=3.8" +python-versions = ">=3.9" +groups = ["test"] files = [ - {file = "platformdirs-4.3.6-py3-none-any.whl", hash = "sha256:73e575e1408ab8103900836b97580d5307456908a03e92031bab39e4554cc3fb"}, - {file = "platformdirs-4.3.6.tar.gz", hash = "sha256:357fb2acbc885b0419afd3ce3ed34564c13c9b95c89360cd9563f73aa5e2b907"}, + {file = "platformdirs-4.3.7-py3-none-any.whl", hash = "sha256:a03875334331946f13c549dbd8f4bac7a13a50a895a0eb1e8c6a8ace80d40a94"}, + {file = "platformdirs-4.3.7.tar.gz", hash = "sha256:eb437d586b6a0986388f0d6f74aa0cde27b48d0e3d66843640bfb6bdcdb6e351"}, ] [package.extras] -docs = ["furo (>=2024.8.6)", "proselint (>=0.14)", "sphinx (>=8.0.2)", "sphinx-autodoc-typehints (>=2.4)"] -test = ["appdirs (==1.4.4)", "covdefaults (>=2.3)", "pytest (>=8.3.2)", "pytest-cov (>=5)", "pytest-mock (>=3.14)"] -type = ["mypy (>=1.11.2)"] +docs = ["furo (>=2024.8.6)", "proselint (>=0.14)", "sphinx (>=8.1.3)", "sphinx-autodoc-typehints (>=3)"] +test = ["appdirs (==1.4.4)", "covdefaults (>=2.3)", "pytest (>=8.3.4)", "pytest-cov (>=6)", "pytest-mock (>=3.14)"] +type = ["mypy (>=1.14.1)"] [[package]] name = "pluggy" @@ -641,6 +717,7 @@ version = "1.5.0" description = "plugin and hook calling mechanisms for python" optional = false python-versions = ">=3.8" +groups = ["test"] files = [ {file = "pluggy-1.5.0-py3-none-any.whl", hash = "sha256:44e1ad92c8ca002de6377e165f3e0f1be63266ab4d554740532335b9d75ea669"}, {file = "pluggy-1.5.0.tar.gz", hash = "sha256:2cffa88e94fdc978c4c574f15f9e59b7f4201d439195c3715ca9e2486f1d0cf1"}, @@ -650,12 +727,25 @@ files = [ dev = ["pre-commit", "tox"] testing = ["pytest", "pytest-benchmark"] +[[package]] +name = "py-cpuinfo" +version = "9.0.0" +description = "Get CPU info with pure Python" +optional = false +python-versions = "*" +groups = ["test"] +files = [ + {file = "py-cpuinfo-9.0.0.tar.gz", hash = "sha256:3cdbbf3fac90dc6f118bfd64384f309edeadd902d7c8fb17f02ffa1fc3f49690"}, + {file = "py_cpuinfo-9.0.0-py3-none-any.whl", hash = "sha256:859625bc251f64e21f077d099d4162689c762b5d6a4c3c97553d56241c9674d5"}, +] + [[package]] name = "pygments" version = "2.19.1" description = "Pygments is a syntax highlighting package written in Python." optional = false python-versions = ">=3.8" +groups = ["docs"] files = [ {file = "pygments-2.19.1-py3-none-any.whl", hash = "sha256:9ea1544ad55cecf4b8242fab6dd35a93bbce657034b0611ee383099054ab6d8c"}, {file = "pygments-2.19.1.tar.gz", hash = "sha256:61c16d2a8576dc0649d9f39e089b5f02bcd27fba10d8fb4dcc28173f7a45151f"}, @@ -666,13 +756,14 @@ windows-terminal = ["colorama (>=0.4.6)"] [[package]] name = "pytest" -version = "8.3.4" +version = "8.3.5" description = "pytest: simple powerful testing with Python" optional = false python-versions = ">=3.8" +groups = ["test"] files = [ - {file = "pytest-8.3.4-py3-none-any.whl", hash = "sha256:50e16d954148559c9a74109af1eaf0c945ba2d8f30f0a3d3335edde19788b6f6"}, - {file = "pytest-8.3.4.tar.gz", hash = "sha256:965370d062bce11e73868e0335abac31b4d3de0e82f4007408d242b4f8610761"}, + {file = "pytest-8.3.5-py3-none-any.whl", hash = "sha256:c69214aa47deac29fad6c2a4f590b9c4a9fdb16a403176fe154b79c0b4d4d820"}, + {file = "pytest-8.3.5.tar.gz", hash = "sha256:f4efe70cc14e511565ac476b57c279e12a855b11f48f212af1080ef2263d3845"}, ] [package.dependencies] @@ -686,12 +777,34 @@ tomli = {version = ">=1", markers = "python_version < \"3.11\""} [package.extras] dev = ["argcomplete", "attrs (>=19.2)", "hypothesis (>=3.56)", "mock", "pygments (>=2.7.2)", "requests", "setuptools", "xmlschema"] +[[package]] +name = "pytest-benchmark" +version = "5.1.0" +description = "A ``pytest`` fixture for benchmarking code. It will group the tests into rounds that are calibrated to the chosen timer." +optional = false +python-versions = ">=3.9" +groups = ["test"] +files = [ + {file = "pytest-benchmark-5.1.0.tar.gz", hash = "sha256:9ea661cdc292e8231f7cd4c10b0319e56a2118e2c09d9f50e1b3d150d2aca105"}, + {file = "pytest_benchmark-5.1.0-py3-none-any.whl", hash = "sha256:922de2dfa3033c227c96da942d1878191afa135a29485fb942e85dff1c592c89"}, +] + +[package.dependencies] +py-cpuinfo = "*" +pytest = ">=8.1" + +[package.extras] +aspect = ["aspectlib"] +elasticsearch = ["elasticsearch"] +histogram = ["pygal", "pygaljs", "setuptools"] + [[package]] name = "pytest-cov" version = "6.0.0" description = "Pytest plugin for measuring coverage." optional = false python-versions = ">=3.9" +groups = ["test"] files = [ {file = "pytest-cov-6.0.0.tar.gz", hash = "sha256:fde0b595ca248bb8e2d76f020b465f3b107c9632e6a1d1705f17834c89dcadc0"}, {file = "pytest_cov-6.0.0-py3-none-any.whl", hash = "sha256:eee6f1b9e61008bd34975a4d5bab25801eb31898b032dd55addc93e96fcaaa35"}, @@ -710,6 +823,7 @@ version = "2.32.3" description = "Python HTTP for Humans." optional = false python-versions = ">=3.8" +groups = ["docs"] files = [ {file = "requests-2.32.3-py3-none-any.whl", hash = "sha256:70761cfe03c773ceb22aa2f671b4757976145175cdfca038c02654d061d6dcc6"}, {file = "requests-2.32.3.tar.gz", hash = "sha256:55365417734eb18255590a9ff9eb97e9e1da868d4ccd6402399eaf68af20a760"}, @@ -727,29 +841,30 @@ use-chardet-on-py3 = ["chardet (>=3.0.2,<6)"] [[package]] name = "ruff" -version = "0.7.4" +version = "0.9.10" description = "An extremely fast Python linter and code formatter, written in Rust." optional = false python-versions = ">=3.7" +groups = ["test"] files = [ - {file = "ruff-0.7.4-py3-none-linux_armv6l.whl", hash = "sha256:a4919925e7684a3f18e18243cd6bea7cfb8e968a6eaa8437971f681b7ec51478"}, - {file = "ruff-0.7.4-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:cfb365c135b830778dda8c04fb7d4280ed0b984e1aec27f574445231e20d6c63"}, - {file = "ruff-0.7.4-py3-none-macosx_11_0_arm64.whl", hash = "sha256:63a569b36bc66fbadec5beaa539dd81e0527cb258b94e29e0531ce41bacc1f20"}, - {file = "ruff-0.7.4-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0d06218747d361d06fd2fdac734e7fa92df36df93035db3dc2ad7aa9852cb109"}, - {file = "ruff-0.7.4-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:e0cea28d0944f74ebc33e9f934238f15c758841f9f5edd180b5315c203293452"}, - {file = "ruff-0.7.4-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:80094ecd4793c68b2571b128f91754d60f692d64bc0d7272ec9197fdd09bf9ea"}, - {file = "ruff-0.7.4-py3-none-manylinux_2_17_ppc64.manylinux2014_ppc64.whl", hash = "sha256:997512325c6620d1c4c2b15db49ef59543ef9cd0f4aa8065ec2ae5103cedc7e7"}, - {file = "ruff-0.7.4-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:00b4cf3a6b5fad6d1a66e7574d78956bbd09abfd6c8a997798f01f5da3d46a05"}, - {file = "ruff-0.7.4-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:7dbdc7d8274e1422722933d1edddfdc65b4336abf0b16dfcb9dedd6e6a517d06"}, - {file = "ruff-0.7.4-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0e92dfb5f00eaedb1501b2f906ccabfd67b2355bdf117fea9719fc99ac2145bc"}, - {file = "ruff-0.7.4-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:3bd726099f277d735dc38900b6a8d6cf070f80828877941983a57bca1cd92172"}, - {file = "ruff-0.7.4-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:2e32829c429dd081ee5ba39aef436603e5b22335c3d3fff013cd585806a6486a"}, - {file = "ruff-0.7.4-py3-none-musllinux_1_2_i686.whl", hash = "sha256:662a63b4971807623f6f90c1fb664613f67cc182dc4d991471c23c541fee62dd"}, - {file = "ruff-0.7.4-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:876f5e09eaae3eb76814c1d3b68879891d6fde4824c015d48e7a7da4cf066a3a"}, - {file = "ruff-0.7.4-py3-none-win32.whl", hash = "sha256:75c53f54904be42dd52a548728a5b572344b50d9b2873d13a3f8c5e3b91f5cac"}, - {file = "ruff-0.7.4-py3-none-win_amd64.whl", hash = "sha256:745775c7b39f914238ed1f1b0bebed0b9155a17cd8bc0b08d3c87e4703b990d6"}, - {file = "ruff-0.7.4-py3-none-win_arm64.whl", hash = "sha256:11bff065102c3ae9d3ea4dc9ecdfe5a5171349cdd0787c1fc64761212fc9cf1f"}, - {file = "ruff-0.7.4.tar.gz", hash = "sha256:cd12e35031f5af6b9b93715d8c4f40360070b2041f81273d0527683d5708fce2"}, + {file = "ruff-0.9.10-py3-none-linux_armv6l.whl", hash = "sha256:eb4d25532cfd9fe461acc83498361ec2e2252795b4f40b17e80692814329e42d"}, + {file = "ruff-0.9.10-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:188a6638dab1aa9bb6228a7302387b2c9954e455fb25d6b4470cb0641d16759d"}, + {file = "ruff-0.9.10-py3-none-macosx_11_0_arm64.whl", hash = "sha256:5284dcac6b9dbc2fcb71fdfc26a217b2ca4ede6ccd57476f52a587451ebe450d"}, + {file = "ruff-0.9.10-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:47678f39fa2a3da62724851107f438c8229a3470f533894b5568a39b40029c0c"}, + {file = "ruff-0.9.10-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:99713a6e2766b7a17147b309e8c915b32b07a25c9efd12ada79f217c9c778b3e"}, + {file = "ruff-0.9.10-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:524ee184d92f7c7304aa568e2db20f50c32d1d0caa235d8ddf10497566ea1a12"}, + {file = "ruff-0.9.10-py3-none-manylinux_2_17_ppc64.manylinux2014_ppc64.whl", hash = "sha256:df92aeac30af821f9acf819fc01b4afc3dfb829d2782884f8739fb52a8119a16"}, + {file = "ruff-0.9.10-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:de42e4edc296f520bb84954eb992a07a0ec5a02fecb834498415908469854a52"}, + {file = "ruff-0.9.10-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:d257f95b65806104b6b1ffca0ea53f4ef98454036df65b1eda3693534813ecd1"}, + {file = "ruff-0.9.10-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b60dec7201c0b10d6d11be00e8f2dbb6f40ef1828ee75ed739923799513db24c"}, + {file = "ruff-0.9.10-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:d838b60007da7a39c046fcdd317293d10b845001f38bcb55ba766c3875b01e43"}, + {file = "ruff-0.9.10-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:ccaf903108b899beb8e09a63ffae5869057ab649c1e9231c05ae354ebc62066c"}, + {file = "ruff-0.9.10-py3-none-musllinux_1_2_i686.whl", hash = "sha256:f9567d135265d46e59d62dc60c0bfad10e9a6822e231f5b24032dba5a55be6b5"}, + {file = "ruff-0.9.10-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:5f202f0d93738c28a89f8ed9eaba01b7be339e5d8d642c994347eaa81c6d75b8"}, + {file = "ruff-0.9.10-py3-none-win32.whl", hash = "sha256:bfb834e87c916521ce46b1788fbb8484966e5113c02df216680102e9eb960029"}, + {file = "ruff-0.9.10-py3-none-win_amd64.whl", hash = "sha256:f2160eeef3031bf4b17df74e307d4c5fb689a6f3a26a2de3f7ef4044e3c484f1"}, + {file = "ruff-0.9.10-py3-none-win_arm64.whl", hash = "sha256:5fd804c0327a5e5ea26615550e706942f348b197d5475ff34c19733aee4b2e69"}, + {file = "ruff-0.9.10.tar.gz", hash = "sha256:9bacb735d7bada9cfb0f2c227d3658fc443d90a727b47f206fb33f52f3c0eac7"}, ] [[package]] @@ -758,6 +873,7 @@ version = "2.2.0" description = "This package provides 29 stemmers for 28 languages generated from Snowball algorithms." optional = false python-versions = "*" +groups = ["docs"] files = [ {file = "snowballstemmer-2.2.0-py2.py3-none-any.whl", hash = "sha256:c8e1716e83cc398ae16824e5572ae04e0d9fc2c6b985fb0f900f5f0c96ecba1a"}, {file = "snowballstemmer-2.2.0.tar.gz", hash = "sha256:09b16deb8547d3412ad7b590689584cd0fe25ec8db3be37788be3810cbf19cb1"}, @@ -765,27 +881,28 @@ files = [ [[package]] name = "sphinx" -version = "7.3.7" +version = "7.4.7" description = "Python documentation generator" optional = false python-versions = ">=3.9" +groups = ["docs"] files = [ - {file = "sphinx-7.3.7-py3-none-any.whl", hash = "sha256:413f75440be4cacf328f580b4274ada4565fb2187d696a84970c23f77b64d8c3"}, - {file = "sphinx-7.3.7.tar.gz", hash = "sha256:a4a7db75ed37531c05002d56ed6948d4c42f473a36f46e1382b0bd76ca9627bc"}, + {file = "sphinx-7.4.7-py3-none-any.whl", hash = "sha256:c2419e2135d11f1951cd994d6eb18a1835bd8fdd8429f9ca375dc1f3281bd239"}, + {file = "sphinx-7.4.7.tar.gz", hash = "sha256:242f92a7ea7e6c5b406fdc2615413890ba9f699114a9c09192d7dfead2ee9cfe"}, ] [package.dependencies] alabaster = ">=0.7.14,<0.8.0" -babel = ">=2.9" -colorama = {version = ">=0.4.5", markers = "sys_platform == \"win32\""} -docutils = ">=0.18.1,<0.22" +babel = ">=2.13" +colorama = {version = ">=0.4.6", markers = "sys_platform == \"win32\""} +docutils = ">=0.20,<0.22" imagesize = ">=1.3" -importlib-metadata = {version = ">=4.8", markers = "python_version < \"3.10\""} -Jinja2 = ">=3.0" -packaging = ">=21.0" -Pygments = ">=2.14" -requests = ">=2.25.0" -snowballstemmer = ">=2.0" +importlib-metadata = {version = ">=6.0", markers = "python_version < \"3.10\""} +Jinja2 = ">=3.1" +packaging = ">=23.0" +Pygments = ">=2.17" +requests = ">=2.30.0" +snowballstemmer = ">=2.2" sphinxcontrib-applehelp = "*" sphinxcontrib-devhelp = "*" sphinxcontrib-htmlhelp = ">=2.0.0" @@ -796,27 +913,28 @@ tomli = {version = ">=2", markers = "python_version < \"3.11\""} [package.extras] docs = ["sphinxcontrib-websupport"] -lint = ["flake8 (>=3.5.0)", "importlib_metadata", "mypy (==1.9.0)", "pytest (>=6.0)", "ruff (==0.3.7)", "sphinx-lint", "tomli", "types-docutils", "types-requests"] -test = ["cython (>=3.0)", "defusedxml (>=0.7.1)", "pytest (>=6.0)", "setuptools (>=67.0)"] +lint = ["flake8 (>=6.0)", "importlib-metadata (>=6.0)", "mypy (==1.10.1)", "pytest (>=6.0)", "ruff (==0.5.2)", "sphinx-lint (>=0.9)", "tomli (>=2)", "types-docutils (==0.21.0.20240711)", "types-requests (>=2.30.0)"] +test = ["cython (>=3.0)", "defusedxml (>=0.7.1)", "pytest (>=8.0)", "setuptools (>=70.0)", "typing_extensions (>=4.9)"] [[package]] name = "sphinx-autodoc-typehints" -version = "1.25.3" +version = "2.3.0" description = "Type hints (PEP 484) support for the Sphinx autodoc extension" optional = false -python-versions = ">=3.8" +python-versions = ">=3.9" +groups = ["docs"] files = [ - {file = "sphinx_autodoc_typehints-1.25.3-py3-none-any.whl", hash = "sha256:d3da7fa9a9761eff6ff09f8b1956ae3090a2d4f4ad54aebcade8e458d6340835"}, - {file = "sphinx_autodoc_typehints-1.25.3.tar.gz", hash = "sha256:70db10b391acf4e772019765991d2de0ff30ec0899b9ba137706dc0b3c4835e0"}, + {file = "sphinx_autodoc_typehints-2.3.0-py3-none-any.whl", hash = "sha256:3098e2c6d0ba99eacd013eb06861acc9b51c6e595be86ab05c08ee5506ac0c67"}, + {file = "sphinx_autodoc_typehints-2.3.0.tar.gz", hash = "sha256:535c78ed2d6a1bad393ba9f3dfa2602cf424e2631ee207263e07874c38fde084"}, ] [package.dependencies] -sphinx = ">=7.1.2" +sphinx = ">=7.3.5" [package.extras] -docs = ["furo (>=2023.9.10)"] +docs = ["furo (>=2024.1.29)"] numpy = ["nptyping (>=2.5)"] -testing = ["covdefaults (>=2.3)", "coverage (>=7.3.2)", "diff-cover (>=8.0.1)", "pytest (>=7.4.3)", "pytest-cov (>=4.1)", "sphobjinv (>=2.3.1)", "typing-extensions (>=4.8)"] +testing = ["covdefaults (>=2.3)", "coverage (>=7.4.4)", "defusedxml (>=0.7.1)", "diff-cover (>=9)", "pytest (>=8.1.1)", "pytest-cov (>=5)", "sphobjinv (>=2.3.1)", "typing-extensions (>=4.11)"] [[package]] name = "sphinx-pyproject" @@ -824,6 +942,7 @@ version = "0.3.0" description = "Move some of your Sphinx configuration into pyproject.toml" optional = false python-versions = ">=3.6" +groups = ["docs"] files = [ {file = "sphinx_pyproject-0.3.0-py3-none-any.whl", hash = "sha256:3aca968919f5ecd390f96874c3f64a43c9c7fcfdc2fd4191a781ad9228501b52"}, {file = "sphinx_pyproject-0.3.0.tar.gz", hash = "sha256:efc4ee9d96f579c4e4ed1ac273868c64565e88c8e37fe6ec2dc59fbcd57684ab"}, @@ -835,22 +954,23 @@ domdf-python-tools = ">=2.7.0" [[package]] name = "sphinx-rtd-theme" -version = "1.3.0" +version = "3.0.2" description = "Read the Docs theme for Sphinx" optional = false -python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*,>=2.7" +python-versions = ">=3.8" +groups = ["docs"] files = [ - {file = "sphinx_rtd_theme-1.3.0-py2.py3-none-any.whl", hash = "sha256:46ddef89cc2416a81ecfbeaceab1881948c014b1b6e4450b815311a89fb977b0"}, - {file = "sphinx_rtd_theme-1.3.0.tar.gz", hash = "sha256:590b030c7abb9cf038ec053b95e5380b5c70d61591eb0b552063fbe7c41f0931"}, + {file = "sphinx_rtd_theme-3.0.2-py2.py3-none-any.whl", hash = "sha256:422ccc750c3a3a311de4ae327e82affdaf59eb695ba4936538552f3b00f4ee13"}, + {file = "sphinx_rtd_theme-3.0.2.tar.gz", hash = "sha256:b7457bc25dda723b20b086a670b9953c859eab60a2a03ee8eb2bb23e176e5f85"}, ] [package.dependencies] -docutils = "<0.19" -sphinx = ">=1.6,<8" +docutils = ">0.18,<0.22" +sphinx = ">=6,<9" sphinxcontrib-jquery = ">=4,<5" [package.extras] -dev = ["bump2version", "sphinxcontrib-httpdomain", "transifex-client", "wheel"] +dev = ["bump2version", "transifex-client", "twine", "wheel"] [[package]] name = "sphinxcontrib-applehelp" @@ -858,6 +978,7 @@ version = "2.0.0" description = "sphinxcontrib-applehelp is a Sphinx extension which outputs Apple help books" optional = false python-versions = ">=3.9" +groups = ["docs"] files = [ {file = "sphinxcontrib_applehelp-2.0.0-py3-none-any.whl", hash = "sha256:4cd3f0ec4ac5dd9c17ec65e9ab272c9b867ea77425228e68ecf08d6b28ddbdb5"}, {file = "sphinxcontrib_applehelp-2.0.0.tar.gz", hash = "sha256:2f29ef331735ce958efa4734873f084941970894c6090408b079c61b2e1c06d1"}, @@ -874,6 +995,7 @@ version = "2.0.0" description = "sphinxcontrib-devhelp is a sphinx extension which outputs Devhelp documents" optional = false python-versions = ">=3.9" +groups = ["docs"] files = [ {file = "sphinxcontrib_devhelp-2.0.0-py3-none-any.whl", hash = "sha256:aefb8b83854e4b0998877524d1029fd3e6879210422ee3780459e28a1f03a8a2"}, {file = "sphinxcontrib_devhelp-2.0.0.tar.gz", hash = "sha256:411f5d96d445d1d73bb5d52133377b4248ec79db5c793ce7dbe59e074b4dd1ad"}, @@ -890,6 +1012,7 @@ version = "2.1.0" description = "sphinxcontrib-htmlhelp is a sphinx extension which renders HTML help files" optional = false python-versions = ">=3.9" +groups = ["docs"] files = [ {file = "sphinxcontrib_htmlhelp-2.1.0-py3-none-any.whl", hash = "sha256:166759820b47002d22914d64a075ce08f4c46818e17cfc9470a9786b759b19f8"}, {file = "sphinxcontrib_htmlhelp-2.1.0.tar.gz", hash = "sha256:c9e2916ace8aad64cc13a0d233ee22317f2b9025b9cf3295249fa985cc7082e9"}, @@ -906,6 +1029,7 @@ version = "4.1" description = "Extension to include jQuery on newer Sphinx releases" optional = false python-versions = ">=2.7" +groups = ["docs"] files = [ {file = "sphinxcontrib-jquery-4.1.tar.gz", hash = "sha256:1620739f04e36a2c779f1a131a2dfd49b2fd07351bf1968ced074365933abc7a"}, {file = "sphinxcontrib_jquery-4.1-py2.py3-none-any.whl", hash = "sha256:f936030d7d0147dd026a4f2b5a57343d233f1fc7b363f68b3d4f1cb0993878ae"}, @@ -920,6 +1044,7 @@ version = "1.0.1" description = "A sphinx extension which renders display math in HTML via JavaScript" optional = false python-versions = ">=3.5" +groups = ["docs"] files = [ {file = "sphinxcontrib-jsmath-1.0.1.tar.gz", hash = "sha256:a9925e4a4587247ed2191a22df5f6970656cb8ca2bd6284309578f2153e0c4b8"}, {file = "sphinxcontrib_jsmath-1.0.1-py2.py3-none-any.whl", hash = "sha256:2ec2eaebfb78f3f2078e73666b1415417a116cc848b72e5172e596c871103178"}, @@ -934,6 +1059,7 @@ version = "2.0.0" description = "sphinxcontrib-qthelp is a sphinx extension which outputs QtHelp documents" optional = false python-versions = ">=3.9" +groups = ["docs"] files = [ {file = "sphinxcontrib_qthelp-2.0.0-py3-none-any.whl", hash = "sha256:b18a828cdba941ccd6ee8445dbe72ffa3ef8cbe7505d8cd1fa0d42d3f2d5f3eb"}, {file = "sphinxcontrib_qthelp-2.0.0.tar.gz", hash = "sha256:4fe7d0ac8fc171045be623aba3e2a8f613f8682731f9153bb2e40ece16b9bbab"}, @@ -950,6 +1076,7 @@ version = "2.0.0" description = "sphinxcontrib-serializinghtml is a sphinx extension which outputs \"serialized\" HTML files (json and pickle)" optional = false python-versions = ">=3.9" +groups = ["docs"] files = [ {file = "sphinxcontrib_serializinghtml-2.0.0-py3-none-any.whl", hash = "sha256:6e2cb0eef194e10c27ec0023bfeb25badbbb5868244cf5bc5bdc04e4464bf331"}, {file = "sphinxcontrib_serializinghtml-2.0.0.tar.gz", hash = "sha256:e9d912827f872c029017a53f0ef2180b327c3f7fd23c87229f7a8e8b70031d4d"}, @@ -966,6 +1093,7 @@ version = "2.2.1" description = "A lil' TOML parser" optional = false python-versions = ">=3.8" +groups = ["docs", "test"] files = [ {file = "tomli-2.2.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:678e4fa69e4575eb77d103de3df8a895e1591b48e740211bd1067378c69e8249"}, {file = "tomli-2.2.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:023aa114dd824ade0100497eb2318602af309e5a55595f76b626d6d9f3b7b0a6"}, @@ -1007,6 +1135,7 @@ version = "4.12.2" description = "Backported and Experimental Type Hints for Python 3.8+" optional = false python-versions = ">=3.8" +groups = ["docs"] files = [ {file = "typing_extensions-4.12.2-py3-none-any.whl", hash = "sha256:04e5ca0351e0f3f85c6853954072df659d0d13fac324d0072316b67d7794700d"}, {file = "typing_extensions-4.12.2.tar.gz", hash = "sha256:1a7ead55c7e559dd4dee8856e3a88b41225abfe1ce8df57b7c13915fe121ffb8"}, @@ -1018,26 +1147,28 @@ version = "2.3.0" description = "HTTP library with thread-safe connection pooling, file post, and more." optional = false python-versions = ">=3.9" +groups = ["docs"] files = [ {file = "urllib3-2.3.0-py3-none-any.whl", hash = "sha256:1cee9ad369867bfdbbb48b7dd50374c0967a0bb7710050facf0dd6911440e3df"}, {file = "urllib3-2.3.0.tar.gz", hash = "sha256:f8c5449b3cf0861679ce7e0503c7b44b5ec981bec0d1d3795a07f1ba96f0204d"}, ] [package.extras] -brotli = ["brotli (>=1.0.9)", "brotlicffi (>=0.8.0)"] +brotli = ["brotli (>=1.0.9) ; platform_python_implementation == \"CPython\"", "brotlicffi (>=0.8.0) ; platform_python_implementation != \"CPython\""] h2 = ["h2 (>=4,<5)"] socks = ["pysocks (>=1.5.6,!=1.5.7,<2.0)"] zstd = ["zstandard (>=0.18.0)"] [[package]] name = "virtualenv" -version = "20.29.2" +version = "20.29.3" description = "Virtual Python Environment builder" optional = false python-versions = ">=3.8" +groups = ["test"] files = [ - {file = "virtualenv-20.29.2-py3-none-any.whl", hash = "sha256:febddfc3d1ea571bdb1dc0f98d7b45d24def7428214d4fb73cc486c9568cce6a"}, - {file = "virtualenv-20.29.2.tar.gz", hash = "sha256:fdaabebf6d03b5ba83ae0a02cfe96f48a716f4fae556461d180825866f75b728"}, + {file = "virtualenv-20.29.3-py3-none-any.whl", hash = "sha256:3e3d00f5807e83b234dfb6122bf37cfadf4be216c53a49ac059d02414f819170"}, + {file = "virtualenv-20.29.3.tar.gz", hash = "sha256:95e39403fcf3940ac45bc717597dba16110b74506131845d9b687d5e73d947ac"}, ] [package.dependencies] @@ -1047,7 +1178,7 @@ platformdirs = ">=3.9.1,<5" [package.extras] docs = ["furo (>=2023.7.26)", "proselint (>=0.13)", "sphinx (>=7.1.2,!=7.3)", "sphinx-argparse (>=0.4)", "sphinxcontrib-towncrier (>=0.2.1a0)", "towncrier (>=23.6)"] -test = ["covdefaults (>=2.3)", "coverage (>=7.2.7)", "coverage-enable-subprocess (>=1)", "flaky (>=3.7)", "packaging (>=23.1)", "pytest (>=7.4)", "pytest-env (>=0.8.2)", "pytest-freezer (>=0.4.8)", "pytest-mock (>=3.11.1)", "pytest-randomly (>=3.12)", "pytest-timeout (>=2.1)", "setuptools (>=68)", "time-machine (>=2.10)"] +test = ["covdefaults (>=2.3)", "coverage (>=7.2.7)", "coverage-enable-subprocess (>=1)", "flaky (>=3.7)", "packaging (>=23.1)", "pytest (>=7.4)", "pytest-env (>=0.8.2)", "pytest-freezer (>=0.4.8) ; platform_python_implementation == \"PyPy\" or platform_python_implementation == \"CPython\" and sys_platform == \"win32\" and python_version >= \"3.13\"", "pytest-mock (>=3.11.1)", "pytest-randomly (>=3.12)", "pytest-timeout (>=2.1)", "setuptools (>=68)", "time-machine (>=2.10) ; platform_python_implementation == \"CPython\""] [[package]] name = "zipp" @@ -1055,20 +1186,22 @@ version = "3.21.0" description = "Backport of pathlib-compatible object wrapper for zip files" optional = false python-versions = ">=3.9" +groups = ["docs"] +markers = "python_version < \"3.10\"" files = [ {file = "zipp-3.21.0-py3-none-any.whl", hash = "sha256:ac1bbe05fd2991f160ebce24ffbac5f6d11d83dc90891255885223d42b3cd931"}, {file = "zipp-3.21.0.tar.gz", hash = "sha256:2c9958f6430a2040341a52eb608ed6dd93ef4392e02ffe219417c1b28b5dd1f4"}, ] [package.extras] -check = ["pytest-checkdocs (>=2.4)", "pytest-ruff (>=0.2.1)"] +check = ["pytest-checkdocs (>=2.4)", "pytest-ruff (>=0.2.1) ; sys_platform != \"cygwin\""] cover = ["pytest-cov"] doc = ["furo", "jaraco.packaging (>=9.3)", "jaraco.tidelift (>=1.4)", "rst.linker (>=1.9)", "sphinx (>=3.5)", "sphinx-lint"] enabler = ["pytest-enabler (>=2.2)"] -test = ["big-O", "importlib-resources", "jaraco.functools", "jaraco.itertools", "jaraco.test", "more-itertools", "pytest (>=6,!=8.1.*)", "pytest-ignore-flaky"] +test = ["big-O", "importlib-resources ; python_version < \"3.9\"", "jaraco.functools", "jaraco.itertools", "jaraco.test", "more-itertools", "pytest (>=6,!=8.1.*)", "pytest-ignore-flaky"] type = ["pytest-mypy"] [metadata] -lock-version = "2.0" -python-versions = ">=3.9,<3.15" -content-hash = "ac25afc7dd34ee5361620f30a1602d9112d674d4c8f00a2aaac85f34f826e3f9" +lock-version = "2.1" +python-versions = ">= 3.9" +content-hash = "38fbbe57866b8c63e3de60d3edef54a30fe5fe3e5274d4423caeb0afe9cda15c" diff --git a/pyproject.toml b/pyproject.toml index 03ef635..06bafb6 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,24 +1,19 @@ [build-system] -requires = ["poetry-core>=1.7.0", "setuptools>=67.7.2", "Cython>=3.0.2"] -build-backend = "poetry.core.masonry.api" +requires = ["poetry-core>=2.0.1", "setuptools>=75.8.0", "Cython>=3.0.12"] +build-backend = "poetry.core.masonry.api" -[tool.poetry] +[project] name = "python-constraint2" # when set back to "python-constraint", don't forget to remove '2' in other places (e.g. README) -packages = [ - { include = "constraint", from = "." }, - { include = "tests", format = "sdist" } -] -include = [{ path = "constraint/*.so", format = "wheel" }] description = "python-constraint is a module for efficiently solving CSPs (Constraint Solving Problems) over finite domains." -version = "2.1.0" # adhere to PEP440 versioning: https://packaging.python.org/en/latest/guides/distributing-packages-using-setuptools/#id55 +version = "2.2.0" # adhere to PEP440 versioning: https://packaging.python.org/en/latest/guides/distributing-packages-using-setuptools/#id55 authors = [ - "Gustavo Niemeyer ", - "Sébastien Celles ", - "Floris-Jan Willemsen ", + {name = "Gustavo Niemeyer", email = "gustavo@niemeyer.net"}, + {name = "Sébastien Celles", email = "s.celles@gmail.com"}, + {name = "Floris-Jan Willemsen", email = "fjwillemsen97@gmail.com"}, ] license = "BSD-2-Clause" readme = "README.rst" -maintainers = ["Floris-Jan Willemsen "] +maintainers = [{name = "Floris-Jan Willemsen", email = "fjwillemsen97@gmail.com"}] repository = "https://github.com/python-constraint/python-constraint" documentation = "http://python-constraint.github.io/python-constraint/" keywords = [ @@ -31,7 +26,7 @@ keywords = [ ] classifiers = [ "Environment :: Console", - "Development Status :: 4 - Beta", + "Development Status :: 5 - Production/Stable", "Intended Audience :: Developers", "Intended Audience :: Science/Research", "Intended Audience :: Education", @@ -41,35 +36,44 @@ classifiers = [ "Topic :: Scientific/Engineering", "Topic :: Software Development", ] + +# ATTENTION: if anything is changed here, run `poetry update` +requires-python = ">= 3.9" # when changing the Python versions, also change the test versions in the Noxfile and GitHub Actions + +[tool.poetry] +include = [{ path = "constraint/*.so", format = "wheel" }] +packages = [ + { include = "constraint", from = "." }, + { include = "tests", format = "sdist" } +] + + [tool.poetry.build] generate-setup-file = false script = "cythonize_build.py" -# ATTENTION: if anything is changed here, run `poetry update` -[tool.poetry.dependencies] -python = ">=3.9,<3.15" # when changing the Python versions, also change the test versions in the Noxfile and GitHub Actions -[tool.poetry.group.dev.dependencies] -Cython = "^3.0.2" - # ATTENTION: if anything is changed here, run `poetry update` and `poetry export --with docs --without-hashes --format=requirements.txt > docs/requirements.txt` [tool.poetry.group.docs] optional = true [tool.poetry.group.docs.dependencies] -sphinx = "^7.1.2" -sphinx-autodoc-typehints = "^1.24.0" -sphinx_rtd_theme = "^1.3.0" +sphinx = "^7.4.7" # can be updated to >=8.*.* when Python 3.9 is dropped +sphinx-autodoc-typehints = "^2.3.0" # can be updated to >=3.*.* when Python 3.9 is dropped +sphinx_rtd_theme = "^3.0.2" sphinx-pyproject = "^0.3.0" # ATTENTION: if anything is changed here, run `poetry update` +[tool.poetry.group.dev.dependencies] +Cython = "^3.0.12" [tool.poetry.group.test] optional = true [tool.poetry.group.test.dependencies] pytest = "^8.3.3" +pytest-benchmark = "^5.1.0" pytest-cov = "^6.0.0" -nox = "^2024.10.9" -ruff = "^0.7.2" +nox = "^2025.2.9" +ruff = "^0.9.6" pep440 = "^0.1.2" -tomli = "^2.0.2" # can be replaced by built-in [tomllib](https://docs.python.org/3.11/library/tomllib.html) from Python 3.11 +tomli = "^2.2.1" # can be replaced by built-in [tomllib](https://docs.python.org/3.11/library/tomllib.html) from Python 3.11 # development dependencies are unused for now, as this is already covered by test and docs # # ATTENTION: if anything is changed here, run `poetry update` diff --git a/tests/benchmarks.py b/tests/benchmarks.py new file mode 100644 index 0000000..ac591b3 --- /dev/null +++ b/tests/benchmarks.py @@ -0,0 +1,109 @@ +"""Module providing various search spaces for benchmarking, ordered on number of solutions.""" + +from constraint import Problem + +# device properties (for A4000 on DAS6 using get_opencl_device_info.cpp) +dev = { + "max_threads": 1024, + "max_threads_per_sm": 1024, + "max_threads_per_block": 1536, + "max_shared_memory_per_block": 49152, + "max_shared_memory": 102400, + "max_wi_size": [1024, 1024, 64], + "max_wg_size": 1024, +} + +def dedispersion(): + """Based on the Dedispersion search space in the paper.""" + benchmark_name = "dedispersion" + expected_num_solutions = 11130 + + # setup the tunable parameters + problem = Problem() + problem.addVariable("block_size_x", [1, 2, 4, 8] + [16 * i for i in range(1, 3)]) + problem.addVariable("block_size_y", [8 * i for i in range(4, 33)]) + problem.addVariable("block_size_z", [1]) + problem.addVariable("tile_size_x", [i for i in range(1, 5)]) + problem.addVariable("tile_size_y", [i for i in range(1, 9)]) + problem.addVariable("tile_stride_x", [0, 1]) + problem.addVariable("tile_stride_y", [0, 1]) + problem.addVariable("loop_unroll_factor_channel", [ + 0 + ]) + + # setup the restrictions + check_block_size = "32 <= block_size_x * block_size_y <= 1024" + check_tile_stride_x = "tile_size_x > 1 or tile_stride_x == 0" + check_tile_stride_y = "tile_size_y > 1 or tile_stride_y == 0" + problem.addConstraint([check_block_size, check_tile_stride_x, check_tile_stride_y]) + + return benchmark_name, problem, expected_num_solutions + +def microhh(): + """Based on the MicroHH search space in the paper.""" + benchmark_name = "microhh" + expected_num_solutions = 138600 + + cta_padding = 0 # default argument + + # setup the tunable parameters + problem = Problem() + problem.addVariable("STATIC_STRIDES", [0]) + problem.addVariable("TILING_STRATEGY", [0]) + problem.addVariable("REWRITE_INTERP", [0]) + problem.addVariable("BLOCK_SIZE_X", [1, 2, 4, 8, 16, 32, 128, 256, 512, 1024]) + problem.addVariable("BLOCK_SIZE_Y", [1, 2, 4, 8, 16, 32]) + problem.addVariable("BLOCK_SIZE_Z", [1, 2, 4]) + problem.addVariable("TILING_FACTOR_X", [1, 2, 4, 8]) + problem.addVariable("TILING_FACTOR_Y", [1, 2, 4]) + problem.addVariable("TILING_FACTOR_Z", [1, 2, 4]) + problem.addVariable("LOOP_UNROLL_FACTOR_X",[1, 2, 4, 8]) + problem.addVariable("LOOP_UNROLL_FACTOR_Y", [1, 2, 4]) + problem.addVariable("LOOP_UNROLL_FACTOR_Z", [1, 2, 4]) + problem.addVariable("BLOCKS_PER_MP", [0, 1, 2, 3, 4]) + + # setup the restrictions + problem.addConstraint([ + f"BLOCK_SIZE_X * BLOCK_SIZE_Y * BLOCK_SIZE_Z * BLOCKS_PER_MP <= {dev['max_threads_per_sm']}", + f"32 <= BLOCK_SIZE_X * BLOCK_SIZE_Y * BLOCK_SIZE_Z <= {dev['max_threads_per_block']}", + "LOOP_UNROLL_FACTOR_X == 0 or TILING_FACTOR_X % LOOP_UNROLL_FACTOR_X == 0", + "LOOP_UNROLL_FACTOR_Y == 0 or TILING_FACTOR_Y % LOOP_UNROLL_FACTOR_Y == 0", + "LOOP_UNROLL_FACTOR_Z == 0 or TILING_FACTOR_Z % LOOP_UNROLL_FACTOR_Z == 0", + f"BLOCK_SIZE_X * TILING_FACTOR_X > {cta_padding}", + f"BLOCK_SIZE_Y * TILING_FACTOR_Y > {cta_padding}", + f"BLOCK_SIZE_Z * TILING_FACTOR_Z > {cta_padding}", + ]) + + return benchmark_name, problem, expected_num_solutions + +def hotspot(): + """Based on the Hotspot search space in the paper.""" + benchmark_name = "hotspot" + expected_num_solutions = 349853 + + # constants + temporal_tiling_factor = [i for i in range(1, 11)] + max_tfactor = max(temporal_tiling_factor) + + # setup the tunable parameters + problem = Problem() + problem.addVariable("block_size_x", [1, 2, 4, 8, 16] + [32 * i for i in range(1, 33)]) + problem.addVariable("block_size_y", [2**i for i in range(6)]) + problem.addVariable("tile_size_x", [i for i in range(1, 11)]) + problem.addVariable("tile_size_y", [i for i in range(1, 11)]) + problem.addVariable("temporal_tiling_factor", temporal_tiling_factor) + problem.addVariable("max_tfactor", [max_tfactor]) + problem.addVariable("loop_unroll_factor_t", [i for i in range(1, max_tfactor + 1)]) + problem.addVariable("sh_power", [0, 1]) + problem.addVariable("blocks_per_sm", [0, 1, 2, 3, 4]) + + # setup the restrictions + problem.addConstraint([ + "block_size_x*block_size_y >= 32", + "temporal_tiling_factor % loop_unroll_factor_t == 0", + f"block_size_x*block_size_y <= {dev['max_threads']}", + f"(block_size_x*tile_size_x + temporal_tiling_factor * 2) * (block_size_y*tile_size_y + temporal_tiling_factor * 2) * (2+sh_power) * 4 <= {dev['max_shared_memory_per_block']}", + f"blocks_per_sm == 0 or (((block_size_x*tile_size_x + temporal_tiling_factor * 2) * (block_size_y*tile_size_y + temporal_tiling_factor * 2) * (2+sh_power) * 4) * blocks_per_sm <= {dev['max_shared_memory']})", + ]) + + return benchmark_name, problem, expected_num_solutions diff --git a/tests/test_util_benchmark.py b/tests/test_util_benchmark.py new file mode 100644 index 0000000..39b4ee0 --- /dev/null +++ b/tests/test_util_benchmark.py @@ -0,0 +1,148 @@ +"""Test run times with benchmarks against reference times. File is called test_util_benchmarks to be ran as last test.""" + +import pytest +from random import random +from time import perf_counter +from math import sqrt + +from .benchmarks import dedispersion, microhh, hotspot + + +# reference times (using A4000 on DAS6) +reference_microbenchmark_mean = [0.3784186691045761, 0.4737640768289566, 0.10726054509480794, 0.10744890073935191, 0.10979799057046573, 0.15360217044750848, 0.14483965436617532, 0.054416230569283165, 0.13835338006416956, 0.1371802551050981] # noqa E501 +reference_results = { + "microhh": 1.1565620, + "dedispersion": 0.1171140, + "hotspot": 2.6839208, +} +# collect benchmark times +benchmark_results = dict() + +@pytest.mark.skip +def get_performance_factor(repeats=3): + """Run microbenchmarks to indicate how much slower this system is compared to the reference.""" + + def cpu_1(): + """Matrix multiplication""" + size = 100 + A = [[random() for _ in range(size)] for _ in range(size)] + B = [[random() for _ in range(size)] for _ in range(size)] + result = [[sum(A[i][k] * B[k][j] for k in range(size)) for j in range(size)] for i in range(size)] + return result + + def cpu_2(): + """Element-wise arithmetic""" + N = 10**6 + A = [random() for _ in range(N)] + B = [random() for _ in range(N)] + return [A[i] + B[i] for i in range(N)] + + def cpu_3(): + """Addition""" + N = 10**6 + return [i + i for i in range(N)] + + def cpu_4(): + """Multiplication""" + N = 10**6 + return [i * i for i in range(N)] + + def cpu_5(): + """Division""" + N = 10**6 + return [i / i for i in range(1, N+1)] + + def mem_1(): + """Array copying""" + N = 10**6 + A = [random() for _ in range(N)] + return A.copy() + + def mem_2(): + """Array slicing""" + N = 10**6 + A = [random() for _ in range(N)] + return A[::2] + + def mem_3(): + """Dictionary lookup""" + N = 10**3 + keys = list(range(N)) + values = list(range(N)) + lst = list(zip(keys, values)) + return [next((v for k, v in lst if k == i), None) for i in range(N)] + + def cache_1(): + """Sequential array sum""" + N = 10**6 + A = [random() for _ in range(N)] + return sum(A) + + def cache_2(): + """Strided array sum""" + N = 10**6 + A = [random() for _ in range(N)] + return sum(A[::2]) + + # run the benchmarks + benchmarks = [cpu_1, cpu_2, cpu_3, cpu_4, cpu_5, mem_1, mem_2, mem_3, cache_1, cache_2] + raw_data = [list() for _ in range(repeats)] + for i in range(repeats): + for f in benchmarks: + start = perf_counter() + f() + duration = perf_counter() - start + raw_data[i].append(duration) + + # non-Numpy implementation of statistics calculation + transposed_data = list(zip(*raw_data)) # transpose the raw_data to get columns as rows + + # calculate mean along axis=0 (column-wise) (`benchmark_data.mean(axis=0)`) + benchmark_mean = [sum(column) / len(column) for column in transposed_data] + + # calculate standard deviation along axis=0 (column-wise) + def stddev(column, mean): + variance = sum((x - mean) ** 2 for x in column) / len(column) + return sqrt(variance) + + # calculate relative standard deviation (`(benchmark_data.std(axis=0) / abs(np_benchmark_mean))`) + benchmark_std = [stddev(column, mean) for column, mean in zip(transposed_data, benchmark_mean)] + relative_std = [(s / abs(m)) if m != 0 else 0 for s, m in zip(benchmark_std, benchmark_mean)] + + # calculate mean relative standard deviation and apply threshold (`max(np.mean(np_relative_std), 0.125)`) + mean_relative_std = max(sum(relative_std) / len(relative_std), 0.125) + + # calculate performance factor (`np.mean(np_benchmark_mean / reference_microbenchmark_mean)`) + performance_factor = sum(bm / rm for bm, rm in zip(benchmark_mean, reference_microbenchmark_mean)) / len(benchmark_mean) + return performance_factor, mean_relative_std + +performance_factor, mean_relative_std = get_performance_factor() +print(f"\nSystem performance factor: {round(performance_factor, 3)}") + +@pytest.mark.skip +def check_benchmark_performance(benchmark_name, mean, std): + """Utility function to check whether the performance of a benchmark is within the expected range and print information.""" + reference_result = reference_results[benchmark_name] + assert mean - std * 2 <= reference_result * (performance_factor + mean_relative_std * 2) + print(f"Benchmark {benchmark_name}: reference: {round(reference_result, 3)}, run: {round(mean, 3)}, expected: {round(reference_result * performance_factor, 3)}") + +@pytest.mark.skip +def run_and_check_benchmark(benchmark, benchmark_name, problem, expected_num_solutions): + """Utility function to run and check a benchmark.""" + # run the benchmark + solutions = benchmark(problem.getSolutions) + benchmark_result = benchmark.stats.stats.mean + benchmark_results[benchmark_name] = benchmark_result + # check for valid outcome + assert len(solutions) == expected_num_solutions + # check for performance degradation + check_benchmark_performance(benchmark_name, benchmark_result, benchmark.stats.stats.stddev) + +def test_microhh(benchmark): + run_and_check_benchmark(benchmark, *microhh()) + +def test_dedispersion(benchmark): + run_and_check_benchmark(benchmark, *dedispersion()) + +def test_hotspot(benchmark): + run_and_check_benchmark(benchmark, *hotspot())