Skip to content

stromatolith/peabox

Repository files navigation

peabox

an evolutionary algorithm toolbox written in python

Use it if you want to tinker around with evolutionary algorithms and you do not yet know wheter it will take you into the direction of GA, ES, PSO, DE, simulated annealing etc or if you decline that decision at all. The library is geared towards being intuitive to use and thus enabling rapid prototyping of evolutionary algorithms. It is made for you if you share my opinion that trying stuff out quickly is better than only reading up on EAs in sometimes boring and often uncomparable papers.

core features:

  • class Individual: if dude is an individual, you can do dude.mutate(), dude.become_mixture_of(parentA,parentB), dude.CO_with(otherdude) and stuff like that
  • class Population: if p1 is a population, you can do p1.sort(), p1.new_random_genes(), p1.get_DNAs(), p1.eval_all(), p1.eval_all_threaded(), p3=p2+p1, and similar things.

This lets you write down concise code for casting your new evolutionary algorithm idea in python. Some more shorthands or convenience routines still missing in the library? (E.g. wanting binary DNA with a different dude.mutate()?) The classes Individual and Population can be expanded and/or subclassed in an easy and intuitive manner, the feeling of straightforwardness is there already after a highschool biology class, and not only for experienced master programmers.

some more features of interest:

  • visualisable test functions: watch how solutions become better and better, this speeds up your trial and error iteration cycle
  • algorithm codes: PSO, simple ES, CMA-ES, simple RCGA, scatter search
  • examples of combinations of different oldschool EAs
  • how to call the CEC-2013 test function suite, which is coded in C, from within python via ctypes
  • there's a tutorial, just go to the readme in the tutorial folder

explanation (for EA newbies)

find it in the folder intro_for_EA_newbies

Below some more words of explanation and motivation will follow addressing readers with a bit of background knowledge of EAs and perhaps some programming experience.

motivation (for EA pros)

Learning by doing is the only way to familiarise oneself with evolutionary algorithms. Hence, the interest in rapid algorithm prototyping. So, wouldn't it be nice to be able to hack away like this?

p1=Population(fitfunc,psize,searchspace)
p2=Population(fitfunc,2*psize,searchspace)

p1.new_random_genes()
p1.eval_all()
print [dude.score for dude in p1]
dude1,dude2=p1[:2]           # now we can address these two guys individually
print dude1<dude2            # wanting to implicitly compare dude1.score with dude2.score
print dude1.isbetter(dude2)  # dudes should know whether goal is to minimise or maximise score
p1.sort()                    # should be based on the isbetter operator

p2[0].copy_DNA_of(p1[0])     # conserve best

for dude in p2[1:]:          # now wildly mixing traditional EA approaches
    if in_the_mood_for_CO():
        parentA,parentB=randint(psize,size=2)
        dude.CO_from(p1[parentA],p1[parentB])  # uniform crossing-over
    elif in_the_mood_for_mutation():
        dude.copy_DNA_of(p1[randint(psize)])
        dude.mutate(P,standarddeviation)       # adding a vector of normally distributed numbers as one mutation option
    elif in_the_mood_for_averaging():
        parentA,parentB=randint(psize,size=2)
        dude.become_mixture_of(p1[parentA],p1[parentB])   # center of connecting line, i.e. mean DNA vector
    elif in_the_mood_for_DE():
        pA,pB,pC=find_three_DE_parents(p1)
        dude.become_DE_child(pA,pB,pC)         # differential evolution step
    else:
        dude.whatever()   # easily invent a new dude.method() based on basal Individual's methods

p2.eval_all()
p2.sort()

Often it makes sense to work with test problems of which you can easily visualise a solution candidate (e.g. 2D truss bridge or FM-synthesis wave matching), which will allow you to quickly judge online whether the best solution found in a population improves over time or not. In that case I'd like to have the possibility of subclassing the Individual and add a specific plot_yourself() function.

bestdude=p2[0]
bestdude.plot_yourself(path) 

p2.sort_for('otherprop')  # assuming each Individual has a property dude.otherprop
funnydude=p2[0]
funnydude.plot_yourself(path2)

And some more generally desired behaviour ...

p3=p1+p2                  # we want to be able to merge populations
p3.sort()
p4=p3[:10]                # of course then we also want to be able to take a slice of a population

print p1[0] is p3[0]      # did the best of p1 stay the best in p3?
print p1[0] is p2[0]      # and did it stay the best in p2? no, hold on, p2 is now sorted the other way, but wait...
print p1[0] is bestdude   # ... that's how to ask that question

p3.pickle_self(path)      # being able to pickle and unpickle populations definitely makes sense

We want to be able to pull out important data in the form of lists or arrays:

finalDNAs=p4.get_DNAs()
finalscores=p4.get_scores()
bestDNA=bestdude.get_copy_of_DNA()
bestDNApointer=bestdude.DNA

And after a couple of generations, maybe you want to plot something like this:

p1.plot_score_history_cloud(plotpath)
p1.plot_best_DNA_development(plotpath)

Well, my answer was yes, it definitely would be nice to have such shortcut methods, so I coded up two classes for Individual and Population and some test function and plotting routines. I really think it made experimenting with evolutionary algorithms much easier and faster for me.

In order to share the library with you on github, these days I am stripping the code of parts too specific to my application, hoping to get rid of everything potentially annoying and conserving the core utilities of general interest.

purpose of this project

class library for rapid prototyping of evolutionary optimisers

  • focus on real parameter optimisation
  • flexibility implementing complex optimisation problems (by subclassing Individual)
  • implementing solution candidate plotting is easy (adding plot routine to Individual subclass)
  • learning about EA with the help of test functions with visualisable solution candidates (using Matplotlib)
  • experimenting with useful visualisation of EA run statistics (using Matplotlib)

The goal is a rapid iteration cycle (algorithm idea -> code -> testing -> new idea) for the experimenting architect of evolutionary algorithms.

current features

  • Individual class with operators for dealing with own and fellow DNA (i.e. copying, mutating, crossover like uniform, BLX, WHX ...)
  • Population class with functionality for sorting, splitting, merging, of populations ensuring freedom for EA invention
  • populations behave like a python list, so you can append and slice them
  • individuals have comparison operators looking at the fitness for asking dude1<dude2 and dude1.isbetter(dude2)
  • hence, a population p can easily be sorted:
    • p.sort() sorts according to score/fitness of Individuals
    • p.sort_for('anything') sorts for that if individuals have a property dude.anything
  • mutation and recombination operators are able to respect search domain boundaries
  • some CEC-2005 test functions and some other popular test functions
  • new: how to call the CEC-2013 test function suite from within python via ctypes
  • new: basic evolution strategies (ES)
  • new: a basic real-coded genetic algorithm (RCGA) with several options for selection pressure
  • new: scatter search (SCS or SS)
  • new: EA combination examples, e.g. ES+GA+DE-combination
  • new: own folder with visualisable test functions and motivating thoughts
  • new: particle swarm optimisation (PSO)
  • a recorder class for regularly taking notes on population status
  • utilities for plotting population histories based on data from recorder objects
  • a little tutorial

tutorial lessons

  • tutorial lesson 1: simple evolution strategy, a (mu,lambda)-ES
  • tutorial lesson 2: simple genetic algorithm (GA) with roulette wheel parent selection
  • tutorial lesson 3a: comparison operators of the Individual class
  • tutorial lesson 3b: old-school crossing-over operators for individual's DNAs
  • tutorial lesson 3c: mutation operators - plot DNA vector density distributions
  • tutorial lesson 4: an EA homebrew - stages of exploring a new EA concept
  • tutorial lesson 5: FM synthesis wave matching - object-oriented implementation of a real-world problem with a candidate solution plotting method

interesting features still missing

If you enjoy python coding and EAs belong to your interests, I would be happy about you joining the team!

  • your EA idea
  • SaDE
  • NSGA-II
  • maybe binary DNAs would be interesting, e.g. for the sake of testing the CHC-GA
  • BGA mutation operator and other popular GA operators

keywords

evolutionary algorithm, evolutionary computation, evolutionary optimisation, global search, derivative-less optimisation

not featured

  • binary DNA
  • operators (mutation, CO) for integer-coded DNA
  • DNA of symbols
  • DNA of variable length within one population
  • program installation --> just copy the files you need into your work folder (sorry, I didn't take the time yet to figure out how to use distutils or other such stuff)

About

an evolutionary algorithm toolbox written in python

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published

Languages