def __kahn_topological_sort(constraint_problem: ConstraintProblem) -> List[Variable]:
    variables = constraint_problem.get_unassigned_variables()
    directed_graph = defaultdict(set)
    for var in variables:
        for neighbor in constraint_problem.get_unassigned_neighbors(var):
            if var not in directed_graph[neighbor]:
                directed_graph[var].add(neighbor)

    in_degree = {var: 0 for var in variables}
    for var in variables:
        for neighbor in directed_graph[var]:
            in_degree[neighbor] += 1

    zero_in_degree_variables = set(filter(lambda variable: in_degree[variable] == 0, in_degree.keys()))
    topologically_sorted_unassigned_variables = list()
    while zero_in_degree_variables:
        var = zero_in_degree_variables.pop()
        topologically_sorted_unassigned_variables.append(var)
        for neighbor in directed_graph[var]:
            in_degree[neighbor] -= 1
            if in_degree[neighbor] == 0:
                zero_in_degree_variables.add(neighbor)

    if len(topologically_sorted_unassigned_variables) != len(variables):
        return list()
    return topologically_sorted_unassigned_variables
コード例 #2
0
def ac3(constraint_problem: ConstraintProblem,
        assigned_variable: Variable = None) -> bool:
    if assigned_variable is not None:  # usage of ac3 as part of Maintaining Arc Consistency (MAC) algorithm
        unassigned_neighbors = constraint_problem.get_unassigned_neighbors(
            assigned_variable)
        arcs = {(unassigned_neighbor, assigned_variable)
                for unassigned_neighbor in unassigned_neighbors}
    else:
        arcs = {(variable, neighbor)
                for variable in constraint_problem.get_unassigned_variables()
                for neighbor in constraint_problem.get_neighbors(variable)}

    while arcs:
        variable, neighbor = arcs.pop()
        if __revise(constraint_problem, variable, neighbor):
            if not constraint_problem.get_consistent_domain(variable):
                return False
            rest_of_neighbors = constraint_problem.get_neighbors(variable) - {
                neighbor
            }
            if rest_of_neighbors:
                for other_neighbor in rest_of_neighbors:
                    arcs.add((other_neighbor, variable))

    for var in constraint_problem.get_variables():
        if not var.domain or not constraint_problem.get_consistent_domain(var):
            return False
    return True
コード例 #3
0
def forward_check(constraint_problem: ConstraintProblem,
                  assigned_variable: Variable) -> bool:
    unassigned_neighbors_frozenset = constraint_problem.get_unassigned_neighbors(
        assigned_variable)
    unsatisfiable_neighbors = filter(
        lambda unassigned_neighbor: not constraint_problem.
        get_consistent_domain(unassigned_neighbor),
        unassigned_neighbors_frozenset)
    return False if any(unsatisfiable_neighbors) else True
def degree_heuristic(
        constraint_problem: ConstraintProblem,
        variables: Optional[FrozenSet[Variable]] = None
) -> FrozenSet[Variable]:
    if variables is not None:  # then we're using degree_heuristic as secondary key
        max_variable = max(
            variables,
            key=lambda var: len(
                constraint_problem.get_unassigned_neighbors(var)))
        return frozenset({max_variable})

    unassigned_variables = constraint_problem.get_unassigned_variables()
    max_variable = max(
        unassigned_variables,
        key=lambda var: len(constraint_problem.get_unassigned_neighbors(var)))
    max_degree = len(constraint_problem.get_unassigned_neighbors(max_variable))
    max_variables = filter(
        lambda var: len(constraint_problem.get_unassigned_neighbors(var)) ==
        max_degree, unassigned_variables)
    return frozenset(max_variables)
コード例 #5
0
def least_constraining_value(constraint_problem: ConstraintProblem,
                             variable: Variable) -> list:
    unassigned_neighbors = constraint_problem.get_unassigned_neighbors(
        variable)

    def neighbors_consistent_domain_lengths(value) -> int:
        variable.assign(value)
        consistent_domain_lengths = map(
            lambda neighbor: len(
                (constraint_problem.get_consistent_domain(neighbor))),
            unassigned_neighbors)
        variable.unassign()
        return sum(consistent_domain_lengths)

    return sorted(constraint_problem.get_consistent_domain(variable),
                  key=neighbors_consistent_domain_lengths,
                  reverse=True)
コード例 #6
0
def __forward_checking_backtrack(
        constraint_problem: ConstraintProblem,
        find_all_solutions: bool = False,
        with_history: bool = False) -> Optional[Dict[Variable, Any]]:
    variable, *_ = constraint_problem.get_unassigned_variables()
    for value in variable.domain:
        variable.assign(value)
        if with_history:
            __actions_history.append((variable, value))

        unassigned_neighbors_frozenset = constraint_problem.get_unassigned_neighbors(
            variable)
        unsatisfiable_neighbors = filter(
            lambda unassigned_neighbor: not constraint_problem.
            get_consistent_domain(unassigned_neighbor),
            unassigned_neighbors_frozenset)
        if any(unsatisfiable_neighbors):
            variable.unassign()
            if with_history:
                __actions_history.append((variable, None))
            continue

        if constraint_problem.is_completely_assigned():
            if constraint_problem.is_consistently_assigned():
                if find_all_solutions:
                    yield constraint_problem.get_current_assignment()
                else:
                    yield None

            variable.unassign()
            if with_history:
                __actions_history.append((variable, None))
            continue

        if constraint_problem.is_consistently_assigned():
            for solution_assignment in __forward_checking_backtrack(
                    constraint_problem, find_all_solutions, with_history):
                yield solution_assignment

        variable.unassign()
        if with_history:
            __actions_history.append((variable, None))
コード例 #7
0
def __optimized_heuristic_backtrack(constraint_problem: ConstraintProblem,
                                    find_all_solutions: bool = False,
                                    with_history: bool = False):
    unassigned_variables = constraint_problem.get_unassigned_variables()
    min_variable = min(
        unassigned_variables,
        key=lambda var: len(constraint_problem.get_consistent_domain(var)))
    min_remaining_values = len(
        constraint_problem.get_consistent_domain(min_variable))
    min_variables = filter(
        lambda var: len(constraint_problem.get_consistent_domain(var)) ==
        min_remaining_values, unassigned_variables)
    selected_unassigned_vars = frozenset(min_variables)
    if len(selected_unassigned_vars) > 1:
        selected_variable = max(
            selected_unassigned_vars,
            key=lambda var: len(
                constraint_problem.get_unassigned_neighbors(var)))
    else:
        selected_variable, *_ = selected_unassigned_vars

    unassigned_neighbors = constraint_problem.get_unassigned_neighbors(
        selected_variable)

    def neighbors_consistent_domain_lengths(val) -> int:
        selected_variable.assign(val)
        consistent_domain_lengths = map(
            lambda neighbor: len(
                (constraint_problem.get_consistent_domain(neighbor))),
            unassigned_neighbors)
        selected_variable.unassign()
        return sum(consistent_domain_lengths)

    sorted_domain = sorted(
        constraint_problem.get_consistent_domain(selected_variable),
        key=neighbors_consistent_domain_lengths,
        reverse=True)

    for value in sorted_domain:
        selected_variable.assign(value)
        if with_history:
            __actions_history.append((selected_variable, value))

        if constraint_problem.is_completely_assigned():
            if constraint_problem.is_consistently_assigned():
                if find_all_solutions:
                    yield constraint_problem.get_current_assignment()
                else:
                    yield None

            selected_variable.unassign()
            if with_history:
                __actions_history.append((selected_variable, None))
            continue

        if constraint_problem.is_consistently_assigned():
            for solution_assignment in __optimized_heuristic_backtrack(
                    constraint_problem, find_all_solutions, with_history):
                yield solution_assignment

        selected_variable.unassign()
        if with_history:
            __actions_history.append((selected_variable, None))