Skip to content

Commit

Permalink
Added supporting text for table and changed truncation and tournament…
Browse files Browse the repository at this point in the history
… ops names to be consistent with other selection operators
  • Loading branch information
markcoletti committed Sep 18, 2020
1 parent 770d31a commit 06479c4
Show file tree
Hide file tree
Showing 21 changed files with 100 additions and 65 deletions.
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ algorithm.

Here's an example that applies a genetic algorithm variant to solve the
`MaxOnes` optimization problem. It uses bitflip mutation, uniform crossover,
and binary tournament selection:
and binary tournament_selection selection:

```Python
from leap_ec.algorithm import generational_ea
Expand All @@ -66,7 +66,7 @@ ea = generational_ea(generations=100, pop_size=pop_size,
),

# The operator pipeline
pipeline=[ops.tournament, # Select parents via tournament selection
pipeline=[ops.tournament_selection, # Select parents via tournament_selection selection
ops.clone, # Copy them (just to be safe)
ops.mutate_bitflip, # Basic mutation: defaults to a 1/L mutation rate
ops.uniform_crossover(p_swap=0.4), # Crossover with a 40% chance of swapping each gene
Expand Down
4 changes: 2 additions & 2 deletions _static/UML_classes.uxf
Original file line number Diff line number Diff line change
Expand Up @@ -487,7 +487,7 @@ bg=#00aaaa</panel_attributes>
<w>200</w>
<h>40</h>
</coordinates>
<panel_attributes>truncate
<panel_attributes>truncation_selection
bg=#aa55aa</panel_attributes>
<additional_attributes/>
</element>
Expand All @@ -510,7 +510,7 @@ bg=#aa55aa</panel_attributes>
<w>200</w>
<h>40</h>
</coordinates>
<panel_attributes>truncate
<panel_attributes>truncation_selection
bg=#aaaa00</panel_attributes>
<additional_attributes/>
</element>
Expand Down
4 changes: 2 additions & 2 deletions docs/source/concepts.rst
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ Here is an example of a LEAP pipeline:
gen = 0
while gen < max_generation:
offspring = toolz.pipe(parents,
ops.tournament,
ops.tournament_selection,
ops.clone,
mutate_bitflip,
ops.evaluate,
Expand All @@ -64,7 +64,7 @@ The above code snippet is an example of a very basic genetic algorithm
implementation that uses a `toolz.pipe()` function to link
together a series of operators to do the following:

#. binary tournament selection on a set of parents
#. binary tournament_selection selection on a set of parents
#. clone those that were selected
#. perform mutation bitflip on the clones
#. evaluate the offspring
Expand Down
79 changes: 57 additions & 22 deletions docs/source/ops.rst
Original file line number Diff line number Diff line change
Expand Up @@ -90,7 +90,7 @@ For example, consider the following snippet:
gen = 0
while gen < max_generation:
offspring = toolz.pipe(parents,
ops.tournament,
ops.tournament_selection,
ops.clone,
mutate_bitflip,
ops.evaluate,
Expand All @@ -103,7 +103,7 @@ The above code snippet is an example of a very basic genetic algorithm
implementation that uses a `toolz.pipe()` function to link
together a series of operators to do the following:

#. binary tournament selection on a set of parents
#. binary tournament_selection selection on a set of parents
#. clone those that were selected
#. perform mutation bit-flip on the clones
#. evaluate the offspring
Expand All @@ -118,7 +118,7 @@ by adding crossover:
gen = 0
while gen < max_generation:
offspring = toolz.pipe(parents,
ops.tournament,
ops.tournament_selection,
ops.clone,
mutate_bitflip,
ops.uniform_crossover, # NEW OPERATOR
Expand All @@ -130,15 +130,15 @@ by adding crossover:
This does the following:

#. binary tournament selection on a set of parents
#. binary tournament_selection selection on a set of parents
#. clone those that were selected
#. perform mutation bitflip on the clones
#. perform uniform crossover between the two offspring
#. evaluate the offspring
#. accumulate as many offspring as there are parents

Adding crossover means that now **two** parents are selected instead of one. However,
note that the tournament selection operator wasn't changed. It automatically
note that the tournament_selection selection operator wasn't changed. It automatically
selects two parents instead of one, as necessary.

Let's take a closer look at `uniform_crossover()` (this is a simplified version;
Expand Down Expand Up @@ -186,18 +186,18 @@ such as selection and pooling operators. Generally:
accept an `Iterator` from which to get the `next()` `Individual`, and returns a collection of `Individuals`

Below shows an example of a selection operator, which is a simplified version of
the `tournament()` operator:
the `tournament_selection()` operator:

.. code-block:: python
def tournament(population: List, k: int = 2) -> Iterator:
def tournament_selection(population: List, k: int = 2) -> Iterator:
while True:
choices = random.choices(population, k=k)
best = max(choices)
yield best
(Again, the actual :py:func:`leap_ec.ops.tournament` has checks and docstrings.)
(Again, the actual :py:func:`leap_ec.ops.tournament_selection` has checks and docstrings.)

This depicts how a typical selection pipeline operator works. It accepts a
population parameter (plus some optional parameters), and yields the selected
Expand Down Expand Up @@ -234,33 +234,68 @@ Pipeline operators that take on user-settable parameters are all wrapped with
Operator Class
^^^^^^^^^^^^^^

Table of Operators
^^^^^^^^^^^^^^^^^^

Table of Pipeline Operators
^^^^^^^^^^^^^^^^^^^^^^^^^^^
+--------------------------------+--------------------------+---------------------------+
| Representation | Iterator → Iterator | clone(),\ |
| Agnostic | | evaluate(),\ |
| | | uniform_crossover(),\ |
| | | n_ary_crossover(),\ |
| | | CooperativeEvaluate, |
| Representation Specificity | Input -> Output | Operator |
+================================+==========================+===========================+
| Representation | Iterator → Iterator | clone() |
| | +---------------------------+
| Agnostic | | evaluate() |
| | +---------------------------+
| | | uniform_crossover() |
| | +---------------------------+
| | | n_ary_crossover() |
| | +---------------------------+
| | | CooperativeEvaluate |
| +--------------------------+---------------------------+
| | Iterator → population | pool() |
| +--------------------------+---------------------------+
| | population → population | truncate(), |
| | | const_evaluate(), |
| | | insertion_selection(), |
| | population → population | truncation_selection() |
| | +---------------------------+
| | | const_evaluate() |
| | +---------------------------+
| | | insertion_selection() |
| | +---------------------------+
| | | migrate() |
| +--------------------------+---------------------------+
| | population → Iterator | tournament(), |
| | | naive_cyclic_selection(), |
| | | cyclic_selection(), |
| | population → Iterator | tournament_selection() |
| | +---------------------------+
| | | naive_cyclic_selection() |
| | +---------------------------+
| | | cyclic_selection() |
| | +---------------------------+
| | | random_selection() |
+-------------------+------------+--------------------------+---------------------------+
| Representation | binary_rep | Iterator → Iterator | mutate_bitflip() |
| Dependent +------------+--------------------------+---------------------------+
| | real_rep | Iterator → Iterator | mutate_gaussian() |
+-------------------+------------+--------------------------+---------------------------+

Admittedly it can be confusing when considering the full suite of LEAP pipeline operators,
especially in remembering what kind of operators "connect" to what. With that in mind,
the above table breaks down pipeline operators into different categories. First,
there are two broad categories of pipeline operators --- operators that don't care
about the internal representation of `Individuals`, or "Representation Agnostic" operators;
and those operators that do depend on the internal representation, or "Representation
Dependent" operators. Most of the operators are "Representation Agnostic" in that it doesn't matter
if a given `Individual` has a genome of bits, real-values, or some other
representation. Only two operators are dependent on representation, and those
will be discussed later.

The next category is broken down by what kind of input and output a given
operator takes. That is, generally, an operator takes a population (collection
of `Individuals`) or an `Iterator` from which a next `Individual` can be found.
Likewise, a given operator can return a population or yield an `Iterator` to
a next `Individual`. So, operators that return an `Iterator` can be connected
to operators that expect an `Iterator` for input. Similarly, an operator that
expects a population can be connected directly to a collection of `Individuals`
(e.g., be the second argument to ``toolz.pipe()``) or to an operator that
returns a collection of `Individuals`.

If you are familiar with evolutionary algorithms, most of these connections are
just common sense. For example, selection operators would select from a
population.

Type-checking Decorator Functions
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
Expand Down
4 changes: 2 additions & 2 deletions docs/source/readme.rst
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@ algorithm.

Here's an example that applies a genetic algorithm variant to solve the
`MaxOnes` optimization problem. It uses bitflip mutation, uniform crossover,
and binary tournament selection:
and binary tournament_selection selection:

.. code-block:: Python
Expand All @@ -83,7 +83,7 @@ and binary tournament selection:
),
# The operator pipeline
pipeline=[ops.tournament, # Select parents via tournament selection
pipeline=[ops.tournament_selection, # Select parents via tournament_selection selection
ops.clone, # Copy them (just to be safe)
mutate_bitflip, # Basic mutation: defaults to a 1/L mutation rate
ops.uniform_crossover(p_swap=0.4), # Crossover with a 40% chance of swapping each gene
Expand Down
2 changes: 1 addition & 1 deletion docs/source/roadmap.rst
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ The LEAP development roadmap is as follows:
* mutate gaussian
* selection operators
* truncation selection
* tournament selection
* tournament_selection selection
* random selection
* deterministic cyclic selection
* insertion selection
Expand Down
2 changes: 1 addition & 1 deletion examples/coevolution.py
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@

# Operator pipeline
shared_pipeline=[
ops.tournament,
ops.tournament_selection,
ops.clone,
mutate_bitflip(expected=1),
ops.CooperativeEvaluate(
Expand Down
4 changes: 2 additions & 2 deletions examples/island_model.py
Original file line number Diff line number Diff line change
Expand Up @@ -99,15 +99,15 @@ def viz_plots(problems, modulo):

# Operator pipeline
shared_pipeline=[
ops.tournament,
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,
emigrant_selector=ops.tournament_selection,
replacement_selector=ops.random_selection,
migration_gap=50),
probe.FitnessStatsCSVProbe(
Expand Down
4 changes: 2 additions & 2 deletions examples/jupyter_plotting.ipynb
Original file line number Diff line number Diff line change
Expand Up @@ -906,7 +906,7 @@
" ),\n",
"\n",
" pipeline=[\n",
" ops.tournament,\n",
" ops.tournament_selection,\n",
" ops.clone,\n",
" mutate_gaussian(std=0.5),\n",
" ops.evaluate,\n",
Expand Down Expand Up @@ -3393,7 +3393,7 @@
" ),\n",
"\n",
" pipeline=[\n",
" ops.tournament,\n",
" ops.tournament_selection,\n",
" ops.clone,\n",
" mutate_gaussian(std=50, hard_bounds=problem.bounds),\n",
" ops.evaluate,\n",
Expand Down
2 changes: 1 addition & 1 deletion examples/openai_gym.py
Original file line number Diff line number Diff line change
Expand Up @@ -136,7 +136,7 @@ def evolve_pitt(runs, steps, env, evals, pop_size,

# The operator pipeline.
pipeline=[
ops.tournament,
ops.tournament_selection,
ops.clone,
mutate_gaussian(
std=mutate_std, hard_bounds=(0, 1)),
Expand Down
4 changes: 2 additions & 2 deletions examples/simple_ep.py
Original file line number Diff line number Diff line change
Expand Up @@ -70,8 +70,8 @@ def print_population(population, generation):
ops.pool(
size=len(parents) * BROOD_SIZE),
# create the brood
ops.truncate(size=len(parents),
parents=parents)) # mu + lambda
ops.truncation_selection(size=len(parents),
parents=parents)) # mu + lambda

parents = offspring

Expand Down
4 changes: 2 additions & 2 deletions examples/simple_es.py
Original file line number Diff line number Diff line change
Expand Up @@ -88,8 +88,8 @@ def anneal_std(generation):
ops.pool(
size=len(parents) * BROOD_SIZE),
# create the brood
ops.truncate(size=len(parents),
parents=parents)) # mu + lambda
ops.truncation_selection(size=len(parents),
parents=parents)) # mu + lambda

parents = offspring

Expand Down
2 changes: 1 addition & 1 deletion examples/simple_ga.py
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ def print_population(population, generation):

while generation_counter.generation() < max_generation:
offspring = pipe(parents,
ops.tournament,
ops.tournament_selection,
ops.clone,
# these are optional probes to demonstrate their use
probe.print_individual(prefix='before mutation: '),
Expand Down
2 changes: 1 addition & 1 deletion examples/simple_sync_distributed.ipynb
Original file line number Diff line number Diff line change
Expand Up @@ -173,7 +173,7 @@
"source": [
"for current_generation in range(5):\n",
" offspring = toolz.pipe(parents,\n",
" ops.tournament,\n",
" ops.tournament_selection,\n",
" ops.clone,\n",
" mutate_bitflip,\n",
" ops.uniform_crossover,\n",
Expand Down
2 changes: 1 addition & 1 deletion examples/simple_sync_distributed.py
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@

for current_generation in range(5):
offspring = toolz.pipe(parents,
ops.tournament,
ops.tournament_selection,
ops.clone,
mutate_bitflip,
ops.uniform_crossover,
Expand Down
6 changes: 3 additions & 3 deletions leap_ec/algorithm.py
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,7 @@ def generational_ea(generations, pop_size, representation, problem, pipeline):
...
... # The operator pipeline
... pipeline=[
... ops.tournament, # Select parents via tournament selection
... ops.tournament_selection, # Select parents via tournament selection
... ops.clone, # Copy them (just to be safe)
... mutate_bitflip, # Basic mutation: defaults to a 1/L mutation rate
... ops.uniform_crossover(p_swap=0.4), # Crossover with a 40% chance of swapping each gene
Expand Down Expand Up @@ -195,14 +195,14 @@ def multi_population_ea(generations, num_populations, pop_size, problem,
... ),
...
... shared_pipeline=[
... ops.tournament,
... 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,
... emigrant_selector=ops.tournament_selection,
... replacement_selector=ops.random_selection,
... migration_gap=50)
... ])
Expand Down
Loading

0 comments on commit 06479c4

Please sign in to comment.