def mutate(self, parent: Tree): if (self.mutation_algorithms is None) or (self.mutation_algorithms is []): return elif random.random() > self.mutation_rate: return rand_mutation_method: str = self.mutation_algorithms[random.randrange( 0, self.mutation_algorithms.__len__())] # todo not sure about correct names for these types of mutations if rand_mutation_method is "delete": # delete children underneath and attach random terminals to it self.__mutate_delete(parent) elif rand_mutation_method is "change": # change the label of the node with respect to its max_num_of_children self.__mutate_change(parent) elif rand_mutation_method is "add": # adds a whole new tree as one of its children self.__mutate_add(parent) elif rand_mutation_method is "exchange": # change the type (function to terminal and otherwise) pass # todo implement this else: raise Exception("Invalid Algorithm for Mutation") parent.is_mutated = True parent.update_tree() if parent.depth > self.max_depth: parent.reshape_max_depth(self.max_depth)
def __mutate_delete(self, parent: Tree): rand_node_index = random.randrange(0, parent.number_of_nodes_in_tree) temp_node: Node = parent.get_node(rand_node_index) if temp_node is None: raise Exception("Invalid Node Index") while temp_node.type is "T": rand_node_index = random.randrange(0, parent.number_of_nodes_in_tree) temp_node = parent.get_node(rand_node_index) for i in range(temp_node.max_num_of_children): temp_node.children_list[i] = parent.generate_random_terminal()
def calculate_fitness_for_individual(circuit: Tree): global found_solution temp_fitness = 0 for state in truth_table: if solve_circuit(state[0], circuit) is state[1]: temp_fitness += 1 if temp_fitness is total_combinations: circuit.is_answer = True found_solution = True input("Found Solution in Generation : {0}".format(gp.generation)) # temp_fitness /= circuit.depth + 1 circuit.fitness = temp_fitness
def __mutate_add(self, parent: Tree): rand_node_index = random.randrange(1, parent.number_of_nodes_in_tree) temp_node: Node = parent.get_node(rand_node_index) while temp_node.type is "T": rand_node_index = random.randrange(0, parent.number_of_nodes_in_tree) temp_node: Node = parent.get_node(rand_node_index) final_depth = parent.depth if hp.GP.mutate_add_depth < 2 else hp.GP.mutate_add_depth temp_tree = Tree(final_depth, self.function_set, self.terminal_set) temp_tree.populate_random_tree(["grow", "full" ].__getitem__(random.randrange(0, 2))) temp_node.children_list[random.randrange( 0, temp_node.max_num_of_children)] = temp_tree.root
def __mutate_change(self, parent: Tree): rand_node_index = random.randrange(0, parent.number_of_nodes_in_tree) temp_node: Node = parent.get_node(rand_node_index) # make sure excluding current terminal won't break our lovely program if (temp_node.type is "T") and (self.terminal_set.__len__() > 1): temp_remaining_terminals = [ t for t in self.terminal_set if t is not temp_node.label ] temp_node.label = temp_remaining_terminals[random.randrange( 0, temp_remaining_terminals.__len__())] if (temp_node.type is "F") and (self.function_set.__len__() > 1): # generating a list of tuples from remaining function excluding current function label temp_remaining_functions = [ f_tpl[0] for f_tpl in self.function_set if (f_tpl[0] is not temp_node.label) and ( f_tpl[1] is temp_node.max_num_of_children) ] if temp_remaining_functions.__len__() > 0: temp_node.label = temp_remaining_functions[random.randrange( 0, temp_remaining_functions.__len__())]
def __cross_over(self, parent_1: Tree, parent_2: Tree) -> Tree: # getting a random node from parent_2 temp_node = parent_2.get_random_node().copy() # region generating a index range for parent_1 depth_min_range = hp.GP.cross_over_min_range depth_max_range = int(hp.GP.cross_over_min_range_multiplier * parent_1.number_of_nodes_in_tree) if depth_min_range >= depth_max_range: raise Exception("Invalid Range for crossover replacement : (", depth_min_range, " , ", depth_max_range, ")") if depth_max_range is 1: depth_max_range += 1 depth_range = (depth_min_range, depth_max_range) # endregion parent_1.select_random_node_and_replace(depth_range, temp_node) # update and reshape the tree if needed parent_1.update_tree() if parent_1.depth > self.max_depth: parent_1.reshape_max_depth(self.max_depth) return parent_1
def initialize_population(self, initialization_method: str, shuffle: bool = True): if initialization_method is "full": for i in range(self.population_size): rand_depth = random.randrange(self.depth_range[0], self.depth_range[1] + 1) temp_tree = Tree(rand_depth, self.function_set, self.terminal_set) temp_tree.populate_random_tree("full") self.population.append(temp_tree) elif initialization_method is "grow": for i in range(self.population_size): rand_depth = random.randrange(self.depth_range[0], self.depth_range[1] + 1) temp_tree = Tree(rand_depth, self.function_set, self.terminal_set) temp_tree.populate_random_tree("grow") self.population.append(temp_tree) # ramped (or ramped half and half) is a combination of both "grow" and "full" elif initialization_method is "ramped": for i in range(0, int(self.population_size / 2)): rand_depth = random.randrange(self.depth_range[0], self.depth_range[1] + 1) temp_tree = Tree(rand_depth, self.function_set, self.terminal_set) temp_tree.populate_random_tree("grow") self.population.append(temp_tree) for i in range(int(self.population_size / 2), self.population_size): rand_depth = random.randrange(self.depth_range[0], self.depth_range[1] + 1) temp_tree = Tree(rand_depth, self.function_set, self.terminal_set) temp_tree.populate_random_tree("full") self.population.append(temp_tree) else: raise Exception("Invalid Algorithm for initializing population") if shuffle: random.shuffle(self.population)