Ejemplo n.º 1
0
    def force_distinct(self, solution, determined = False, indent = 0, verbosity = 0):
        """Force search_pattern to have at least one differnence from given solution"""

        print_message("Forcing pattern to be different from solution...", 3, indent = indent, verbosity = verbosity)

        clause = []

        for t, generation in enumerate(self.grid):
            if t == 0 or not determined:
                for y, row in enumerate(generation):
                    for x, cell in enumerate(row):
                        other_cell = solution.grid[t][y][x]
                        assert other_cell in ["0", "1"], "Only use force_distinct against solved patterns"
                        if other_cell == "0":
                            clause.append(cell)
                        else:
                            clause.append(negate(cell))

        for transition, literal in self.rule.items():
            other_literal = solution.rule[transition]
            assert other_literal in ["0", "1"], "Only use force_distinct against solved patterns"
            if other_literal == "0":
                clause.append(literal)
            else:
                clause.append(negate(literal))
        self.clauses.append(clause)
        print_message("Done\n", 3, indent = indent, verbosity = verbosity)
Ejemplo n.º 2
0
    def substitute_solution(self, solution, DIMACS_variables_from_CNF_list_variables, indent = 0, verbosity = 0):
        """Return a copy of the search_pattern with the solution substituted back into it"""
        grid = copy.deepcopy(self.grid)
        rule = copy.deepcopy(self.rule)

        print_message('Substituting solution back into search grid...', 3, indent = indent, verbosity = verbosity)

        # Remove the first line that just says "SAT", and split into a list of literals
        solution = solution.split("\n")[1].split()

        for t, generation in enumerate(grid):
            for y, row in enumerate(generation):
                for x, cell in enumerate(row):
                    if cell in ["0","1"]:
                        pass
                    else:
                        (CNF_variable, negated) = variable_from_literal(cell)
                        if DIMACS_variables_from_CNF_list_variables.has_key(CNF_variable):
                            DIMACS_variable = DIMACS_variables_from_CNF_list_variables[CNF_variable]

                            DIMACS_literal = negate(DIMACS_variable, negated)

                            if DIMACS_literal in solution:
                                grid[t][y][x] = "1"
                            else:
                                grid[t][y][x] = "0"
                        else:
                            grid[t][y][x] = "0"

        for transition, literal in rule.items():
            if literal in ["0","1"]:
                pass
            else:
                (CNF_variable, negated) = variable_from_literal(literal)
                if DIMACS_variables_from_CNF_list_variables.has_key(CNF_variable):
                    DIMACS_variable = DIMACS_variables_from_CNF_list_variables[CNF_variable]

                    DIMACS_literal = negate(DIMACS_variable, negated)

                    if DIMACS_literal in solution:
                        rule[transition] = "1"
                    else:
                        rule[transition] = "0"
                else:
                    rule[transition] = "0"

        print_message('Done\n', 3, indent = indent, verbosity = verbosity)

        return SearchPattern(grid, rule = rule)
Ejemplo n.º 3
0
    def force_change(self, t_0, t_1, indent = 0, verbosity = 0):
        """Adds clauses forcing at least one cell to change between specified generations"""

        print_message("Forcing at least one cell to change between generations " + str(t_0) + " and " + str(t_1) + " ...", 3, indent = indent, verbosity = verbosity)

        generation_0 = self.grid[t_0]
        generation_1 = self.grid[t_1]

        clause = []
        clauses = []

        for y, rows in enumerate(zip(generation_0,generation_1)):
            for x, cells in enumerate(zip(*rows)):
                cells_equal = ("x" + str(x) +
                               "y" + str(y) +
                               "is_equal_at" +
                               "t" + str(t_0) +
                               "and" +
                               "t" + str(t_1))
                clauses.append(implies(cells, cells_equal))
                clauses.append(implies(map(negate, cells), cells_equal))
                clause.append(negate(cells_equal))

        clauses.append(clause)
        print_message("Number of clauses used: " + str(len(clauses)), 3, indent = indent + 1, verbosity = verbosity)
        self.clauses += clauses
        print_message("Done\n", 3, indent = indent, verbosity = verbosity)
Ejemplo n.º 4
0
def DIMACS_from_CNF_list(clauses, indent=0, verbosity=0):
    """Convert CNF list-of-lists to DIMACS format"""

    clauses_copy = copy.deepcopy(clauses)

    print_message("Converting to DIMACS format...",
                  3,
                  indent=indent,
                  verbosity=verbosity)

    print_message("Subsituting in DIMACS variable names...",
                  3,
                  indent=indent + 1,
                  verbosity=verbosity)

    # In DIMACS format variables are called "1", "2", ... . So we will rename
    # all our variables. This keeps track of which numbers we've used
    numbers_used = 0

    # We'll also build a dictionary of which of our old variables recieves
    # which new name
    DIMACS_variables_from_CNF_list_variables = {}
    for clause_number, clause in enumerate(clauses_copy):
        for literal_number, literal in enumerate(clause):
            (variable, negated) = variable_from_literal(literal, DIMACS=True)

            # If we haven't seen it before then add it to the dictionary
            if not DIMACS_variables_from_CNF_list_variables.has_key(variable):
                DIMACS_variables_from_CNF_list_variables[variable] = str(
                    numbers_used + 1)
                numbers_used += 1  # We've used another number, so increment the counter

            # Substitute in its new name
            clauses_copy[clause_number][literal_number] = negate(
                DIMACS_variables_from_CNF_list_variables[variable],
                negated,
                DIMACS=True)

    print_message("Done\n", 3, indent=indent + 1, verbosity=verbosity)

    number_of_clauses = len(clauses_copy)
    number_of_variables = numbers_used

    # From our list of clauses create a string according to the DIMACS format
    print_message("Creating DIMACS string...",
                  3,
                  indent=indent + 1,
                  verbosity=verbosity)
    DIMACS_string = "p cnf " + str(number_of_variables) + " " + str(number_of_clauses) + \
        "\n" + "\n".join([(" ".join(clause) + " 0") for clause in clauses_copy])
    print_message("Done\n", 3, indent=indent + 1, verbosity=verbosity)
    print_message("Done\n", 3, indent=indent, verbosity=verbosity)

    return DIMACS_string, DIMACS_variables_from_CNF_list_variables, number_of_variables, number_of_clauses
Ejemplo n.º 5
0
def transition_rule(grid, x, y, t):
    """Outputs clauses enforcing the transition rule at coordinates x, y, t of grid"""

    clauses = []

    # These clauses define variables a_i meaning at least i of the neighbours were alive at time t - 1
    clauses += definition_clauses(grid, x, y, t - 1, "a", at_least=2)
    clauses += definition_clauses(grid, x, y, t - 1, "a", at_least=3)
    clauses += definition_clauses(grid, x, y, t - 1, "a", at_least=4)

    cell = literal_name(grid, x, y, t)
    predecessor_cell = literal_name(grid, x, y, t - 1)
    # These clauses implement the cellular automaton rule

    # If there are at least 4 neighbours in the previous generation then the cell dies
    clauses.append(
        implies(literal_name(grid, x, y, t - 1, "a", at_least=4),
                negate(cell)))
    # If there aren't at least 2 neighbours in the previous generation then the cell dies
    clauses.append(
        implies(negate(literal_name(grid, x, y, t - 1, "a", at_least=2)),
                negate(cell)))
    # If the predecessor is dead and there aren't at least 3 neighbours then the cell dies
    clauses.append(
        implies([
            negate(predecessor_cell),
            negate(literal_name(grid, x, y, t - 1, "a", at_least=3))
        ], negate(cell)))
    # If the predecessor is dead and there are at least 3 neighbours then the cell lives TODO: This doesn't seem true
    clauses.append(
        implies([
            negate(literal_name(grid, x, y, t - 1, "a", at_least=4)),
            literal_name(grid, x, y, t - 1, "a", at_least=3)
        ], cell))
    # If the predecessor is alive and there are at least 2 neighbours but not at least 4 neighbours then the cell lives
    clauses.append(
        implies([
            predecessor_cell,
            literal_name(grid, x, y, t - 1, "a", at_least=2),
            negate(literal_name(grid, x, y, t - 1, "a", at_least=4))
        ], cell))

    return clauses
Ejemplo n.º 6
0
    def standardise_varaibles_names(self, indent = 0, verbosity = 0):
        print_message("Standardising variable names...", 3, indent = indent, verbosity = verbosity)

        #Give variables standard names and replace stars with new variable names
        standard_variables_from_input_variables = {}
        current_variable_number = 0

        for t, generation in enumerate(self.grid):
            for y, row in enumerate(generation):
                for x, cell in enumerate(row):
                    if cell == "*":
                        self.grid[t][y][x] = "c" + str(current_variable_number)
                        current_variable_number += 1
                    elif cell not in ["0","1"]:
                        (variable, negated) = variable_from_literal(cell)
                        if not standard_variables_from_input_variables.has_key(variable):
                            standard_variables_from_input_variables[variable] = negate("c" + str(current_variable_number),negated)
                            current_variable_number += 1
                        self.grid[t][y][x] = negate(standard_variables_from_input_variables[variable],negated)
        # Rename any literals in clauses
        for clause_number, clause in enumerate(self.clauses):
            for literal_number, literal in enumerate(clause):
                if literal not in ["0", "1"]:
                    (variable, negated) = variable_from_literal(literal)
                    if not standard_variables_from_input_variables.has_key(variable):
                        standard_variables_from_input_variables[variable] = negate("c" + str(current_variable_number),negated)
                        current_variable_number += 1
                    self.clauses[clause_number][literal_number] = negate(standard_variables_from_input_variables[variable],negated)
        # Rename any literals in rule
        for transition, literal in self.rule.items():
            if literal not in ["0", "1"]:
                (variable, negated) = variable_from_literal(literal)
                if not standard_variables_from_input_variables.has_key(variable):
                    standard_variables_from_input_variables[variable] = negate("c" + str(current_variable_number),negated)
                    current_variable_number += 1
                self.rule[transition] = negate(standard_variables_from_input_variables[variable],negated)

        print_message("Done\n", 3, indent = indent, verbosity = verbosity)
Ejemplo n.º 7
0
def definition_clauses(grid, x, y, t, letter, at_least):
    """Defines clauses that define variables for Knuth's neighbour counting scheme"""

    if letter == None:
        return []
    else:
        (child_1_letter, child_1_x, child_1_y, child_2_letter, child_2_x,
         child_2_y) = children(letter, x, y)

        maximum_number_of_live_cells_1 = maximum_number_of_live_cells(
            child_1_letter)
        maximum_number_of_live_cells_2 = maximum_number_of_live_cells(
            child_2_letter)

        clauses = [
        ]  # We'll build up a list of the clauses we need one at a time
        child_1_needing_definition = [
        ]  # A list of child1 variables we need to define
        child_2_needing_definition = [
        ]  # A list of child2 variables we need to define

        # If at_least is obviously too small or too big, give the obvious answer
        if at_least <= 0:
            clauses.append([literal_name(grid, x, y, t, letter, at_least)])
        elif at_least > maximum_number_of_live_cells_1 + maximum_number_of_live_cells_2:
            clauses.append(
                [negate(literal_name(grid, x, y, t, letter, at_least))])

        # Otherwise define the appropriate clauses
        else:
            if at_least <= maximum_number_of_live_cells_1:
                clauses.append([
                    negate(
                        literal_name(grid, child_1_x, child_1_y, t,
                                     child_1_letter, at_least)),
                    literal_name(grid, x, y, t, letter, at_least)
                ])
                child_1_needing_definition.append(at_least)
            for j in range(1, maximum_number_of_live_cells_2 + 1):
                for i in range(1, maximum_number_of_live_cells_1 + 1):
                    if i + j == at_least:
                        clauses.append([
                            negate(
                                literal_name(grid, child_1_x, child_1_y, t,
                                             child_1_letter, i)),
                            negate(
                                literal_name(grid, child_2_x, child_2_y, t,
                                             child_2_letter, j)),
                            literal_name(grid, x, y, t, letter, at_least)
                        ])
                        child_1_needing_definition.append(i)
                        child_2_needing_definition.append(j)
            if at_least <= maximum_number_of_live_cells_2:
                clauses.append([
                    negate(
                        literal_name(grid, child_2_x, child_2_y, t,
                                     child_2_letter, at_least)),
                    literal_name(grid, x, y, t, letter, at_least)
                ])
                child_2_needing_definition.append(at_least)

            if at_least > maximum_number_of_live_cells_2:
                i = at_least - maximum_number_of_live_cells_2
                clauses.append([
                    literal_name(grid, child_1_x, child_1_y, t, child_1_letter,
                                 i),
                    negate(literal_name(grid, x, y, t, letter, at_least))
                ])
                child_1_needing_definition.append(i)
            for j in range(1, maximum_number_of_live_cells_2 + 1):
                for i in range(1, maximum_number_of_live_cells_1 + 1):
                    if i + j == at_least + 1:
                        clauses.append([
                            literal_name(grid, child_1_x, child_1_y, t,
                                         child_1_letter, i),
                            literal_name(grid, child_2_x, child_2_y, t,
                                         child_2_letter, j),
                            negate(
                                literal_name(grid, x, y, t, letter, at_least))
                        ])
                        child_1_needing_definition.append(i)
                        child_2_needing_definition.append(j)
            if at_least > maximum_number_of_live_cells_1:
                j = at_least - maximum_number_of_live_cells_1
                clauses.append([
                    literal_name(grid, child_2_x, child_2_y, t, child_2_letter,
                                 j),
                    negate(literal_name(grid, x, y, t, letter, at_least))
                ])
                child_2_needing_definition.append(j)

        # Remove duplicates from our lists of child variables we need to define
        child_1_needing_definition = set(child_1_needing_definition)
        child_2_needing_definition = set(child_2_needing_definition)

        # Define the child variables
        for child_1_at_least in child_1_needing_definition:
            clauses += definition_clauses(grid, child_1_x, child_1_y, t,
                                          child_1_letter, child_1_at_least)
        for child_2_at_least in child_2_needing_definition:
            clauses += definition_clauses(grid, child_2_x, child_2_y, t,
                                          child_2_letter, child_2_at_least)

        return clauses
Ejemplo n.º 8
0
    def force_equal(self, argument_0, argument_1 = None):

        grid_changed = False
        clauses_changed = False
        rule_changed = False

        if argument_1 != None:
            assert isinstance(argument_0, basestring) and isinstance(argument_1, basestring), "force_equal arguments not understood"
            cell_pair_list = [(argument_0, argument_1)]
        elif argument_0 == []:
            return grid_changed, clauses_changed, rule_changed
        elif isinstance(argument_0[0], basestring):
                assert len(argument_0) == 2 and isinstance(argument_0[1], basestring), "force_equal arguments not understood"
                cell_pair_list = [argument_0]
        else:
            cell_pair_list = argument_0


        replacement = {}
        replaces = {}

        for cell_0, cell_1 in cell_pair_list:
            while cell_0 not in ["0", "1"]:
                variable_0, negated_0 = variable_from_literal(cell_0)
                if replacement.has_key(variable_0):
                    cell_0 = negate(replacement[variable_0], negated_0)
                else:
                    break
            while cell_1 not in ["0", "1"]:
                variable_1, negated_1 = variable_from_literal(cell_1)
                if replacement.has_key(variable_1):
                    cell_1 = negate(replacement[variable_1], negated_1)
                else:
                    break
            if cell_0 != cell_1:
                if cell_0 == negate(cell_1):
                    raise UnsatInPreprocessing
                elif cell_0 in ["0", "1"]:
                    cell_0, cell_1 = cell_1, cell_0

                variable_0, negated_0 = variable_from_literal(cell_0)
                cell_0, cell_1 = variable_0, negate(cell_1, negated_0)

                if cell_1 not in ["0", "1"]:
                    variable_1, negated_1 = variable_from_literal(cell_1)
                    if not replaces.has_key(variable_1):
                        replaces[variable_1] = []

                if replaces.has_key(variable_0):
                    for variable in replaces[variable_0]:
                        replacement_variable, replacement_negated = variable_from_literal(replacement[variable])
                        replacement[variable] = negate(cell_1, replacement_negated)
                        if cell_1 not in ["0", "1"]:
                            replaces[variable_1].append(variable)
                    del replaces[variable_0]

                replacement[variable_0] = cell_1
                if cell_1 not in ["0", "1"]:
                    replaces[variable_1].append(variable_0)

        for t, generation in enumerate(self.grid):
            for y, row in enumerate(generation):
                for x, cell in enumerate(row):
                    if cell not in ["0", "1"]:
                        variable, negated = variable_from_literal(cell)
                        if replacement.has_key(variable):
                            if replacement[variable] != variable:
                                grid_changed = True
                                self.grid[t][y][x] = negate(replacement[variable], negated)

        for clause_number, clause in enumerate(self.clauses):
            for literal_number, literal in enumerate(clause):
                if literal not in ["0", "1"]:
                    variable, negated = variable_from_literal(literal)
                    if replacement.has_key(variable):
                        if replacement[variable] != variable:
                            clauses_changed = True
                            self.clauses[clause_number][literal_number] = negate(replacement[variable], negated)

        for transition, literal in self.rule.items():
            if literal not in ["0", "1"]:
                variable, negated = variable_from_literal(literal)
                if replacement.has_key(variable):
                    if replacement[variable] != variable:
                        rule_changed = True
                        self.rule[transition] = negate(replacement[variable], negated)

        return grid_changed, clauses_changed, rule_changed
Ejemplo n.º 9
0
    def define_cardinality_variable(self, literals, at_least, already_defined = None, preprocessing = True):
        """Generates clauses defining a cardinality variable"""

        if preprocessing:
            #Remove "0"s and "1"s
            literals_copy = []
            for literal in literals:
                if literal in ["0","1"]:
                    at_least -= int(literal)
                else:
                    literals_copy.append(literal)

            literals_copy.sort()
        else:
            literals_copy = copy.deepcopy(literals)

        if already_defined == None:
            already_defined = []


        def cardinality_variable_name(literals, at_least):
            return "at_least_" + str(at_least) + "_of_" + str(literals)

        name = cardinality_variable_name(literals_copy, at_least)
        clauses = []
        number_of_clauses = 0

        if name not in already_defined:
            already_defined.append(name)

            max_literals = len(literals_copy) #The most literals that could be true
            max_literals_1 = max_literals/2
            literals_1 = literals_copy[:max_literals_1]
            variables_to_define_1 = []  # A list of variables we need to define
            max_literals_2 = max_literals - max_literals_1
            literals_2 = literals_copy[max_literals_1:]
            variables_to_define_2 = []  # A list of variables we need to define

            # If at_least is obviously too small or too big, give the obvious answer
            if at_least <= 0:
                clauses.append([name])
            elif at_least > max_literals:
                clauses.append([negate(name)])
            elif max_literals == 1:
                literal = literals_copy[0]
                clauses.append([negate(name), literal])
                clauses.append([name, negate(literal)])

            # Otherwise define the appropriate clauses
            else:
                if at_least <= max_literals_1:
                    clauses.append(
                        implies(
                            cardinality_variable_name(literals_1, at_least),
                            name))
                    variables_to_define_1.append(at_least)
                for j in range(1, max_literals_2 + 1):
                    for i in range(1, max_literals_1 + 1):
                        if i + j == at_least:
                            clauses.append(
                                implies(
                                    [cardinality_variable_name(literals_1, i),
                                    cardinality_variable_name(literals_2, j)],
                                    name))
                            variables_to_define_1.append(i)
                            variables_to_define_2.append(j)
                if at_least <= max_literals_2:
                    clauses.append(
                        implies(
                            cardinality_variable_name(literals_2, at_least),
                            name))
                    variables_to_define_2.append(at_least)

                if at_least > max_literals_2:
                    i = at_least - max_literals_2
                    clauses.append(
                        implies(
                            negate(cardinality_variable_name(literals_1, i)),
                            negate(name)))
                    variables_to_define_1.append(i)
                for j in range(1, max_literals_2 + 1):
                    for i in range(1, max_literals_1 + 1):
                        if i + j == at_least + 1:
                            clauses.append(implies([
                                    negate(cardinality_variable_name(literals_1, i)),
                                    negate(cardinality_variable_name(literals_2, j))],
                                    negate(name)))
                            variables_to_define_1.append(i)
                            variables_to_define_2.append(j)
                if at_least > max_literals_1:
                    j = at_least - max_literals_1
                    clauses.append(
                        implies(
                            negate(cardinality_variable_name(literals_2, j)),
                            negate(name)))
                    variables_to_define_2.append(j)

            # Remove duplicates from our lists of child variables we need to define
            variables_to_define_1 = set(variables_to_define_1)
            variables_to_define_2 = set(variables_to_define_2)

            # Define the child variables
            for at_least_1 in variables_to_define_1:
                _, number_of_extra_clauses = self.define_cardinality_variable(literals_1, at_least_1, already_defined, preprocessing = False)
                number_of_clauses += number_of_extra_clauses
            for at_least_2 in variables_to_define_2:
                _, number_of_extra_clauses = self.define_cardinality_variable(literals_2, at_least_2, already_defined, preprocessing = False)
                number_of_clauses += number_of_extra_clauses
        number_of_clauses += len(clauses)
        self.clauses += clauses
        return name, number_of_clauses
Ejemplo n.º 10
0
    def force_evolution(self, method=None, indent = 0, verbosity = 0):
        """Adds clauses that force the search pattern to obey the transition rule"""

        # Methods:
        # 0. An implementation of the scheme Knuth describes in TAOCP Volume 4, Fascile 6, solution to exercise 65b (57 clauses and 13 auxillary variables per cell)
        # 1. An implementation of the naive scheme Knuth gives in the solution to exercise 65a                      (190 clauses and 0 auxillary variables per cell)
        # 2. A very naive scheme just listing all possible predecessor neighbourhoods                               (512 clauses and 0 auxillary variables per cell)

        print_message("Enforcing evolution rule...", 3, indent = indent, verbosity = verbosity)

        if method is None:
            if LLS_rules.rulestring_from_rule(self.rule) == "B3/S23":
                method = 1 # Optimal method for Life
            else:
                method = 2 # Default method
        assert method in range(3), "Method not found"
        assert method == 2 or LLS_rules.rulestring_from_rule(self.rule) == "B3/S23", "Rules other than Life can only use method 2"

        print_message("Method: " + str(method), 3, indent = indent + 1, verbosity = verbosity)

        clauses = []
        # Iterate over all cells not in the first generation
        for t, generation in enumerate(self.grid):
            if t > 0:
                for y, row in enumerate(generation):
                    for x, cell in enumerate(row):
                        if not self.ignore_transition[t][y][x]:

                            if method == 0:
                                clauses += LLS_taocp_variable_scheme.transition_rule(self.grid, x, y, t)

                            elif method == 1:
                                predecessor_cell = self.grid[t - 1][y][x]
                                neighbours = neighbours_from_coordinates(self.grid, x, y, t)

                                #TODO: Do the following clauses work if there aren't eight neighbours?

                                # If any four neighbours were live, then the cell is
                                # dead
                                for four_neighbours in itertools.combinations(neighbours, 4):
                                    clause = implies(four_neighbours, negate(cell))
                                    clauses.append(clause)

                                # If any seven neighbours were dead, the cell is dead
                                for seven_neighbours in itertools.combinations(neighbours, 7):
                                    clause = implies(map(negate,seven_neighbours), negate(cell))
                                    clauses.append(clause)

                                # If the cell was dead, and any six neighbours were
                                # dead, the cell is dead
                                for six_neighbours in itertools.combinations(neighbours, 6):
                                    clause = implies([negate(predecessor_cell)] + map(negate,six_neighbours), negate(cell))
                                    clauses.append(clause)

                                # If three neighbours were alive and five were dead,
                                # then the cell is live
                                for three_neighbours in itertools.combinations(neighbours, 3):
                                    neighbours_counter = collections.Counter(neighbours)
                                    neighbours_counter.subtract(three_neighbours)
                                    three_neighbours, five_neighbours = list(three_neighbours), list(neighbours_counter.elements())

                                    clause = implies(three_neighbours + map(negate, five_neighbours), cell)
                                    clauses.append(clause)

                                # Finally, if the cell was live, and two neighbours
                                # were live, and five neighbours were dead, then the
                                # cell is live (independantly of the final neighbour)
                                for two_neighbours in itertools.combinations(neighbours, 2):
                                    neighbours_counter = collections.Counter(neighbours)
                                    neighbours_counter.subtract(two_neighbours)
                                    two_neighbours, five_neighbours = list(two_neighbours), list(neighbours_counter.elements())[1:]

                                    clause = implies([predecessor_cell] + two_neighbours + map(negate, five_neighbours), cell)
                                    clauses.append(clause)

                            elif method == 2:

                                predecessor_cell = self.grid[t - 1][y][x]
                                neighbours = neighbours_from_coordinates(self.grid,x,y,t)

                                booleans = [True, False]

                                # For each combination of neighbourhoods
                                for predecessor_cell_alive in booleans:
                                    for neighbours_alive in itertools.product(booleans,repeat=8):

                                        BS_letter = "S" if predecessor_cell_alive else "B"
                                        transition = LLS_rules.transition_from_cells(neighbours_alive)
                                        transition_literal = self.rule[BS_letter + transition]

                                        clauses.append(implies([transition_literal] + [negate(predecessor_cell, not predecessor_cell_alive)] + map(negate, neighbours, map(lambda P: not P, neighbours_alive)), cell))
                                        clauses.append(implies([negate(transition_literal)] + [negate(predecessor_cell, not predecessor_cell_alive)] + map(negate, neighbours, map(lambda P: not P, neighbours_alive)), negate(cell)))

        print_message("Number of clauses used: " + str(len(clauses)), 3, indent = indent + 1, verbosity = verbosity)
        print_message("Done\n", 3, indent = indent, verbosity = verbosity)

        self.clauses += clauses
Ejemplo n.º 11
0
    def improve_clauses(self, indent = 0, verbosity = 0):

        print_message("Improving clause list...", 3, indent = indent, verbosity = verbosity)

        print_message('Tidying clauses...', 3, indent = indent + 1, verbosity = verbosity)
        clauses_to_remove = set()
        to_force_equal = []
        clauses_seen_so_far = set()
        clauses_changed0 = False
        for clause_number, clause in enumerate(self.clauses):
            remove_flag = False
            if "1" in clause:
                remove_flag = True
            else:
                for literal in clause:
                    if negate(literal) in clause:
                        remove_flag = True
            if remove_flag:
                clauses_to_remove.add(clause_number)
            else:
                starting_length = len(self.clauses[clause_number])
                self.clauses[clause_number] = [literal for literal in sorted(list(set(clause))) if literal != "0"]
                number_of_literals = len(self.clauses[clause_number])
                if starting_length != number_of_literals:
                    clauses_changed0 = True
                if number_of_literals == 1:
                    to_force_equal.append((self.clauses[clause_number][0],"1"))
                elif number_of_literals == 2:
                    if str(sorted([negate(self.clauses[clause_number][0]), negate(self.clauses[clause_number][1])])) in clauses_seen_so_far:
                        to_force_equal.append((self.clauses[clause_number][0],negate(self.clauses[clause_number][1])))
                    elif str(sorted([self.clauses[clause_number][0], negate(self.clauses[clause_number][1])])) in clauses_seen_so_far:
                        to_force_equal.append((self.clauses[clause_number][0],"1"))
                    elif str(sorted([negate(self.clauses[clause_number][0]), self.clauses[clause_number][1]])) in clauses_seen_so_far:
                        to_force_equal.append((self.clauses[clause_number][1],"1"))
                    else:
                        clauses_seen_so_far.add(str(self.clauses[clause_number]))
        if clauses_to_remove:
            clauses_changed0 = True
        self.clauses = [clause for clause_number, clause in enumerate(self.clauses) if clause_number not in clauses_to_remove]
        print_message('Done\n', 3, indent = indent + 1, verbosity = verbosity)

        print_message('Removing duplicate clauses...', 3, indent = indent + 1, verbosity = verbosity)
        seen = set()
        temporary_list = []
        for clause in self.clauses:
            clause.sort()
            clause_string = str(clause)
            if clause_string not in seen:
                seen.add(clause_string)
                temporary_list.append(clause)
            else:
                clauses_changed0 = True
        self.clauses = temporary_list
        print_message('Done\n', 3, indent = indent + 1, verbosity = verbosity)

        print_message('Making deductions...', 3, indent = indent + 1, verbosity = verbosity)
        grid_changed, clauses_changed1, rule_changed = self.force_equal(to_force_equal)
        print_message('Done\n', 3, indent = indent + 1, verbosity = verbosity)
        clauses_changed = clauses_changed0 or clauses_changed1
        print_message("Done\n", 3, indent = indent, verbosity = verbosity)

        return grid_changed, clauses_changed, rule_changed
Ejemplo n.º 12
0
    def improve_grid(self, indent = 0, verbosity = 0):
        print_message("Improving grid...", 3, indent = indent, verbosity = verbosity)
        parents_dict = {}
        to_force_equal = []
        grid_changed0 = False
        outer_totalistic = LLS_rules.outer_totalistic(self.rule)
        for t, generation in enumerate(self.grid):
            if t > 0:
                for y, row in enumerate(generation):
                    for x, cell in enumerate(row):
                        predecessor_cell = self.grid[t - 1][y][x]
                        neighbours = neighbours_from_coordinates(self.grid, x, y, t)

                        if not self.ignore_transition[t][y][x]:
                            parents = [predecessor_cell] + list(LLS_rules.sort_neighbours(neighbours, outer_totalistic))
                            parents_string = str(parents)
                            if parents_dict.has_key(parents_string):
                                self.grid[t][y][x] = parents_dict[parents_string]
                                if self.grid[t][y][x] != cell:
                                    grid_changed0 = True
                                to_force_equal.append((parents_dict[parents_string],cell))
                                self.ignore_transition[t][y][x] = True
                            elif all(parent in ["0", "1"] for parent in parents):
                                BS_letter = ["B", "S"][["0", "1"].index(predecessor_cell)]
                                transition = LLS_rules.transition_from_cells(neighbours)
                                child = self.rule[BS_letter + transition]
                                self.grid[t][y][x] = child
                                if self.grid[t][y][x] != cell:
                                    grid_changed0 = True
                                to_force_equal.append((cell, child))
                                self.ignore_transition[t][y][x] = True
                                parents_dict[parents_string] = child
                            else:
                                parents_dict[parents_string] = cell
                                variables = []
                                for literal in [cell, predecessor_cell] + neighbours:
                                    if literal not in ["0", "1"]:
                                        variable, _ = variable_from_literal(literal)
                                        if variable not in variables:
                                            variables.append(variable)
                                booleans = [False, True]

                                transition_redundant = True

                                variables_true = set(range(len(variables)))
                                variables_false = set(range(len(variables)))
                                variables_equal = set(itertools.combinations(range(len(variables)),2))
                                variables_unequal = set(itertools.combinations(range(len(variables)),2))

                                for variables_alive in itertools.product(booleans, repeat=len(variables)):
                                    dead_literals = map(negate, variables, variables_alive)
                                    if cell == "0":
                                        cell_alive = False
                                    elif cell not in dead_literals:
                                        cell_alive = True
                                    else:
                                        cell_alive = False

                                    if predecessor_cell == "0":
                                        predecessor_cell_alive = False
                                    elif predecessor_cell not in dead_literals:
                                        predecessor_cell_alive = True
                                    else:
                                        predecessor_cell_alive = False

                                    neighbours_alive = []
                                    for neighbour in neighbours:
                                        if neighbour == "0":
                                            neighbours_alive.append(False)
                                        elif neighbour not in dead_literals:
                                            neighbours_alive.append(True)
                                        else:
                                            neighbours_alive.append(False)

                                    BS_letter = "S" if predecessor_cell_alive else "B"
                                    transition = LLS_rules.transition_from_cells(neighbours_alive)
                                    transition_variable = self.rule[BS_letter + transition]


                                    if (transition_variable not in ["0", "1"]) or (transition_variable == "0" and not cell_alive) or (transition_variable == "1" and cell_alive):
                                        to_remove = []
                                        for variable_number in variables_true:
                                            if not variables_alive[variable_number]:
                                                to_remove.append(variable_number)
                                        variables_true.difference_update(to_remove)

                                        to_remove = []
                                        for variable_number in variables_false:
                                            if variables_alive[variable_number]:
                                                to_remove.append(variable_number)
                                        variables_false.difference_update(to_remove)

                                        to_remove = []
                                        for variable_number_0, variable_number_1 in variables_equal:
                                            if variables_alive[variable_number_0] != variables_alive[variable_number_1]:
                                                to_remove.append((variable_number_0, variable_number_1))
                                        variables_equal.difference_update(to_remove)

                                        to_remove = []
                                        for variable_number_0, variable_number_1 in variables_unequal:
                                            if variables_alive[variable_number_0] == variables_alive[variable_number_1]:
                                                to_remove.append((variable_number_0, variable_number_1))
                                        variables_unequal.difference_update(to_remove)

                                    if (transition_variable not in ["0", "1"]) or (transition_variable == "0" and cell_alive) or (transition_variable == "1" and not cell_alive):
                                        transition_redundant = False
                                if transition_redundant:
                                    self.ignore_transition[t][y][x] = True
                                for variable_number in variables_true:
                                    to_force_equal.append((variables[variable_number], "1"))
                                for variable_number in variables_false:
                                    to_force_equal.append((variables[variable_number], "0"))
                                for variable_number_0, variable_number_1 in variables_equal:
                                    to_force_equal.append((variables[variable_number_0], variables[variable_number_1]))
                                for variable_number_0, variable_number_1 in variables_unequal:
                                    to_force_equal.append((variables[variable_number_0], negate(variables[variable_number_1])))
        grid_changed1, clauses_changed, rule_changed = self.force_equal(to_force_equal)
        grid_changed = grid_changed0 or grid_changed1
        print_message("Done\n", 3, indent = indent, verbosity = verbosity)

        return grid_changed, clauses_changed, rule_changed