Exemplo n.º 1
0
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]
Exemplo n.º 2
0
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]
Exemplo n.º 3
0
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]
Exemplo n.º 4
0
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]
Exemplo n.º 5
0
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
Exemplo n.º 6
0
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]
Exemplo n.º 7
0
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]
Exemplo n.º 8
0
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)
Exemplo n.º 9
0
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
Exemplo n.º 11
0
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)]
Exemplo n.º 13
0
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()
Exemplo n.º 14
0
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']]
Exemplo n.º 15
0
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
Exemplo n.º 16
0
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
Exemplo n.º 17
0
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]
Exemplo n.º 18
0
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)]
Exemplo n.º 19
0
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)
Exemplo n.º 20
0
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
Exemplo n.º 21
0
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]
Exemplo n.º 22
0
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]
Exemplo n.º 23
0
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
Exemplo n.º 24
0
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
Exemplo n.º 26
0
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
Exemplo n.º 28
0
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
Exemplo n.º 29
0
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
Exemplo n.º 30
0
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