Esempio n. 1
0
    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]
Esempio n. 2
0
    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]
Esempio n. 3
0
    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]
Esempio n. 4
0
    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]
Esempio n. 5
0
    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]