def LTGE_crossover(p_0, p_1): """Crossover in the LTGE representation.""" # crossover and repair. # the LTGE crossover produces one child, and is symmetric (ie # xover(p0, p1) is not different from xover(p1, p0)), but since it's # stochastic we can just run it twice to get two individuals # expected to be different. g_0, ph_0 = latent_tree_repair( latent_tree_crossover(p_0.genome, p_1.genome), params['BNF_GRAMMAR'], params['MAX_TREE_DEPTH']) g_1, ph_1 = latent_tree_repair( latent_tree_crossover(p_0.genome, p_1.genome), params['BNF_GRAMMAR'], params['MAX_TREE_DEPTH']) # wrap up in Individuals and fix up various Individual attributes ind_0 = individual.Individual(g_0, None, False) ind_1 = individual.Individual(g_1, None, False) ind_0.phenotype = ph_0 ind_1.phenotype = ph_1 # number of nodes is the number of decisions in the genome ind_0.nodes = ind_0.used_codons = len(g_0) ind_1.nodes = ind_1.used_codons = len(g_1) # each key is the length of a path from root ind_0.depth = max(len(k) for k in g_0) ind_1.depth = max(len(k) for k in g_1) # in LTGE there are no invalid individuals ind_0.invalid = False ind_1.invalid = False return [ind_0, ind_1]
def fixedlength_onepoint(p_0, p_1, within_used=True): """Given two individuals, create two children using fixed-length one-point crossover (i.e., like a GA with a single locus shared between both parents) and return them.""" # Get the chromosomes c_p_0, c_p_1 = p_0.genome, p_1.genome # Uniformly generate a single crossover point. if within_used: max_p_0, max_p_1 = p_0.used_codons, p_1.used_codons else: max_p_0 = len(c_p_0) pt_p_0 = randint(1, max_p_0) # Make new chromosomes by crossover: these slices perform copies if random() < params['CROSSOVER_PROBABILITY']: c_0 = c_p_0[:pt_p_0] + c_p_1[pt_p_0:] c_1 = c_p_1[:pt_p_0] + c_p_0[pt_p_0:] else: c_0, c_1 = c_p_0[:], c_p_1[:] # Put the new chromosomes into new individuals ind_0 = individual.Individual(c_0, None) ind_1 = individual.Individual(c_1, None) return [ind_0, ind_1]
def subtree(p_0, p_1): """Given two individuals, create two children using subtree crossover and return them.""" if random() > params['CROSSOVER_PROBABILITY']: ind0 = p_1 ind1 = p_0 else: tail_0, tail_1 = p_0.genome[p_0.used_codons:], \ p_1.genome[p_1.used_codons:] tree_0, genome_0, tree_1, genome_1 = do_subtree_crossover( p_0.tree, p_1.tree) ind0 = individual.Individual(genome_0, tree_0) ind0.genome = genome_0 + tail_0 ind0.used_codons = len(genome_0) ind0.depth, ind0.nodes = tree_0.get_tree_info(tree_0) ind0.depth += 1 ind1 = individual.Individual(genome_1, tree_1) ind1.genome = genome_1 + tail_1 ind1.used_codons = len(genome_1) ind1.depth, ind1.nodes = tree_1.get_tree_info(tree_1) ind1.depth += 1 return [ind0, ind1]
def onepoint(p_0, p_1, within_used=True): """Given two individuals, create two children using one-point crossover and return them.""" # Get the chromosomes c_p_0, c_p_1 = p_0.genome, p_1.genome # Uniformly generate crossover points. If within_used==True, # points will be within the used section. if within_used: max_p_0, max_p_1 = p_0.used_codons, p_1.used_codons else: max_p_0, max_p_1 = len(c_p_0), len(c_p_1) pt_p_0, pt_p_1 = randint(1, max_p_0), randint(1, max_p_1) # Make new chromosomes by crossover: these slices perform copies if random() < params['CROSSOVER_PROBABILITY']: c_0 = c_p_0[:pt_p_0] + c_p_1[pt_p_1:] c_1 = c_p_1[:pt_p_1] + c_p_0[pt_p_0:] else: c_0, c_1 = c_p_0[:], c_p_1[:] # Put the new chromosomes into new individuals ind_0 = individual.Individual(c_0, None) ind_1 = individual.Individual(c_1, None) return [ind_0, ind_1]
def crossover(parents): """ Perform crossover on a population """ cross_pop = [] while len(cross_pop) < params['GENERATION_SIZE']: inds_in = sample(parents, 2) ind_0 = individual.Individual(inds_in[0].genome, None) ind_1 = individual.Individual(inds_in[1].genome, None) if ind_0.invalid or ind_1.invalid: print("Error, invalid inds selected for crossover") exit(2) inds = params['CROSSOVER'](ind_0, ind_1) if any([ind.invalid for ind in inds]): # we have an invalid, need to do crossover again pass elif any([ind.depth > params['MAX_TREE_DEPTH'] for ind in inds]): # Tree is too big, need to do crossover again pass else: cross_pop.extend(inds) return cross_pop
def fixed_twopoint(p_0, p_1): """ Given two individuals, create two children using two-point crossover and return them. The same points are selected on both genomes for crossover to occur. Crossover points are selected within the used portion of the genome by default (i.e. crossover does not occur in the tail of the individual). :param p_0: Parent 0 :param p_1: Parent 1 :return: A list of crossed-over individuals. """ genome_0, genome_1 = p_0.genome, p_1.genome # Uniformly generate crossover points. max_p_0, max_p_1 = get_max_genome_index(p_0, p_1) # Select the same points on both genomes for crossover to occur. a, b = randint(1, max_p_0), randint(1, max_p_1) pt_0, pt_1 = min([a, b]), max([a, b]) # Make new chromosomes by crossover: these slices perform copies. if random() < params['CROSSOVER_PROBABILITY']: c_0 = genome_0[:pt_0] + genome_1[pt_0:pt_1] + genome_0[pt_1:] c_1 = genome_1[:pt_0] + genome_0[pt_0:pt_1] + genome_1[pt_1:] else: c_0, c_1 = genome_0[:], genome_1[:] # Put the new chromosomes into new individuals. ind_0 = individual.Individual(c_0, None) ind_1 = individual.Individual(c_1, None) return [ind_0, ind_1]
def variable_onepoint(p_0, p_1): """ Given two individuals, create two children using one-point crossover and return them. A different point is selected on each genome for crossover to occur. Note that this allows for genomes to grow or shrink in size. Crossover points are selected within the used portion of the genome by default (i.e. crossover does not occur in the tail of the individual). :param p_0: Parent 0 :param p_1: Parent 1 :return: A list of crossed-over individuals. """ # Get the chromosomes. genome_0, genome_1 = p_0.genome, p_1.genome # Uniformly generate crossover points. max_p_0, max_p_1 = get_max_genome_index(p_0, p_1) # Select unique points on each genome for crossover to occur. pt_0, pt_1 = randint(1, max_p_0), randint(1, max_p_1) # Make new chromosomes by crossover: these slices perform copies. if random() < params['CROSSOVER_PROBABILITY']: c_0 = genome_0[:pt_0] + genome_1[pt_1:] c_1 = genome_1[:pt_1] + genome_0[pt_0:] else: c_0, c_1 = genome_0[:], genome_1[:] # Put the new chromosomes into new individuals. ind_0 = individual.Individual(c_0, None) ind_1 = individual.Individual(c_1, None) return [ind_0, ind_1]
def check_ind_from_parser(ind, target): """ Checks the mapping of an individual generated by the GE parser against the specified target string to ensure the GE individual is correct. :param ind: An instance of the representation.individaul.Individual class. :param target: A target string against which to match the phenotype of the individual. :return: Nothing. """ # Re-map individual using genome mapper to check everything is ok. new_ind = individual.Individual(ind.genome, None) # Check phenotypes are the same. if new_ind.phenotype != ind.phenotype: s = "utilities.representation.check_methods.check_ind_from_parser\n" \ "Error: Solution phenotype doesn't match genome mapping.\n" \ " Solution phenotype: \t %s\n" \ " Solution from genome:\t %s\n" \ " Derived genome: \t %s" % \ (ind.phenotype, new_ind.phenotype, ind.genome) raise Exception(s) # Check the phenotype matches the target string. elif ind.phenotype != target: s = "utilities.representation.check_methods.check_ind_from_parser\n" \ "Error: Solution phenotype doesn't match target.\n" \ " Target: \t %s\n" \ " Solution: \t %s" % (target, ind.phenotype) raise Exception(s) else: # Check the tree matches the phenotype. check_genome_mapping(ind)
def int_flip_per_ind(ind): """ Mutate the genome of an individual by randomly choosing a new int with probability p_mut. Works per-individual. Mutation is performed over the entire length of the genome by default, but the flag within_used is provided to limit mutation to only the effective length of the genome. :param ind: An individual to be mutated. :return: A mutated individual. """ # Set effective genome length over which mutation will be performed. eff_length = get_effective_length(ind) if not eff_length: # Linear mutation cannot be performed on this individual. return ind for _ in range(params['MUTATION_EVENTS']): idx = randint(0, eff_length - 1) ind.genome[idx] = randint(0, params['CODON_SIZE']) # Re-build a new individual with the newly mutated genetic information. new_ind = individual.Individual(ind.genome, None) return new_ind
def int_flip_per_ind(ind): """ Mutate the genome of an individual by randomly choosing a new int with probability p_mut. Works per-individual. Mutation is performed over the entire length of the genome by default, but the flag within_used is provided to limit mutation to only the effective length of the genome. :param ind: An individual to be mutated. :return: A mutated individual. """ # Set effective genome length over which mutation will be performed. if params['WITHIN_USED']: eff_length = min(len(ind.genome), ind.used_codons) else: eff_length = len(ind.genome) for _ in params['MUTATION_EVENTS']: idx = randint(0, eff_length-1) ind.genome[idx] = randint(0, params['CODON_SIZE']) # Re-build a new individual with the newly mutated genetic information. new_ind = individual.Individual(ind.genome, None) return new_ind
def LTGE_initialisation(size): """Initialise a population in the LTGE representation.""" pop = [] for _ in range(size): # Random genotype g, ph = latent_tree_random_ind(params['BNF_GRAMMAR'], params['MAX_TREE_DEPTH']) # wrap up in an Individual and fix up various Individual attributes ind = individual.Individual(g, None, False) ind.phenotype = ph # number of nodes is the number of decisions in the genome ind.nodes = ind.used_codons = len(g) # each key is the length of a path from root ind.depth = max(len(k) for k in g) # in LTGE there are no invalid individuals ind.invalid = False pop.append(ind) return pop
def random_init(size): """ Randomly create a population of size and return. :param size: The size of the required population. :return: A full population composed of randomly generated individuals. """ return [individual.Individual(None, None) for _ in range(size)]
def check_ind(ind): """ Checks all aspects of an individual to ensure everything is correct. :param ind: An instance of the representation.individaul.Individual class. :return: Nothing. """ # Re-map individual using fast genome mapper to check everything is ok new_ind = individual.Individual(ind.genome, None) # Get attributes of both individuals. attributes_0 = vars(ind) attributes_1 = vars(new_ind) if params['GENOME_OPERATIONS']: # If this parameter is set then the new individual will have no tree. attributes_0['tree'] = None else: compare_trees(attributes_0['tree'], attributes_1['tree']) # Must remove the tree variable as instances of classes cannot be # directly compared at the moment. # TODO: Write comparison function for tree class. attributes_0['tree'], attributes_1['tree'] = None, None if attributes_0 != attributes_1: print("Error: utilities.check_methods.check_ind." "Individual attributes do not match correct attributes.") print("Original attributes:\n", attributes_0) print("Correct attributes:\n", attributes_1) quit()
def grid_generational(new_pop, individuals): """Return new pop. The ELITE_SIZE best individuals are appended to new pop if they are better than the worst individuals in new pop""" from algorithm.evaluate_fitness import evaluation from representation import individual if params['GENERATION_SIZE']<params['GRID_SIZE']: print("Generations must be more than grid size with Grid Generational " "Replacement") quit() individuals.sort(reverse=True) for ind in individuals[:params['ELITE_SIZE']]: new_pop.append(copy(ind)) new_pop.sort(reverse=True) new_pop = new_pop[:(params['GENERATION_SIZE']+params['ELITE_SIZE']- params['GRID_SIZE'])] grid_pop = [] if params['GRID_SIZE'] == 64: index = [2, 4, 6, 8] else: index = [1, 3, 5, 7, 9] for x in range(len(index)): for y in range(len(index)): for z in range(len(index)): grid_pop.append(individual.Individual([0, (index[x] + 10), 0, 0, 0, (index[y] + 10), 0, 0, 0, (index[z] + 10), 0, 0, 0], None)) grid_pop = evaluation(grid_pop,grid_eval=params['GRID_TOTAL_VISION']) new_pop = new_pop + grid_pop new_pop.sort(reverse=True) return new_pop[:params['GENERATION_SIZE']+params['ELITE_SIZE']]
def generate_PI_ind_tree(max_depth): """ Generate an individual using a given Position Independent subtree initialisation method. :param max_depth: The maximum depth for the initialised subtree. :return: A fully built individual. """ # Initialise an instance of the tree class ind_tree = Tree(str(params['BNF_GRAMMAR'].start_rule["symbol"]), None) # Generate a tree genome, output, nodes, depth = pi_grow(ind_tree, max_depth) # Get remaining individual information phenotype, invalid, used_cod = "".join(output), False, len(genome) if params['BNF_GRAMMAR'].python_mode: # Grammar contains python code phenotype = python_filter(phenotype) # Initialise individual ind = individual.Individual(genome, ind_tree, map_ind=False) # Set individual parameters ind.phenotype, ind.nodes = phenotype, nodes ind.depth, ind.used_codons, ind.invalid = depth, used_cod, invalid # Generate random tail for genome. ind.genome = genome + [randint(0, params['CODON_SIZE']) for _ in range(int(ind.used_codons / 2))] return ind
def subtree(ind): """ Mutate the individual by replacing a randomly selected subtree with a new randomly generated subtree. Guaranteed one event per individual, unless params['MUTATION_EVENTS'] is specified as a higher number. :param ind: An individual to be mutated. :return: A mutated individual. """ def subtree_mutate(ind_tree): """ Creates a list of all nodes and picks one node at random to mutate. Because we have a list of all nodes, we can (but currently don't) choose what kind of nodes to mutate on. Handy. :param ind_tree: The full tree of an individual. :return: The full mutated tree and the associated genome. """ # Find the list of nodes we can mutate from. targets = ind_tree.get_target_nodes( [], target=params['BNF_GRAMMAR'].non_terminals) # Pick a node. new_tree = choice(targets) # Set the depth limits for the new subtree. if params['MAX_TREE_DEPTH']: # Set the limit to the tree depth. max_depth = params['MAX_TREE_DEPTH'] - new_tree.depth else: # There is no limit to tree depth. max_depth = None # Mutate a new subtree. generate_tree(new_tree, [], [], "random", 0, 0, 0, max_depth) return ind_tree if ind.invalid: # The individual is invalid. tail = [] else: # Save the tail of the genome. tail = ind.genome[ind.used_codons:] # Allows for multiple mutation events should that be desired. for i in range(params['MUTATION_EVENTS']): ind.tree = subtree_mutate(ind.tree) # Re-build a new individual with the newly mutated genetic information. ind = individual.Individual(None, ind.tree) # Add in the previous tail. ind.genome = ind.genome + tail return ind
def onepoint(p_0, p_1, within_used=True): """ Given two individuals, create two children using one-point crossover and return them. A different point is selected on each genome for crossover to occur. Crossover points are selected within the used portion of the genome by default (i.e. crossover does not occur in the tail of the individual). Onepoint crossover in Grammatical Evolution is explained further in: O'Neill, M., Ryan, C., Keijzer, M. and Cattolico, M., 2003. Crossover in grammatical evolution. Genetic programming and evolvable machines, 4(1), pp.67-93. DOI: 10.1023/A:1021877127167 :param p_0: Parent 0 :param p_1: Parent 1 :param within_used: Boolean flag for selecting whether or not crossover is performed within the used portion of the genome. Default set to True. :return: A list of crossed-over individuals. """ # Get the chromosomes. c_p_0, c_p_1 = p_0.genome, p_1.genome # Uniformly generate crossover points. If within_used==True, # points will be within the used section. if within_used: max_p_0, max_p_1 = p_0.used_codons, p_1.used_codons else: max_p_0, max_p_1 = len(c_p_0), len(c_p_1) # Select unique points on each genome for crossover to occur. pt_p_0, pt_p_1 = randint(1, max_p_0), randint(1, max_p_1) # Make new chromosomes by crossover: these slices perform copies. if random() < params['CROSSOVER_PROBABILITY']: c_0 = c_p_0[:pt_p_0] + c_p_1[pt_p_1:] c_1 = c_p_1[:pt_p_1] + c_p_0[pt_p_0:] else: c_0, c_1 = c_p_0[:], c_p_1[:] # Put the new chromosomes into new individuals. ind_0 = individual.Individual(c_0, None) ind_1 = individual.Individual(c_1, None) return [ind_0, ind_1]
def uniform_genome(size): """ Create a population of individuals by sampling genomes uniformly. :param size: The size of the required population. :return: A full population composed of randomly generated individuals. """ return [individual.Individual(sample_genome(), None) for _ in range(size)]
def seed_initialisation(size): """ Create a population of size where all individuals are the same seeded individual. :param size: The size of the required population. :return: A full population composed of the seeded individual. """ # Include seed genome if defined if params['SEED_GENOME']: # A genome has been specified as the seed. Check if ind is valid. test_ind = individual.Individual(params['SEED_GENOME'], None) if test_ind.invalid: s = "operators.initialisation.seed_initialisation\n" \ "Error: SEED_GENOME maps to an invalid PonyGE individual." raise Exception(s) # Map to individual. return [ individual.Individual(params['SEED_GENOME'], None) for _ in range(size) ] elif params['SEED_INDIVIDUAL']: # A full individual has been specified as the seed. if not isinstance(params['SEED_INDIVIDUAL'], individual.Individual): # The seed object is not a PonyGE individual. s = "operators.initialisation.seed_initialisation\n" \ "Error: SEED_INDIVIDUAL is not a PonyGE individual." raise Exception(s) else: # Return population of seed individuals. return [params['SEED_INDIVIDUAL'].deep_copy() for _ in range(size)] else: # No seed individual specified. s = "operators.initialisation.seed_initialisation\n" \ "Error: No seed individual specified for seed initialisation." raise Exception(s)
def check_snippets_for_solution(): """ Check the snippets repository to see if we have built up the correct solution yet. :return: An individual representing the correct solution if it exists, otherwise None. """ # Initialise None biggest snippet biggest_snippet = [0, None] for snippet in sorted(trackers.snippets.keys()): # Check each snippet to find the largest one. # Find length of snippet index = get_num_from_str(snippet) length = index[1] - index[0] if length > biggest_snippet[0]: # We have a new biggest snippet. biggest_snippet = [length, snippet] # Get the phenotype of the largest snippet largest_snippet = get_output(trackers.snippets[biggest_snippet[1]]) if largest_snippet != params['REVERSE_MAPPING_TARGET'] and \ params['VERBOSE']: # The solution doesn't match the target string. # Get the location of the phenotype of the largest snippet on the # target string. largest_indexes = get_num_from_str(biggest_snippet[1]) # Generate whitespace to position the phenotype accordingly. spaces = "".join([" " for _ in range(largest_indexes[0] - 1)]) s = "operators.subtree_parse.check_snippets_for_solution\n" \ "Error: Solution doesn't match the target string.\n" \ " Target: \t %s\n" \ " Solution: \t %s %s\n" \ " Check grammar file to ensure the grammar is capable of " \ "producing the exact target string." % \ (params['REVERSE_MAPPING_TARGET'], spaces, largest_snippet) raise Exception(s) if largest_snippet == params['REVERSE_MAPPING_TARGET']: # We have a perfect match # Generate individual that represents the perfect solution. ind = individual.Individual(None, trackers.snippets[biggest_snippet[1]]) # Return ind. return ind
def variable_twopoint(p_0, p_1): """ Given two individuals, create two children using two-point crossover and return them. Different points are selected on both genomes for crossover to occur. Note that this allows for genomes to grow or shrink in size. Crossover points are selected within the used portion of the genome by default (i.e. crossover does not occur in the tail of the individual). :param p_0: Parent 0 :param p_1: Parent 1 :return: A list of crossed-over individuals. """ genome_0, genome_1 = p_0.genome, p_1.genome # Uniformly generate crossover points. If within_used==True, points will # be within the used section. if params['WITHIN_USED']: max_p_0, max_p_1 = p_0.used_codons, p_1.used_codons else: max_p_0, max_p_1 = len(genome_0), len(genome_1) # Select the same points on both genomes for crossover to occur. a_0, b_0 = randint(1, max_p_0), randint(1, max_p_1) a_1, b_1 = randint(1, max_p_0), randint(1, max_p_1) pt_0, pt_1 = min([a_0, b_0]), max([a_0, b_0]) pt_2, pt_3 = min([a_1, b_1]), max([a_1, b_1]) # Make new chromosomes by crossover: these slices perform copies. if random() < params['CROSSOVER_PROBABILITY']: c_0 = genome_0[:pt_0] + genome_1[pt_2:pt_3] + genome_0[pt_1:] c_1 = genome_1[:pt_2] + genome_0[pt_0:pt_1] + genome_1[pt_3:] else: c_0, c_1 = genome_0[:], genome_1[:] # Put the new chromosomes into new individuals. ind_0 = individual.Individual(c_0, None) ind_1 = individual.Individual(c_1, None) return [ind_0, ind_1]
def fixed_onepoint(p_0, p_1): """ Given two individuals, create two children using one-point crossover and return them. The same point is selected on both genomes for crossover to occur. Crossover points are selected within the used portion of the genome by default (i.e. crossover does not occur in the tail of the individual). :param p_0: Parent 0 :param p_1: Parent 1 :return: A list of crossed-over individuals. """ # Get the chromosomes. genome_0, genome_1 = p_0.genome, p_1.genome # Uniformly generate crossover points. If within_used==True, # points will be within the used section. if params['WITHIN_USED']: max_p_0, max_p_1 = p_0.used_codons, p_1.used_codons else: max_p_0, max_p_1 = len(genome_0), len(genome_1) # Select the same point on both genomes for crossover to occur. pt = randint(1, min(max_p_0, max_p_1)) # Make new chromosomes by crossover: these slices perform copies. if random() < params['CROSSOVER_PROBABILITY']: c_0 = genome_0[:pt] + genome_1[pt:] c_1 = genome_1[:pt] + genome_0[pt:] else: c_0, c_1 = genome_0[:], genome_1[:] # Put the new chromosomes into new individuals. ind_0 = individual.Individual(c_0, None) ind_1 = individual.Individual(c_1, None) return [ind_0, ind_1]
def int_flip(ind): """Mutate the individual by randomly choosing a new int with probability p_mut. Works per-codon, hence no need for "within_used" option.""" if params['MUTATION_PROBABILITY']: p_mut = params['MUTATION_PROBABILITY'] else: p_mut = params['MUTATION_EVENTS'] / len(ind.genome) for i in range(len(ind.genome)): if random() < p_mut: ind.genome[i] = randint(0, params['CODON_SIZE']) new_ind = individual.Individual(ind.genome, None) return new_ind
def check_genome_mapping(ind): """ Re-maps individual to ensure genome is correct, i.e. that it maps to the correct phenotype and individual. :param ind: An instance of the representation.individual.Individual class. :return: Nothing. """ # Re-map individual using fast genome mapper to check everything is ok new_ind = individual.Individual(ind.genome, None) # Get attributes of both individuals. attributes_0 = vars(ind) attributes_1 = vars(new_ind) if params['GENOME_OPERATIONS']: # If this parameter is set then the new individual will have no tree. attributes_0['tree'] = None else: if attributes_0['tree'] != attributes_1['tree']: print("Error: utilities.check_methods.check_ind." "Individual trees do not match.") # Must remove the tree variable as instances of classes cannot be # directly compared at the moment. attributes_0['tree'], attributes_1['tree'] = None, None # Check that all attributes match across both individuals. for a_0 in sorted(attributes_0.keys()): for a_1 in sorted(attributes_1.keys()): if a_0 == a_1 and attributes_0[a_0] != attributes_1[a_1] and not \ (type(attributes_0[a_0]) is float and type(attributes_1[a_1]) is float and np.isnan(attributes_0[a_0]) and np.isnan(attributes_1[a_1])): s = "utilities.representation.check_methods.check_ind\n" \ "Error: Individual attributes do not match.\n" \ " Original attribute:\n" \ " %s :\t %s\n" \ " Correct attribute:\n" \ " %s :\t %s" % \ (a_0, attributes_0[a_0], a_1, attributes_1[a_1]) raise Exception(s)
def grid_init(size): """ Initialise to a grid of points where points are int values :return: """ population = [] if params['GRID_SIZE'] == 64: index = [2, 4, 6, 8] else: index = [1, 3, 5, 7, 9] for x in range(len(index)): for y in range(len(index)): for z in range(len(index)): population.append( individual.Individual([ 0, (index[x] + 10), 0, 0, 0, (index[y] + 10), 0, 0, 0, (index[z] + 10), 0, 0, 0 ], None)) return population
def int_flip_per_codon(ind): """ Mutate the genome of an individual by randomly choosing a new int with probability p_mut. Works per-codon. Mutation is performed over the effective length (i.e. within used codons, not tails) by default; within_used=False switches this off. :param ind: An individual to be mutated. :return: A mutated individual. """ # Set effective genome length over which mutation will be performed. eff_length = get_effective_length(ind) if not eff_length: # Linear mutation cannot be performed on this individual. return ind # Set mutation probability. Default is 1 over the length of the genome. if params['MUTATION_PROBABILITY'] and params['MUTATION_EVENTS'] == 1: p_mut = params['MUTATION_PROBABILITY'] elif params['MUTATION_PROBABILITY'] and params['MUTATION_EVENTS'] > 1: s = "operators.mutation.int_flip_per_codon\n" \ "Error: mutually exclusive parameters for 'MUTATION_PROBABILITY'" \ "and 'MUTATION_EVENTS' have been explicitly set.\n" \ " Only one of these parameters can be used at a time with" \ "int_flip_per_codon mutation." raise Exception(s) else: # Default mutation events per individual is 1. Raising this number # will influence the mutation probability for each codon. p_mut = params['MUTATION_EVENTS'] / eff_length # Mutation probability works per-codon over the portion of the # genome as defined by the within_used flag. for i in range(eff_length): if random() < p_mut: ind.genome[i] = randint(0, params['CODON_SIZE']) # Re-build a new individual with the newly mutated genetic information. new_ind = individual.Individual(ind.genome, None) return new_ind
def test_init(size): """ Initialise to a grid of points where points are int values :return: """ population = [] for i in range(size): #The first zero is for a unit production!!!!!!! population.append( individual.Individual([ 0, 0, 0, randint(0, 19), randint(0, 19), 0, 0, randint(0, 19), randint(0, 19), 0, 0, randint(0, 19), randint(0, 19) ], None)) return population
def generate_ind_tree(max_depth, method): """ Generate an individual using a given subtree initialisation method. :param max_depth: The maximum depth for the initialised subtree. :param method: The method of subtree initialisation required. :return: """ # Initialise an instance of the tree class ind_tree = Tree(str(params['BNF_GRAMMAR'].start_rule[0]), None, depth_limit=max_depth - 1) # Generate a tree genome, output, nodes, _, depth = generate_tree(ind_tree, [], [], method, 0, 0, 0, max_depth - 1) # Get remaining individual information phenotype, invalid, used_cod = "".join(output), False, len(genome) if params['BNF_GRAMMAR'].python_mode: # Grammar contains python code phenotype = python_filter(phenotype) # Initialise individual ind = individual.Individual(genome, ind_tree, map_ind=False) # Set individual parameters ind.phenotype, ind.nodes = phenotype, nodes ind.depth, ind.used_codons, ind.invalid = depth, used_cod, invalid # Generate random tail for genome. ind.genome = genome + [ randint(0, params['CODON_SIZE']) for _ in range(int(ind.used_codons / 2)) ] return ind
def LTGE_mutation(ind): """Mutation in the LTGE representation.""" # mutate and repair. g, ph = latent_tree_repair(latent_tree_mutate(ind.genome), params['BNF_GRAMMAR'], params['MAX_TREE_DEPTH']) # wrap up in an Individual and fix up various Individual attributes ind = individual.Individual(g, None, False) ind.phenotype = ph # number of nodes is the number of decisions in the genome ind.nodes = ind.used_codons = len(g) # each key is the length of a path from root ind.depth = max(len(k) for k in g) # in LTGE there are no invalid individuals ind.invalid = False return ind
def int_flip(ind, within_used=True): """ Mutate the genome of an individual by randomly choosing a new int with probability p_mut. Works per-codon. Mutation is performed over the entire length of the genome by default, but the flag within_used is provided to limit mutation to only the effective length of the genome. :param ind: An individual to be mutated. :param within_used: Boolean flag for selecting whether or not mutation is performed within the used portion of the genome. Default set to True. :return: A mutated individual. """ # Set effective genome length over which mutation will be performed. if within_used: eff_length = len(ind.genome[:ind.used_codons]) else: eff_length = len(ind.genome) # Set mutation probability. Default is 1 over the length of the genome. if params['MUTATION_PROBABILITY']: p_mut = params['MUTATION_PROBABILITY'] else: # Default mutation events per individual is 1. Raising this number # will influence the mutation probability for each codon. p_mut = params['MUTATION_EVENTS'] / eff_length # Mutation probability works per-codon over the portion of the # genome as defined by the within_used flag. for i in range(eff_length): if random() < p_mut: ind.genome[i] = randint(0, params['CODON_SIZE']) # Re-build a new individual with the newly mutated genetic information. new_ind = individual.Individual(ind.genome, None) return new_ind