From 2d3885d6bde1a37e720efef262ac721846447b09 Mon Sep 17 00:00:00 2001 From: fjwillemsen Date: Tue, 11 Feb 2025 17:14:40 +0100 Subject: [PATCH 01/41] Changed ParallelSolver location and docstrings --- constraint/solvers.c | 8520 ++++++++++++++++++++--------------------- constraint/solvers.py | 168 +- 2 files changed, 4344 insertions(+), 4344 deletions(-) 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 From 20ad6a4539d1b9d429d08e8f9e3977c5c66ad7a3 Mon Sep 17 00:00:00 2001 From: fjwillemsen Date: Wed, 12 Feb 2025 16:27:11 +0100 Subject: [PATCH 02/41] Added microbenchmark for relative performnace factor --- tests/test_benchmark.py | 85 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 85 insertions(+) create mode 100644 tests/test_benchmark.py diff --git a/tests/test_benchmark.py b/tests/test_benchmark.py new file mode 100644 index 0000000..9b10714 --- /dev/null +++ b/tests/test_benchmark.py @@ -0,0 +1,85 @@ +import numpy as np +from time import perf_counter +import pytest + +@pytest.mark.skip +def get_performance_factor(repeats=3): + """Run microbenchmarks to indicate how much faster / slower this system is compared to the reference.""" + + def cpu_1(): + """Matrix multiplication""" + A = np.random.random((1000, 1000)) + B = np.random.random((1000, 1000)) + return np.dot(A, B) + + def cpu_2(): + """Element-wise arithmetic""" + A = np.random.random(10**6) + B = np.random.random(10**6) + return A + B + + 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""" + A = np.random.random(10**6) + return np.copy(A) + + def mem_2(): + """Array slicing""" + A = np.random.random(10**6) + 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""" + A = np.random.random(10**6) + return np.sum(A) + + def cache_2(): + """Strided array sum""" + A = np.random.random(10**6) + return np.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) + + # calculate statistics + benchmark_data = np.array(raw_data) + benchmark_mean = benchmark_data.mean(axis=0) + relative_std = (benchmark_data.std(axis=0) / np.abs(benchmark_mean)) + mean_relative_std = max(np.mean(relative_std), 0.025) + + # calculate the performance factor relative to the reference + reference_benchmark_mean = np.array([0.03569697, 0.04690351, 0.1586863, 0.13609187, 0.13637274, 0.01238605, 0.01072952, 0.07484022, 0.01054054, 0.01030138]) + performance_factor: float = np.mean(benchmark_mean / reference_benchmark_mean) + return performance_factor, mean_relative_std + +performance_factor, mean_relative_std = get_performance_factor() From 2cf9f5e668a60119c09f6c66d9dac6dedd76467f Mon Sep 17 00:00:00 2001 From: fjwillemsen Date: Wed, 12 Feb 2025 16:28:00 +0100 Subject: [PATCH 03/41] Added pytest-benchmark, updated dependencies --- poetry.lock | 155 ++++++++++++++++++++++++++++++------------------- pyproject.toml | 1 + 2 files changed, 97 insertions(+), 59 deletions(-) diff --git a/poetry.lock b/poetry.lock index f4d5a42..1332c01 100644 --- a/poetry.lock +++ b/poetry.lock @@ -181,68 +181,74 @@ development = ["black", "flake8", "mypy", "pytest", "types-colorama"] [[package]] name = "coverage" -version = "7.6.11" +version = "7.6.12" description = "Code coverage measurement for Python" optional = false python-versions = ">=3.9" 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.6.12-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:704c8c8c6ce6569286ae9622e534b4f5b9759b6f2cd643f1c1a61f666d534fe8"}, + {file = "coverage-7.6.12-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:ad7525bf0241e5502168ae9c643a2f6c219fa0a283001cee4cf23a9b7da75879"}, + {file = "coverage-7.6.12-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:06097c7abfa611c91edb9e6920264e5be1d6ceb374efb4986f38b09eed4cb2fe"}, + {file = "coverage-7.6.12-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:220fa6c0ad7d9caef57f2c8771918324563ef0d8272c94974717c3909664e674"}, + {file = "coverage-7.6.12-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3688b99604a24492bcfe1c106278c45586eb819bf66a654d8a9a1433022fb2eb"}, + {file = "coverage-7.6.12-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:d1a987778b9c71da2fc8948e6f2656da6ef68f59298b7e9786849634c35d2c3c"}, + {file = "coverage-7.6.12-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:cec6b9ce3bd2b7853d4a4563801292bfee40b030c05a3d29555fd2a8ee9bd68c"}, + {file = "coverage-7.6.12-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:ace9048de91293e467b44bce0f0381345078389814ff6e18dbac8fdbf896360e"}, + {file = "coverage-7.6.12-cp310-cp310-win32.whl", hash = "sha256:ea31689f05043d520113e0552f039603c4dd71fa4c287b64cb3606140c66f425"}, + {file = "coverage-7.6.12-cp310-cp310-win_amd64.whl", hash = "sha256:676f92141e3c5492d2a1596d52287d0d963df21bf5e55c8b03075a60e1ddf8aa"}, + {file = "coverage-7.6.12-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:e18aafdfb3e9ec0d261c942d35bd7c28d031c5855dadb491d2723ba54f4c3015"}, + {file = "coverage-7.6.12-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:66fe626fd7aa5982cdebad23e49e78ef7dbb3e3c2a5960a2b53632f1f703ea45"}, + {file = "coverage-7.6.12-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0ef01d70198431719af0b1f5dcbefc557d44a190e749004042927b2a3fed0702"}, + {file = "coverage-7.6.12-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:07e92ae5a289a4bc4c0aae710c0948d3c7892e20fd3588224ebe242039573bf0"}, + {file = "coverage-7.6.12-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e695df2c58ce526eeab11a2e915448d3eb76f75dffe338ea613c1201b33bab2f"}, + {file = "coverage-7.6.12-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:d74c08e9aaef995f8c4ef6d202dbd219c318450fe2a76da624f2ebb9c8ec5d9f"}, + {file = "coverage-7.6.12-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:e995b3b76ccedc27fe4f477b349b7d64597e53a43fc2961db9d3fbace085d69d"}, + {file = "coverage-7.6.12-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:b1f097878d74fe51e1ddd1be62d8e3682748875b461232cf4b52ddc6e6db0bba"}, + {file = "coverage-7.6.12-cp311-cp311-win32.whl", hash = "sha256:1f7ffa05da41754e20512202c866d0ebfc440bba3b0ed15133070e20bf5aeb5f"}, + {file = "coverage-7.6.12-cp311-cp311-win_amd64.whl", hash = "sha256:e216c5c45f89ef8971373fd1c5d8d1164b81f7f5f06bbf23c37e7908d19e8558"}, + {file = "coverage-7.6.12-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:b172f8e030e8ef247b3104902cc671e20df80163b60a203653150d2fc204d1ad"}, + {file = "coverage-7.6.12-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:641dfe0ab73deb7069fb972d4d9725bf11c239c309ce694dd50b1473c0f641c3"}, + {file = "coverage-7.6.12-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0e549f54ac5f301e8e04c569dfdb907f7be71b06b88b5063ce9d6953d2d58574"}, + {file = "coverage-7.6.12-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:959244a17184515f8c52dcb65fb662808767c0bd233c1d8a166e7cf74c9ea985"}, + {file = "coverage-7.6.12-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bda1c5f347550c359f841d6614fb8ca42ae5cb0b74d39f8a1e204815ebe25750"}, + {file = "coverage-7.6.12-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:1ceeb90c3eda1f2d8c4c578c14167dbd8c674ecd7d38e45647543f19839dd6ea"}, + {file = "coverage-7.6.12-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:0f16f44025c06792e0fb09571ae454bcc7a3ec75eeb3c36b025eccf501b1a4c3"}, + {file = "coverage-7.6.12-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:b076e625396e787448d27a411aefff867db2bffac8ed04e8f7056b07024eed5a"}, + {file = "coverage-7.6.12-cp312-cp312-win32.whl", hash = "sha256:00b2086892cf06c7c2d74983c9595dc511acca00665480b3ddff749ec4fb2a95"}, + {file = "coverage-7.6.12-cp312-cp312-win_amd64.whl", hash = "sha256:7ae6eabf519bc7871ce117fb18bf14e0e343eeb96c377667e3e5dd12095e0288"}, + {file = "coverage-7.6.12-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:488c27b3db0ebee97a830e6b5a3ea930c4a6e2c07f27a5e67e1b3532e76b9ef1"}, + {file = "coverage-7.6.12-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:5d1095bbee1851269f79fd8e0c9b5544e4c00c0c24965e66d8cba2eb5bb535fd"}, + {file = "coverage-7.6.12-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0533adc29adf6a69c1baa88c3d7dbcaadcffa21afbed3ca7a225a440e4744bf9"}, + {file = "coverage-7.6.12-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:53c56358d470fa507a2b6e67a68fd002364d23c83741dbc4c2e0680d80ca227e"}, + {file = "coverage-7.6.12-cp313-cp313-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:64cbb1a3027c79ca6310bf101014614f6e6e18c226474606cf725238cf5bc2d4"}, + {file = "coverage-7.6.12-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:79cac3390bfa9836bb795be377395f28410811c9066bc4eefd8015258a7578c6"}, + {file = "coverage-7.6.12-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:9b148068e881faa26d878ff63e79650e208e95cf1c22bd3f77c3ca7b1d9821a3"}, + {file = "coverage-7.6.12-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:8bec2ac5da793c2685ce5319ca9bcf4eee683b8a1679051f8e6ec04c4f2fd7dc"}, + {file = "coverage-7.6.12-cp313-cp313-win32.whl", hash = "sha256:200e10beb6ddd7c3ded322a4186313d5ca9e63e33d8fab4faa67ef46d3460af3"}, + {file = "coverage-7.6.12-cp313-cp313-win_amd64.whl", hash = "sha256:2b996819ced9f7dbb812c701485d58f261bef08f9b85304d41219b1496b591ef"}, + {file = "coverage-7.6.12-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:299cf973a7abff87a30609879c10df0b3bfc33d021e1adabc29138a48888841e"}, + {file = "coverage-7.6.12-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:4b467a8c56974bf06e543e69ad803c6865249d7a5ccf6980457ed2bc50312703"}, + {file = "coverage-7.6.12-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2458f275944db8129f95d91aee32c828a408481ecde3b30af31d552c2ce284a0"}, + {file = "coverage-7.6.12-cp313-cp313t-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:0a9d8be07fb0832636a0f72b80d2a652fe665e80e720301fb22b191c3434d924"}, + {file = "coverage-7.6.12-cp313-cp313t-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:14d47376a4f445e9743f6c83291e60adb1b127607a3618e3185bbc8091f0467b"}, + {file = "coverage-7.6.12-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:b95574d06aa9d2bd6e5cc35a5bbe35696342c96760b69dc4287dbd5abd4ad51d"}, + {file = "coverage-7.6.12-cp313-cp313t-musllinux_1_2_i686.whl", hash = "sha256:ecea0c38c9079570163d663c0433a9af4094a60aafdca491c6a3d248c7432827"}, + {file = "coverage-7.6.12-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:2251fabcfee0a55a8578a9d29cecfee5f2de02f11530e7d5c5a05859aa85aee9"}, + {file = "coverage-7.6.12-cp313-cp313t-win32.whl", hash = "sha256:eb5507795caabd9b2ae3f1adc95f67b1104971c22c624bb354232d65c4fc90b3"}, + {file = "coverage-7.6.12-cp313-cp313t-win_amd64.whl", hash = "sha256:f60a297c3987c6c02ffb29effc70eadcbb412fe76947d394a1091a3615948e2f"}, + {file = "coverage-7.6.12-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:e7575ab65ca8399c8c4f9a7d61bbd2d204c8b8e447aab9d355682205c9dd948d"}, + {file = "coverage-7.6.12-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:8161d9fbc7e9fe2326de89cd0abb9f3599bccc1287db0aba285cb68d204ce929"}, + {file = "coverage-7.6.12-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3a1e465f398c713f1b212400b4e79a09829cd42aebd360362cd89c5bdc44eb87"}, + {file = "coverage-7.6.12-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f25d8b92a4e31ff1bd873654ec367ae811b3a943583e05432ea29264782dc32c"}, + {file = "coverage-7.6.12-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1a936309a65cc5ca80fa9f20a442ff9e2d06927ec9a4f54bcba9c14c066323f2"}, + {file = "coverage-7.6.12-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:aa6f302a3a0b5f240ee201297fff0bbfe2fa0d415a94aeb257d8b461032389bd"}, + {file = "coverage-7.6.12-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:f973643ef532d4f9be71dd88cf7588936685fdb576d93a79fe9f65bc337d9d73"}, + {file = "coverage-7.6.12-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:78f5243bb6b1060aed6213d5107744c19f9571ec76d54c99cc15938eb69e0e86"}, + {file = "coverage-7.6.12-cp39-cp39-win32.whl", hash = "sha256:69e62c5034291c845fc4df7f8155e8544178b6c774f97a99e2734b05eb5bed31"}, + {file = "coverage-7.6.12-cp39-cp39-win_amd64.whl", hash = "sha256:b01a840ecc25dce235ae4c1b6a0daefb2a203dba0e6e980637ee9c2f6ee0df57"}, + {file = "coverage-7.6.12-pp39.pp310-none-any.whl", hash = "sha256:7e39e845c4d764208e7b8f6a21c541ade741e2c41afabdfa1caa28687a3c98cf"}, + {file = "coverage-7.6.12-py3-none-any.whl", hash = "sha256:eb8668cfbc279a536c633137deeb9435d2962caec279c3f8cf8b91fff6ff8953"}, + {file = "coverage-7.6.12.tar.gz", hash = "sha256:48cfc4641d95d34766ad41d9573cc0f22a48aa88d22657a1fe01dca0dbae4de2"}, ] [package.dependencies] @@ -650,6 +656,17 @@ 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 = "*" +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" @@ -686,6 +703,26 @@ 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" +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" @@ -1071,4 +1108,4 @@ type = ["pytest-mypy"] [metadata] lock-version = "2.0" python-versions = ">=3.9,<3.15" -content-hash = "ac25afc7dd34ee5361620f30a1602d9112d674d4c8f00a2aaac85f34f826e3f9" +content-hash = "ea292d92d9b2e84e7875683b8144dea8124bc26c86212c9b2f75086467afa803" diff --git a/pyproject.toml b/pyproject.toml index 03ef635..2df1344 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -65,6 +65,7 @@ sphinx-pyproject = "^0.3.0" 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" From 6d555cce4d30477419c1bafcd036fcb1c7e7c63b Mon Sep 17 00:00:00 2001 From: fjwillemsen Date: Wed, 12 Feb 2025 18:29:26 +0100 Subject: [PATCH 04/41] Added MicroHH kernel and comparison to reference --- tests/test_benchmark.py | 56 +++++++++++++++++++++++++++++++++++++++-- 1 file changed, 54 insertions(+), 2 deletions(-) diff --git a/tests/test_benchmark.py b/tests/test_benchmark.py index 9b10714..ea2baaa 100644 --- a/tests/test_benchmark.py +++ b/tests/test_benchmark.py @@ -1,6 +1,24 @@ import numpy as np from time import perf_counter import pytest +from constraint import Problem + + +# reference times (using A4000 on DAS6) +reference_microbenchmark_mean = np.array([0.03569697, 0.04690351, 0.1586863, 0.13609187, 0.13637274, 0.01238605, 0.01072952, 0.07484022, 0.01054054, 0.01030138]) # noqa E501 +reference_results = { + "microhh": 1.1565620 +} +# 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, +} @pytest.mark.skip def get_performance_factor(repeats=3): @@ -78,8 +96,42 @@ def cache_2(): mean_relative_std = max(np.mean(relative_std), 0.025) # calculate the performance factor relative to the reference - reference_benchmark_mean = np.array([0.03569697, 0.04690351, 0.1586863, 0.13609187, 0.13637274, 0.01238605, 0.01072952, 0.07484022, 0.01054054, 0.01030138]) - performance_factor: float = np.mean(benchmark_mean / reference_benchmark_mean) + performance_factor: float = np.mean(benchmark_mean / reference_microbenchmark_mean) return performance_factor, mean_relative_std performance_factor, mean_relative_std = get_performance_factor() + + +def test_microhh(benchmark): + 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}", + ]) + + benchmark(problem.getSolutions) + assert benchmark.stats.stats.mean <= reference_results["microhh"] * (performance_factor + mean_relative_std) From 545c60a61f5a47fd72ecabf83aad3c97535fcbf6 Mon Sep 17 00:00:00 2001 From: fjwillemsen Date: Thu, 13 Feb 2025 08:21:14 +0100 Subject: [PATCH 05/41] Implemented support for saving benchmark data and passing OS name as argument --- .github/workflows/build-test-python-package.yml | 2 +- .gitignore | 1 + noxfile.py | 8 +++++++- tests/test_benchmark.py | 2 +- 4 files changed, 10 insertions(+), 3 deletions(-) diff --git a/.github/workflows/build-test-python-package.yml b/.github/workflows/build-test-python-package.yml index 62da4f6..b7e5ffa 100644 --- a/.github/workflows/build-test-python-package.yml +++ b/.github/workflows/build-test-python-package.yml @@ -25,7 +25,7 @@ jobs: - uses: actions/checkout@v4 - uses: fjwillemsen/setup-nox2@v3.0.0 - run: | - nox + nox -- ${{ runner.os }} - name: Report to Coveralls uses: coverallsapp/github-action@v2 with: 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/noxfile.py b/noxfile.py index 0cab3a0..9dc6481 100644 --- a/noxfile.py +++ b/noxfile.py @@ -35,13 +35,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/tests/test_benchmark.py b/tests/test_benchmark.py index ea2baaa..6fec275 100644 --- a/tests/test_benchmark.py +++ b/tests/test_benchmark.py @@ -134,4 +134,4 @@ def test_microhh(benchmark): ]) benchmark(problem.getSolutions) - assert benchmark.stats.stats.mean <= reference_results["microhh"] * (performance_factor + mean_relative_std) + assert benchmark.stats.stats.mean - benchmark.stats.stats.std <= reference_results["microhh"] * (performance_factor + mean_relative_std) From 0ea091f3e06c0b0d220c3bde1bf80c78d65ce5c8 Mon Sep 17 00:00:00 2001 From: Floris-Jan Willemsen Date: Thu, 13 Feb 2025 09:46:05 +0100 Subject: [PATCH 06/41] Made Numpy-free implementation of microbenchmarks to avoid adding Numpy dependency --- tests/test_benchmark.py | 81 ++++++++++++++++++++++++++++------------- 1 file changed, 56 insertions(+), 25 deletions(-) diff --git a/tests/test_benchmark.py b/tests/test_benchmark.py index 6fec275..85116da 100644 --- a/tests/test_benchmark.py +++ b/tests/test_benchmark.py @@ -1,11 +1,12 @@ -import numpy as np +from random import random from time import perf_counter import pytest from constraint import Problem +from math import sqrt # reference times (using A4000 on DAS6) -reference_microbenchmark_mean = np.array([0.03569697, 0.04690351, 0.1586863, 0.13609187, 0.13637274, 0.01238605, 0.01072952, 0.07484022, 0.01054054, 0.01030138]) # noqa E501 +reference_microbenchmark_mean = [0.03569697, 0.04690351, 0.1586863, 0.13609187, 0.13637274, 0.01238605, 0.01072952, 0.07484022, 0.01054054, 0.01030138] # noqa E501 reference_results = { "microhh": 1.1565620 } @@ -22,19 +23,22 @@ @pytest.mark.skip def get_performance_factor(repeats=3): - """Run microbenchmarks to indicate how much faster / slower this system is compared to the reference.""" + """Run microbenchmarks to indicate how much slower this system is compared to the reference.""" def cpu_1(): """Matrix multiplication""" - A = np.random.random((1000, 1000)) - B = np.random.random((1000, 1000)) - return np.dot(A, B) + 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""" - A = np.random.random(10**6) - B = np.random.random(10**6) - return A + B + 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""" @@ -53,12 +57,14 @@ def cpu_5(): def mem_1(): """Array copying""" - A = np.random.random(10**6) - return np.copy(A) - + N = 10**6 + A = [random() for _ in range(N)] + return A.copy() + def mem_2(): """Array slicing""" - A = np.random.random(10**6) + N = 10**6 + A = [random() for _ in range(N)] return A[::2] def mem_3(): @@ -71,13 +77,15 @@ def mem_3(): def cache_1(): """Sequential array sum""" - A = np.random.random(10**6) - return np.sum(A) + N = 10**6 + A = [random() for _ in range(N)] + return sum(A) def cache_2(): """Strided array sum""" - A = np.random.random(10**6) - return np.sum(A[::2]) + 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] @@ -89,14 +97,37 @@ def cache_2(): duration = perf_counter() - start raw_data[i].append(duration) - # calculate statistics - benchmark_data = np.array(raw_data) - benchmark_mean = benchmark_data.mean(axis=0) - relative_std = (benchmark_data.std(axis=0) / np.abs(benchmark_mean)) - mean_relative_std = max(np.mean(relative_std), 0.025) + # # below is the non-Numpy equivalent of the following statistics calculation + # benchmark_data = np.array(raw_data) + # np_benchmark_mean = benchmark_data.mean(axis=0) + # np_relative_std = (benchmark_data.std(axis=0) / abs(np_benchmark_mean)) + # np_mean_relative_std = max(np.mean(np_relative_std), 0.025) + # # calculate the performance factor relative to the reference + # np_performance_factor: float = np.mean(np_benchmark_mean / reference_microbenchmark_mean) + + + # Transpose the raw_data to get columns as rows + transposed_data = list(zip(*raw_data)) + + # Calculate mean along axis=0 (column-wise) + 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) + + benchmark_std = [stddev(column, mean) for column, mean in zip(transposed_data, benchmark_mean)] + + # Calculate relative standard deviation + 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 + mean_relative_std = max(sum(relative_std) / len(relative_std), 0.025) - # calculate the performance factor relative to the reference - performance_factor: float = np.mean(benchmark_mean / reference_microbenchmark_mean) + # Calculate performance factor + performance_factor = sum(bm / rm for bm, rm in zip(benchmark_mean, reference_microbenchmark_mean)) / len(benchmark_mean) + raise ValueError(benchmark_mean) return performance_factor, mean_relative_std performance_factor, mean_relative_std = get_performance_factor() @@ -134,4 +165,4 @@ def test_microhh(benchmark): ]) benchmark(problem.getSolutions) - assert benchmark.stats.stats.mean - benchmark.stats.stats.std <= reference_results["microhh"] * (performance_factor + mean_relative_std) + assert benchmark.stats.stats.mean - benchmark.stats.stats.stddev <= reference_results["microhh"] * (performance_factor + mean_relative_std) From 263e22f99d2c1f95023ebf30b5b79fb8e4a1f909 Mon Sep 17 00:00:00 2001 From: Floris-Jan Willemsen Date: Thu, 13 Feb 2025 09:47:11 +0100 Subject: [PATCH 07/41] Register benchmarks folder and path --- noxfile.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/noxfile.py b/noxfile.py index 9dc6481..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 @@ -47,7 +51,7 @@ def tests(session: Session) -> None: # session.poetry.installroot(distribution_format="sdist") # run pytest on the package with C-extensions, disable required coverage percentage - session.run("pytest", "--no-cov", "--benchmark-json" f".benchmarks/benchmark_{os_name}_{session.python}.json") + 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]: From 337449e1364a8827c35d8e99a0a33ff0ac7b6deb Mon Sep 17 00:00:00 2001 From: fjwillemsen Date: Thu, 13 Feb 2025 09:53:58 +0100 Subject: [PATCH 08/41] Updated reference microbenchmark times, improved comments --- tests/test_benchmark.py | 27 ++++++++------------------- 1 file changed, 8 insertions(+), 19 deletions(-) diff --git a/tests/test_benchmark.py b/tests/test_benchmark.py index 85116da..75bac1f 100644 --- a/tests/test_benchmark.py +++ b/tests/test_benchmark.py @@ -6,7 +6,7 @@ # reference times (using A4000 on DAS6) -reference_microbenchmark_mean = [0.03569697, 0.04690351, 0.1586863, 0.13609187, 0.13637274, 0.01238605, 0.01072952, 0.07484022, 0.01054054, 0.01030138] # noqa E501 +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 } @@ -97,37 +97,26 @@ def cache_2(): duration = perf_counter() - start raw_data[i].append(duration) - # # below is the non-Numpy equivalent of the following statistics calculation - # benchmark_data = np.array(raw_data) - # np_benchmark_mean = benchmark_data.mean(axis=0) - # np_relative_std = (benchmark_data.std(axis=0) / abs(np_benchmark_mean)) - # np_mean_relative_std = max(np.mean(np_relative_std), 0.025) - # # calculate the performance factor relative to the reference - # np_performance_factor: float = np.mean(np_benchmark_mean / reference_microbenchmark_mean) + # non-Numpy implementation of statistics calculation + transposed_data = list(zip(*raw_data)) # transpose the raw_data to get columns as rows - - # Transpose the raw_data to get columns as rows - transposed_data = list(zip(*raw_data)) - - # Calculate mean along axis=0 (column-wise) + # 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) + # 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)] - - # Calculate relative standard deviation 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 + # calculate mean relative standard deviation and apply threshold (`max(np.mean(np_relative_std), 0.025)``) mean_relative_std = max(sum(relative_std) / len(relative_std), 0.025) - # Calculate performance factor + # 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) - raise ValueError(benchmark_mean) return performance_factor, mean_relative_std performance_factor, mean_relative_std = get_performance_factor() From 60c97514186f0ec9b331e87818efab7f6b697104 Mon Sep 17 00:00:00 2001 From: fjwillemsen Date: Thu, 13 Feb 2025 10:03:33 +0100 Subject: [PATCH 09/41] Added the dedispersion benchmark and reference performance --- tests/test_benchmark.py | 36 +++++++++++++++++++++++++++++++++++- 1 file changed, 35 insertions(+), 1 deletion(-) diff --git a/tests/test_benchmark.py b/tests/test_benchmark.py index 75bac1f..cf5479f 100644 --- a/tests/test_benchmark.py +++ b/tests/test_benchmark.py @@ -8,7 +8,8 @@ # 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 + "microhh": 1.1565620, + "dedispersion": 0.1171140, } # device properties (for A4000 on DAS6 using get_opencl_device_info.cpp) dev = { @@ -123,6 +124,8 @@ def stddev(column, mean): def test_microhh(benchmark): + """Based on the MicroHH search space in the paper.""" + cta_padding = 0 # default argument # setup the tunable parameters @@ -153,5 +156,36 @@ def test_microhh(benchmark): f"BLOCK_SIZE_Z * TILING_FACTOR_Z > {cta_padding}", ]) + # run the benchmark and check for performance degradation benchmark(problem.getSolutions) assert benchmark.stats.stats.mean - benchmark.stats.stats.stddev <= reference_results["microhh"] * (performance_factor + mean_relative_std) + + +def test_dedispersion(benchmark): + """Based on the Dedispersion search space in the paper.""" + + # 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 + ]) # + [i for i in range(1,nr_channels+1) if nr_channels % i == 0] #[i for i in range(nr_channels+1)] + # tune_params["loop_unroll_factor_x", [0] #[i for i in range(1,max(tune_params["tile_size_x"]))] + # tune_params["loop_unroll_factor_y", [0] #[i for i in range(1,max(tune_params["tile_size_y"]))] + # tune_params["blocks_per_sm", [i for i in range(5)] + + # 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]) + + # run the benchmark and check for performance degradation + benchmark(problem.getSolutions) + assert benchmark.stats.stats.mean - benchmark.stats.stats.stddev <= reference_results["dedispersion"] * (performance_factor + mean_relative_std) From dd1bb3ad11969632b6c3c2b59a77187cbc8440ad Mon Sep 17 00:00:00 2001 From: fjwillemsen Date: Thu, 13 Feb 2025 10:12:05 +0100 Subject: [PATCH 10/41] Added the Hotspot benchmark and reference performance --- tests/test_benchmark.py | 37 +++++++++++++++++++++++++++++++++---- 1 file changed, 33 insertions(+), 4 deletions(-) diff --git a/tests/test_benchmark.py b/tests/test_benchmark.py index cf5479f..124c7a1 100644 --- a/tests/test_benchmark.py +++ b/tests/test_benchmark.py @@ -10,6 +10,7 @@ reference_results = { "microhh": 1.1565620, "dedispersion": 0.1171140, + "hotspot": 2.6839208, } # device properties (for A4000 on DAS6 using get_opencl_device_info.cpp) dev = { @@ -175,10 +176,7 @@ def test_dedispersion(benchmark): problem.addVariable("tile_stride_y", [0, 1]) problem.addVariable("loop_unroll_factor_channel", [ 0 - ]) # + [i for i in range(1,nr_channels+1) if nr_channels % i == 0] #[i for i in range(nr_channels+1)] - # tune_params["loop_unroll_factor_x", [0] #[i for i in range(1,max(tune_params["tile_size_x"]))] - # tune_params["loop_unroll_factor_y", [0] #[i for i in range(1,max(tune_params["tile_size_y"]))] - # tune_params["blocks_per_sm", [i for i in range(5)] + ]) # setup the restrictions check_block_size = "32 <= block_size_x * block_size_y <= 1024" @@ -189,3 +187,34 @@ def test_dedispersion(benchmark): # run the benchmark and check for performance degradation benchmark(problem.getSolutions) assert benchmark.stats.stats.mean - benchmark.stats.stats.stddev <= reference_results["dedispersion"] * (performance_factor + mean_relative_std) + +def test_hotspot(benchmark): + """Based on the Hotspot search space in the paper.""" + # 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']})", + ]) + + # run the benchmark and check for performance degradation + benchmark(problem.getSolutions) + assert benchmark.stats.stats.mean - benchmark.stats.stats.stddev <= reference_results["hotspot"] * (performance_factor + mean_relative_std) From eaf9aa9a29760bc73c746cb1d1b4290350e0864d Mon Sep 17 00:00:00 2001 From: fjwillemsen Date: Thu, 13 Feb 2025 10:18:40 +0100 Subject: [PATCH 11/41] Benchmark outcomes are validated --- tests/test_benchmark.py | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/tests/test_benchmark.py b/tests/test_benchmark.py index 124c7a1..9d15f34 100644 --- a/tests/test_benchmark.py +++ b/tests/test_benchmark.py @@ -157,8 +157,9 @@ def test_microhh(benchmark): f"BLOCK_SIZE_Z * TILING_FACTOR_Z > {cta_padding}", ]) - # run the benchmark and check for performance degradation - benchmark(problem.getSolutions) + # run the benchmark and check for valid outcome and performance degradation + solutions = benchmark(problem.getSolutions) + assert len(solutions) == 138600 assert benchmark.stats.stats.mean - benchmark.stats.stats.stddev <= reference_results["microhh"] * (performance_factor + mean_relative_std) @@ -184,8 +185,9 @@ def test_dedispersion(benchmark): 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]) - # run the benchmark and check for performance degradation - benchmark(problem.getSolutions) + # run the benchmark and check for valid outcome and performance degradation + solutions = benchmark(problem.getSolutions) + assert len(solutions) == 11130 assert benchmark.stats.stats.mean - benchmark.stats.stats.stddev <= reference_results["dedispersion"] * (performance_factor + mean_relative_std) def test_hotspot(benchmark): @@ -215,6 +217,7 @@ def test_hotspot(benchmark): 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']})", ]) - # run the benchmark and check for performance degradation - benchmark(problem.getSolutions) + # run the benchmark and check for valid outcome and performance degradation + solutions = benchmark(problem.getSolutions) + assert len(solutions) == 349853 assert benchmark.stats.stats.mean - benchmark.stats.stats.stddev <= reference_results["hotspot"] * (performance_factor + mean_relative_std) From dd9b71d430efea9574a2b3273199153b8e2bdcc1 Mon Sep 17 00:00:00 2001 From: Floris-Jan Willemsen Date: Thu, 13 Feb 2025 10:54:29 +0100 Subject: [PATCH 12/41] Benchmark results collection and printing --- tests/test_benchmark.py | 30 +++++++++++++++++++++++++----- 1 file changed, 25 insertions(+), 5 deletions(-) diff --git a/tests/test_benchmark.py b/tests/test_benchmark.py index 9d15f34..742ae1d 100644 --- a/tests/test_benchmark.py +++ b/tests/test_benchmark.py @@ -22,6 +22,8 @@ "max_wi_size": [1024, 1024, 64], "max_wg_size": 1024, } +# collect benchmark times +benchmark_results = dict() @pytest.mark.skip def get_performance_factor(repeats=3): @@ -114,18 +116,20 @@ def stddev(column, 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.025)``) + # calculate mean relative standard deviation and apply threshold (`max(np.mean(np_relative_std), 0.025)`) mean_relative_std = max(sum(relative_std) / len(relative_std), 0.025) - # calculate performance factor (`np.mean(np_benchmark_mean / reference_microbenchmark_mean)``) + # 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)}") def test_microhh(benchmark): """Based on the MicroHH search space in the paper.""" + benchmark_name = "microhh" cta_padding = 0 # default argument @@ -159,12 +163,17 @@ def test_microhh(benchmark): # run the benchmark and check for valid outcome and performance degradation solutions = benchmark(problem.getSolutions) + reference_result = reference_results[benchmark_name] + benchmark_result = benchmark.stats.stats.mean + benchmark_results[benchmark_name] = benchmark_result assert len(solutions) == 138600 - assert benchmark.stats.stats.mean - benchmark.stats.stats.stddev <= reference_results["microhh"] * (performance_factor + mean_relative_std) + assert benchmark_result - benchmark.stats.stats.stddev <= reference_result * (performance_factor + mean_relative_std) + print(f"Reference: {round(reference_result, 3)}, benchmark: {round(benchmark_result, 3)}, expected: {round(reference_result * performance_factor, 3)}") def test_dedispersion(benchmark): """Based on the Dedispersion search space in the paper.""" + benchmark_name = "dedispersion" # setup the tunable parameters problem = Problem() @@ -187,11 +196,18 @@ def test_dedispersion(benchmark): # run the benchmark and check for valid outcome and performance degradation solutions = benchmark(problem.getSolutions) + reference_result = reference_results[benchmark_name] + benchmark_result = benchmark.stats.stats.mean + benchmark_results[benchmark_name] = benchmark_result assert len(solutions) == 11130 - assert benchmark.stats.stats.mean - benchmark.stats.stats.stddev <= reference_results["dedispersion"] * (performance_factor + mean_relative_std) + assert benchmark_results[benchmark_name] - benchmark.stats.stats.stddev <= reference_results["dedispersion"] * (performance_factor + mean_relative_std) + print(f"Reference: {round(reference_result, 3)}, benchmark: {round(benchmark_result, 3)}, expected: {round(reference_result * performance_factor, 3)}") + def test_hotspot(benchmark): """Based on the Hotspot search space in the paper.""" + benchmark_name = "hotspot" + # constants temporal_tiling_factor = [i for i in range(1, 11)] max_tfactor = max(temporal_tiling_factor) @@ -219,5 +235,9 @@ def test_hotspot(benchmark): # run the benchmark and check for valid outcome and performance degradation solutions = benchmark(problem.getSolutions) + reference_result = reference_results[benchmark_name] + benchmark_result = benchmark.stats.stats.mean + benchmark_results[benchmark_name] = benchmark_result assert len(solutions) == 349853 - assert benchmark.stats.stats.mean - benchmark.stats.stats.stddev <= reference_results["hotspot"] * (performance_factor + mean_relative_std) + assert benchmark_results[benchmark_name] - benchmark.stats.stats.stddev <= reference_results[benchmark_name] * (performance_factor + mean_relative_std) + print(f"Reference: {round(reference_result, 3)}, benchmark: {round(benchmark_result, 3)}, expected: {round(reference_result * performance_factor, 3)}") From 1f25e9a62db9eb535a8cb772badbecf66fbf8450 Mon Sep 17 00:00:00 2001 From: Floris-Jan Willemsen Date: Thu, 13 Feb 2025 11:20:45 +0100 Subject: [PATCH 13/41] Improved and standardized performance check and printing --- tests/test_benchmark.py | 20 ++++++++++++-------- 1 file changed, 12 insertions(+), 8 deletions(-) diff --git a/tests/test_benchmark.py b/tests/test_benchmark.py index 742ae1d..8cb07a3 100644 --- a/tests/test_benchmark.py +++ b/tests/test_benchmark.py @@ -116,8 +116,8 @@ def stddev(column, 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.025)`) - mean_relative_std = max(sum(relative_std) / len(relative_std), 0.025) + # 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) @@ -126,6 +126,13 @@ def stddev(column, mean): 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"Reference: {round(reference_result, 3)}, benchmark: {round(mean, 3)}, expected: {round(reference_result * performance_factor, 3)}") + def test_microhh(benchmark): """Based on the MicroHH search space in the paper.""" @@ -167,8 +174,7 @@ def test_microhh(benchmark): benchmark_result = benchmark.stats.stats.mean benchmark_results[benchmark_name] = benchmark_result assert len(solutions) == 138600 - assert benchmark_result - benchmark.stats.stats.stddev <= reference_result * (performance_factor + mean_relative_std) - print(f"Reference: {round(reference_result, 3)}, benchmark: {round(benchmark_result, 3)}, expected: {round(reference_result * performance_factor, 3)}") + check_benchmark_performance(benchmark_name, benchmark_result, benchmark.stats.stats.stddev) def test_dedispersion(benchmark): @@ -200,8 +206,7 @@ def test_dedispersion(benchmark): benchmark_result = benchmark.stats.stats.mean benchmark_results[benchmark_name] = benchmark_result assert len(solutions) == 11130 - assert benchmark_results[benchmark_name] - benchmark.stats.stats.stddev <= reference_results["dedispersion"] * (performance_factor + mean_relative_std) - print(f"Reference: {round(reference_result, 3)}, benchmark: {round(benchmark_result, 3)}, expected: {round(reference_result * performance_factor, 3)}") + check_benchmark_performance(benchmark_name, benchmark_result, benchmark.stats.stats.stddev) def test_hotspot(benchmark): @@ -239,5 +244,4 @@ def test_hotspot(benchmark): benchmark_result = benchmark.stats.stats.mean benchmark_results[benchmark_name] = benchmark_result assert len(solutions) == 349853 - assert benchmark_results[benchmark_name] - benchmark.stats.stats.stddev <= reference_results[benchmark_name] * (performance_factor + mean_relative_std) - print(f"Reference: {round(reference_result, 3)}, benchmark: {round(benchmark_result, 3)}, expected: {round(reference_result * performance_factor, 3)}") + check_benchmark_performance(benchmark_name, benchmark_result, benchmark.stats.stats.stddev) From 6743764bed911df03c50e594379c9d724b026e6a Mon Sep 17 00:00:00 2001 From: Floris-Jan Willemsen Date: Thu, 13 Feb 2025 14:27:20 +0100 Subject: [PATCH 14/41] Added GH benchmark actions --- .github/workflows/build-test-python-package.yml | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/.github/workflows/build-test-python-package.yml b/.github/workflows/build-test-python-package.yml index b7e5ffa..f6914ba 100644 --- a/.github/workflows/build-test-python-package.yml +++ b/.github/workflows/build-test-python-package.yml @@ -26,6 +26,11 @@ jobs: - uses: fjwillemsen/setup-nox2@v3.0.0 - run: | 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 - name: Report to Coveralls uses: coverallsapp/github-action@v2 with: From 5b11a8721b506b21d86546e883e3b1d43c3c3133 Mon Sep 17 00:00:00 2001 From: Floris-Jan Willemsen Date: Thu, 13 Feb 2025 14:52:43 +0100 Subject: [PATCH 15/41] Fixed an error with the benchmark output file path --- .github/workflows/build-test-python-package.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/build-test-python-package.yml b/.github/workflows/build-test-python-package.yml index f6914ba..46d30e8 100644 --- a/.github/workflows/build-test-python-package.yml +++ b/.github/workflows/build-test-python-package.yml @@ -30,7 +30,7 @@ jobs: uses: benchmark-action/github-action-benchmark@v1 with: tool: "pytest" - output-file-path: .benchmarks/benchmark_{${{ runner.os }}}_3.13.json + output-file-path: .benchmarks/benchmark_${{ runner.os }}_3.13.json - name: Report to Coveralls uses: coverallsapp/github-action@v2 with: From d909bffbda00e144af3ff68111e35e41c3e8527e Mon Sep 17 00:00:00 2001 From: Floris-Jan Willemsen Date: Thu, 13 Feb 2025 15:15:00 +0100 Subject: [PATCH 16/41] Created docs folder for benchmarks, point GH action to main instead of gh-pages branch --- .github/workflows/build-test-python-package.yml | 2 ++ docs/benchmarks/.gitkeep | 0 2 files changed, 2 insertions(+) create mode 100644 docs/benchmarks/.gitkeep diff --git a/.github/workflows/build-test-python-package.yml b/.github/workflows/build-test-python-package.yml index 46d30e8..1a12d8e 100644 --- a/.github/workflows/build-test-python-package.yml +++ b/.github/workflows/build-test-python-package.yml @@ -31,6 +31,8 @@ jobs: with: tool: "pytest" output-file-path: .benchmarks/benchmark_${{ runner.os }}_3.13.json + gh-pages-branch: main + benchmark-data-dir-path: docs/benchmarks - name: Report to Coveralls uses: coverallsapp/github-action@v2 with: diff --git a/docs/benchmarks/.gitkeep b/docs/benchmarks/.gitkeep new file mode 100644 index 0000000..e69de29 From 31640bb4f34506156e9961cccef82d64193dfbf0 Mon Sep 17 00:00:00 2001 From: Floris-Jan Willemsen Date: Thu, 13 Feb 2025 15:32:35 +0100 Subject: [PATCH 17/41] Added token to save benchmark results --- .github/workflows/build-test-python-package.yml | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/.github/workflows/build-test-python-package.yml b/.github/workflows/build-test-python-package.yml index 1a12d8e..5938f92 100644 --- a/.github/workflows/build-test-python-package.yml +++ b/.github/workflows/build-test-python-package.yml @@ -33,6 +33,12 @@ jobs: output-file-path: .benchmarks/benchmark_${{ runner.os }}_3.13.json gh-pages-branch: main benchmark-data-dir-path: docs/benchmarks + fail-on-alert: true + # GitHub API token to make a commit comment + github-token: ${{ secrets.GITHUB_TOKEN }} + # Enable alert commit comment + comment-on-alert: true + # alert-comment-cc-users: mention a GitHub user in the comment - name: Report to Coveralls uses: coverallsapp/github-action@v2 with: From 9fd0036e43b3bd01fc35de877049dff326b0963d Mon Sep 17 00:00:00 2001 From: Floris-Jan Willemsen Date: Thu, 13 Feb 2025 16:00:38 +0100 Subject: [PATCH 18/41] Minor update to GH action build & test workflow --- .github/workflows/build-test-python-package.yml | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/.github/workflows/build-test-python-package.yml b/.github/workflows/build-test-python-package.yml index 5938f92..b739f70 100644 --- a/.github/workflows/build-test-python-package.yml +++ b/.github/workflows/build-test-python-package.yml @@ -36,11 +36,12 @@ jobs: fail-on-alert: true # GitHub API token to make a commit comment github-token: ${{ secrets.GITHUB_TOKEN }} - # Enable alert commit comment comment-on-alert: true - # alert-comment-cc-users: mention a GitHub user in the comment + comment-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 From 9e78b00ba5c7cf2983ce5f2bdf0b4cb232fd658b Mon Sep 17 00:00:00 2001 From: Floris-Jan Willemsen Date: Thu, 13 Feb 2025 16:12:52 +0100 Subject: [PATCH 19/41] Added auto-push to benchmarking results --- .github/workflows/build-test-python-package.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/build-test-python-package.yml b/.github/workflows/build-test-python-package.yml index b739f70..59970b2 100644 --- a/.github/workflows/build-test-python-package.yml +++ b/.github/workflows/build-test-python-package.yml @@ -36,6 +36,7 @@ jobs: fail-on-alert: true # GitHub API token to make a commit comment github-token: ${{ secrets.GITHUB_TOKEN }} + auto-push: true comment-on-alert: true comment-always: true # alert-comment-cc-users: '@fjwillemsen' mention a GitHub user in the comment From ccc72c3c608df661cf624d2c9c9d4427dfe5f207 Mon Sep 17 00:00:00 2001 From: Floris-Jan Willemsen Date: Thu, 13 Feb 2025 17:13:33 +0100 Subject: [PATCH 20/41] Split actions into general test and test-on-push to allow modifying contents --- .../build-test-python-package-pull.yml | 23 +++++++++++++++++++ .../workflows/build-test-python-package.yml | 10 +++++--- 2 files changed, 30 insertions(+), 3 deletions(-) create mode 100644 .github/workflows/build-test-python-package-pull.yml 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 59970b2..d975f62 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,9 +15,12 @@ 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: From c5d35e0e2e590dc6d8b66166828108782d530471 Mon Sep 17 00:00:00 2001 From: Floris-Jan Willemsen Date: Thu, 13 Feb 2025 17:32:47 +0100 Subject: [PATCH 21/41] Avoid detached head state --- .github/workflows/build-test-python-package.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.github/workflows/build-test-python-package.yml b/.github/workflows/build-test-python-package.yml index d975f62..22a57db 100644 --- a/.github/workflows/build-test-python-package.yml +++ b/.github/workflows/build-test-python-package.yml @@ -27,6 +27,8 @@ jobs: 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 - uses: fjwillemsen/setup-nox2@v3.0.0 - run: | nox -- ${{ runner.os }} From e852dc7485c23c24cf24eae0da50dae6635e8dee Mon Sep 17 00:00:00 2001 From: Floris-Jan Willemsen Date: Thu, 13 Feb 2025 17:45:54 +0100 Subject: [PATCH 22/41] Skip fetching to avoid error --- .github/workflows/build-test-python-package.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/build-test-python-package.yml b/.github/workflows/build-test-python-package.yml index 22a57db..9db059f 100644 --- a/.github/workflows/build-test-python-package.yml +++ b/.github/workflows/build-test-python-package.yml @@ -38,6 +38,7 @@ jobs: tool: "pytest" output-file-path: .benchmarks/benchmark_${{ runner.os }}_3.13.json gh-pages-branch: main + skip-fetch-gh-pages: true benchmark-data-dir-path: docs/benchmarks fail-on-alert: true # GitHub API token to make a commit comment From d34c63316e977c4f73d4ec1adb4318ce106cd14c Mon Sep 17 00:00:00 2001 From: Floris-Jan Willemsen Date: Thu, 13 Feb 2025 18:09:11 +0100 Subject: [PATCH 23/41] Use external instead --- .github/workflows/build-test-python-package.yml | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/.github/workflows/build-test-python-package.yml b/.github/workflows/build-test-python-package.yml index 9db059f..7d9ddb6 100644 --- a/.github/workflows/build-test-python-package.yml +++ b/.github/workflows/build-test-python-package.yml @@ -29,6 +29,11 @@ jobs: - 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 -- ${{ runner.os }} @@ -37,13 +42,8 @@ jobs: with: tool: "pytest" output-file-path: .benchmarks/benchmark_${{ runner.os }}_3.13.json - gh-pages-branch: main - skip-fetch-gh-pages: true - benchmark-data-dir-path: docs/benchmarks + 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 }} - auto-push: true comment-on-alert: true comment-always: true # alert-comment-cc-users: '@fjwillemsen' mention a GitHub user in the comment From b58b78eb771de9191b3ddaf863cfef20d24c1404 Mon Sep 17 00:00:00 2001 From: Floris-Jan Willemsen Date: Thu, 13 Feb 2025 18:18:22 +0100 Subject: [PATCH 24/41] Include Gitub token --- .github/workflows/build-test-python-package.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.github/workflows/build-test-python-package.yml b/.github/workflows/build-test-python-package.yml index 7d9ddb6..fe7b2a4 100644 --- a/.github/workflows/build-test-python-package.yml +++ b/.github/workflows/build-test-python-package.yml @@ -44,6 +44,8 @@ jobs: 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-on-alert: true comment-always: true # alert-comment-cc-users: '@fjwillemsen' mention a GitHub user in the comment From 7dba4ec5e8722f9279add2dea507c9d0f48642e4 Mon Sep 17 00:00:00 2001 From: Floris-Jan Willemsen Date: Thu, 13 Feb 2025 22:00:59 +0100 Subject: [PATCH 25/41] Provide a summary of the benchmarks --- .github/workflows/build-test-python-package.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/build-test-python-package.yml b/.github/workflows/build-test-python-package.yml index fe7b2a4..a2951ed 100644 --- a/.github/workflows/build-test-python-package.yml +++ b/.github/workflows/build-test-python-package.yml @@ -46,8 +46,8 @@ jobs: fail-on-alert: true # GitHub API token to make a commit comment github-token: ${{ secrets.GITHUB_TOKEN }} - comment-on-alert: true 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 From ebd0441d4d7d8cd61c07fec22ced2ef10a35adc7 Mon Sep 17 00:00:00 2001 From: fjwillemsen Date: Fri, 14 Feb 2025 09:06:11 +0100 Subject: [PATCH 26/41] Added check whether passed solver is an instance of Solver --- constraint/problem.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/constraint/problem.py b/constraint/problem.py index 4641718..6428c31 100644 --- a/constraint/problem.py +++ b/constraint/problem.py @@ -26,6 +26,9 @@ 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 From 259e004636922e18f1131a20fcf4a8080cf00879 Mon Sep 17 00:00:00 2001 From: fjwillemsen Date: Fri, 14 Feb 2025 09:43:46 +0100 Subject: [PATCH 27/41] Switched to poetry-core 2, updated pyproject.toml to use project over tool.poetry --- pyproject.toml | 39 +++++++++++++++++++++------------------ 1 file changed, 21 insertions(+), 18 deletions(-) diff --git a/pyproject.toml b/pyproject.toml index 2df1344..495a2b2 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"] +requires = ["poetry-core>=2.0.1", "setuptools>=67.7.2", "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 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 = [ @@ -41,15 +36,21 @@ classifiers = [ "Topic :: Scientific/Engineering", "Topic :: Software Development", ] -[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" +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` and `poetry export --with docs --without-hashes --format=requirements.txt > docs/requirements.txt` [tool.poetry.group.docs] @@ -61,6 +62,8 @@ sphinx_rtd_theme = "^1.3.0" 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] From 8ad90f7ca1bda129205facb56b402d1c45017ea1 Mon Sep 17 00:00:00 2001 From: fjwillemsen Date: Fri, 14 Feb 2025 09:48:27 +0100 Subject: [PATCH 28/41] Updated setuptools, updated dependencies --- poetry.lock | 69 +++++++++++++++++++++++++++++++++++++++++++++----- pyproject.toml | 4 +-- 2 files changed, 64 insertions(+), 9 deletions(-) diff --git a/poetry.lock b/poetry.lock index 1332c01..d44d648 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.0.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"}, @@ -17,6 +18,7 @@ version = "3.5.3" 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"}, @@ -31,6 +33,7 @@ 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"}, @@ -45,6 +48,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 +60,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 +162,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 +175,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"}, @@ -185,6 +193,7 @@ version = "7.6.12" description = "Code coverage measurement for Python" optional = false python-versions = ">=3.9" +groups = ["test"] files = [ {file = "coverage-7.6.12-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:704c8c8c6ce6569286ae9622e534b4f5b9759b6f2cd643f1c1a61f666d534fe8"}, {file = "coverage-7.6.12-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:ad7525bf0241e5502168ae9c643a2f6c219fa0a283001cee4cf23a9b7da75879"}, @@ -263,6 +272,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"}, @@ -336,6 +346,7 @@ 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"}, @@ -347,6 +358,7 @@ version = "0.18.1" description = "Docutils -- Python Documentation Utilities" optional = false python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" +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"}, @@ -358,6 +370,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"}, @@ -369,13 +382,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] @@ -392,6 +406,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"}, @@ -406,6 +422,7 @@ version = "3.17.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"}, @@ -422,6 +439,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"}, @@ -436,6 +454,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"}, @@ -447,6 +466,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"}, @@ -470,6 +491,7 @@ version = "2.0.0" description = "brain-dead simple config-ini parsing" optional = false python-versions = ">=3.7" +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"}, @@ -481,6 +503,7 @@ version = "3.1.5" 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"}, @@ -498,6 +521,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"}, @@ -568,6 +592,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"}, @@ -583,6 +608,7 @@ version = "2024.10.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"}, @@ -605,6 +631,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"}, @@ -616,6 +643,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"}, @@ -631,6 +659,7 @@ version = "4.3.6" description = "A small Python package for determining appropriate platform-specific dirs, e.g. a `user data dir`." optional = false python-versions = ">=3.8" +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"}, @@ -647,6 +676,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"}, @@ -662,6 +692,7 @@ 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"}, @@ -673,6 +704,7 @@ 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"}, @@ -687,6 +719,7 @@ version = "8.3.4" 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"}, @@ -709,6 +742,7 @@ 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"}, @@ -729,6 +763,7 @@ 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"}, @@ -747,6 +782,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"}, @@ -768,6 +804,7 @@ version = "0.7.4" 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"}, @@ -795,6 +832,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"}, @@ -806,6 +844,7 @@ version = "7.3.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"}, @@ -842,6 +881,7 @@ version = "1.25.3" description = "Type hints (PEP 484) support for the Sphinx autodoc extension" optional = false python-versions = ">=3.8" +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"}, @@ -861,6 +901,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"}, @@ -876,6 +917,7 @@ version = "1.3.0" 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" +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"}, @@ -895,6 +937,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"}, @@ -911,6 +954,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"}, @@ -927,6 +971,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"}, @@ -943,6 +988,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"}, @@ -957,6 +1003,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"}, @@ -971,6 +1018,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"}, @@ -987,6 +1035,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"}, @@ -1003,6 +1052,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"}, @@ -1044,6 +1094,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"}, @@ -1055,6 +1106,7 @@ 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"}, @@ -1072,6 +1124,7 @@ version = "20.29.2" 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"}, @@ -1092,6 +1145,8 @@ 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"}, @@ -1106,6 +1161,6 @@ test = ["big-O", "importlib-resources", "jaraco.functools", "jaraco.itertools", type = ["pytest-mypy"] [metadata] -lock-version = "2.0" -python-versions = ">=3.9,<3.15" -content-hash = "ea292d92d9b2e84e7875683b8144dea8124bc26c86212c9b2f75086467afa803" +lock-version = "2.1" +python-versions = ">= 3.9" +content-hash = "19b7703ecb50804de3375743f231fed2c035247074a50c038b2b9746533c0b44" diff --git a/pyproject.toml b/pyproject.toml index 495a2b2..c9de916 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [build-system] -requires = ["poetry-core>=2.0.1", "setuptools>=67.7.2", "Cython>=3.0.12"] -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" [project] name = "python-constraint2" # when set back to "python-constraint", don't forget to remove '2' in other places (e.g. README) From 8c0039a6b299d44e7e6827ac4d8d8fd1369d14b2 Mon Sep 17 00:00:00 2001 From: fjwillemsen Date: Fri, 14 Feb 2025 09:51:37 +0100 Subject: [PATCH 29/41] Updated test dependendencies --- poetry.lock | 89 ++++++++++++++++++++++++++++++++++++-------------- pyproject.toml | 6 ++-- 2 files changed, 68 insertions(+), 27 deletions(-) diff --git a/poetry.lock b/poetry.lock index d44d648..6f28a5a 100644 --- a/poetry.lock +++ b/poetry.lock @@ -27,6 +27,26 @@ files = [ [package.extras] test = ["coverage", "mypy", "pexpect", "ruff", "wheel"] +[[package]] +name = "attrs" +version = "25.1.0" +description = "Classes Without Boilerplate" +optional = false +python-versions = ">=3.8" +groups = ["test"] +files = [ + {file = "attrs-25.1.0-py3-none-any.whl", hash = "sha256:c75a69e28a550a7e93789579c22aa26b0f5b83b75dc4e08fe092980051e1090a"}, + {file = "attrs-25.1.0.tar.gz", hash = "sha256:1c97078a80c814273a76b2a298a932eb681c87415c11dee0a6921de7f1b02c3e"}, +] + +[package.extras] +benchmark = ["cloudpickle", "hypothesis", "mypy (>=1.11.1)", "pympler", "pytest (>=4.3.0)", "pytest-codspeed", "pytest-mypy-plugins", "pytest-xdist[psutil]"] +cov = ["cloudpickle", "coverage[toml] (>=5.3)", "hypothesis", "mypy (>=1.11.1)", "pympler", "pytest (>=4.3.0)", "pytest-mypy-plugins", "pytest-xdist[psutil]"] +dev = ["cloudpickle", "hypothesis", "mypy (>=1.11.1)", "pre-commit-uv", "pympler", "pytest (>=4.3.0)", "pytest-mypy-plugins", "pytest-xdist[psutil]"] +docs = ["cogapp", "furo", "myst-parser", "sphinx", "sphinx-notfound-page", "sphinxcontrib-towncrier", "towncrier (<24.7)"] +tests = ["cloudpickle", "hypothesis", "mypy (>=1.11.1)", "pympler", "pytest (>=4.3.0)", "pytest-mypy-plugins", "pytest-xdist[psutil]"] +tests-mypy = ["mypy (>=1.11.1)", "pytest-mypy-plugins"] + [[package]] name = "babel" version = "2.17.0" @@ -340,6 +360,25 @@ 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"] + [[package]] name = "distlib" version = "0.3.9" @@ -604,25 +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", "jinja2", "tox (>=4)"] uv = ["uv (>=0.1.6)"] [[package]] @@ -800,30 +841,30 @@ use-chardet-on-py3 = ["chardet (>=3.0.2,<6)"] [[package]] name = "ruff" -version = "0.7.4" +version = "0.9.6" 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.6-py3-none-linux_armv6l.whl", hash = "sha256:2f218f356dd2d995839f1941322ff021c72a492c470f0b26a34f844c29cdf5ba"}, + {file = "ruff-0.9.6-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:b908ff4df65dad7b251c9968a2e4560836d8f5487c2f0cc238321ed951ea0504"}, + {file = "ruff-0.9.6-py3-none-macosx_11_0_arm64.whl", hash = "sha256:b109c0ad2ececf42e75fa99dc4043ff72a357436bb171900714a9ea581ddef83"}, + {file = "ruff-0.9.6-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1de4367cca3dac99bcbd15c161404e849bb0bfd543664db39232648dc00112dc"}, + {file = "ruff-0.9.6-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:ac3ee4d7c2c92ddfdaedf0bf31b2b176fa7aa8950efc454628d477394d35638b"}, + {file = "ruff-0.9.6-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:5dc1edd1775270e6aa2386119aea692039781429f0be1e0949ea5884e011aa8e"}, + {file = "ruff-0.9.6-py3-none-manylinux_2_17_ppc64.manylinux2014_ppc64.whl", hash = "sha256:4a091729086dffa4bd070aa5dab7e39cc6b9d62eb2bef8f3d91172d30d599666"}, + {file = "ruff-0.9.6-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:d1bbc6808bf7b15796cef0815e1dfb796fbd383e7dbd4334709642649625e7c5"}, + {file = "ruff-0.9.6-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:589d1d9f25b5754ff230dce914a174a7c951a85a4e9270613a2b74231fdac2f5"}, + {file = "ruff-0.9.6-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:dc61dd5131742e21103fbbdcad683a8813be0e3c204472d520d9a5021ca8b217"}, + {file = "ruff-0.9.6-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:5e2d9126161d0357e5c8f30b0bd6168d2c3872372f14481136d13de9937f79b6"}, + {file = "ruff-0.9.6-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:68660eab1a8e65babb5229a1f97b46e3120923757a68b5413d8561f8a85d4897"}, + {file = "ruff-0.9.6-py3-none-musllinux_1_2_i686.whl", hash = "sha256:c4cae6c4cc7b9b4017c71114115db0445b00a16de3bcde0946273e8392856f08"}, + {file = "ruff-0.9.6-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:19f505b643228b417c1111a2a536424ddde0db4ef9023b9e04a46ed8a1cb4656"}, + {file = "ruff-0.9.6-py3-none-win32.whl", hash = "sha256:194d8402bceef1b31164909540a597e0d913c0e4952015a5b40e28c146121b5d"}, + {file = "ruff-0.9.6-py3-none-win_amd64.whl", hash = "sha256:03482d5c09d90d4ee3f40d97578423698ad895c87314c4de39ed2af945633caa"}, + {file = "ruff-0.9.6-py3-none-win_arm64.whl", hash = "sha256:0e2bb706a2be7ddfea4a4af918562fdc1bcb16df255e5fa595bbd800ce322a5a"}, + {file = "ruff-0.9.6.tar.gz", hash = "sha256:81761592f72b620ec8fa1068a6fd00e98a5ebee342a3642efd84454f3031dca9"}, ] [[package]] @@ -1163,4 +1204,4 @@ type = ["pytest-mypy"] [metadata] lock-version = "2.1" python-versions = ">= 3.9" -content-hash = "19b7703ecb50804de3375743f231fed2c035247074a50c038b2b9746533c0b44" +content-hash = "ab95f20c9c35baccf4a61ff699d1942de0e06ef9f91c3209189c043f3f6a4d89" diff --git a/pyproject.toml b/pyproject.toml index c9de916..4dd519b 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -70,10 +70,10 @@ optional = true 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` From f0e95b44f17c0123534bb874c4f3b3e0a040de20 Mon Sep 17 00:00:00 2001 From: fjwillemsen Date: Fri, 14 Feb 2025 13:23:26 +0100 Subject: [PATCH 30/41] warning when using GIL in non-threaded mode --- constraint/problem.py | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/constraint/problem.py b/constraint/problem.py index 6428c31..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.""" @@ -32,6 +38,8 @@ def __init__(self, solver: Solver=None): # 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. From cc26aadcd803eeac30e0fa69fc994baa231c90b9 Mon Sep 17 00:00:00 2001 From: Floris-Jan Willemsen Date: Fri, 14 Feb 2025 13:31:43 +0100 Subject: [PATCH 31/41] Update pyproject.toml --- pyproject.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pyproject.toml b/pyproject.toml index 4dd519b..0d27807 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -50,7 +50,7 @@ packages = [ [tool.poetry.build] generate-setup-file = false -# script = "cythonize_build.py" +script = "cythonize_build.py" # 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] From cc3ac536168b2b9e5532ec4d0afc7af3b0477001 Mon Sep 17 00:00:00 2001 From: fjwillemsen Date: Fri, 14 Feb 2025 14:10:14 +0100 Subject: [PATCH 32/41] Updated documentation building dependencies --- poetry.lock | 66 +++++++++++++++++++++++++------------------------- pyproject.toml | 6 ++--- 2 files changed, 36 insertions(+), 36 deletions(-) diff --git a/poetry.lock b/poetry.lock index 6f28a5a..45fc111 100644 --- a/poetry.lock +++ b/poetry.lock @@ -393,14 +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]] @@ -881,28 +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" @@ -913,28 +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" @@ -954,23 +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" @@ -1204,4 +1204,4 @@ type = ["pytest-mypy"] [metadata] lock-version = "2.1" python-versions = ">= 3.9" -content-hash = "ab95f20c9c35baccf4a61ff699d1942de0e06ef9f91c3209189c043f3f6a4d89" +content-hash = "38fbbe57866b8c63e3de60d3edef54a30fe5fe3e5274d4423caeb0afe9cda15c" diff --git a/pyproject.toml b/pyproject.toml index 0d27807..b886e5c 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -56,9 +56,9 @@ script = "cythonize_build.py" [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` From 115c1f6e8def449373e0929d33740ea55a002fa7 Mon Sep 17 00:00:00 2001 From: fjwillemsen Date: Fri, 14 Feb 2025 14:12:46 +0100 Subject: [PATCH 33/41] Updated documentation building dependencies --- docs/requirements.txt | 62 +++++++++++++++++++++---------------------- 1 file changed, 31 insertions(+), 31 deletions(-) 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" From bfae2a96d7df93d5c6ac2ca388ef623c0df4e5c2 Mon Sep 17 00:00:00 2001 From: fjwillemsen Date: Fri, 14 Feb 2025 14:25:18 +0100 Subject: [PATCH 34/41] Switched from poetry to pep621 SphinxConnfig style --- docs/conf.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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" From c85aed572165c1202318592e8b99d603e206d646 Mon Sep 17 00:00:00 2001 From: fjwillemsen Date: Fri, 14 Feb 2025 16:53:18 +0100 Subject: [PATCH 35/41] Renamed and improvements to benchmark tests --- tests/{test_benchmark.py => test_util_benchmark.py} | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) rename tests/{test_benchmark.py => test_util_benchmark.py} (96%) diff --git a/tests/test_benchmark.py b/tests/test_util_benchmark.py similarity index 96% rename from tests/test_benchmark.py rename to tests/test_util_benchmark.py index 8cb07a3..f23ff1e 100644 --- a/tests/test_benchmark.py +++ b/tests/test_util_benchmark.py @@ -1,7 +1,9 @@ +"""Test run times with benchmarks against reference times. File is called test_util_benchmarks to be ran as last test.""" + from random import random from time import perf_counter import pytest -from constraint import Problem +from constraint import Problem, ParallelSolver from math import sqrt @@ -131,7 +133,7 @@ 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"Reference: {round(reference_result, 3)}, benchmark: {round(mean, 3)}, expected: {round(reference_result * performance_factor, 3)}") + print(f"Benchmark {benchmark_name}: reference: {round(reference_result, 3)}, run: {round(mean, 3)}, expected: {round(reference_result * performance_factor, 3)}") def test_microhh(benchmark): @@ -170,7 +172,6 @@ def test_microhh(benchmark): # run the benchmark and check for valid outcome and performance degradation solutions = benchmark(problem.getSolutions) - reference_result = reference_results[benchmark_name] benchmark_result = benchmark.stats.stats.mean benchmark_results[benchmark_name] = benchmark_result assert len(solutions) == 138600 @@ -202,7 +203,6 @@ def test_dedispersion(benchmark): # run the benchmark and check for valid outcome and performance degradation solutions = benchmark(problem.getSolutions) - reference_result = reference_results[benchmark_name] benchmark_result = benchmark.stats.stats.mean benchmark_results[benchmark_name] = benchmark_result assert len(solutions) == 11130 @@ -240,7 +240,6 @@ def test_hotspot(benchmark): # run the benchmark and check for valid outcome and performance degradation solutions = benchmark(problem.getSolutions) - reference_result = reference_results[benchmark_name] benchmark_result = benchmark.stats.stats.mean benchmark_results[benchmark_name] = benchmark_result assert len(solutions) == 349853 From 2a2cdcf4b5d063dc69a0f9d9e2925ef4ac9c89e1 Mon Sep 17 00:00:00 2001 From: fjwillemsen Date: Fri, 14 Feb 2025 17:03:47 +0100 Subject: [PATCH 36/41] Moved benchmarks to separate files for reusability --- tests/benchmarks.py | 109 +++++++++++++++++++++++++++++++++++ tests/test_util_benchmark.py | 104 +++------------------------------ 2 files changed, 118 insertions(+), 95 deletions(-) create mode 100644 tests/benchmarks.py 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 index f23ff1e..969fa83 100644 --- a/tests/test_util_benchmark.py +++ b/tests/test_util_benchmark.py @@ -1,11 +1,12 @@ """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 -import pytest -from constraint import Problem, ParallelSolver 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 @@ -14,16 +15,6 @@ "dedispersion": 0.1171140, "hotspot": 2.6839208, } -# 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, -} # collect benchmark times benchmark_results = dict() @@ -137,110 +128,33 @@ def check_benchmark_performance(benchmark_name, mean, std): def test_microhh(benchmark): - """Based on the MicroHH search space in the paper.""" - benchmark_name = "microhh" - - 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}", - ]) + benchmark_name, problem, expected_num_solutions = microhh() # run the benchmark and check for valid outcome and performance degradation solutions = benchmark(problem.getSolutions) benchmark_result = benchmark.stats.stats.mean benchmark_results[benchmark_name] = benchmark_result - assert len(solutions) == 138600 + assert len(solutions) == expected_num_solutions check_benchmark_performance(benchmark_name, benchmark_result, benchmark.stats.stats.stddev) def test_dedispersion(benchmark): - """Based on the Dedispersion search space in the paper.""" - benchmark_name = "dedispersion" - - # 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]) + benchmark_name, problem, expected_num_solutions = dedispersion() # run the benchmark and check for valid outcome and performance degradation solutions = benchmark(problem.getSolutions) benchmark_result = benchmark.stats.stats.mean benchmark_results[benchmark_name] = benchmark_result - assert len(solutions) == 11130 + assert len(solutions) == expected_num_solutions check_benchmark_performance(benchmark_name, benchmark_result, benchmark.stats.stats.stddev) def test_hotspot(benchmark): - """Based on the Hotspot search space in the paper.""" - benchmark_name = "hotspot" - - # 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']})", - ]) + benchmark_name, problem, expected_num_solutions = hotspot() # run the benchmark and check for valid outcome and performance degradation solutions = benchmark(problem.getSolutions) benchmark_result = benchmark.stats.stats.mean benchmark_results[benchmark_name] = benchmark_result - assert len(solutions) == 349853 + assert len(solutions) == expected_num_solutions check_benchmark_performance(benchmark_name, benchmark_result, benchmark.stats.stats.stddev) From d81ec4c018293799555146484f3225def22b045d Mon Sep 17 00:00:00 2001 From: fjwillemsen Date: Fri, 14 Feb 2025 17:15:10 +0100 Subject: [PATCH 37/41] Much simplified benchmark test interface --- tests/test_util_benchmark.py | 32 ++++++++++---------------------- 1 file changed, 10 insertions(+), 22 deletions(-) diff --git a/tests/test_util_benchmark.py b/tests/test_util_benchmark.py index 969fa83..39b4ee0 100644 --- a/tests/test_util_benchmark.py +++ b/tests/test_util_benchmark.py @@ -126,35 +126,23 @@ def check_benchmark_performance(benchmark_name, mean, std): 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)}") - -def test_microhh(benchmark): - benchmark_name, problem, expected_num_solutions = microhh() - - # run the benchmark and check for valid outcome and performance degradation +@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): - benchmark_name, problem, expected_num_solutions = dedispersion() - - # run the benchmark and check for valid outcome and performance degradation - solutions = benchmark(problem.getSolutions) - benchmark_result = benchmark.stats.stats.mean - benchmark_results[benchmark_name] = benchmark_result - assert len(solutions) == expected_num_solutions - check_benchmark_performance(benchmark_name, benchmark_result, benchmark.stats.stats.stddev) - + run_and_check_benchmark(benchmark, *dedispersion()) def test_hotspot(benchmark): - benchmark_name, problem, expected_num_solutions = hotspot() - - # run the benchmark and check for valid outcome and performance degradation - solutions = benchmark(problem.getSolutions) - benchmark_result = benchmark.stats.stats.mean - benchmark_results[benchmark_name] = benchmark_result - assert len(solutions) == expected_num_solutions - check_benchmark_performance(benchmark_name, benchmark_result, benchmark.stats.stats.stddev) + run_and_check_benchmark(benchmark, *hotspot()) From 3d8bdc956b76fac945b1d1f4da4e1dc770c059a7 Mon Sep 17 00:00:00 2001 From: fjwillemsen Date: Fri, 14 Feb 2025 17:26:53 +0100 Subject: [PATCH 38/41] Updated roadmap in readme --- README.rst | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) 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 From 016d6c9088528b34da81ffab6e7c6c1ba2e6c077 Mon Sep 17 00:00:00 2001 From: Floris-Jan Willemsen Date: Tue, 25 Mar 2025 11:05:44 +0100 Subject: [PATCH 39/41] Updated dependencies --- poetry.lock | 260 ++++++++++++++++++++++++++-------------------------- 1 file changed, 130 insertions(+), 130 deletions(-) diff --git a/poetry.lock b/poetry.lock index 45fc111..bcd104c 100644 --- a/poetry.lock +++ b/poetry.lock @@ -1,4 +1,4 @@ -# This file is automatically @generated by Poetry 2.0.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" @@ -14,14 +14,14 @@ 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] @@ -29,23 +29,23 @@ test = ["coverage", "mypy", "pexpect", "ruff", "wheel"] [[package]] name = "attrs" -version = "25.1.0" +version = "25.3.0" description = "Classes Without Boilerplate" optional = false python-versions = ">=3.8" groups = ["test"] files = [ - {file = "attrs-25.1.0-py3-none-any.whl", hash = "sha256:c75a69e28a550a7e93789579c22aa26b0f5b83b75dc4e08fe092980051e1090a"}, - {file = "attrs-25.1.0.tar.gz", hash = "sha256:1c97078a80c814273a76b2a298a932eb681c87415c11dee0a6921de7f1b02c3e"}, + {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", "hypothesis", "mypy (>=1.11.1)", "pympler", "pytest (>=4.3.0)", "pytest-codspeed", "pytest-mypy-plugins", "pytest-xdist[psutil]"] -cov = ["cloudpickle", "coverage[toml] (>=5.3)", "hypothesis", "mypy (>=1.11.1)", "pympler", "pytest (>=4.3.0)", "pytest-mypy-plugins", "pytest-xdist[psutil]"] -dev = ["cloudpickle", "hypothesis", "mypy (>=1.11.1)", "pre-commit-uv", "pympler", "pytest (>=4.3.0)", "pytest-mypy-plugins", "pytest-xdist[psutil]"] -docs = ["cogapp", "furo", "myst-parser", "sphinx", "sphinx-notfound-page", "sphinxcontrib-towncrier", "towncrier (<24.7)"] -tests = ["cloudpickle", "hypothesis", "mypy (>=1.11.1)", "pympler", "pytest (>=4.3.0)", "pytest-mypy-plugins", "pytest-xdist[psutil]"] -tests-mypy = ["mypy (>=1.11.1)", "pytest-mypy-plugins"] +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" @@ -60,7 +60,7 @@ files = [ ] [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" @@ -209,82 +209,82 @@ development = ["black", "flake8", "mypy", "pytest", "types-colorama"] [[package]] name = "coverage" -version = "7.6.12" +version = "7.7.1" description = "Code coverage measurement for Python" optional = false python-versions = ">=3.9" groups = ["test"] files = [ - {file = "coverage-7.6.12-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:704c8c8c6ce6569286ae9622e534b4f5b9759b6f2cd643f1c1a61f666d534fe8"}, - {file = "coverage-7.6.12-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:ad7525bf0241e5502168ae9c643a2f6c219fa0a283001cee4cf23a9b7da75879"}, - {file = "coverage-7.6.12-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:06097c7abfa611c91edb9e6920264e5be1d6ceb374efb4986f38b09eed4cb2fe"}, - {file = "coverage-7.6.12-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:220fa6c0ad7d9caef57f2c8771918324563ef0d8272c94974717c3909664e674"}, - {file = "coverage-7.6.12-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3688b99604a24492bcfe1c106278c45586eb819bf66a654d8a9a1433022fb2eb"}, - {file = "coverage-7.6.12-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:d1a987778b9c71da2fc8948e6f2656da6ef68f59298b7e9786849634c35d2c3c"}, - {file = "coverage-7.6.12-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:cec6b9ce3bd2b7853d4a4563801292bfee40b030c05a3d29555fd2a8ee9bd68c"}, - {file = "coverage-7.6.12-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:ace9048de91293e467b44bce0f0381345078389814ff6e18dbac8fdbf896360e"}, - {file = "coverage-7.6.12-cp310-cp310-win32.whl", hash = "sha256:ea31689f05043d520113e0552f039603c4dd71fa4c287b64cb3606140c66f425"}, - {file = "coverage-7.6.12-cp310-cp310-win_amd64.whl", hash = "sha256:676f92141e3c5492d2a1596d52287d0d963df21bf5e55c8b03075a60e1ddf8aa"}, - {file = "coverage-7.6.12-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:e18aafdfb3e9ec0d261c942d35bd7c28d031c5855dadb491d2723ba54f4c3015"}, - {file = "coverage-7.6.12-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:66fe626fd7aa5982cdebad23e49e78ef7dbb3e3c2a5960a2b53632f1f703ea45"}, - {file = "coverage-7.6.12-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0ef01d70198431719af0b1f5dcbefc557d44a190e749004042927b2a3fed0702"}, - {file = "coverage-7.6.12-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:07e92ae5a289a4bc4c0aae710c0948d3c7892e20fd3588224ebe242039573bf0"}, - {file = "coverage-7.6.12-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e695df2c58ce526eeab11a2e915448d3eb76f75dffe338ea613c1201b33bab2f"}, - {file = "coverage-7.6.12-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:d74c08e9aaef995f8c4ef6d202dbd219c318450fe2a76da624f2ebb9c8ec5d9f"}, - {file = "coverage-7.6.12-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:e995b3b76ccedc27fe4f477b349b7d64597e53a43fc2961db9d3fbace085d69d"}, - {file = "coverage-7.6.12-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:b1f097878d74fe51e1ddd1be62d8e3682748875b461232cf4b52ddc6e6db0bba"}, - {file = "coverage-7.6.12-cp311-cp311-win32.whl", hash = "sha256:1f7ffa05da41754e20512202c866d0ebfc440bba3b0ed15133070e20bf5aeb5f"}, - {file = "coverage-7.6.12-cp311-cp311-win_amd64.whl", hash = "sha256:e216c5c45f89ef8971373fd1c5d8d1164b81f7f5f06bbf23c37e7908d19e8558"}, - {file = "coverage-7.6.12-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:b172f8e030e8ef247b3104902cc671e20df80163b60a203653150d2fc204d1ad"}, - {file = "coverage-7.6.12-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:641dfe0ab73deb7069fb972d4d9725bf11c239c309ce694dd50b1473c0f641c3"}, - {file = "coverage-7.6.12-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0e549f54ac5f301e8e04c569dfdb907f7be71b06b88b5063ce9d6953d2d58574"}, - {file = "coverage-7.6.12-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:959244a17184515f8c52dcb65fb662808767c0bd233c1d8a166e7cf74c9ea985"}, - {file = "coverage-7.6.12-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bda1c5f347550c359f841d6614fb8ca42ae5cb0b74d39f8a1e204815ebe25750"}, - {file = "coverage-7.6.12-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:1ceeb90c3eda1f2d8c4c578c14167dbd8c674ecd7d38e45647543f19839dd6ea"}, - {file = "coverage-7.6.12-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:0f16f44025c06792e0fb09571ae454bcc7a3ec75eeb3c36b025eccf501b1a4c3"}, - {file = "coverage-7.6.12-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:b076e625396e787448d27a411aefff867db2bffac8ed04e8f7056b07024eed5a"}, - {file = "coverage-7.6.12-cp312-cp312-win32.whl", hash = "sha256:00b2086892cf06c7c2d74983c9595dc511acca00665480b3ddff749ec4fb2a95"}, - {file = "coverage-7.6.12-cp312-cp312-win_amd64.whl", hash = "sha256:7ae6eabf519bc7871ce117fb18bf14e0e343eeb96c377667e3e5dd12095e0288"}, - {file = "coverage-7.6.12-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:488c27b3db0ebee97a830e6b5a3ea930c4a6e2c07f27a5e67e1b3532e76b9ef1"}, - {file = "coverage-7.6.12-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:5d1095bbee1851269f79fd8e0c9b5544e4c00c0c24965e66d8cba2eb5bb535fd"}, - {file = "coverage-7.6.12-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0533adc29adf6a69c1baa88c3d7dbcaadcffa21afbed3ca7a225a440e4744bf9"}, - {file = "coverage-7.6.12-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:53c56358d470fa507a2b6e67a68fd002364d23c83741dbc4c2e0680d80ca227e"}, - {file = "coverage-7.6.12-cp313-cp313-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:64cbb1a3027c79ca6310bf101014614f6e6e18c226474606cf725238cf5bc2d4"}, - {file = "coverage-7.6.12-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:79cac3390bfa9836bb795be377395f28410811c9066bc4eefd8015258a7578c6"}, - {file = "coverage-7.6.12-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:9b148068e881faa26d878ff63e79650e208e95cf1c22bd3f77c3ca7b1d9821a3"}, - {file = "coverage-7.6.12-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:8bec2ac5da793c2685ce5319ca9bcf4eee683b8a1679051f8e6ec04c4f2fd7dc"}, - {file = "coverage-7.6.12-cp313-cp313-win32.whl", hash = "sha256:200e10beb6ddd7c3ded322a4186313d5ca9e63e33d8fab4faa67ef46d3460af3"}, - {file = "coverage-7.6.12-cp313-cp313-win_amd64.whl", hash = "sha256:2b996819ced9f7dbb812c701485d58f261bef08f9b85304d41219b1496b591ef"}, - {file = "coverage-7.6.12-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:299cf973a7abff87a30609879c10df0b3bfc33d021e1adabc29138a48888841e"}, - {file = "coverage-7.6.12-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:4b467a8c56974bf06e543e69ad803c6865249d7a5ccf6980457ed2bc50312703"}, - {file = "coverage-7.6.12-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2458f275944db8129f95d91aee32c828a408481ecde3b30af31d552c2ce284a0"}, - {file = "coverage-7.6.12-cp313-cp313t-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:0a9d8be07fb0832636a0f72b80d2a652fe665e80e720301fb22b191c3434d924"}, - {file = "coverage-7.6.12-cp313-cp313t-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:14d47376a4f445e9743f6c83291e60adb1b127607a3618e3185bbc8091f0467b"}, - {file = "coverage-7.6.12-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:b95574d06aa9d2bd6e5cc35a5bbe35696342c96760b69dc4287dbd5abd4ad51d"}, - {file = "coverage-7.6.12-cp313-cp313t-musllinux_1_2_i686.whl", hash = "sha256:ecea0c38c9079570163d663c0433a9af4094a60aafdca491c6a3d248c7432827"}, - {file = "coverage-7.6.12-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:2251fabcfee0a55a8578a9d29cecfee5f2de02f11530e7d5c5a05859aa85aee9"}, - {file = "coverage-7.6.12-cp313-cp313t-win32.whl", hash = "sha256:eb5507795caabd9b2ae3f1adc95f67b1104971c22c624bb354232d65c4fc90b3"}, - {file = "coverage-7.6.12-cp313-cp313t-win_amd64.whl", hash = "sha256:f60a297c3987c6c02ffb29effc70eadcbb412fe76947d394a1091a3615948e2f"}, - {file = "coverage-7.6.12-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:e7575ab65ca8399c8c4f9a7d61bbd2d204c8b8e447aab9d355682205c9dd948d"}, - {file = "coverage-7.6.12-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:8161d9fbc7e9fe2326de89cd0abb9f3599bccc1287db0aba285cb68d204ce929"}, - {file = "coverage-7.6.12-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3a1e465f398c713f1b212400b4e79a09829cd42aebd360362cd89c5bdc44eb87"}, - {file = "coverage-7.6.12-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f25d8b92a4e31ff1bd873654ec367ae811b3a943583e05432ea29264782dc32c"}, - {file = "coverage-7.6.12-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1a936309a65cc5ca80fa9f20a442ff9e2d06927ec9a4f54bcba9c14c066323f2"}, - {file = "coverage-7.6.12-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:aa6f302a3a0b5f240ee201297fff0bbfe2fa0d415a94aeb257d8b461032389bd"}, - {file = "coverage-7.6.12-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:f973643ef532d4f9be71dd88cf7588936685fdb576d93a79fe9f65bc337d9d73"}, - {file = "coverage-7.6.12-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:78f5243bb6b1060aed6213d5107744c19f9571ec76d54c99cc15938eb69e0e86"}, - {file = "coverage-7.6.12-cp39-cp39-win32.whl", hash = "sha256:69e62c5034291c845fc4df7f8155e8544178b6c774f97a99e2734b05eb5bed31"}, - {file = "coverage-7.6.12-cp39-cp39-win_amd64.whl", hash = "sha256:b01a840ecc25dce235ae4c1b6a0daefb2a203dba0e6e980637ee9c2f6ee0df57"}, - {file = "coverage-7.6.12-pp39.pp310-none-any.whl", hash = "sha256:7e39e845c4d764208e7b8f6a21c541ade741e2c41afabdfa1caa28687a3c98cf"}, - {file = "coverage-7.6.12-py3-none-any.whl", hash = "sha256:eb8668cfbc279a536c633137deeb9435d2962caec279c3f8cf8b91fff6ff8953"}, - {file = "coverage-7.6.12.tar.gz", hash = "sha256:48cfc4641d95d34766ad41d9573cc0f22a48aa88d22657a1fe01dca0dbae4de2"}, + {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" @@ -377,7 +377,7 @@ packaging = "*" tomli = {version = "*", markers = "python_version < \"3.11\""} [package.extras] -cli = ["tomli"] +cli = ["tomli ; python_version < \"3.11\""] [[package]] name = "distlib" @@ -457,20 +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" @@ -516,36 +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] @@ -663,7 +663,7 @@ tomli = {version = ">=1", markers = "python_version < \"3.11\""} virtualenv = ">=20.14.1" [package.extras] -tox-to-nox = ["importlib-resources", "jinja2", "tox (>=4)"] +tox-to-nox = ["importlib-resources ; python_version < \"3.9\"", "jinja2", "tox (>=4)"] uv = ["uv (>=0.1.6)"] [[package]] @@ -696,20 +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" @@ -756,14 +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] @@ -841,30 +841,30 @@ use-chardet-on-py3 = ["chardet (>=3.0.2,<6)"] [[package]] name = "ruff" -version = "0.9.6" +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.9.6-py3-none-linux_armv6l.whl", hash = "sha256:2f218f356dd2d995839f1941322ff021c72a492c470f0b26a34f844c29cdf5ba"}, - {file = "ruff-0.9.6-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:b908ff4df65dad7b251c9968a2e4560836d8f5487c2f0cc238321ed951ea0504"}, - {file = "ruff-0.9.6-py3-none-macosx_11_0_arm64.whl", hash = "sha256:b109c0ad2ececf42e75fa99dc4043ff72a357436bb171900714a9ea581ddef83"}, - {file = "ruff-0.9.6-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1de4367cca3dac99bcbd15c161404e849bb0bfd543664db39232648dc00112dc"}, - {file = "ruff-0.9.6-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:ac3ee4d7c2c92ddfdaedf0bf31b2b176fa7aa8950efc454628d477394d35638b"}, - {file = "ruff-0.9.6-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:5dc1edd1775270e6aa2386119aea692039781429f0be1e0949ea5884e011aa8e"}, - {file = "ruff-0.9.6-py3-none-manylinux_2_17_ppc64.manylinux2014_ppc64.whl", hash = "sha256:4a091729086dffa4bd070aa5dab7e39cc6b9d62eb2bef8f3d91172d30d599666"}, - {file = "ruff-0.9.6-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:d1bbc6808bf7b15796cef0815e1dfb796fbd383e7dbd4334709642649625e7c5"}, - {file = "ruff-0.9.6-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:589d1d9f25b5754ff230dce914a174a7c951a85a4e9270613a2b74231fdac2f5"}, - {file = "ruff-0.9.6-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:dc61dd5131742e21103fbbdcad683a8813be0e3c204472d520d9a5021ca8b217"}, - {file = "ruff-0.9.6-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:5e2d9126161d0357e5c8f30b0bd6168d2c3872372f14481136d13de9937f79b6"}, - {file = "ruff-0.9.6-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:68660eab1a8e65babb5229a1f97b46e3120923757a68b5413d8561f8a85d4897"}, - {file = "ruff-0.9.6-py3-none-musllinux_1_2_i686.whl", hash = "sha256:c4cae6c4cc7b9b4017c71114115db0445b00a16de3bcde0946273e8392856f08"}, - {file = "ruff-0.9.6-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:19f505b643228b417c1111a2a536424ddde0db4ef9023b9e04a46ed8a1cb4656"}, - {file = "ruff-0.9.6-py3-none-win32.whl", hash = "sha256:194d8402bceef1b31164909540a597e0d913c0e4952015a5b40e28c146121b5d"}, - {file = "ruff-0.9.6-py3-none-win_amd64.whl", hash = "sha256:03482d5c09d90d4ee3f40d97578423698ad895c87314c4de39ed2af945633caa"}, - {file = "ruff-0.9.6-py3-none-win_arm64.whl", hash = "sha256:0e2bb706a2be7ddfea4a4af918562fdc1bcb16df255e5fa595bbd800ce322a5a"}, - {file = "ruff-0.9.6.tar.gz", hash = "sha256:81761592f72b620ec8fa1068a6fd00e98a5ebee342a3642efd84454f3031dca9"}, + {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]] @@ -1154,21 +1154,21 @@ files = [ ] [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] @@ -1178,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" @@ -1194,11 +1194,11 @@ files = [ ] [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] From 452e71db0a6d95f614eb5e4f5e987c638eee2671 Mon Sep 17 00:00:00 2001 From: Floris-Jan Willemsen Date: Tue, 25 Mar 2025 11:10:24 +0100 Subject: [PATCH 40/41] Bumped version --- pyproject.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pyproject.toml b/pyproject.toml index b886e5c..eba70b9 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -5,7 +5,7 @@ build-backend = "poetry.core.masonry.api" [project] name = "python-constraint2" # when set back to "python-constraint", don't forget to remove '2' in other places (e.g. README) 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 = [ {name = "Gustavo Niemeyer", email = "gustavo@niemeyer.net"}, {name = "Sébastien Celles", email = "s.celles@gmail.com"}, From bfac27958a091fb874ed27f064e65bd5e86bc73e Mon Sep 17 00:00:00 2001 From: Floris-Jan Willemsen Date: Tue, 25 Mar 2025 11:23:41 +0100 Subject: [PATCH 41/41] Changed development status from beta to production --- pyproject.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pyproject.toml b/pyproject.toml index eba70b9..06bafb6 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -26,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",