def test_program_init_depth():
    """Check 'full' creates constant depth programs for single depth limit"""

    params = {'function_set': [add2, sub2, mul2, div2, sqrt1, log1, abs1, max2,
                               min2],
              'arities': {1: [sqrt1, log1, abs1],
                          2: [add2, sub2, mul2, div2, max2, min2]},
              'init_depth': (6, 6),
              'n_features': 10,
              'const_range': (-1.0, 1.0),
              'metric': 'mean absolute error',
              'p_point_replace': 0.05,
              'parsimony_coefficient': 0.1}
    random_state = check_random_state(415)
    programs = []
    for i in range(20):
        programs.append(_Program(init_method='full',
                                 random_state=random_state, **params))
    full_depth = np.bincount([gp.depth_ for gp in programs])
    programs = []
    for _ in range(20):
        programs.append(_Program(init_method='half and half',
                                 random_state=random_state, **params))
    hnh_depth = np.bincount([gp.depth_ for gp in programs])
    programs = []
    for i in range(20):
        programs.append(_Program(init_method='grow',
                                 random_state=random_state, **params))
    grow_depth = np.bincount([gp.depth_ for gp in programs])

    assert_true(full_depth[-1] == 20)
    assert_false(hnh_depth[-1] == 20)
    assert_false(grow_depth[-1] == 20)
Esempio n. 2
0
def test_export_graphviz():
    """Check output of a simple program to Graphviz"""

    params = {
        'function_set': [add2, sub2, mul2, div2],
        'arities': {
            2: [add2, sub2, mul2, div2]
        },
        'init_depth': (2, 6),
        'init_method': 'half and half',
        'n_features': 10,
        'const_range': (-1.0, 1.0),
        'metric': 'mean absolute error',
        'p_point_replace': 0.05,
        'parsimony_coefficient': 0.1
    }
    random_state = check_random_state(415)

    # Test for a small program
    test_gp = [mul2, div2, 8, 1, sub2, 9, .5]
    gp = _Program(random_state=random_state, program=test_gp, **params)
    output = gp.export_graphviz()
    tree = 'digraph program {\n' \
           'node [style=filled]0 [label="mul", fillcolor="#136ed4"] ;\n' \
           '1 [label="div", fillcolor="#136ed4"] ;\n' \
           '2 [label="X8", fillcolor="#60a6f6"] ;\n' \
           '3 [label="X1", fillcolor="#60a6f6"] ;\n' \
           '1 -> 3 ;\n1 -> 2 ;\n' \
           '4 [label="sub", fillcolor="#136ed4"] ;\n' \
           '5 [label="X9", fillcolor="#60a6f6"] ;\n' \
           '6 [label="0.500", fillcolor="#60a6f6"] ;\n' \
           '4 -> 6 ;\n4 -> 5 ;\n0 -> 4 ;\n0 -> 1 ;\n}'
    assert_true(output == tree)

    # Test with fade_nodes
    output = gp.export_graphviz(fade_nodes=[0, 1, 2, 3])
    tree = 'digraph program {\n' \
           'node [style=filled]0 [label="mul", fillcolor="#cecece"] ;\n' \
           '1 [label="div", fillcolor="#cecece"] ;\n' \
           '2 [label="X8", fillcolor="#cecece"] ;\n' \
           '3 [label="X1", fillcolor="#cecece"] ;\n' \
           '1 -> 3 ;\n1 -> 2 ;\n' \
           '4 [label="sub", fillcolor="#136ed4"] ;\n' \
           '5 [label="X9", fillcolor="#60a6f6"] ;\n' \
           '6 [label="0.500", fillcolor="#60a6f6"] ;\n' \
           '4 -> 6 ;\n4 -> 5 ;\n0 -> 4 ;\n0 -> 1 ;\n}'
    assert_true(output == tree)

    # Test a degenerative single-node program
    test_gp = [1]
    gp = _Program(random_state=random_state, program=test_gp, **params)
    output = gp.export_graphviz()
    tree = 'digraph program {\n' \
           'node [style=filled]0 [label="X1", fillcolor="#60a6f6"] ;\n}'
    assert_true(output == tree)
Esempio n. 3
0
def test_print_overloading():
    """Check that printing a program object results in 'pretty' output"""

    params = {
        'function_set': [add2, sub2, mul2, div2],
        'arities': {
            2: [add2, sub2, mul2, div2]
        },
        'init_depth': (2, 6),
        'init_method': 'half and half',
        'n_features': 10,
        'const_range': (-1.0, 1.0),
        'metric': 'mean absolute error',
        'p_point_replace': 0.05,
        'parsimony_coefficient': 0.1
    }
    random_state = check_random_state(415)

    test_gp = [mul2, div2, 8, 1, sub2, 9, .5]

    gp = _Program(random_state=random_state, program=test_gp, **params)

    orig_stdout = sys.stdout
    try:
        out = StringIO()
        sys.stdout = out
        print(gp)
        output = out.getvalue().strip()
    finally:
        sys.stdout = orig_stdout

    lisp = "mul(div(X8, X1), sub(X9, 0.500))"
    assert_true(output == lisp)

    # Test with feature names
    params['feature_names'] = [str(n) for n in range(10)]
    gp = _Program(random_state=random_state, program=test_gp, **params)

    orig_stdout = sys.stdout
    try:
        out = StringIO()
        sys.stdout = out
        print(gp)
        output = out.getvalue().strip()
    finally:
        sys.stdout = orig_stdout

    lisp = "mul(div(8, 1), sub(9, 0.500))"
    assert_true(output == lisp)
Esempio n. 4
0
def test_get_subtree():
    """Check that get subtree does the same thing for self and new programs"""

    params = {
        'function_set': [add2, sub2, mul2, div2],
        'arities': {
            2: [add2, sub2, mul2, div2]
        },
        'init_depth': (2, 6),
        'init_method': 'half and half',
        'n_features': 10,
        'const_range': (-1.0, 1.0),
        'metric': 'mean absolute error',
        'p_point_replace': 0.05,
        'parsimony_coefficient': 0.1
    }
    random_state = check_random_state(415)

    # Test for a small program
    test_gp = [mul2, div2, 8, 1, sub2, 9, .5]
    gp = _Program(random_state=random_state, program=test_gp, **params)

    self_test = gp.get_subtree(check_random_state(0))
    external_test = gp.get_subtree(check_random_state(0), test_gp)

    assert_equal(self_test, external_test)
Esempio n. 5
0
def test_all_metrics():
    """Check all supported metrics work"""

    params = {
        'function_set': [add2, sub2, mul2, div2],
        'arities': {
            2: [add2, sub2, mul2, div2]
        },
        'init_depth': (2, 6),
        'init_method': 'half and half',
        'n_features': 10,
        'const_range': (-1.0, 1.0),
        'metric': 'mean absolute error',
        'p_point_replace': 0.05,
        'parsimony_coefficient': 0.1
    }
    random_state = check_random_state(415)

    # Test for a small program
    test_gp = [mul2, div2, 8, 1, sub2, 9, .5]
    gp = _Program(random_state=random_state, program=test_gp, **params)
    X = np.reshape(random_state.uniform(size=50), (5, 10))
    y = random_state.uniform(size=5)
    sample_weight = np.ones(5)
    expected = [
        1.48719809776, 1.82389179833, 1.76013763179, -0.2928200724, -0.5
    ]
    result = []
    for m in ['mean absolute error', 'mse', 'rmse', 'pearson', 'spearman']:
        gp.metric = _fitness_map[m]
        gp.raw_fitness_ = gp.raw_fitness(X, y, sample_weight)
        result.append(gp.fitness())
    assert_array_almost_equal(result, expected)
Esempio n. 6
0
def test_execute():
    """Check executing the program works"""

    params = {
        'function_set': [add2, sub2, mul2, div2],
        'arities': {
            2: [add2, sub2, mul2, div2]
        },
        'init_depth': (2, 6),
        'init_method': 'half and half',
        'n_features': 10,
        'const_range': (-1.0, 1.0),
        'metric': 'mean absolute error',
        'p_point_replace': 0.05,
        'parsimony_coefficient': 0.1
    }
    random_state = check_random_state(415)

    # Test for a small program
    test_gp = [mul2, div2, 8, 1, sub2, 9, .5]
    X = np.reshape(random_state.uniform(size=50), (5, 10))
    gp = _Program(random_state=random_state, program=test_gp, **params)
    result = gp.execute(X)
    expected = [-0.19656208, 0.78197782, -1.70123845, -0.60175969, -0.01082618]
    assert_array_almost_equal(result, expected)
Esempio n. 7
0
def test_indices():
    """Check that indices are stable when generated on the fly."""

    params = {
        'function_set': [add2, sub2, mul2, div2],
        'arities': {
            2: [add2, sub2, mul2, div2]
        },
        'init_depth': (2, 6),
        'init_method': 'half and half',
        'n_features': 10,
        'const_range': (-1.0, 1.0),
        'metric': 'mean absolute error',
        'p_point_replace': 0.05,
        'parsimony_coefficient': 0.1
    }
    random_state = check_random_state(415)
    test_gp = [mul2, div2, 8, 1, sub2, 9, .5]
    gp = _Program(random_state=random_state, program=test_gp, **params)

    assert_raises(ValueError, gp.get_all_indices)
    assert_raises(ValueError, gp._indices)

    def get_indices_property():
        return gp.indices_

    assert_raises(ValueError, get_indices_property)

    indices, _ = gp.get_all_indices(10, 7, random_state)

    assert_array_equal(indices, gp.get_all_indices()[0])
    assert_array_equal(indices, gp._indices())
    assert_array_equal(indices, gp.indices_)
def test_validate_program():
    """Check that valid programs are accepted & invalid ones raise error"""

    function_set = [add2, sub2, mul2, div2, sqrt1, log1, abs1, max2, min2]
    arities = {1: [sqrt1, log1, abs1],
               2: [add2, sub2, mul2, div2, max2, min2]},
    init_depth = (2, 6)
    init_method = 'half and half'
    n_features = 10
    const_range = (-1.0, 1.0)
    metric = 'mean absolute error'
    p_point_replace = 0.05
    parsimony_coefficient = 0.1

    random_state = check_random_state(415)
    test_gp = [sub2, abs1, sqrt1, log1, log1, sqrt1, 7, abs1, abs1, abs1, log1,
               sqrt1, 2]

    # This one should be fine
    _ = _Program(function_set, arities, init_depth, init_method, n_features,
                 const_range, metric, p_point_replace, parsimony_coefficient,
                 random_state, program=test_gp)

    # Now try a couple that shouldn't be
    assert_raises(ValueError, _Program, function_set, arities, init_depth,
                  init_method, n_features, const_range, metric,
                  p_point_replace, parsimony_coefficient, random_state,
                  program=test_gp[:-1])
    assert_raises(ValueError, _Program, function_set, arities, init_depth,
                  init_method, n_features, const_range, metric,
                  p_point_replace, parsimony_coefficient, random_state,
                  program=test_gp + [1])
Esempio n. 9
0
def test_program_init_method():
    """Check 'full' creates longer and deeper programs than other methods"""

    params = {
        'function_set':
        [add2, sub2, mul2, div2, sqrt1, log1, abs1, max2, min2],
        'arities': {
            1: [sqrt1, log1, abs1],
            2: [add2, sub2, mul2, div2, max2, min2]
        },
        'init_depth': (2, 6),
        'n_features': 10,
        'const_range': (-1.0, 1.0),
        'metric': 'mean absolute error',
        'p_point_replace': 0.05,
        'parsimony_coefficient': 0.1
    }
    random_state = check_random_state(415)
    programs = []
    for i in range(20):
        programs.append(
            _Program(init_method='full', random_state=random_state, **params))
    full_length = np.mean([gp.length_ for gp in programs])
    full_depth = np.mean([gp.depth_ for gp in programs])
    programs = []
    for i in range(20):
        programs.append(
            _Program(init_method='half and half',
                     random_state=random_state,
                     **params))
    hnh_length = np.mean([gp.length_ for gp in programs])
    hnh_depth = np.mean([gp.depth_ for gp in programs])
    programs = []
    for i in range(20):
        programs.append(
            _Program(init_method='grow', random_state=random_state, **params))
    grow_length = np.mean([gp.length_ for gp in programs])
    grow_depth = np.mean([gp.depth_ for gp in programs])

    assert_greater(full_length, hnh_length)
    assert_greater(hnh_length, grow_length)
    assert_greater(full_depth, hnh_depth)
    assert_greater(hnh_depth, grow_depth)
Esempio n. 10
0
def test_genetic_operations():
    """Check all genetic operations are stable and don't change programs"""

    params = {
        'function_set': [add2, sub2, mul2, div2],
        'arities': {
            2: [add2, sub2, mul2, div2]
        },
        'init_depth': (2, 6),
        'init_method': 'half and half',
        'n_features': 10,
        'const_range': (-1.0, 1.0),
        'metric': 'mean absolute error',
        'p_point_replace': 0.05,
        'parsimony_coefficient': 0.1
    }
    random_state = check_random_state(415)

    # Test for a small program
    test_gp = [mul2, div2, 8, 1, sub2, 9, .5]
    donor = [add2, 0.1, sub2, 2, 7]

    gp = _Program(random_state=random_state, program=test_gp, **params)

    assert_equal(
        [f.name if isinstance(f, _Function) else f for f in gp.reproduce()],
        ['mul', 'div', 8, 1, 'sub', 9, 0.5])
    assert_equal(gp.program, test_gp)
    assert_equal([
        f.name if isinstance(f, _Function) else f
        for f in gp.crossover(donor, random_state)[0]
    ], ['sub', 2, 7])
    assert_equal(gp.program, test_gp)
    assert_equal([
        f.name if isinstance(f, _Function) else f
        for f in gp.subtree_mutation(random_state)[0]
    ], ['mul', 'div', 8, 1, 'sub', 'sub', 3, 5, 'add', 6, 3])
    assert_equal(gp.program, test_gp)
    assert_equal([
        f.name if isinstance(f, _Function) else f
        for f in gp.hoist_mutation(random_state)[0]
    ], ['div', 8, 1])
    assert_equal(gp.program, test_gp)
    assert_equal([
        f.name if isinstance(f, _Function) else f
        for f in gp.point_mutation(random_state)[0]
    ], ['mul', 'div', 8, 1, 'sub', 9, 0.5])
    assert_equal(gp.program, test_gp)
Esempio n. 11
0
def pse_generator(random, args):

    individual = _Program(
        args["function_set"],
        args["arities"],
        args["init_depth"],
        args["init_method"],
        args["n_features"],
        args["const_range"],
        args["metric"],
        args["p_point_replace"],
        args["parsimony_coefficient"],
        args["random_state"],
    )
    individual.build_program(args["random_state"])
    while not individual.validate_program():
        individual.build_program(args["random_state"])

    return individual
def _parallel_evolve(n_programs, parents, X, y, sample_weight, seeds, params):
    """Private function used to build a batch of programs within a job."""
    n_samples, n_features = X.shape
    # Unpack parameters
    tournament_size = params['tournament_size']
    function_set = params['function_set']
    arities = params['arities']
    init_depth = params['init_depth']
    init_method = params['init_method']
    const_range = params['const_range']
    metric = params['_metric']
    parsimony_coefficient = params['parsimony_coefficient']
    method_probs = params['method_probs']
    p_point_replace = params['p_point_replace']
    max_samples = params['max_samples']

    max_samples = int(max_samples * n_samples)

    def _tournament():
        """Find the fittest individual from a sub-population."""
        contenders = random_state.randint(0, len(parents), tournament_size)
        fitness = [parents[p].fitness_ for p in contenders]
        if metric.greater_is_better:
            parent_index = contenders[np.argmax(fitness)]
        else:
            parent_index = contenders[np.argmin(fitness)]
        return parents[parent_index], parent_index

    # Build programs
    programs = []

    for i in range(n_programs):

        random_state = check_random_state(seeds[i])

        if parents is None:
            program = None
            genome = None
        else:
            method = random_state.uniform()
            parent, parent_index = _tournament()

            if method < method_probs[0]:
                # crossover
                donor, donor_index = _tournament()
                program, removed, remains = parent.crossover(
                    donor.program, random_state)
                genome = {
                    'method': 'Crossover',
                    'parent_idx': parent_index,
                    'parent_nodes': removed,
                    'donor_idx': donor_index,
                    'donor_nodes': remains
                }
            elif method < method_probs[1]:
                # subtree_mutation
                program, removed, _ = parent.subtree_mutation(random_state)
                genome = {
                    'method': 'Subtree Mutation',
                    'parent_idx': parent_index,
                    'parent_nodes': removed
                }
            elif method < method_probs[2]:
                # hoist_mutation
                program, removed = parent.hoist_mutation(random_state)
                genome = {
                    'method': 'Hoist Mutation',
                    'parent_idx': parent_index,
                    'parent_nodes': removed
                }
            elif method < method_probs[3]:
                # point_mutation
                program, mutated = parent.point_mutation(random_state)
                genome = {
                    'method': 'Point Mutation',
                    'parent_idx': parent_index,
                    'parent_nodes': mutated
                }
            else:
                # reproduction
                program = parent.reproduce()
                genome = {
                    'method': 'Reproduction',
                    'parent_idx': parent_index,
                    'parent_nodes': []
                }

        program = _Program(function_set=function_set,
                           arities=arities,
                           init_depth=init_depth,
                           init_method=init_method,
                           n_features=n_features,
                           metric=metric,
                           const_range=const_range,
                           p_point_replace=p_point_replace,
                           parsimony_coefficient=parsimony_coefficient,
                           random_state=random_state,
                           program=program)

        program.parents = genome

        # Draw samples, using sample weights, and then fit
        if sample_weight is None:
            curr_sample_weight = np.ones((n_samples, ))
        else:
            curr_sample_weight = sample_weight.copy()
        oob_sample_weight = curr_sample_weight.copy()

        indices, not_indices = program.get_all_indices(n_samples, max_samples,
                                                       random_state)

        curr_sample_weight[not_indices] = 0
        oob_sample_weight[indices] = 0

        program.raw_fitness_ = program.raw_fitness(X, y, curr_sample_weight)
        if max_samples < n_samples:
            # Calculate OOB fitness
            program.oob_fitness_ = program.raw_fitness(X, y, oob_sample_weight)

        programs.append(program)

    return programs
Esempio n. 13
0
def pse_variator(random, parent1, parent2, args):

    children = []

    #parent1 = copy.deepcopy(parent1)
    #parent2 = copy.deepcopy(parent2)

    program1 = None
    program2 = None

    # TODO some default hard-coded probabilities...to be changed
    p_crossover = 0.8
    p_subtree_mutation = 0.01
    p_hoist_mutation = 0.01
    p_point_mutation = 0.01

    # TODO 	understand better how the different functions work; apparently, they do not
    #	modify the individual, but return a new 'program' that is later used to initialize an individual
    if random.random() < p_crossover:
        program1, removed, remains = parent1.crossover(parent2.program,
                                                       args["random_state"])
        program2, removed, remains = parent2.crossover(parent1.program,
                                                       args["random_state"])

    elif random.random() < p_crossover + p_subtree_mutation:
        program1, removed, _ = parent1.subtree_mutation(args["random_state"])
        program2, removed, _ = parent2.subtree_mutation(args["random_state"])

    elif random.random() < p_crossover + p_subtree_mutation + p_hoist_mutation:
        program1, removed = parent1.hoist_mutation(args["random_state"])
        program2, removed = parent2.hoist_mutation(args["random_state"])

    # TODO: point_mutation has an issue with 'arity' (that should be a list or something, it's an int instead)
    #if random.random() < p_point_mutation :
    #	program1, mutated = parent1.point_mutation(args["random_state"])
    #	program2, mutated = parent2.point_mutation(args["random_state"])

    if program1 != None and program2 != None:

        child1 = _Program(args["function_set"],
                          args["arities"],
                          args["init_depth"],
                          args["init_method"],
                          args["n_features"],
                          args["const_range"],
                          args["metric"],
                          args["p_point_replace"],
                          args["parsimony_coefficient"],
                          args["random_state"],
                          program=program1)

        child2 = _Program(args["function_set"],
                          args["arities"],
                          args["init_depth"],
                          args["init_method"],
                          args["n_features"],
                          args["const_range"],
                          args["metric"],
                          args["p_point_replace"],
                          args["parsimony_coefficient"],
                          args["random_state"],
                          program=program2)

        #print("child1=", child1)
        #print("child2=", child2)
        #if child1.validate_program() : children.append( copy.deepcopy(child1) )
        #if child2.validate_program() : children.append( copy.deepcopy(child2) )
        if child1.validate_program(): children.append(child1)
        if child2.validate_program(): children.append(child2)

    return children