Beispiel #1
0
def solution(dimension, solver=None):
    """Generate binary puzzle solution."""
    problem = Problem()
    if solver is not None:
        problem.setSolver(solver)
    else:
        problem.setSolver(BacktrackingSolver())
    problem.addVariables(range(dimension**2), [0, 1])
    for i in range(dimension):
        row_positions = range(i * dimension, (i + 1) * dimension)
        column_positions = range(i, dimension**2, dimension)
        # same number of zeros and ones in each row
        problem.addConstraint(ExactSumConstraint(dimension / 2), row_positions)
        problem.addConstraint(ExactSumConstraint(dimension / 2),
                              column_positions)
        # maximum two of the same next to each other
        for triplet in _nwise(row_positions, 3):
            problem.addConstraint(MaxSumConstraint(2), triplet)
            problem.addConstraint(MinSumConstraint(1), triplet)
        for triplet in _nwise(column_positions, 3):
            problem.addConstraint(MaxSumConstraint(2), triplet)
            problem.addConstraint(MinSumConstraint(1), triplet)
    # unique rows and columns
    problem.addConstraint(
        FunctionConstraint(partial(_test_uniqueness, dimension=dimension)),
        range(dimension**2))
    if isinstance(solver, RecursiveBacktrackingSolver):
        return problem.getSolutions()
    if isinstance(solver, MinConflictsSolver):
        return (problem.getSolution(), )
    return problem.getSolutionIter()
Beispiel #2
0
 def _generate_solutions(cls, period, doms):
     """
     Each child gets as domain a set of ShiftAssignables, 
     which is generated by their shift preferences;
     each solution selects for each child a ShiftAssignable
     so that all assignments are compatible.
     Here we configure a problem from the constraint library,
     then call the solver.
     The problem takes a mapping, doms, from child_pk to a set of assignables for that child, plus a specification, across children, of which assignables are pairwise consistent
     The solver yields all compatible sets of assignables
     """
     problem = Problem()
     prefs = (ShiftPreference.objects.filter(
         period=period).select_related('shift').select_related('child'))
     for pref in prefs:
         for assignable in pref.assignables():
             if assignable.is_active:
                 doms[assignable.child.pk].append(assignable)
     for k, dom in doms.items():
         try:
             problem.addVariable(k, dom)
         except ValueError:
             return {}
     cached_compatibility = functools.lru_cache()(
         lambda a1, a2: a1.is_compatible_with(a2))
     for k1, k2 in itertools.combinations(doms.keys(), 2):
         problem.addConstraint(cached_compatibility, (k1, k2))
     # call the solver
     return problem.getSolutionIter()
class SudokuProblem(object):
    def __init__(self):
        self._problem = Problem()

    def _each_once_per_line(self):
        for line_index in range(9):
            variable_names = [self._variable_name(line_index, column_index) for column_index in range(9)]
            self._problem.addConstraint(AllDifferentConstraint(), variable_names)

    def _each_once_per_column(self):
        for column_index in range(9):
            variable_names = [self._variable_name(line_index, column_index) for line_index in range(9)]
            self._problem.addConstraint(AllDifferentConstraint(), variable_names)

    def _each_once_per_square(self):
        for line_square_index in range(3):
            for column_square_index in range(3):
                variable_names = []
                line_index_start = line_square_index * 3
                for line_index in range(line_index_start, line_index_start + 3):
                    column_index_start = column_square_index * 3
                    for column_index in range(column_index_start, column_index_start + 3):
                        variable_names.append(self._variable_name(line_index, column_index))
                self._problem.addConstraint(AllDifferentConstraint(), variable_names)

    def generate_constraints(self):
        self._each_once_per_line()
        self._each_once_per_column()
        self._each_once_per_square()

    def _variable_name(self, line_index, column_index):
        return '(l%d,c%d)' % (line_index, column_index)

    def feed_puzzle(self, values_of_colum_of_line):
        for line_index, values_of_column in values_of_colum_of_line.items():
            for column_index, values in values_of_column.items():
                variable_name = self._variable_name(line_index, column_index)
                self._problem.addVariable(variable_name, values)

    def iterate_solutions(self):
        return self._problem.getSolutionIter()

    def format_solution(self, solution_dict, indent_text):
        chunks = []
        for line_index in range(9):
            values = []
            for column_index in range(9):
                value = solution_dict[self._variable_name(line_index, column_index)]
                values.append(value)
            chunks.append(indent_text + '%d %d %d | %d %d %d | %d %d %d' % tuple(values))

            if line_index % 3 == 2 and line_index < 8:
                chunks.append(indent_text + '------+-------+------')

        return '\n'.join(chunks)
Beispiel #4
0
def solve():
    problem = Problem()
    total = 3.00
    variables = ("0.02", "0.09", "0.13", "1.50", "2.00")
    values = [float(x) for x in variables]
    for variable, value in zip(variables, values):
        problem.addVariable(variable, range(int(total / value)))
    problem.addConstraint(ExactSumConstraint(total, values), variables)
    problem.addConstraint(ExactSumConstraint(100))
    solutions = problem.getSolutionIter()
    return solutions, variables
def solve():
    problem = Problem()
    total = 5.00
    variables = ("0.01", "0.05", "0.10", "0.50", "1.00")
    values = [float(x) for x in variables]
    for variable, value in zip(variables, values):
        problem.addVariable(variable, range(int(total / value)))
    problem.addConstraint(ExactSumConstraint(total, values), variables)
    problem.addConstraint(ExactSumConstraint(100))
    solutions = problem.getSolutionIter()
    return solutions, variables
Beispiel #6
0
def processResults(all_data):

    prob = Problem()
    for i, d in enumerate(all_data):
        prob.addVariable(i, d["logic"])

    prob.addConstraint(MaxSumConstraint(234720))

    solutions = prob.getSolutionIter()

    for i, s in enumerate(solutions):
        if i % 1000 == 0:
            print(i)
def compute_using_external_solver(predicate, env, varList):
    # TODO: import at module level
    # external software:
    # install http://labix.org/python-constraint
    # download and unzip python-constraint-1.1.tar.bz2
    # python setup.py build
    # python setup.py install
    #from pretty_printer import pretty_print
    #print "predicate:", pretty_print(predicate)
    from constraint import Problem
    assert isinstance(predicate, Predicate)
    var_and_domain_lst = []
    # get domain 
    for idNode in varList:
        assert isinstance(idNode, AIdentifierExpression)
        atype = env.get_type_by_node(idNode)
        #if USE_RPYTHON_CODE:
        #    domain = all_values_by_type_RPYTHON(atype, env, idNode)
        #else:
        #    domain = all_values_by_type(atype, env, idNode)
        domain = all_values_by_type(atype, env, idNode)
        tup = (idNode.idName, domain)
        var_and_domain_lst.append(tup)
    problem = Problem() # import from "constraint"
    for tup in var_and_domain_lst:
        name = tup[0]
        lst  = tup[1]
        if isinstance(lst, frozenset):
            lst = set_to_list(lst) 
        problem.addVariable(name, lst)
    qme_nodes = []
    constraint_string = pretty_print_python_style(env, varList, predicate, qme_nodes)
    names = [x.idName for x in varList]
    expr = "lambda "
    for n in names[0:-1]:
        expr += n+","
    expr += varList[-1].idName+":"+constraint_string
    #print expr
    my_globales = {"qme_nodes":qme_nodes, "quick_member_eval":quick_member_eval, "env":env}
    lambda_func = eval(expr, my_globales)  # TODO:(#ISSUE 16) not Rpython
    problem.addConstraint(lambda_func, names)
    return problem.getSolutionIter()
Beispiel #8
0
def calculate_solutions_and_store(
    problem: constraint.Problem,
    solution_queue: "multiprocessing.Queue[Solution]",
    queue_lock: "multiprocessing.synchronize.Lock",
) -> None:
    """
    Uses the getSolutionIter interface to find solutions to the given problem one by one and add
    them to the given multiprocess queue.
    """
    solution_iter = problem.getSolutionIter()
    while True:
        try:
            new_solution = next(solution_iter)
            try:
                queue_lock.acquire()
                solution_queue.put(new_solution)
            finally:
                queue_lock.release()
        except StopIteration:
            break
Beispiel #9
0
def getSolutions(problem: constraint.Problem,
                 numSlots: int,
                 maxSolutions=0,
                 timeout=0.,
                 timeoutSearch=0.) -> list:
    """

    Args:
        problem: the problem to solve, after having added all constraints
        numSlots: the number of variables (slots) defined for this problem
        maxSolutions: stop searching for solutions if this amount is reached
        timeout: raise Timedout if now solutions were found before
            this time.
        timeoutSearch: interrupt search after this period of time. Returns the
            results so far

    Returns:
        a list of solutions, where each solution is a list with the values for each slot

    Raises:
        Timedout: if timeout > 0 and no solution is found in that time
    """
    solutions = []
    if timeout:
        # try to get one solution
        try:
            func_timeout.func_timeout(timeout, problem.getSolution)
        except func_timeout.FunctionTimedOut:
            raise Timedout("Function timed out before first solution")

    t0 = time.time()
    for sol in problem.getSolutionIter():
        if not sol:
            continue
        vals = [sol[k] for k in range(numSlots)]
        solutions.append(vals)
        if maxSolutions and len(solutions) >= maxSolutions:
            break
        if timeoutSearch > 0 and time.time() - t0 > timeoutSearch:
            break
    return solutions
def derive_depths(original_markers, additional_constraints=[]):
    """Use constraint programming to derive the paragraph depths associated
    with a list of paragraph markers. Additional constraints (e.g. expected
    marker types, etc.) can also be added. Such constraints are functions of
    two parameters, the constraint function (problem.addConstraint) and a
    list of all variables"""
    if not original_markers:
        return []
    problem = Problem()
    marker_list = _compress_markerless(original_markers)

    # Depth in the tree, with an arbitrary limit of 10
    problem.addVariables(["depth" + str(i) for i in range(len(marker_list))],
                         range(10))

    # Always start at depth 0
    problem.addConstraint(rules.must_be(0), ("depth0",))

    all_vars = []
    for idx, marker in enumerate(marker_list):
        type_var = "type{}".format(idx)
        depth_var = "depth{}".format(idx)
        # Index within the marker list. Though this variable is redundant, it
        # makes the code easier to understand and doesn't have a significant
        # performance penalty
        idx_var = "idx{}".format(idx)

        typ_opts = [t for t in markers.types if marker in t]
        idx_opts = [i for t in typ_opts for i in range(len(t))
                    if t[i] == marker]
        problem.addVariable(type_var, typ_opts)
        problem.addVariable(idx_var, idx_opts)

        problem.addConstraint(rules.type_match(marker), [type_var, idx_var])
        all_vars.extend([type_var, idx_var, depth_var])

        if idx > 0:
            pairs = all_vars[3*(idx-1):]
            problem.addConstraint(rules.depth_check, pairs)

        if idx > 1:
            pairs = all_vars[3*(idx-2):]
            problem.addConstraint(rules.markerless_sandwich, pairs)
            problem.addConstraint(rules.star_sandwich, pairs)

    # separate loop so that the simpler checks run first
    for idx in range(1, len(marker_list)):
        # start with the current idx
        params = all_vars[3*idx:3*(idx+1)]
        # then add on all previous
        params += all_vars[:3*idx]
        problem.addConstraint(rules.sequence, params)

    # @todo: There's probably efficiency gains to making these rules over
    # prefixes (see above) rather than over the whole collection at once
    problem.addConstraint(rules.same_parent_same_type, all_vars)
    problem.addConstraint(rules.stars_occupy_space, all_vars)

    for constraint in additional_constraints:
        constraint(problem.addConstraint, all_vars)

    solutions = []
    for assignment in problem.getSolutionIter():
        assignment = _decompress_markerless(assignment, original_markers)
        solutions.append(Solution(assignment))
    return solutions
Beispiel #11
0
def derive_depths(original_markers, additional_constraints=[]):
    """Use constraint programming to derive the paragraph depths associated
    with a list of paragraph markers. Additional constraints (e.g. expected
    marker types, etc.) can also be added. Such constraints are functions of
    two parameters, the constraint function (problem.addConstraint) and a
    list of all variables"""
    if not original_markers:
        return []
    problem = Problem()
    marker_list = _compress_markerless(original_markers)

    # Depth in the tree, with an arbitrary limit of 10
    problem.addVariables(["depth" + str(i) for i in range(len(marker_list))],
                         range(10))

    # Always start at depth 0
    problem.addConstraint(rules.must_be(0), ("depth0", ))

    all_vars = []
    for idx, marker in enumerate(marker_list):
        type_var = "type{}".format(idx)
        depth_var = "depth{}".format(idx)
        # Index within the marker list. Though this variable is redundant, it
        # makes the code easier to understand and doesn't have a significant
        # performance penalty
        idx_var = "idx{}".format(idx)

        typ_opts = [t for t in markers.types if marker in t]
        idx_opts = [
            i for t in typ_opts for i in range(len(t)) if t[i] == marker
        ]
        problem.addVariable(type_var, typ_opts)
        problem.addVariable(idx_var, idx_opts)

        problem.addConstraint(rules.type_match(marker), [type_var, idx_var])
        all_vars.extend([type_var, idx_var, depth_var])

        if idx > 0:
            pairs = all_vars[3 * (idx - 1):]
            problem.addConstraint(pair_rules, pairs)

        if idx > 1:
            pairs = all_vars[3 * (idx - 2):]
            problem.addConstraint(rules.triplet_tests, pairs)

    # separate loop so that the simpler checks run first
    for idx in range(1, len(marker_list)):
        # start with the current idx
        params = all_vars[3 * idx:3 * (idx + 1)]
        # then add on all previous
        params += all_vars[:3 * idx]
        problem.addConstraint(rules.continue_previous_seq, params)

    # @todo: There's probably efficiency gains to making these rules over
    # prefixes (see above) rather than over the whole collection at once
    problem.addConstraint(rules.same_parent_same_type, all_vars)
    problem.addConstraint(rules.stars_occupy_space, all_vars)

    for constraint in additional_constraints:
        constraint(problem.addConstraint, all_vars)

    solutions = []
    for assignment in problem.getSolutionIter():
        assignment = _decompress_markerless(assignment, original_markers)
        solutions.append(Solution(assignment))
    return solutions