def solve2(self, specs, features, guess=True, alg='BDD', returnall=False, minimal_hint=False, unsat_only=False): log.debug("Solving for %s" % str(specs)) # First try doing it the "old way", i.e., just look at the most recent # version of each package from the specs. This doesn't handle the more # complicated cases that the pseudo-boolean solver does, but it's also # much faster when it does work. try: dists = self.get_dists(specs, max_only=True) except NoPackagesFound: # Handle packages that are not included because some dependencies # couldn't be found. pass else: v = {} # map fn to variable number w = {} # map variable number to fn i = -1 # in case the loop doesn't run for i, fn in enumerate(sorted(dists)): v[fn] = i + 1 w[i + 1] = fn m = i + 1 dotlog.debug("Solving using max dists only") clauses = set(self.gen_clauses(v, dists, specs, features)) try: solutions = min_sat(clauses, alg='iterate', raise_on_max_n=True) except MaximumIterationsError: pass else: if len(solutions) == 1: ret = [w[lit] for lit in solutions.pop(0) if 0 < lit <= m] if returnall: return [ret] return ret dists = self.get_dists(specs) v = {} # map fn to variable number w = {} # map variable number to fn i = -1 # in case the loop doesn't run for i, fn in enumerate(sorted(dists)): v[fn] = i + 1 w[i + 1] = fn m = i + 1 clauses = set(self.gen_clauses(v, dists, specs, features)) if not clauses: if returnall: return [[]] return [] eq, max_rhs = self.generate_version_eq(v, dists) # Second common case, check if it's unsatisfiable dotlog.debug("Checking for unsatisfiability") solution = sat(clauses) if not solution: if guess: if minimal_hint: stderrlog.info('\nError: Unsatisfiable package ' 'specifications.\nGenerating minimal hint: \n') sys.exit(self.minimal_unsatisfiable_subset(clauses, v, w)) else: stderrlog.info('\nError: Unsatisfiable package ' 'specifications.\nGenerating hint: \n') sys.exit(self.guess_bad_solve(specs, features)) raise RuntimeError("Unsatisfiable package specifications") if unsat_only: return True log.debug("Using alg %s" % alg) def version_constraints(lo, hi): return set(generate_constraints(eq, m, [lo, hi], alg=alg)) log.debug("Bisecting the version constraint") evaluate_func = partial(evaluate_eq, eq) constraints = bisect_constraints(0, max_rhs, clauses, version_constraints, evaluate_func=evaluate_func) # Only relevant for build_BDD if constraints and false in constraints: # XXX: This should *never* happen. build_BDD only returns false # when the linear constraint is unsatisfiable, but any linear # constraint can equal 0, by setting all the variables to 0. solution = [] else: if constraints and true in constraints: constraints = set([]) dotlog.debug("Finding the minimal solution") try: solutions = min_sat(clauses | constraints, N=m + 1, alg='iterate', raise_on_max_n=True) except MaximumIterationsError: solutions = min_sat(clauses | constraints, N=m + 1, alg='sorter') assert solutions, (specs, features) if len(solutions) > 1: stdoutlog.info('\nWarning: %s possible package resolutions (only showing differing packages):\n' % len(solutions)) pretty_solutions = [{w[lit] for lit in sol if 0 < lit <= m} for sol in solutions] common = set.intersection(*pretty_solutions) for sol in pretty_solutions: stdoutlog.info('\t%s,\n' % sorted(sol - common)) if returnall: return [[w[lit] for lit in sol if 0 < lit <= m] for sol in solutions] return [w[lit] for lit in solutions.pop(0) if 0 < lit <= m]
def solve2(self, specs, features, guess=True, alg='BDD', returnall=False, minimal_hint=False, unsat_only=False): log.debug("Solving for %s" % str(specs)) log.debug("Using alg %s" % alg) # First try doing it the "old way", i.e., just look at the most recent # version of each package from the specs. This doesn't handle the more # complicated cases that the pseudo-boolean solver does, but it's also # much faster when it does work. try: dists = self.get_dists(specs, max_only=True) except NoPackagesFound: # Handle packages that are not included because some dependencies # couldn't be found. pass else: v = {} # map fn to variable number w = {} # map variable number to fn i = -1 # in case the loop doesn't run for i, fn in enumerate(sorted(dists)): v[fn] = i + 1 w[i + 1] = fn m = i + 1 dotlog.debug("Solving using max dists only") clauses = set(self.gen_clauses(v, dists, specs, features)) solutions = min_sat(clauses) if len(solutions) == 1: ret = [w[lit] for lit in solutions.pop(0) if 0 < lit <= m] if returnall: return [ret] return ret dists = self.get_dists(specs) v = {} # map fn to variable number w = {} # map variable number to fn i = -1 # in case the loop doesn't run for i, fn in enumerate(sorted(dists)): v[fn] = i + 1 w[i + 1] = fn m = i + 1 clauses = set(self.gen_clauses(v, dists, specs, features)) if not clauses: if returnall: return [[]] return [] eq, max_rhs = self.generate_version_eq(v, dists) # Second common case, check if it's unsatisfiable dotlog.debug("Checking for unsatisfiability") solution = sat(clauses) if not solution: if guess: stderrlog.info('\nError: Unsatisfiable package ' 'specifications.\nGenerating hint: ') if minimal_hint: sys.exit(self.minimal_unsatisfiable_subset(clauses, v, w)) else: sys.exit(self.guess_bad_solve(specs, features)) raise RuntimeError("Unsatisfiable package specifications") if unsat_only: return True def version_constraints(lo, hi): return set(generate_constraints(eq, m, [lo, hi], alg=alg)) log.debug("Bisecting the version constraint") evaluate_func = partial(evaluate_eq, eq) constraints = bisect_constraints(0, max_rhs, clauses, version_constraints, evaluate_func=evaluate_func) # Only relevant for build_BDD if constraints and false in constraints: # XXX: This should *never* happen. build_BDD only returns false # when the linear constraint is unsatisfiable, but any linear # constraint can equal 0, by setting all the variables to 0. solution = [] else: if constraints and true in constraints: constraints = set([]) dotlog.debug("Finding the minimal solution") solutions = min_sat(clauses | constraints, N=m + 1) assert solutions, (specs, features) if len(solutions) > 1: stdoutlog.info('Warning: %s possible package resolutions:' % len(solutions)) for sol in solutions: stdoutlog.info('\t' + str([w[lit] for lit in sol if 0 < lit <= m])) if returnall: return [[w[lit] for lit in sol if 0 < lit <= m] for sol in solutions] return [w[lit] for lit in solutions.pop(0) if 0 < lit <= m]
def solve2(self, specs, features, installed=(), guess=True, alg='BDD', returnall=False, minimal_hint=False, unsat_only=False, update_deps=True, try_max_only=None): log.debug("Solving for %s" % str(specs)) log.debug("Features: %s" % str(features)) log.debug("Installed: %s" % str(installed)) # This won't packages that aren't in the index, but there isn't much # we can do with such packages here anyway. installed_dists = {pkg: Package(pkg, self.index[pkg]) for pkg in installed if pkg in self.index} if try_max_only is None: if unsat_only or update_deps: try_max_only = False else: try_max_only = True if try_max_only: try: dists = self.get_dists(specs, max_only=True) except NoPackagesFound: # Handle packages that are not included because some dependencies # couldn't be found. pass else: v = {} # map fn to variable number w = {} # map variable number to fn i = -1 # in case the loop doesn't run for i, fn in enumerate(sorted(dists)): v[fn] = i + 1 w[i + 1] = fn m = i + 1 dotlog.debug("Solving using max dists only") clauses = set(self.gen_clauses(v, dists, specs, features)) try: solutions = min_sat(clauses, alg='iterate', raise_on_max_n=True) except MaximumIterationsError: pass else: if len(solutions) == 1: ret = [w[lit] for lit in solutions.pop(0) if 0 < lit <= m] if returnall: return [ret] return ret dists = self.get_dists(specs) v = {} # map fn to variable number w = {} # map variable number to fn i = -1 # in case the loop doesn't run for i, fn in enumerate(sorted(dists)): v[fn] = i + 1 w[i + 1] = fn m = i + 1 clauses = set(self.gen_clauses(v, dists, specs, features)) if not clauses: if returnall: return [[]] return [] eq, max_rhs = self.generate_version_eq(v, dists, installed_dists, specs, update_deps=update_deps) # Second common case, check if it's unsatisfiable dotlog.debug("Checking for unsatisfiability") solution = sat(clauses) if not solution: if guess: if minimal_hint: stderrlog.info('\nError: Unsatisfiable package ' 'specifications.\nGenerating minimal hint: \n') sys.exit(self.minimal_unsatisfiable_subset(clauses, v, w)) else: stderrlog.info('\nError: Unsatisfiable package ' 'specifications.\nGenerating hint: \n') sys.exit(self.guess_bad_solve(specs, features)) raise RuntimeError("Unsatisfiable package specifications") if unsat_only: return True log.debug("Using alg %s" % alg) def version_constraints(lo, hi): return set(generate_constraints(eq, m, [lo, hi], alg=alg)) log.debug("Bisecting the version constraint") evaluate_func = partial(evaluate_eq, eq) constraints = bisect_constraints(0, max_rhs, clauses, version_constraints, evaluate_func=evaluate_func) # Only relevant for build_BDD if constraints and false in constraints: # XXX: This should *never* happen. build_BDD only returns false # when the linear constraint is unsatisfiable, but any linear # constraint can equal 0, by setting all the variables to 0. solution = [] else: if constraints and true in constraints: constraints = set([]) dotlog.debug("Finding the minimal solution") try: solutions = min_sat(clauses | constraints, N=m + 1, alg='iterate', raise_on_max_n=True) except MaximumIterationsError: solutions = min_sat(clauses | constraints, N=m + 1, alg='sorter') assert solutions, (specs, features) if len(solutions) > 1: stdoutlog.info('\nWarning: %s possible package resolutions (only showing differing packages):\n' % len(solutions)) pretty_solutions = [{w[lit] for lit in sol if 0 < lit <= m} for sol in solutions] common = set.intersection(*pretty_solutions) for sol in pretty_solutions: stdoutlog.info('\t%s,\n' % sorted(sol - common)) log.debug("Older versions in the solution(s):") for sol in solutions: log.debug([(i, w[j]) for i, j in eq if j in sol]) if returnall: return [[w[lit] for lit in sol if 0 < lit <= m] for sol in solutions] return [w[lit] for lit in solutions.pop(0) if 0 < lit <= m]
def solve2(self, specs, features, installed=(), guess=True, alg='BDD', returnall=False, minimal_hint=False, unsat_only=False, update_deps=True, try_max_only=None): log.debug("Solving for %s" % str(specs)) log.debug("Features: %s" % str(features)) log.debug("Installed: %s" % str(installed)) # This won't packages that aren't in the index, but there isn't much # we can do with such packages here anyway. installed_dists = { pkg: Package(pkg, self.index[pkg]) for pkg in installed if pkg in self.index } if try_max_only is None: if unsat_only or update_deps: try_max_only = False else: try_max_only = True # XXX: Should try_max_only use the filtered list? if try_max_only: try: dists = self.get_dists(specs, max_only=True, filtered=False) except NoPackagesFound: # Handle packages that are not included because some dependencies # couldn't be found. pass else: v = {} # map fn to variable number w = {} # map variable number to fn i = -1 # in case the loop doesn't run for i, fn in enumerate(sorted(dists)): v[fn] = i + 1 w[i + 1] = fn m = i + 1 dotlog.debug("Solving using max dists only") clauses = set(self.gen_clauses(v, dists, specs, features)) try: solutions = min_sat(clauses, alg='iterate', raise_on_max_n=True) except MaximumIterationsError: pass else: if len(solutions) == 1: ret = [ w[lit] for lit in solutions.pop(0) if 0 < lit <= m ] if returnall: return [ret] return ret dists = self.get_dists(specs, filtered=True) v = {} # map fn to variable number w = {} # map variable number to fn i = -1 # in case the loop doesn't run for i, fn in enumerate(sorted(dists)): v[fn] = i + 1 w[i + 1] = fn m = i + 1 clauses = set(self.gen_clauses(v, dists, specs, features)) if not clauses: if returnall: return [[]] return [] eq, max_rhs = self.generate_version_eq(v, dists, installed_dists, specs, update_deps=update_deps) # Second common case, check if it's unsatisfiable dotlog.debug("Checking for unsatisfiability") solution = sat(clauses) if not solution: if guess: if minimal_hint: stderrlog.info( '\nError: Unsatisfiable package ' 'specifications.\nGenerating minimal hint: \n') sys.exit(self.minimal_unsatisfiable_subset(clauses, v, w)) else: stderrlog.info('\nError: Unsatisfiable package ' 'specifications.\nGenerating hint: \n') sys.exit(self.guess_bad_solve(specs, features)) raise RuntimeError("Unsatisfiable package specifications") if unsat_only: return True log.debug("Using alg %s" % alg) def version_constraints(lo, hi): return set(generate_constraints(eq, m, [lo, hi], alg=alg)) log.debug("Bisecting the version constraint") evaluate_func = partial(evaluate_eq, eq) constraints = bisect_constraints(0, max_rhs, clauses, version_constraints, evaluate_func=evaluate_func) # Only relevant for build_BDD if constraints and false in constraints: # XXX: This should *never* happen. build_BDD only returns false # when the linear constraint is unsatisfiable, but any linear # constraint can equal 0, by setting all the variables to 0. solution = [] else: if constraints and true in constraints: constraints = set([]) dotlog.debug("Finding the minimal solution") try: solutions = min_sat(clauses | constraints, N=m + 1, alg='iterate', raise_on_max_n=True) except MaximumIterationsError: solutions = min_sat(clauses | constraints, N=m + 1, alg='sorter') assert solutions, (specs, features) if len(solutions) > 1: stdoutlog.info( '\nWarning: %s possible package resolutions (only showing differing packages):\n' % len(solutions)) pretty_solutions = [{w[lit] for lit in sol if 0 < lit <= m} for sol in solutions] common = set.intersection(*pretty_solutions) for sol in pretty_solutions: stdoutlog.info('\t%s,\n' % sorted(sol - common)) log.debug("Older versions in the solution(s):") for sol in solutions: log.debug([(i, w[j]) for i, j in eq if j in sol]) if returnall: return [[w[lit] for lit in sol if 0 < lit <= m] for sol in solutions] return [w[lit] for lit in solutions.pop(0) if 0 < lit <= m]
def solve2(self, specs, features, guess=True, alg='sorter', returnall=False): log.debug("Solving for %s" % str(specs)) # First try doing it the "old way", i.e., just look at the most recent # version of each package from the specs. This doesn't handle the more # complicated cases that the pseudo-boolean solver does, but it's also # much faster when it does work. try: dists = self.get_dists(specs, max_only=True) except NoPackagesFound: # Handle packages that are not included because some dependencies # couldn't be found. pass else: v = {} # map fn to variable number w = {} # map variable number to fn i = -1 # in case the loop doesn't run for i, fn in enumerate(sorted(dists)): v[fn] = i + 1 w[i + 1] = fn m = i + 1 dotlog.debug("Solving using max dists only") clauses = self.gen_clauses(v, dists, specs, features) solutions = min_sat(clauses) if len(solutions) == 1: ret = [w[lit] for lit in solutions.pop(0) if 0 < lit] if returnall: return [ret] return ret dists = self.get_dists(specs) v = {} # map fn to variable number w = {} # map variable number to fn i = -1 # in case the loop doesn't run for i, fn in enumerate(sorted(dists)): v[fn] = i + 1 w[i + 1] = fn m = i + 1 clauses = list(self.gen_clauses(v, dists, specs, features)) if not clauses: if returnall: return [[]] return [] eq, max_rhs = self.generate_version_eq(v, dists) # Check the common case first dotlog.debug("Building the constraint with rhs: [0, 0]") constraints = list(generate_constraints(eq, m, [0, 0], alg=alg)) # Only relevant for build_BDD if constraints and constraints[0] == [false]: # XXX: This should *never* happen. build_BDD only returns false # when the linear constraint is unsatisfiable, but any linear # constraint can equal 0, by setting all the variables to 0. solution = [] else: if constraints and constraints[0] == [true]: constraints = [] dotlog.debug("Checking for solutions with rhs: [0, 0]") solution = sat(clauses + constraints) if not solution: # Second common case, check if it's unsatisfiable dotlog.debug("Checking for unsatisfiability") solution = sat(clauses) if not solution: if guess: stderrlog.info('\nError: Unsatisfiable package ' 'specifications.\nGenerating hint: ') sys.exit(self.guess_bad_solve(specs, features)) raise RuntimeError("Unsatisfiable package specifications") def version_constraints(lo, hi): return list(generate_constraints(eq, m, [lo, hi], alg=alg)) log.debug("Bisecting the version constraint") constraints = bisect_constraints(0, max_rhs, clauses, version_constraints) dotlog.debug("Finding the minimal solution") solutions = min_sat(clauses + constraints, N=m+1) assert solutions, (specs, features) if len(solutions) > 1: print('Warning:', len(solutions), "possible package resolutions:") for sol in solutions: print('\t', [w[lit] for lit in sol if 0 < lit <= m]) if returnall: return [[w[lit] for lit in sol if 0 < lit <= m] for sol in solutions] return [w[lit] for lit in solutions.pop(0) if 0 < lit <= m]