def guess_bad_solve(self, specs): # TODO: Check features as well from conda.console import setup_verbose_handlers setup_verbose_handlers() def mysat(specs): dists = self.get_dists(specs) groups = build_groups(dists) m, v, w = self.build_vw(groups) clauses = set(self.gen_clauses(v, groups, specs)) return sat(clauses) # Don't show the dots from solve2 in normal mode but do show the # dotlog messages with --debug dotlog.setLevel(logging.INFO) specs = [s for s in specs if not s.optional] hint = minimal_unsatisfiable_subset(specs, sat=mysat, log=True) if not hint: return '' hint = list(map(str, hint)) if len(hint) == 1: # TODO: Generate a hint from the dependencies. ret = (("\nHint: '{0}' has unsatisfiable dependencies (see 'conda " "info {0}')").format(hint[0].split()[0])) else: ret = """ Hint: the following packages conflict with each other: - %s Use 'conda info %s' etc. to see the dependencies for each package.""" % ('\n - '.join(hint), hint[0].split()[0]) return ret
def guess_bad_solve(self, specs, features): # TODO: Check features as well from conda.console import setup_verbose_handlers setup_verbose_handlers() # Don't show the dots from solve2 in normal mode but do show the # dotlog messages with --debug dotlog.setLevel(logging.WARN) def sat(specs): try: self.solve2(specs, features, guess=False, unsat_only=True) except RuntimeError: return False return True hint = minimal_unsatisfiable_subset(specs, sat=sat, log=True) if not hint: return '' if len(hint) == 1: # TODO: Generate a hint from the dependencies. return (( "\nHint: '{0}' has unsatisfiable dependencies (see 'conda " "info {0}')").format(hint[0].split()[0])) return (""" Hint: the following packages conflict with each other: - %s""" % '\n - '.join(hint))
def guess_bad_solve(self, specs, features): # TODO: Check features as well from conda.console import setup_verbose_handlers setup_verbose_handlers() # Don't show the dots from solve2 in normal mode but do show the # dotlog messages with --debug dotlog.setLevel(logging.WARN) def sat(specs): try: self.solve2(specs, features, guess=False, unsat_only=True) except RuntimeError: return False return True hint = minimal_unsatisfiable_subset(specs, sat=sat, log=True) if not hint: return '' if len(hint) == 1: # TODO: Generate a hint from the dependencies. return (("\nHint: '{0}' has unsatisfiable dependencies (see 'conda " "info {0}')").format(hint[0].split()[0])) return (""" Hint: the following packages conflict with each other: - %s""" % '\n - '.join(hint))
def execute_instructions(plan, index=None, verbose=False, _commands=None): """ Execute the instructions in the plan :param plan: A list of (instruction, arg) tuples :param index: The meta-data index :param verbose: verbose output :param _commands: (For testing only) dict mapping an instruction to executable if None then the default commands will be used """ if _commands is None: _commands = commands if verbose: from conda.console import setup_verbose_handlers setup_verbose_handlers() state = {'i': None, 'prefix': config.root_dir, 'index': index} for instruction, args in plan: if not isinstance(args, (list, tuple)): args = (args,) log.debug(' %s%r' % (instruction, args)) if state['i'] is not None and instruction in progress_cmds: state['i'] += 1
def guess_bad_solve(self, specs, features): # TODO: Check features as well from conda.console import setup_verbose_handlers setup_verbose_handlers() # Don't show the dots in normal mode but do show the dotlog messages # with --debug dotlog.setLevel(logging.WARN) hint = [] # Try to find the largest satisfiable subset found = False if len(specs) > 10: stderrlog.info("WARNING: This could take a while. Type Ctrl-C to exit.\n") for i in range(len(specs), 0, -1): if found: logging.getLogger('progress.stop').info(None) break # Too lazy to compute closed form expression ncombs = len(list(combinations(specs, i))) logging.getLogger('progress.start').info(ncombs) for j, comb in enumerate(combinations(specs, i), 1): try: logging.getLogger('progress.update').info(('%s/%s' % (j, ncombs), j)) self.solve2(comb, features, guess=False, unsat_only=True) except RuntimeError: pass else: rem = set(specs) - set(comb) rem.discard('conda') if len(rem) == 1: hint.append("%s" % rem.pop()) else: hint.append("%s" % ' and '.join(rem)) found = True if not hint: return '' if len(hint) == 1: return ("\nHint: %s has a conflict with the remaining packages" % hint[0]) return (""" Hint: the following combinations of packages create a conflict with the remaining packages: - %s""" % '\n - '.join(hint))
def execute_plan(plan, index=None, verbose=False): if verbose: from conda.console import setup_verbose_handlers setup_verbose_handlers() # set default prefix prefix = config.root_dir i = None cmds = cmds_from_plan(plan) for cmd, arg in cmds: if i is not None and cmd in progress_cmds: i += 1 getLogger('progress.update').info((install.name_dist(arg), i)) if cmd == PREFIX: prefix = arg elif cmd == PRINT: getLogger('print').info(arg) elif cmd == FETCH: fetch(index, arg) elif cmd == PROGRESS: i = 0 maxval = int(arg) getLogger('progress.start').info(maxval) elif cmd == EXTRACT: install.extract(config.pkgs_dirs[0], arg) elif cmd == RM_EXTRACTED: install.rm_extracted(config.pkgs_dirs[0], arg) elif cmd == RM_FETCHED: install.rm_fetched(config.pkgs_dirs[0], arg) elif cmd == LINK: link(prefix, arg) elif cmd == UNLINK: install.unlink(prefix, arg) elif cmd == SYMLINK_CONDA: install.symlink_conda(prefix, arg) else: raise Exception("Did not expect command: %r" % cmd) if i is not None and cmd in progress_cmds and maxval == i: i = None getLogger('progress.stop').info(None) install.messages(prefix)
def execute_plan(plan, index=None, verbose=False): if verbose: from conda.console import setup_verbose_handlers setup_verbose_handlers() # set default prefix prefix = config.root_dir i = None cmds = cmds_from_plan(plan) for cmd, arg in cmds: if i is not None and cmd in progress_cmds: i += 1 getLogger('progress.update').info((install.name_dist(arg), i)) if cmd == PREFIX: prefix = arg elif cmd == PRINT: getLogger('print').info(arg) elif cmd == FETCH: fetch(index, arg) elif cmd == PROGRESS: i = 0 maxval = int(arg) getLogger('progress.start').info(maxval) elif cmd == EXTRACT: install.extract(config.pkgs_dirs[0], arg) elif cmd == RM_EXTRACTED: install.rm_extracted(config.pkgs_dirs[0], arg) elif cmd == RM_FETCHED: install.rm_fetched(config.pkgs_dirs[0], arg) elif cmd == LINK: link(prefix, arg, index=index) elif cmd == UNLINK: install.unlink(prefix, arg) elif cmd == SYMLINK_CONDA: install.symlink_conda(prefix, arg) else: raise Exception("Did not expect command: %r" % cmd) if i is not None and cmd in progress_cmds and maxval == i: i = None getLogger('progress.stop').info(None) install.messages(prefix)
def execute_instructions(plan, index=None, verbose=False, _commands=None): """ Execute the instructions in the plan :param plan: A list of (instruction, arg) tuples :param index: The meta-data index :param verbose: verbose output :param _commands: (For testing only) dict mapping an instruction to executable if None then the default commands will be used """ if _commands is None: _commands = commands if verbose: from conda.console import setup_verbose_handlers setup_verbose_handlers() state = {'i': None, 'prefix': config.root_dir, 'index': index} for instruction, arg in plan: log.debug(' %s(%r)' % (instruction, arg)) if state['i'] is not None and instruction in progress_cmds: state['i'] += 1 getLogger('progress.update').info((install.name_dist(arg), state['i']-1)) cmd = _commands.get(instruction) if cmd is None: raise InvalidInstruction(instruction) cmd(state, arg) if (state['i'] is not None and instruction in progress_cmds and state['maxval'] == state['i']): state['i'] = None getLogger('progress.stop').info(None) install.messages(state['prefix'])
def execute_instructions(plan, index=None, verbose=False, _commands=None): """ Execute the instructions in the plan :param plan: A list of (instruction, arg) tuples :param index: The meta-data index :param verbose: verbose output :param _commands: (For testing only) dict mapping an instruction to executable if None then the default commands will be used """ if _commands is None: _commands = commands if verbose: from conda.console import setup_verbose_handlers setup_verbose_handlers() state = {'i': None, 'prefix': config.root_dir, 'index': index} for instruction, arg in plan: log.debug(' %s(%r)' % (instruction, arg)) if state['i'] is not None and instruction in progress_cmds: state['i'] += 1 getLogger('progress.update').info((install.name_dist(arg), state['i'] - 1)) cmd = _commands.get(instruction) if cmd is None: raise InvalidInstruction(instruction) cmd(state, arg) if (state['i'] is not None and instruction in progress_cmds and state['maxval'] == state['i']): state['i'] = None getLogger('progress.stop').info(None) install.messages(state['prefix'])
def minimal_unsatisfiable_subset(clauses, log=False): """ Given a set of clauses, find a minimal unsatisfiable subset (an unsatisfiable core) A set is a minimal unsatisfiable subset if no proper subset is unsatisfiable. A set of clauses may have many minimal unsatisfiable subsets of different sizes. if log=True, progress bars will be displayed with the progress. """ if log: from conda.console import setup_verbose_handlers setup_verbose_handlers() start = lambda x: logging.getLogger('progress.start').info(x) update = lambda x, y: logging.getLogger('progress.update').info( ("%s/%s" % (x, y), x)) stop = lambda: logging.getLogger('progress.stop').info(None) else: start = lambda x: None update = lambda x, y: None stop = lambda: None clauses = tuple(clauses) if sat(clauses): raise ValueError("Clauses are not unsatisfiable") # Algorithm suggested from # http://www.slideshare.net/pvcpvc9/lecture17-31382688. We do a binary # search on the clauses by splitting them in halves A and B. If A or B is # UNSAT, we use that and repeat. Otherwise, we recursively check A, but # each time we do a sat query, we include B, until we have a minimal # subset A* of A such that A* U B is UNSAT. Then we find a minimal subset # B* of B such that A* U B* is UNSAT. Then A* U B* will be a minimal # unsatisfiable subset of the original set of clauses. # Proof: If some proper subset C of A* U B* is UNSAT, then there is some # clause c in A* U B* not in C. If c is in A*, then that means (A* - {c}) # U B* is UNSAT, and hence (A* - {c}) U B is UNSAT, since it is a # superset, which contradicts A* being the minimal subset of A with such # property. Similarly, if c is in B, then A* U (B* - {c}) is UNSAT, but B* # - {c} is a strict subset of B*, contradicting B* being the minimal # subset of B with this property. def split(S): """ Split S into two equal parts """ S = tuple(S) L = len(S) return S[:L // 2], S[L // 2:] def minimal_unsat(clauses, include=()): """ Return a minimal subset A of clauses such that A + include is unsatisfiable. Implicitly assumes that clauses + include is unsatisfiable. """ global L, d # assert not sat(clauses + include), (len(clauses), len(include)) # Base case: Since clauses + include is implicitly assumed to be # unsatisfiable, if clauses has only one element, it must be its own # minimal subset if len(clauses) == 1: return clauses A, B = split(clauses) # If one half is unsatisfiable (with include), we can discard the # other half. # To display progress, every time we discard clauses, we update the # progress by that much. # dotlog.debug("") if not sat(A + include): d += len(B) update(d, L) return minimal_unsat(A, include) # dotlog.debug("") if not sat(B + include): d += len(A) update(d, L) return minimal_unsat(B, include) Astar = minimal_unsat(A, B + include) Bstar = minimal_unsat(B, Astar + include) return Astar + Bstar global L, d L = len(clauses) d = 0 start(L) ret = minimal_unsat(clauses) # Commented out because it hides the progress # stop() return ret
def minimal_unsatisfiable_subset(clauses, sat, log=False): """ Given a set of clauses, find a minimal unsatisfiable subset (an unsatisfiable core) A set is a minimal unsatisfiable subset if no proper subset is unsatisfiable. A set of clauses may have many minimal unsatisfiable subsets of different sizes. If log=True, progress bars will be displayed with the progress. sat should be a function that takes a tuple of clauses and returns True if the clauses are satisfiable and False if they are not. The algorithm will work with any order-reversing function (reversing the order of subset and the order False < True), that is, any function where (A <= B) iff (sat(B) <= sat(A)), where A <= B means A is a subset of B and False < True). Algorithm ========= Algorithm suggested from http://www.slideshare.net/pvcpvc9/lecture17-31382688. We do a binary search on the clauses by splitting them in halves A and B. If A or B is UNSAT, we use that and repeat. Otherwise, we recursively check A, but each time we do a sat query, we include B, until we have a minimal subset A* of A such that A* U B is UNSAT. Then we find a minimal subset B* of B such that A* U B* is UNSAT. Then A* U B* will be a minimal unsatisfiable subset of the original set of clauses. Proof: If some proper subset C of A* U B* is UNSAT, then there is some clause c in A* U B* not in C. If c is in A*, then that means (A* - {c}) U B* is UNSAT, and hence (A* - {c}) U B is UNSAT, since it is a superset, which contradicts A* being the minimal subset of A with such property. Similarly, if c is in B, then A* U (B* - {c}) is UNSAT, but B* - {c} is a strict subset of B*, contradicting B* being the minimal subset of B with this property. """ if log: from conda.console import setup_verbose_handlers setup_verbose_handlers() def start(x): return logging.getLogger('progress.start').info(x) def update(x, y): logging.getLogger('progress.update').info(("%s/%s" % (x, y), x)) def stop(): return logging.getLogger('progress.stop').info(None) else: def start(x): pass def update(x, y): pass def stop(): pass clauses = tuple(clauses) if sat(clauses): raise ValueError("Clauses are not unsatisfiable") def split(S): """ Split S into two equal parts """ S = tuple(S) L = len(S) return S[:L//2], S[L//2:] def minimal_unsat(clauses, include=()): """ Return a minimal subset A of clauses such that A + include is unsatisfiable. Implicitly assumes that clauses + include is unsatisfiable. """ global L, d # assert not sat(clauses + include), (len(clauses), len(include)) # Base case: Since clauses + include is implicitly assumed to be # unsatisfiable, if clauses has only one element, it must be its own # minimal subset if len(clauses) == 1: return clauses A, B = split(clauses) # If one half is unsatisfiable (with include), we can discard the # other half. # To display progress, every time we discard clauses, we update the # progress by that much. if not sat(A + include): d += len(B) update(d, L) return minimal_unsat(A, include) if not sat(B + include): d += len(A) update(d, L) return minimal_unsat(B, include) Astar = minimal_unsat(A, B + include) Bstar = minimal_unsat(B, Astar + include) return Astar + Bstar global L, d L = len(clauses) d = 0 start(L) ret = minimal_unsat(clauses) stop() return ret
def minimal_unsatisfiable_subset(clauses, log=False): """ Given a set of clauses, find a minimal unsatisfiable subset (an unsatisfiable core) A set is a minimal unsatisfiable subset if no proper subset is unsatisfiable. A set of clauses may have many minimal unsatisfiable subsets of different sizes. if log=True, progress bars will be displayed with the progress. """ if log: from conda.console import setup_verbose_handlers setup_verbose_handlers() start = lambda x: logging.getLogger('progress.start').info(x) update = lambda x, y: logging.getLogger('progress.update').info(("%s/%s" % (x, y), x)) stop = lambda: logging.getLogger('progress.stop').info(None) else: start = lambda x: None update = lambda x, y: None stop = lambda: None clauses = tuple(clauses) if sat(clauses): raise ValueError("Clauses are not unsatisfiable") # Algorithm suggested from # http://www.slideshare.net/pvcpvc9/lecture17-31382688. We do a binary # search on the clauses by splitting them in halves A and B. If A or B is # UNSAT, we use that and repeat. Otherwise, we recursively check A, but # each time we do a sat query, we include B, until we have a minimal # subset A* of A such that A* U B is UNSAT. Then we find a minimal subset # B* of B such that A* U B* is UNSAT. Then A* U B* will be a minimal # unsatisfiable subset of the original set of clauses. # Proof: If some proper subset C of A* U B* is UNSAT, then there is some # clause c in A* U B* not in C. If c is in A*, then that means (A* - {c}) # U B* is UNSAT, and hence (A* - {c}) U B is UNSAT, since it is a # superset, which contradicts A* being the minimal subset of A with such # property. Similarly, if c is in B, then A* U (B* - {c}) is UNSAT, but B* # - {c} is a strict subset of B*, contradicting B* being the minimal # subset of B with this property. def split(S): """ Split S into two equal parts """ S = tuple(S) L = len(S) return S[:L//2], S[L//2:] def minimal_unsat(clauses, include=()): """ Return a minimal subset A of clauses such that A + include is unsatisfiable. Implicitly assumes that clauses + include is unsatisfiable. """ global L, d # assert not sat(clauses + include), (len(clauses), len(include)) # Base case: Since clauses + include is implicitly assumed to be # unsatisfiable, if clauses has only one element, it must be its own # minimal subset if len(clauses) == 1: return clauses A, B = split(clauses) # If one half is unsatisfiable (with include), we can discard the # other half. # To display progress, every time we discard clauses, we update the # progress by that much. # dotlog.debug("") if not sat(A + include): d += len(B) update(d, L) return minimal_unsat(A, include) # dotlog.debug("") if not sat(B + include): d += len(A) update(d, L) return minimal_unsat(B, include) Astar = minimal_unsat(A, B + include) Bstar = minimal_unsat(B, Astar + include) return Astar + Bstar global L, d L = len(clauses) d = 0 start(L) ret = minimal_unsat(clauses) # Commented out because it hides the progress # stop() return ret
from conda.exports import NoPackagesFound from conda.exports import Resolve from conda.exports import string_types from conda.models.dist import Dist as _Dist def get_key(dist_or_filename): return dist_or_filename def copy_index(index): return {_Dist(key): index[key] for key in index.keys()} def ensure_dist_or_dict(fn): return _Dist.from_string(fn) from conda.console import setup_verbose_handlers setup_verbose_handlers() from conda.gateways.logging import initialize_logging initialize_logging() elif (4, 2) <= CONDA_VERSION_MAJOR_MINOR < (4, 3): from conda.lock import Locked from conda.exports import get_index from conda.exports import subdir from conda.exports import MatchSpec from conda.exports import Unsatisfiable from conda.exports import NoPackagesFound from conda.exports import Resolve from conda.exports import string_types def get_key(dist_or_filename): return dist_or_filename.fn