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 = []
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 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