def sa(pos, grid, n, m, t, start_T=500, c=0.95): best_path = [] T = start_T counter = 0 moves_manager = MovesManager(grid, pos, n, m) start = time.time() while time.time() - start < t: T = start_T counter = 0 print(time.time() - start, t) cur_pos = pos.copy() cur_path = [] while (not moves_manager.check_for_exit( cur_pos, grid)) and time.time() - start < t: cur_pos = pos.copy() cur_path = moves_manager.random_moves(cur_pos, grid, n, m, (n - 2) * (m - 2)) if time.time() - start >= t: return best_path if len(best_path) == 0 or len(cur_path) < len(best_path): best_path = cur_path.copy() treshold = min(n, m) * len(cur_path) while counter < treshold and T > 0 and time.time() - start < t: temp_path = gen_neighbour(cur_path) temp_path, exit_found = moves_manager.explore( pos.copy(), temp_path, grid) if exit_found: if len(temp_path) <= len(cur_path): cur_path = temp_path.copy() if len(cur_path) < len(best_path): best_path = cur_path.copy() elif uniform(0, 1) <= calculate_probability( len(temp_path) - len(cur_path), T): cur_path = temp_path.copy() T = decrease_temperature(T, c) else: counter += 1 return best_path
class Population: def __init__(self, population_size, all_puzzles, starter_words, start_pos): self.start_pos = start_pos self.all_puzzles = all_puzzles self.moves_manager = MovesManager() self.population_size = population_size self.generation = self._gen_generation(starter_words, start_pos) def __iter__(self): for inhabitant in self.generation: yield inhabitant def _random_word(self, length): return [random.choice(self.all_puzzles) for _ in range(length)] def _gen_generation(self, starter_words, pos): min_size = min([len(word) for word in starter_words]) max_size = max([len(word) for word in starter_words]) generation = [] for word in starter_words: generation.append(Inhabitant(list(word))) for _ in range(len(starter_words), self.population_size): word = self.moves_manager.random_moves() generation.append(Inhabitant(word)) return generation def sorted_generation(self): return sorted(self.generation, key=lambda x: x.value, reverse=True) def make_selection(self, elite_percentage, percentage=0.5): selection = [] sorted_generation = self.sorted_generation() selection_size = int(self.population_size * percentage) elite_size = int(elite_percentage * selection_size) for inhabitant in sorted_generation[:elite_size]: selection.append(inhabitant) if elite_size - selection_size < 0: for inhabitant in sorted_generation[elite_size - selection_size:]: selection.append(inhabitant) return selection def recombinate(self, elite_percentage=0.6): selection = self.make_selection(elite_percentage) permutation = np.random.permutation(len(selection)) new_generation = [] new_generation.append(Inhabitant(selection[0].gene.copy())) new_generation.append(Inhabitant(selection[1].gene.copy())) for i in range(1, len(permutation)): pivot = random.randint( 0, min( len(selection[permutation[i % len(permutation)]]), len(selection[permutation[(i + 1) % len(permutation)]]), ) // 2, ) new_word = ( selection[permutation[i % len(permutation)]][:pivot] + selection[permutation[(i + 1) % len(permutation)]][pivot:]) if len(new_generation) < self.population_size: new_generation.append(Inhabitant(new_word)) new_word = ( selection[permutation[(i + 1) % len(permutation)]][:pivot] + selection[permutation[i % len(permutation)]][pivot:]) if len(new_generation) < self.population_size: new_generation.append(Inhabitant(new_word)) self.generation = new_generation def mutate( self, min_swap_probability=0.2, max_swap_probability=0.7, inverse_probability=0.001, shift_probability=0.001, insert_probability=0.9, ): swap_probability = random.uniform(min_swap_probability, max_swap_probability) for inhabitant in self.generation[1:]: if decision(insert_probability): insert_amount = random.randint(1, 2) if decision(0.5): # remove decision possible_chars = self._random_word(insert_amount) if decision(0.33): inhabitant.gene += possible_chars elif decision(0.5): inhabitant.gene = possible_chars + inhabitant.gene else: insert_index = random.randint(1, len(inhabitant.gene)) inhabitant.gene = inhabitant.gene[: insert_index] + possible_chars + inhabitant.gene[ insert_index:] else: if (len(inhabitant) - insert_amount > 0): if decision(0.5): inhabitant.gene = inhabitant.gene[insert_amount:] else: inhabitant.gene = inhabitant.gene[:-insert_amount] else: if decision(shift_probability): shift_range = random.randint(1, 3) for _ in range(shift_range + 1): inhabitant.gene = [inhabitant.gene[-1] ] + inhabitant.gene[:-1] for i in range(len(inhabitant.gene) // 2): if decision(swap_probability): random_id = random.randint(0, len(inhabitant) - 1) inhabitant.gene[i], inhabitant.gene[random_id] = ( inhabitant.gene[random_id], inhabitant.gene[i], ) if decision(inverse_probability): inhabitant.gene = inhabitant.gene[::-1]