Esempio n. 1
0
def evolve(runs, steps, env, rep, gens, pop_size, num_nodes, mutate_std,
           output, gui):
    """Evolve a controller using a Pitt-style rule system."""
    check_rep(rep)

    print(f"Loading environment '{env}'...")
    environment = gym.make(env)
    print(f"\tObservation space:\t{environment.observation_space}")
    print(f"\tAction space:     \t{environment.action_space}")

    with open(output, 'w') as genomes_file:
        if rep == 'pitt':
            representation = pitt_representation(environment,
                                                 num_rules=num_nodes)
        elif rep == 'neural':
            representation = neural_representation(environment,
                                                   num_hidden_nodes=num_nodes)

        probes = get_probes(genomes_file, environment, rep)

        with Client() as dask_client:
            ea = generational_ea(
                generations=gens,
                pop_size=pop_size,
                # Solve a problem that executes agents in the
                # environment and obtains fitness from it
                problem=problems.EnvironmentProblem(runs, steps, environment,
                                                    'reward', gui),
                representation=representation,

                # The operator pipeline.
                pipeline=[
                    ops.tournament_selection,
                    ops.clone,
                    mutate_gaussian(std=mutate_std, hard_bounds=(-1, 1)),
                    ops.evaluate,
                    ops.pool(size=pop_size),
                    #synchronous.eval_pool(client=dask_client, size=pop_size),
                    *probes  # Inserting all the probes at the end
                ])
            list(ea)
Esempio n. 2
0
def test_mutate_gaussian():
    """If we apply isotropic Gaussian mutation to a given genome a bunch of different times,
    the offsprings' genes should follow a Gaussian distribution around their parents' values."""
    N = 5000  # We'll sample 5,000 independent genomes

    gene0_values = []
    gene1_values = []
    op = ops.mutate_gaussian(std=1.0, expected_num_mutations='isotropic')

    for _ in range(N):
        # Set up two parents with fixed genomes, two genes each
        ind1 = Individual(np.array([0, 0.5]))
        population = iter([ind1])

        # Mutate
        result = op(population)
        result = next(result)  # Pulse the iterator

        gene0_values.append(result.genome[0])
        gene1_values.append(result.genome[1])

    # Use a Kolmogorov-Smirnoff test to verify that the mutations follow a
    # Gaussian distribution with zero mean and unit variance
    p_threshold = 0.01

    # Gene 0 should follow N(0, 1.0)
    _, p = stats.kstest(gene0_values, 'norm')
    print(p)
    assert (p > p_threshold)

    # Gene 1 should follow N(0.5, 1.0)
    gene1_centered_values = [x - 0.5 for x in gene1_values]
    _, p = stats.kstest(gene1_centered_values, 'norm')
    print(p)
    assert (p > p_threshold)

    # Gene 1 should *not* follow N(0, 1.0)
    _, p = stats.kstest(gene1_values, 'norm')
    print(p)
    assert (p <= p_threshold)
Esempio n. 3
0
def ea_solve(function, bounds, generations=100, pop_size=2,
             mutation_std=1.0, maximize=False, viz=False, viz_ylim=(0, 1)):
    """Provides a simple, top-level interfact that optimizes a real-valued
    function using a simple generational EA.

    :param function: the function to optimize; should take lists of real
        numbers as input and return a float fitness value

    :param [(float, float)] bounds: a list of (min, max) bounds to define the
        search space

    :param int generations: the number of generations to run for
    :param int pop_size: the population size
    :param float mutation_std: the width of the mutation distribution
    :param bool maximize: whether to maximize the function (else minimize)
    :param bool viz: whether to display a live best-of-generation plot

    :param (float, float) viz_ylim: initial bounds to use of the plots
        vertical axis

    >>> from leap_ec import simple
    >>> ea_solve(sum, bounds=[(0, 1)]*5) # doctest:+ELLIPSIS
    generation, bsf
    0, ...
    1, ...
    ...
    100, ...
    [..., ..., ..., ..., ...]
    """

    pipeline = [
        ops.tournament_selection,
        ops.clone,
        mutate_gaussian(std=mutation_std),
        ops.uniform_crossover(p_swap=0.4),
        ops.evaluate,
        ops.pool(size=pop_size)
    ]

    if viz:
        plot_probe = probe.PopulationPlotProbe(
            context, ylim=viz_ylim, ax=plt.gca())
        pipeline.append(plot_probe)

    ea = generational_ea(generations=generations, pop_size=pop_size,
                         problem=FunctionProblem(function, maximize),

                         representation=Representation(
                             individual_cls=Individual,
                             decoder=IdentityDecoder(),
                             initialize=create_real_vector(bounds=bounds)
                         ),

                         pipeline=pipeline)

    best_genome = None
    print('generation, bsf')
    for g, ind in ea:
        print(f"{g}, {ind.fitness}")
        best_genome = ind.genome

    return best_genome
Esempio n. 4
0
    context['leap']['std'] = 2

    # We use the provided context, but we could roll our own if we
    # wanted to keep separate contexts.  E.g., island models may want to have
    # their own contexts.
    generation_counter = util.inc_generation(context=context,
                                             callbacks=(anneal_std, ))

    # print initial, random population
    print_population(parents, generation=0)

    while generation_counter.generation() < MAX_GENERATIONS:
        offspring = pipe(
            parents,
            ops.random_selection,
            ops.clone,
            mutate_gaussian(std=context['leap']['std']),
            ops.evaluate,
            ops.pool(size=len(parents) * BROOD_SIZE),
            # create the brood
            ops.truncation_selection(size=len(parents),
                                     parents=parents))  # mu + lambda

        parents = offspring

        generation_counter()  # increment to the next generation

        # Just to demonstrate that we can also get the current generation from
        # the context
        print_population(parents, context['leap']['generation'])
                             # Representation
                             representation=Representation(
                                 # Initialize a population of integer-vector genomes
                                 initialize=create_real_vector(
                                     bounds=[problem.bounds] * l)
                             ),

                             # Operator pipeline
                             pipeline=[
                                 ops.tournament_selection(k=2),
                                 ops.clone,
                                 # Apply binomial mutation: this is a lot like
                                 # additive Gaussian mutation, but adds an integer
                                 # value to each gene
                                 mutate_gaussian(std=0.2, hard_bounds=[problem.bounds]*l,
                                                 expected_num_mutations=1),
                                 ops.evaluate,
                                 ops.pool(size=pop_size),

                                 # Some visualization probes so we can watch what happens
                                 probe.CartesianPhenotypePlotProbe(
                                        xlim=problem.bounds,
                                        ylim=problem.bounds,
                                        contours=problem),
                                 probe.FitnessPlotProbe(),

                                 probe.PopulationMetricsPlotProbe(
                                     metrics=[ probe.pairwise_squared_distance_metric ],
                                     title='Population Diversity'),

                                 probe.FitnessStatsCSVProbe(stream=sys.stdout)
Esempio n. 6
0
                             pop_size=pop_size,
                             problem=problems,  # Fitness function

                             # Representation
                             representation=Representation(
                                 individual_cls=Individual,
                                 initialize=create_real_vector(
                                     bounds=[bounds] * l),
                                 decoder=IdentityDecoder()
                             ),

                             # Operator pipeline
                             shared_pipeline=[
                                 ops.tournament_selection,
                                 ops.clone,
                                 mutate_gaussian(
                                     std=0.03, hard_bounds=bounds),
                                 ops.evaluate,
                                 ops.pool(size=pop_size),
                                 ops.migrate(context,
                                             topology=topology,
                                             emigrant_selector=ops.tournament_selection,
                                             replacement_selector=ops.random_selection,
                                             migration_gap=5,
                                             customs_stamp=problem_stamp(problems)),
                                 probe.FitnessStatsCSVProbe(context, stream=sys.stdout,
                                        extra_columns={ 'island': get_island(context) })
                             ],
                             subpop_pipelines=subpop_probes)

    list(ea)
    plt.show()
Esempio n. 7
0
    parents = Individual.evaluate_population(parents)

    # print initial, random population
    print_population(parents, generation=0)

    max_generation = MAX_GENERATIONS

    # We use the provided context, but we could roll our own if we
    # wanted to keep separate contexts.  E.g., island models may want to have
    # their own contexts.
    generation_counter = util.inc_generation(context=context)

    while generation_counter.generation() < max_generation:
        offspring = pipe(
            parents,
            ops.random_selection,
            ops.clone,
            mutate_gaussian(std=.1),
            ops.evaluate,
            ops.pool(size=len(parents) * BROOD_SIZE),
            # create the brood
            ops.insertion_selection(parents=parents))

        parents = offspring

        generation_counter()  # increment to the next generation

        # Just to demonstrate that we can also get the current generation from
        # the context
        print_population(parents, context['leap']['generation'])
Esempio n. 8
0
    ea = multi_population_ea(
        generations=1000,
        num_populations=topology.number_of_nodes(),
        pop_size=pop_size,
        problem=problem,  # Fitness function

        # Representation
        representation=Representation(
            individual_cls=Individual,
            initialize=create_real_vector(bounds=[problem.bounds] * l),
            decoder=IdentityDecoder()),

        # Operator pipeline
        shared_pipeline=[
            ops.tournament_selection, ops.clone,
            mutate_gaussian(std=30, hard_bounds=problem.bounds), ops.evaluate,
            ops.pool(size=pop_size),
            ops.migrate(context,
                        topology=topology,
                        emigrant_selector=ops.tournament_selection,
                        replacement_selector=ops.random_selection,
                        migration_gap=50),
            probe.FitnessStatsCSVProbe(
                context,
                stream=sys.stdout,
                extra_columns={'island': get_island(context)})
        ],
        subpop_pipelines=subpop_probes)

    list(ea)
    plt.show()
Esempio n. 9
0
    context['leap']['std'] = 2

    # We use the provided context, but we could roll our own if we
    # wanted to keep separate contexts.  E.g., island models may want to have
    # their own contexts.
    generation_counter = util.inc_generation(context=context,
                                             callbacks=(anneal_std, ))

    # print initial, random population
    print_population(parents, generation=0)

    while generation_counter.generation() < max_generation:
        offspring = pipe(
            parents,
            ops.random_selection,
            ops.clone,
            mutate_gaussian(std=context['leap']['std'],
                            expected_num_mutations=1),
            ops.evaluate,
            # create the brood
            ops.pool(size=len(parents) * BROOD_SIZE),
            # mu + lambda
            ops.truncation_selection(size=len(parents), parents=parents))
        parents = offspring

        generation_counter()  # increment to the next generation

        # Just to demonstrate that we can also get the current generation from
        # the context
        print_population(parents, context['leap']['generation'])
Esempio n. 10
0
    pop_size = 10
    ea = multi_population_ea(
        max_generations=generations,
        num_populations=topology.number_of_nodes(),
        pop_size=pop_size,
        problem=problem,  # Fitness function

        # Representation
        representation=Representation(
            individual_cls=Individual,
            initialize=create_real_vector(bounds=[problem.bounds] * l)),

        # Operator pipeline
        shared_pipeline=[
            ops.tournament_selection, ops.clone,
            mutate_gaussian(std=30,
                            expected_num_mutations=1,
                            hard_bounds=problem.bounds), ops.evaluate,
            ops.pool(size=pop_size),
            ops.migrate(topology=topology,
                        emigrant_selector=ops.tournament_selection,
                        replacement_selector=ops.random_selection,
                        migration_gap=50),
            probe.FitnessStatsCSVProbe(
                stream=sys.stdout,
                extra_metrics={'island': get_island(context)})
        ],
        subpop_pipelines=subpop_probes)

    list(ea)
Esempio n. 11
0
    # Evaluate initial population
    parents = Individual.evaluate_population(parents)

    # print initial, random population
    print_population(parents, generation=0)

    max_generation = MAX_GENERATIONS

    # Set up a generation counter using the default global context variable
    generation_counter = util.inc_generation()

    while generation_counter.generation() < max_generation:
        offspring = pipe(parents,
                         ops.random_selection,
                         ops.clone,
                         mutate_gaussian(std=.1, expected_num_mutations=1),
                         ops.evaluate,
                         ops.pool(
                             size=len(parents) * BROOD_SIZE),
                         # create the brood
                         ops.insertion_selection(parents=parents))

        parents = offspring

        generation_counter()  # increment to the next generation

        # Just to demonstrate that we can also get the current generation from
        # the context
        print_population(parents, context['leap']['generation'])
Esempio n. 12
0
    ea = multi_population_ea(
        max_generations=generations,
        num_populations=topology.number_of_nodes(),
        pop_size=pop_size,
        problem=problems,  # Fitness function

        # Representation
        representation=Representation(
            individual_cls=Individual,
            initialize=create_real_vector(bounds=[bounds] * l)),

        # Operator pipeline
        shared_pipeline=[
            ops.tournament_selection, ops.clone,
            mutate_gaussian(std=0.03,
                            expected_num_mutations=1,
                            hard_bounds=bounds), ops.evaluate,
            ops.pool(size=pop_size),
            ops.migrate(topology=topology,
                        emigrant_selector=ops.tournament_selection,
                        replacement_selector=ops.random_selection,
                        migration_gap=5,
                        customs_stamp=problem_stamp(problems)),
            probe.FitnessStatsCSVProbe(
                stream=sys.stdout,
                extra_metrics={'island': get_island(context)})
        ],
        subpop_pipelines=subpop_probes)

    list(ea)
Esempio n. 13
0
def ea_solve(function,
             bounds,
             generations=100,
             pop_size=cpu_count(),
             mutation_std=1.0,
             maximize=False,
             viz=False,
             viz_ylim=(0, 1),
             hard_bounds=True,
             dask_client=None):
    """Provides a simple, top-level interfact that optimizes a real-valued
    function using a simple generational EA.

    :param function: the function to optimize; should take lists of real
        numbers as input and return a float fitness value

    :param [(float, float)] bounds: a list of (min, max) bounds to define the
        search space

    :param int generations: the number of generations to run for
    :param int pop_size: the population size
    :param float mutation_std: the width of the mutation distribution
    :param bool maximize: whether to maximize the function (else minimize)
    :param bool viz: whether to display a live best-of-generation plot
    :param bool hard_bounds: if True, bounds are enforced at all times during
        evolution; otherwise they are only used to initialize the population.

    :param (float, float) viz_ylim: initial bounds to use of the plots
        vertical axis

    :param dask_client: is optional dask Client for enable parallel evaluations

    The basic call includes instrumentation that prints the best-so-far fitness
    value of each generation to stdout:

    >>> from leap_ec.simple import ea_solve
    >>> ea_solve(sum, bounds=[(0, 1)]*5) # doctest:+ELLIPSIS
    generation, bsf
    0, ...
    1, ...
    ...
    100, ...
    array([..., ..., ..., ..., ...])

    When `viz=True`, a live BSF plot will also display:

    >>> ea_solve(sum, bounds=[(0, 1)]*5, viz=True) # doctest:+ELLIPSIS
    generation, bsf
    0, ...
    1, ...
    ...
    100, ...
    array([..., ..., ..., ..., ...])

    .. plot::

        from leap_ec.simple import ea_solve
        ea_solve(sum, bounds=[(0, 1)]*5, viz=True)

    """

    if hard_bounds:
        mutation_op = mutate_gaussian(std=mutation_std,
                                      hard_bounds=bounds,
                                      expected_num_mutations='isotropic')
    else:
        mutation_op = mutate_gaussian(std=mutation_std,
                                      expected_num_mutations='isotropic')

    pipeline = [
        ops.tournament_selection,
        ops.clone,
        mutation_op,
        ops.uniform_crossover(p_swap=0.2),
    ]

    # If a dask client is given, then use the synchronous (map/reduce) parallel
    # evaluation of individuals; else, revert to serial evaluations.
    if dask_client:
        pipeline.append(
            synchronous.eval_pool(client=dask_client, size=pop_size))
    else:
        pipeline.extend([ops.evaluate, ops.pool(size=pop_size)])

    if viz:
        plot_probe = probe.FitnessPlotProbe(ylim=viz_ylim, ax=plt.gca())
        pipeline.append(plot_probe)

    ea = generational_ea(max_generations=generations,
                         pop_size=pop_size,
                         problem=FunctionProblem(function, maximize),
                         representation=Representation(
                             individual_cls=DistributedIndividual,
                             initialize=create_real_vector(bounds=bounds)),
                         pipeline=pipeline)

    best_genome = None
    print('generation, bsf')
    for g, ind in ea:
        print(f"{g}, {ind.fitness}")
        best_genome = ind.genome

    return best_genome
Esempio n. 14
0
    with open('./genomes.csv', 'w') as genomes_file:

        ea = generational_ea(
            max_generations=generations,
            pop_size=pop_size,
            # Solve a problem that executes agents in the
            # environment and obtains fitness from it
            problem=problems.EnvironmentProblem(runs_per_fitness_eval,
                                                simulation_steps,
                                                environment,
                                                'reward',
                                                gui=gui),
            representation=Representation(initialize=create_real_vector(
                bounds=([[-1, 1]] * decoder.wrapped_decoder.length)),
                                          decoder=decoder),

            # The operator pipeline.
            pipeline=[
                ops.tournament_selection,
                ops.clone,
                mutate_gaussian(std=mutate_std,
                                hard_bounds=(-1, 1),
                                expected_num_mutations=1),
                ops.evaluate,
                ops.pool(size=pop_size),
                *build_probes(
                    genomes_file)  # Inserting all the probes at the end
            ])
        list(ea)
Esempio n. 15
0
    print_population(parents, generation=0)

    # When running the test harness, just run for two generations
    # (we use this to quickly ensure our examples don't get bitrot)
    if os.environ.get(test_env_var, False) == 'True':
        max_generation = 2
    else:
        max_generation = 100

    # Set up a generation counter using the default global context variable
    generation_counter = util.inc_generation()

    while generation_counter.generation() < max_generation:
        offspring = pipe(parents,
                         ops.cyclic_selection,
                         ops.clone,
                         mutate_gaussian(std=.1, expected_num_mutations='isotropic'),
                         ops.evaluate,
                         # create the brood
                         ops.pool(size=len(parents) * BROOD_SIZE),
                         # mu + lambda
                         ops.truncation_selection(size=len(parents),
                                                  parents=parents))
        parents = offspring

        generation_counter()  # increment to the next generation

        # Just to demonstrate that we can also get the current generation from
        # the context
        print_population(parents, context['leap']['generation'])