Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Possible improvmeents #62

Closed
Closed
@maciejlibraryx

Description

@maciejlibraryx

Hi!

A few possible improvements (overall I got over 100x speed improvement over your vanilla code).
a) mapping all variable names to integers (internally). This depends, but for me it gave up to 10x speedup.
b) Changing a few things in the solvers. I copy an example of what I did. It's rather simple optimization of taking some of the repeated code out of the loops. Unless I missed it there, there are no dependencies there. (I checked the correctness of the code). This gives around 4x speedup
c) Switching from dicts to lists inside the solvers (havent done that yet). Seems its gonna be possible in a few places. At the moment dictionary copy method in "yield assignments.copy()" takes bulk of the time.

Hope it helps!

class OptimizedSolver(Solver):
"""
Problem solver with backtracking capabilities

Examples:

>>> result = [[('a', 1), ('b', 2)],
...           [('a', 1), ('b', 3)],
...           [('a', 2), ('b', 3)]]

>>> problem = Problem(BacktrackingSolver())
>>> problem.addVariables(["a", "b"], [1, 2, 3])
>>> problem.addConstraint(lambda a, b: b > a, ["a", "b"])

>>> solution = problem.getSolution()
>>> sorted(solution.items()) in result
True

>>> for solution in problem.getSolutionIter():
...     sorted(solution.items()) in result
True
True
True

>>> for solution in problem.getSolutions():
...     sorted(solution.items()) in result
True
True
True
"""

def __init__(self, forwardcheck=True):
    """
    @param forwardcheck: If false forward checking will not be requested
                         to constraints while looking for solutions
                         (default is true)
    @type  forwardcheck: bool
    """
    self._forwardcheck = forwardcheck

def getSolutionIter(self, domains, constraints, vconstraints, lst):
    forwardcheck = self._forwardcheck
    assignments = {}

    queue = []

    while True:

        # Mix the Degree and Minimum Remaing Values (MRV) heuristics
        for variable in lst:
            if variable not in assignments:
                # Found unassigned variable
                values = domains[variable][:]
                if forwardcheck:
                    pushdomains = [
                        domains[x]
                        for x in domains
                        if x not in assignments and x != variable
                    ]
                else:
                    pushdomains = None
                break
        else:
            # No unassigned variables. We've got a solution. Go back
            # to last variable, if there's one.
            yield assignments.copy()
            if not queue:
                return
            variable, values, pushdomains = queue.pop()
            if pushdomains:
                for domain in pushdomains:
                    domain.popState()

        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]
                while queue:
                    variable, values, pushdomains = queue.pop()
                    if pushdomains:
                        for domain in pushdomains:
                            domain.popState()
                    if values:
                        break
                    del assignments[variable]
                else:
                    return

            # Got a value. Check it.
            assignments[variable] = values.pop()

            if pushdomains:
                for domain in pushdomains:
                    domain.pushState()

            for constraint, variables in vconstraints[variable]:
                if not constraint(variables, domains, assignments, pushdomains):
                    # Value is not good.
                    break
            else:
                break

            if pushdomains:
                for domain in pushdomains:
                    domain.popState()

        # Push state before looking for next variable.
        queue.append((variable, values, pushdomains))

    raise RuntimeError("Can't happen")

def getSolutions(self, domains, constraints, vconstraints):
    lst = [
        (-len(vconstraints[variable]), len(domains[variable]), variable)
        for variable in domains
    ]
    lst.sort()
    return list(self.getSolutionIter(domains, constraints, vconstraints, [c for a,b,c in lst]))

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions