def mutate(self, genome): if random.random() < genome.mute_rates["gene_action"]: # Mutate this gene's action self.action = mutated_intenum(self.action, goomba.Action, 1.0, genome.mute_rates["enum_rel"]) elif random.random() < genome.mute_rates["struct_mod"]: # Structure-modifying function mutations. # Select a random node and mutation node = random.choice(self.function.as_list()) mute = weighted_choice(genome.mute_rates["struct_rel"]) if mute == StructMutes.SubTree: new_node = FTreeNode.random(round(genome.fun_gen_depth), len(genome), genome.const_bounds, genome.mute_rates["leaf_rel"], node.parent) if node.parent is None: self.function = new_node elif node.parent.left == node: node.parent.left = new_node else: node.parent.right = new_node elif mute == StructMutes.OpAbove: new_node = FTreeNode(random.choice(list(Op)), None, None, node.parent) if node.parent is None: self.function = new_node elif node.parent.left == node: node.parent.left = new_node else: node.parent.right = new_node new_child = FTreeNode.random(round(genome.fun_gen_depth), len(genome), genome.const_bounds, genome.mute_rates["leaf_rel"], new_node) if random.random() < 0.5: new_node.left = node new_node.right = new_child else: new_node.left = new_child new_node.right = node elif mute == StructMutes.Swap: if isinstance(node, FTreeLeaf): if node.parent is not None: node = node.parent else: return # swap operands tmp = node.left node.left = node.right node.right = tmp else: # Non-strucure-modifying function mutation # Select a random node node = random.choice(self.function.as_list()) if isinstance(node, FTreeNode): # mutate operator node.operator = mutated_intenum(node.operator, Op, 1.0, genome.mute_rates["enum_rel"]) else: if random.random() < genome.mute_rates["leaf_type"]: # mutate the leaf type new_type = node.ref_type # Keep trying to mutate until the value actually changes while new_type == node.ref_type: new_type = mutated_intenum( node.ref_type, RefType, 1.0, genome.mute_rates["leaf_rel"]) if node.ref_type == RefType.Constant: node.val = round( node.val) # In case mutating from float to int node.ref_type = new_type else: # mutate the leaf value if node.ref_type == RefType.Constant: node.val = mutated_num(node.val, 1.0, genome, [None, None]) elif node.ref_type in [ RefType.Pure_Offset_Call, RefType.Impure_Offset_Call ]: node.val = mutated_int_in_range( node.val, 1.0, [-len(genome), len(genome)], genome.mute_rates["enum_rel"]) elif node.ref_type == RefType.Poll_Sensor: node.val = mutated_int_in_range( node.val, 1.0, [0, len(goomba.Sensor) - 1], genome.mute_rates["enum_rel"])
def mutate(self, genome): if random.random() < genome.mute_rates["gene_action"]: # Mutate this gene's action self.action = mutated_intenum(self.action, goomba.Action, 1.0, genome.mute_rates["enum_rel"]) elif random.random() < genome.mute_rates["struct_mod"]: # Structure-modifying function mutations. # Select a random node and mutation node = random.choice(self.function.as_list()) mute = weighted_choice(genome.mute_rates["struct_rel"]) if mute == StructMutes.SubTree: new_node = FTreeNode.random(round(genome.fun_gen_depth), len(genome), genome.const_bounds, genome.mute_rates["leaf_rel"], node.parent) if node.parent is None: self.function = new_node elif node.parent.left == node: node.parent.left = new_node else: node.parent.right = new_node elif mute == StructMutes.OpAbove: new_node = FTreeNode(random.choice(list(Op)), None, None, node.parent) if node.parent is None: self.function = new_node elif node.parent.left == node: node.parent.left = new_node else: node.parent.right = new_node new_child = FTreeNode.random(round(genome.fun_gen_depth), len(genome), genome.const_bounds, genome.mute_rates["leaf_rel"], new_node) if random.random() < 0.5: new_node.left = node new_node.right = new_child else: new_node.left = new_child new_node.right = node elif mute == StructMutes.Swap: if isinstance(node, FTreeLeaf): if node.parent is not None: node = node.parent else: return # swap operands tmp = node.left node.left = node.right node.right = tmp else: # Non-strucure-modifying function mutation # Select a random node node = random.choice(self.function.as_list()) if isinstance(node, FTreeNode): # mutate operator node.operator = mutated_intenum(node.operator, Op, 1.0, genome.mute_rates["enum_rel"]) else: if random.random() < genome.mute_rates["leaf_type"]: # mutate the leaf type new_type = node.ref_type # Keep trying to mutate until the value actually changes while new_type == node.ref_type: new_type = mutated_intenum(node.ref_type, RefType, 1.0, genome.mute_rates["leaf_rel"]) if node.ref_type == RefType.Constant: node.val = round(node.val) # In case mutating from float to int node.ref_type = new_type else: # mutate the leaf value if node.ref_type == RefType.Constant: node.val = mutated_num(node.val, 1.0, genome, [None, None]) elif node.ref_type in [RefType.Pure_Offset_Call, RefType.Impure_Offset_Call]: node.val = mutated_int_in_range(node.val, 1.0, [-len(genome), len(genome)], genome.mute_rates["enum_rel"]) elif node.ref_type == RefType.Poll_Sensor: node.val = mutated_int_in_range(node.val, 1.0, [0, len(goomba.Sensor) - 1], genome.mute_rates["enum_rel"])
def random(cls, max_depth, gen_len, const_bounds, leaf_weights): action = random.choice(list(goomba.Action)) function = FTreeNode.random(max_depth, gen_len, const_bounds, leaf_weights) return cls(action, function)