From 0adc1c583a33b5a55b4ef73be684da3033c31ead Mon Sep 17 00:00:00 2001 From: Chris Kuehl Date: Fri, 19 May 2023 13:21:51 -0500 Subject: [PATCH] perf: avoid iterating through multiple caches for contradicted_incompatibilities (#7950) --- src/poetry/mixology/version_solver.py | 30 ++++++++++++++------------- 1 file changed, 16 insertions(+), 14 deletions(-) diff --git a/src/poetry/mixology/version_solver.py b/src/poetry/mixology/version_solver.py index 81dde5d3369..e9ab5e150cd 100644 --- a/src/poetry/mixology/version_solver.py +++ b/src/poetry/mixology/version_solver.py @@ -105,9 +105,10 @@ def __init__(self, root: ProjectPackage, provider: Provider) -> None: self._provider = provider self._dependency_cache = DependencyCache(provider) self._incompatibilities: dict[str, list[Incompatibility]] = {} - self._contradicted_incompatibilities: dict[int, set[Incompatibility]] = ( - collections.defaultdict(set) - ) + self._contradicted_incompatibilities: set[Incompatibility] = set() + self._contradicted_incompatibilities_by_level: dict[ + int, set[Incompatibility] + ] = collections.defaultdict(set) self._solution = PartialSolution() @property @@ -156,10 +157,7 @@ def _propagate(self, package: str) -> None: # we can derive stronger assignments sooner and more eagerly find # conflicts. for incompatibility in reversed(self._incompatibilities[package]): - if any( - incompatibility in c - for c in self._contradicted_incompatibilities.values() - ): + if incompatibility in self._contradicted_incompatibilities: continue result = self._propagate_incompatibility(incompatibility) @@ -208,9 +206,10 @@ def _propagate_incompatibility( # If term is already contradicted by _solution, then # incompatibility is contradicted as well and there's nothing new we # can deduce from it. - self._contradicted_incompatibilities[self._solution.decision_level].add( - incompatibility - ) + self._contradicted_incompatibilities.add(incompatibility) + self._contradicted_incompatibilities_by_level[ + self._solution.decision_level + ].add(incompatibility) return None elif relation == SetRelation.OVERLAPPING: # If more than one term is inconclusive, we can't deduce anything about @@ -228,9 +227,10 @@ def _propagate_incompatibility( if unsatisfied is None: return _conflict - self._contradicted_incompatibilities[self._solution.decision_level].add( - incompatibility - ) + self._contradicted_incompatibilities.add(incompatibility) + self._contradicted_incompatibilities_by_level[ + self._solution.decision_level + ].add(incompatibility) adverb = "not " if unsatisfied.is_positive() else "" self._log(f"derived: {adverb}{unsatisfied.dependency}") @@ -327,7 +327,9 @@ def _resolve_conflict(self, incompatibility: Incompatibility) -> Incompatibility for level in range( self._solution.decision_level, previous_satisfier_level, -1 ): - self._contradicted_incompatibilities.pop(level, None) + self._contradicted_incompatibilities.difference_update( + self._contradicted_incompatibilities_by_level.pop(level, set()), + ) self._dependency_cache.clear_level(level) self._solution.backtrack(previous_satisfier_level)