def get_best_var_to_flip(self, instance, best_solution,
                             current_no_of_unsat_clauses):
        best_no_of_unsat_clauses = current_no_of_unsat_clauses
        best = best_solution.copy()
        utils = SatUtils()

        for i in range(1, len(best)):
            # checking if given variable is part of tabu list. If it is then next var is selected for the flip
            if self.is_var_tabu(i):
                continue

            tmp_solution = best_solution.copy()
            # working copy of the proposed solution
            var_to_flip = tmp_solution[i]

            # flipping a selected variable to opposing value
            tmp_solution[i] = SatUtils.flip_var(var_to_flip)

            _, no_of_unsat_clauses = SatUtils.solution_status(
                instance, tmp_solution)

            # if solution hasn't been found check if proposed temp solution is better than previous best
            if no_of_unsat_clauses < best_no_of_unsat_clauses:
                best_no_of_unsat_clauses = no_of_unsat_clauses

                # add current selection to tabu list
                self.add_to_tabu(i)
                # remember the best solution found so far for the next iteration
                best = tmp_solution.copy()

        return best
    def main(self,
             max_restarts=10,
             max_iterations=1000,
             instance_path="./sat_data/test.cnf"):
        instance = SatUtils.read_instance(instance_path)
        var_count = len(instance[0])

        start = time.time()
        end = None

        for restart in range(max_restarts):
            best_solution = SatUtils.initialize_variables(var_count)

            for iteration in range(max_iterations):
                solution_status, no_of_unsat_clauses = SatUtils.solution_status(
                    instance, best_solution)

                # if solution has been found terminate the search
                if solution_status is True:
                    end = time.time()

                    print("Iteration,{0},Restart,{1},Duration,{2}".format(
                        iteration, restart, end - start))
                    return
                best_solution = self.get_best_var_to_flip(
                    instance, best_solution, no_of_unsat_clauses)

            # resetting tabu list in between the restarts
            GsatSolver.tabu = []
Beispiel #3
0
    def execute_walk(self, formula, proposed_solution):
        solution_found, unsat_clause, unsat_clause_list = SatUtils.solution_status_with_unsat_clauses(formula,
                                                                                                      proposed_solution)

        random_unsat_clause = random.choice(unsat_clause_list)

        random_variable_in_clause = random.choice(random_unsat_clause)

        # as we're choosing a variable from the unsat clause we can come across negative numbers, where negative
        # sign would indicate variable is in 0 state, however, negative index are not present in the proposed solution
        # array, so it needs to be guaranteed that a positive number is passed as index, hence use of abs()
        proposed_solution[abs(random_variable_in_clause)] = SatUtils.flip_var(abs(random_variable_in_clause))

        return proposed_solution
    def test_read_instance(self):
        test_file_path = './sat_test_data/test.cnf'

        cnf = SatUtils.read_instance(test_file_path)
        self.assertEqual(len(cnf), 2)
        self.assertEqual(len(cnf[0]), 6)
        self.assertEqual(len(cnf[1]), 4)
    def execute_search(self, proposed_solution, currently_flipped_variable,
                       random_clause):
        """
        Choose a variable to be flipped.
        If a randomly chosen variable is present in the randomly selected unsatisfied clause then return that variable.
        Otherwise find best and second best variable to be flipped. The choice between which variable to select, best
        or second best is made based on the probability provided.
        :param proposed_solution:
        :return:
        """
        if currently_flipped_variable not in random_clause:
            return currently_flipped_variable
        else:
            # Chose best or second best variable to flip based on the probability provided
            tmp_solution = proposed_solution.copy()
            flip_scores = {}
            utils = SatUtils()

            # loop over the variables to see which flip generates the lowest number of unsatisfied clauses
            for i in range(len(self.variables)):
                tmp_solution[i] = SatUtils.flip_var(self.variables[i])
                _, unsat_clauses = SatUtils.solution_status(
                    self.instance, tmp_solution)

                # keep track of which variable flip generated what number of unsatisfied clauses
                flip_scores[self.variables[i]] = unsat_clauses

                # flip the selected variable
                tmp_solution[i] = SatUtils.flip_var(self.variables[i])

            # Find best and second best - extremely efficient according to stack overflow
            two_smallest_keys = heapq.nsmallest(2,
                                                flip_scores,
                                                key=flip_scores.get)

            best = two_smallest_keys[0]
            second_best = two_smallest_keys[1]

            # generate noise value
            noise_value = random.uniform(0, 1)

            # compare noise value generated to the probability of second best variable being selected
            if noise_value < self.probability:
                return second_best
            else:
                return best
    def test_basic_solution_status_with_true_state(self):
        formula = [[1, 2, 3, 4, 5, 6],
                   [[1, -2, 3], [1, -2, -3], [1, 2, 4], [-4, -5, 6]]]

        solution = {1: 1, 2: 1, 3: 0, 4: 1, 5: 1, 6: 1}

        solution_found, unsat_result = SatUtils.solution_status(
            formula, solution)
        self.assertTrue(solution_found)
        self.assertEqual(unsat_result, 0)
    def test_solution_status_with_false_state(self):
        formula = [[1, 2, 3, 4, 5, 6],
                   [[1, -2, 3], [1, -2, -3], [1, 2, 4], [-4, -5, 6]]]

        solution = {1: 1, 2: 0, 3: 0, 4: 1, 5: 1, 6: 0}

        solution_found, unsat_result, unsat_list = SatUtils.solution_status_with_unsat_clauses(
            formula, solution)
        self.assertFalse(solution_found)
        self.assertEqual(unsat_result, 1)
        self.assertEqual(len(unsat_list), 1)
Beispiel #8
0
    def main(self, wp, p, max_iterations, instance_path):
        cnf_contents = SatUtils.read_instance(instance_path)
        # instantiate required search and util objects
        novelty_search = NoveltySearch(cnf_contents, p, 1)
        variables = cnf_contents[0]
        walkSat = WalkSat()

        # initialize first solution proposal
        proposed_solution = SatUtils.initialize_variables(len(variables))

        # start the timer
        start = time.time()
        end = None

        for i in range(max_iterations):
            # checking for timeout terminate condition
            if time.time() > start + 60:
                return
            solution_found, unsat_clause, unsat_clause_list = SatUtils.solution_status_with_unsat_clauses(
                cnf_contents, proposed_solution)
            # if a solution has been identified break out of the search loop and record it
            if solution_found is True:
                end = time.time()
                print("Iteration,{0},Duration,{1}".format(i, end - start))
                return

            # pick algorithm to run the solution search based on probability
            if wp < random.uniform(0, 1):
                proposed_solution = walkSat.execute_walk(
                    cnf_contents, proposed_solution)
            else:
                random_variable_to_flip = random.choice(variables)
                random_unsat_clause = random.choice(unsat_clause_list)

                best_flip = novelty_search.execute_search(
                    proposed_solution, random_variable_to_flip,
                    random_unsat_clause)

                proposed_solution[best_flip] = SatUtils.flip_var(
                    proposed_solution[best_flip])
    def main(self):
        proposed_solution = SatUtils.initialize_variables(self.variables)

        start = time.time()
        end = None
        for i in range(self.max_iterations):
            solution_found, unsat_clause, unsat_clause_list = SatUtils.solution_status_with_unsat_clauses(
                self.instance, proposed_solution)

            if solution_found is True:
                end = time.time()
                print("Iteration,{0},Duration,{1}".format(i, end - start))
                return

            random_flip = random.choice(self.variables)
            random_clause = random.choice(unsat_clause_list)

            flip_this_index = self.execute_search(proposed_solution,
                                                  random_flip, random_clause)

            proposed_solution[flip_this_index] = SatUtils.flip_var(
                proposed_solution[flip_this_index])
    def test_initializing_variables(self):
        result = SatUtils.initialize_variables(10)

        print(result)

        self.assertEqual(len(result), 10)
    def test_flip_var(self):
        result = SatUtils.flip_var(0)

        self.assertEqual(result, 1)
                                                flip_scores,
                                                key=flip_scores.get)

            best = two_smallest_keys[0]
            second_best = two_smallest_keys[1]

            # generate noise value
            noise_value = random.uniform(0, 1)

            # compare noise value generated to the probability of second best variable being selected
            if noise_value < self.probability:
                return second_best
            else:
                return best


if __name__ == '__main__':
    instance_path = None

    # check whether a path to input dataset has been provided or should the default path be used
    if len(sys.argv) > 1:
        instance_path = sys.argv[1]
    else:
        instance_path = "./sat_data/uf20-020.cnf"

    cnf_contents = SatUtils.read_instance(instance_path)
    solver = NoveltySearch(cnf_contents, 0.4, 100000)

    for i in range(1):
        solver.main()