Ejemplo n.º 1
0
def make_tree_population(size,
                         pset,
                         init_max_depth,
                         max_depth,
                         initial_type=None,
                         init_method=grow_tree):
    '''
    Make Tree Population

    Args:
        size (int): number of individuals in the Population
        pset (PrimitiveSet): set of primitives to build a random tree
        init_max_depth (int): initial max tree depth
        max_depth (int): max tree depth that translates into max array size
        initial_type (type): when using types, this constraints the initial primitive ot be of this type
        init_method (function): function that generates random trees (grow_tree, full_tree)  

    Returns:
        array of tree based individuals initialized according to given method, with or without types
    '''
    pop = make_empty_population(size)

    for i in range(size):
        pop.individuals[i] = pg.TreeIndividual()
        pop.individuals[i].genotype = init_method(pset,
                                                  init_max_depth,
                                                  max_depth,
                                                  initial_type=initial_type)
        depth, nodes = pg.count_tree_internals(pset,
                                               pop.individuals[i].genotype)
        pop.individuals[i].depth = depth
        pop.individuals[i].nodes = nodes

    return pop
Ejemplo n.º 2
0
def test_count_tree_internals():
    pset = pg.PrimitiveSet()
    pset.addFunction(op.add, 2)
    pset.addFunction(op.sub, 2)
    pset.addTerminal(1)
    pset.addTerminal(2)
    pset.addTerminal(3)
    pset.addVariable("x")
    tree1 = np.array([1, 2, 1, 5, 1, 2, 2, 6, 5, 2, 3, 4, 2, 2, 4, 4, 2, 6, 6, 2, 3, 3, 1,
       2, 5, 5, 1, 5, 6, 0, 0, 0])
    depth, nodes = pg.count_tree_internals(pset, tree1)
    assert depth == 7
    assert nodes == 29
    tree2 = np.array([5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
       0, 0, 0, 0, 0, 0, 0, 0, 0])
    depth, nodes = pg.count_tree_internals(pset, tree2)
    assert depth == 1
    assert nodes == 1
Ejemplo n.º 3
0
def test_count_tree_internals_typed():
    np.random.seed(42)
    pset = pg.PrimitiveSet(typed=True)
    pset.addFunction(op.add, 2, types=[int, int, int])
    pset.addFunction(op.sub, 2, types=[int, int, int])
    pset.addFunction(op.mul, 2, types=[int, int, int])
    pset.addFunction(protected_div, 2, types=[float, float, float])
    num_constants = 5
    for i in range(num_constants):
        pset.addTerminal(np.random.randint(-5, 5), types=[int])
    for i in range(num_constants):
        pset.addTerminal(np.random.uniform(), types=[float])
    pset.addVariable("x", types=[int])
    tree1 = np.array([ 3,  2,  1,  6,  8,  2,  1,  3,  7,  6,  3,  7,  8,  8,  1,  1,  8,
        6,  2, 14,  8,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0])
    depth, nodes = pg.count_tree_internals(pset, tree1)
    assert depth == 6
    assert nodes == 21

    np.random.seed(42)
    pset = pg.PrimitiveSet(typed=True)
    pset.addFunction(op.add, 2, types=[int, int, int])
    pset.addFunction(op.sub, 2, types=[int, float, float])
    pset.addFunction(op.mul, 2, types=[float, int, int])
    pset.addFunction(protected_div, 2, types=[float, float, float])
    num_constants = 5
    for i in range(num_constants):
        pset.addTerminal(np.random.randint(-5, 5), types=[int])

    for i in range(num_constants):
        pset.addTerminal(np.random.uniform(), types=[float])
    pset.addVariable("x", types=[int])
    tree2 = np.array([ 1,  1,  1,  7,  6,  2,  3,  6,  8, 12,  2,  3,  7,  8,  3,  8,  5,
        0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0])
    depth, nodes = pg.count_tree_internals(pset, tree2)
    assert depth == 5
    assert nodes == 17
Ejemplo n.º 4
0
def evaluate_tree_population(pop, fitness_fn, pset, **kargs):
    '''
    Evaluate Tree Population

    Args:
        pop (Population): population to be evaluated in-place
        fitness_fn (function): fitness function that receives an individual
        pset (PrimitiveSet): set of primitives
        **kargs: keyword arguments that fitness_fn might have

    Returns:
        evaluated population by calling the fitness function
    '''
    for i in range(pop.size):
        ind = pop.individuals[i]
        if ind.run_eval:
            ind.fitness = Fitness(fitness_fn(ind.genotype, **kargs))
            depth, nodes = pg.count_tree_internals(pset, ind.genotype)
            ind.depth = depth
            ind.nodes = nodes
            ind.run_eval = False

    return pop
Ejemplo n.º 5
0
def tree_crossover(parent1, parent2, pset=None):
    '''
    Tree Crossover

    Args:
        parent1 (TreeIndividual): first parent
        parent2 (TreeIndividual): second parent
        pset (PrimitiveSet): the set primitives allowed to be used

    Returns:
        offsprings from the two parents
    '''
    def arraycopy(src, src_pos, dest, dest_pos, length):
        dest[dest_pos:dest_pos + length] = src[src_pos:src_pos + length]

    def get_primitive_type(primitive):
        if primitive in pset.ephemeral_constants:
            _, p_type = pset.ephemeral_constants[primitive]
        elif primitive in pset.terminals:
            _, p_type = pset.terminals[primitive]
        elif primitive in pset.variables:
            _, p_type = pset.variables[primitive]
        elif primitive in pset.functions:
            _, _, p_type = pset.functions[primitive]
        else:
            p_type = None
            raise AttributeError(
                'This is a typed primitive set so types are required!')
        return p_type[0]

    # create offsprings
    offspring1 = pg.TreeIndividual(
        tree=np.zeros(parent1.genotype.size, dtype=parent1.genotype.dtype))
    offspring2 = pg.TreeIndividual(
        tree=np.zeros(parent2.genotype.size, dtype=parent2.genotype.dtype))

    # define tree cut points for subtree swap
    start1 = np.random.randint(parent1.nodes)
    end1 = pg.transverse_tree(pset, parent1.genotype, start1)

    # if typed set, start2 must be of the same type as start1
    if pset.typed:
        p1_primitive = parent1.genotype[start1]
        p1_type = get_primitive_type(p1_primitive)
        valid_gene_pos = []
        pos = 0
        while pos < parent2.nodes:
            if p1_type == get_primitive_type(parent2.genotype[pos]):
                valid_gene_pos.append(pos)
            pos += 1

        if valid_gene_pos == []:
            return parent1, parent2  # there is not valid point in the other, return original parents
        else:
            valid_pos = np.array(valid_gene_pos)
            start2 = valid_pos[np.random.randint(valid_pos.size)]
    else:
        start2 = np.random.randint(parent2.nodes)
    end2 = pg.transverse_tree(pset, parent2.genotype, start2)

    # define length of offspring trees
    len1 = start1 + (end2 - start2) + (parent1.nodes - end1)
    len2 = start2 + (end1 - start1) + (parent2.nodes - end2)

    if len1 > parent1.genotype.size:
        # passes max depth, return parent
        offspring1 = parent1
    else:
        # produce offpsring 1
        arraycopy(parent1.genotype, 0, offspring1.genotype, 0, start1)
        num_elements = (end2 - start2)
        arraycopy(parent2.genotype, start2, offspring1.genotype, start1,
                  num_elements)
        num_elements = (parent1.nodes - end1)
        arraycopy(parent1.genotype, end1, offspring1.genotype,
                  start1 + (end2 - start2), num_elements)
        offspring1.depth, offspring1.nodes = pg.count_tree_internals(
            pset, offspring1.genotype)

    if len2 > parent2.genotype.size:
        # passes max depth, return parent
        offspring2 = parent2
    else:
        # produce offspring 2
        arraycopy(parent2.genotype, 0, offspring2.genotype, 0, start2)
        num_elements = (end1 - start1)
        arraycopy(parent1.genotype, start1, offspring2.genotype, start2,
                  num_elements)
        num_elements = (parent2.nodes - end2)
        arraycopy(parent2.genotype, end2, offspring2.genotype,
                  start2 + (end1 - start1), num_elements)
        offspring2.depth, offspring2.nodes = pg.count_tree_internals(
            pset, offspring2.genotype)

    return offspring1, offspring2
Ejemplo n.º 6
0
def subtree_mutation(parent, pset=None, **kargs):
    '''
    SubTree Mutation

    Args:
        parent (TreeIndividual): the individual to be mutated
        pset (PrimitiveSet): the set primitives allowed to be used

    Returns:
        mutated individual
    '''
    def arraycopy(src, src_pos, dest, dest_pos, length):
        dest[dest_pos:dest_pos + length] = src[src_pos:src_pos + length]

    def get_primitive_type(primitive):
        if primitive in pset.ephemeral_constants:
            _, p_type = pset.ephemeral_constants[primitive]
        elif primitive in pset.terminals:
            _, p_type = pset.terminals[primitive]
        elif primitive in pset.variables:
            _, p_type = pset.variables[primitive]
        elif primitive in pset.functions:
            _, _, p_type = pset.functions[primitive]
        else:
            p_type = None
            raise AttributeError(
                'This is a typed primitive set so types are required!')
        return p_type[0]

    offspring = pg.TreeIndividual(
        tree=np.zeros(parent.genotype.size, dtype=parent.genotype.dtype))

    # define tree cut points for subtree replacement
    start1 = np.random.randint(parent.nodes)
    end1 = pg.transverse_tree(pset, parent.genotype, start1)

    # if typed subtree must return the appropriate type
    if pset.typed:
        primitive = parent.genotype[start1]
        parent_type = get_primitive_type(primitive)
    else:
        parent_type = None

    # TODO: the default values to set the size of the generated  tree must be revised
    # and a proper mechanism to set these values on a per-problem case must be available
    # if typed set, start2 must be of the same type as start1
    try:
        subtree = pg.grow_tree(pset,
                               parent.depth - 1,
                               parent.depth,
                               initial_type=parent_type)
    except:
        e = sys.exc_info()[0]
        print('%s' % e)
        print('parent.depth: %s' % parent.depth)

    start2 = 0
    end2 = pg.transverse_tree(pset, subtree, start2)

    len1 = start1 + (end2 - start2) + (parent.nodes - end1)

    # produce offpsring 1
    arraycopy(parent.genotype, 0, offspring.genotype, 0, start1)
    num_elements = (end2 - start2)
    arraycopy(subtree, start2, offspring.genotype, start1, num_elements)
    num_elements = (parent.nodes - end1)
    arraycopy(parent.genotype, end1, offspring.genotype,
              start1 + (end2 - start2), num_elements)

    # update tree metrics
    offspring.depth, offspring.nodes = pg.count_tree_internals(
        pset, offspring.genotype)

    if offspring.nodes <= parent.genotype.size:
        return offspring
    else:
        return parent