Genetic Programming meets Python

I’m proud to announce that the new versions of Pyevolve will have Genetic Programming support; after some time fighting with these evil syntax trees, I think I have a very easy and flexible implementation of GP in Python. I was tired to see people giving up and trying to learn how to implement a simple GP using the hermetic libraries for C/C++ and Java (unfortunatelly I’m a Java web developer hehe).

The implementation is still under some tests and optimization, but it’s working nice, here is some details about it:

The implementation has been done in pure Python, so we still have many bonus from this, but unfortunatelly we lost some performance.

The GP core is very very flexible, because it compiles the GP Trees in Python bytecodes to speed the execution of the function. So, you can use even Python objects as terminals, or any possible Python expression. Any Python function can be used too, and you can use all power of Python to create those functions, which will be automatic detected by the framework using the name prefix =)

As you can see in the source-code, you don’t need to bind variables when calling the syntax tree of the individual, you simple use the “getCompiledCode” method which returns the Python compiled function ready to be executed.

Here is a source-code example:

from pyevolve import *
import math

error_accum = Util.ErrorAccumulator()

# This is the functions used by the GP core,
# Pyevolve will automatically detect them
# and the they number of arguments
def gp_add(a, b): return a+b
def gp_sub(a, b): return a-b
def gp_mul(a, b): return a*b
def gp_sqrt(a):   return math.sqrt(abs(a))

def eval_func(chromosome):
   global error_accum
   error_accum.reset()
   code_comp = chromosome.getCompiledCode()

   for a in xrange(0, 5):
      for b in xrange(0, 5):
         # The eval will execute a pre-compiled syntax tree
         # as a Python expression, and will automatically use
         # the "a" and "b" variables (the terminals defined)
         evaluated     = eval(code_comp)
         target        = math.sqrt((a*a)+(b*b))
         error_accum += (target, evaluated)
   return error_accum.getRMSE()

def main_run():
   genome = GTree.GTreeGP()
   genome.setParams(max_depth=5, method="ramped")
   genome.evaluator.set(eval_func)

   ga = GSimpleGA.GSimpleGA(genome)
   # This method will catch and use every function that
   # begins with "gp", but you can also add them manually.
   # The terminals are Python variables, you can use the
   # ephemeral random consts too, using ephemeral:random.randint(0,2)
   # for example.
   ga.setParams(gp_terminals       = ['a', 'b'],
                gp_function_prefix = "gp")
   # You can even use a function call as terminal, like "func()"
   # and Pyevolve will use the result of the call as terminal
   ga.setMinimax(Consts.minimaxType["minimize"])
   ga.setGenerations(1000)
   ga.setMutationRate(0.08)
   ga.setCrossoverRate(1.0)
   ga.setPopulationSize(2000)
   ga.evolve(freq_stats=5)

   print ga.bestIndividual()

if __name__ == "__main__":
   main_run()

I’m very happy and testing the possibilities of this GP implementation in Python.

And of course, everything in Pyevolve can be visualized any time you want (click to enlarge):

ramped_small

ramped_big

The visualization is very flexible too, if you use Python decorators to set how functions will be graphical represented, you can have many interesting visualization patterns. If I change the function “gp_add” to:

@GTree.gpdec(representation="+", color="red")
def gp_add(a, b): return a+b

We’ll got the follow visualization (click to enlarge):

full

I hope you enjoyed it, I’m currently fixing some bugs, implementing new features, docs and preparing the next release of Pyevolve, which will take some time yet =)

45 thoughts on “Genetic Programming meets Python

  1. Awesome! I’ve been working on resurrecting the old PyGP project (pygp.sf.net), but it’s no where as good as pyevolve.

    How are you going to store save the function after compilation is completed?

    Best of luck! I’d be VERY interested in helping out on this project.

    Best

  2. Hello Ryan, I’m using the code object to keep the code of the compiled expression. I’m still working on the new release, after that, I’m thinking in rewrite Pyevolve in a new version called Pyevolve2, which will break API backw. comp. and adopt some new OO design, but I contact you, I need to take time to prepare the new 0.6 release before. Thank you !

  3. is there a reason the interface has Java style setters and getters?

    # java-style
    ga.setMutationRate(0.8)
    # python-style
    ga.mutation_rate = 0.8

    if you really need to call a function you can wrap the attribute using property().

  4. Yes Jack, this is to keep the API compatibility with older versions. Maybe in the future I’ll make a new version which breaks the API comp. following the conventions of PEP 8. But the project have a large documentation, so I think it’s not a problem for now. Thank you !

  5. Hi! I think your library will be a blessing for my project!
    Just a little problem forced me to install Pyevolve manually:
    I’ve tried using easy_install on ubuntu jaunty 32 bit but I got this error:
    zioLoga@:~$ sudo easy_install pyevolve
    Searching for pyevolve
    Reading http://pypi.python.org/simple/pyevolve/
    Reading http://pyevolve.sourceforge.net
    Reading https://sourceforge.net/project/showfiles.php?group_id=251160&package_id=307022&release_id=655413
    No local packages or download links found for pyevolve
    error: Could not find suitable distribution for Requirement.parse(‘pyevolve’)

    zioLoga@loga:~$

  6. I have both python 2.6.2 and 2.5 installed.
    I now see I have python-dev installed for 2.6.2 version, but not for the 2.5 one. Maybe is this the cause of the problem?

    To install pyevolve I downloaded by hand the egg for python 2.6 and issued easy_install Pyevolve-0.5-py2.6.egg at the prompt. It worked fine.

  7. I think that the python-dev is the problem, maybe it search for another pattern on the download links, since only you reported this problem. Thank you.

  8. I am also getting this error: error: Could not find suitable distribution for Requirement.parse(‘pyevolve’)

    Jaunty fully up to date with python 2.[4|5|6] from repositories. easy_install, easy_install-2.[4|5|6] all return the same problem.

    1. Thank you for reporting Lachlan, it seems that Sourceforge has changed download page and easy_install isn’t getting the links. I’ll fix it now.

          1. I think they mean; how could you have program flow statements in the evolved genome? For example, instead of churning out a procedure which executes linearly, you might want loops, conditionals etc. to allow more advanced algorithms to be produced.

            So how could you have something like a “gp_if”?

  9. Hi all,

    I got the following error message:

    Traceback (most recent call last):
    File “/Users/JoseLuis/workspace/PG/src/PyevolveGP.py”, line 4, in
    error_accum = Util.ErrorAccumulator()
    AttributeError: ‘module’ object has no attribute ‘ErrorAccumulator’

    I am using python 2.6.4 under MacOSX and PyevolveGP.py is the file with the code above.

    I am not sure If I need to import anything else.

    Thanking you in advance

      1. Thank you.

        I was looking for the dev version, but I cann’t to found out. Where can I download it?

        Regards

  10. Looks like an interesting project, but does if *have* to construct Python programs? GP doesn’t literally mean constructing an executable computer program. It only means the structure being evolved is theoretically unbounded. I’d imagine for 99.99% of GP applications, the last thing you’d want to do is evolve literal code, since 99.99% of the search space would be nonsensical non-working code.

    1. Except that it normally is code which is evolved. Look at any of Koza’s early papers and he talks a lot about Lisp and shows how he evolves the code with restricted terminals etc.

    2. I used pyevolve to construct java programs. The nodes return strings:

      def gp_add(a, b): return ‘(%s) – (%s)’ % (a, b)
      def gp_sub(a, b): return ‘(%s) + (%s)’ % (a, b)
      def gp_mul(a, b): return ‘(%s) * (%s)’ % (a, b)

      and the returned program is:

      code = eval(code_comp)

      which was written to a .java file, compiled and run together with my project.

  11. I’m quite excited by this.

    What gp_* functions would need to be added to the core for it to be turing complete, I wonder?

    1. You don’t need to add every gp_* function to the core, in fact you can use the Python native “operator” module functions, like operator.add, etc… =)

  12. Fantastic! Trying it out right now.

    One thing comes to my mind. It would be nice to have some functionality to “reduce” the GPTree to the smallest equivalent form. For example, when I run your sample program, the individual I got was:
    Expression: gp_sqrt(gp_sub(b, gp_add(gp_add(gp_mul(a, a), gp_mul(b, b)), b)))
    Which is, in fact, equivalent to the following shorter expression (the minus sign comes from abs() in gp_sqrt, which allows it to accept negative values):
    Expression: gp_sqrt(- gp_add(gp_mul(a, a), gp_mul(b, b)))

    I wonder if such a functionality would belong in pyevolve or not. What do you think?

  13. Hello,

    It’s very interesting that GTreeGP can be used to find the needed function. The question is how I can save this function and reuse it in another module.

    I tried save data from nodes_list, nodes_branch, nodes_leaf to a file and then read from file but it seems not enough

    Do you have a solution for this, or add some SaveToFile and ReadFromFile for genome

  14. Hi, I tried using pip without success. Strange since it found it when I searched with pip… I have python 2.7 (OS X) and haven’t had any similar issues with the ~50 packages I have installed.

    $ pip search pyevolve
    Pyevolve – A complete python genetic algorithm framework
    $ pip install Pyevolve
    Downloading/unpacking Pyevolve
    Could not find any downloads that satisfy the requirement Pyevolve
    No distributions at all found for Pyevolve
    Storing complete log in /Users/beard/.pip/pip.log

  15. Hi All,

    Im enthusiastic about pyevolve.

    However, starting my first program (just using the example from the pyevolve website), Im getting the following error and I tried heavily to fix it, but Im out of ideas now. Could anybody please help out?

    Im using Wing 4.1 on Ubuntu

    termios.error: (25, ‘Inappropriate ioctl for device’)

    Best wishes

    Andi 😉

  16. FYI: I’m still getting the error: Could not find suitable distribution for… in Mac OSX with the Python.org 2.7 interpreter and latest version of easy_install.

  17. Hello, I’ve tried to use pip/easy_install, but it doesn’t work in my case:

    $ pip search pyevolve
    Pyevolve – A complete python genetic algorithm framework

    $ pip install pyevolve
    Downloading/unpacking pyevolve
    Could not find any downloads that satisfy the requirement pyevolve
    No distributions at all found for pyevolve
    Storing complete log in /home/redcrow/.pip/pip.log

    $ pip install Pyevolve
    Downloading/unpacking Pyevolve
    Could not find any downloads that satisfy the requirement Pyevolve
    No distributions at all found for Pyevolve
    Storing complete log in /home/redcrow/.pip/pip.log

    After reading the pip.log it seems there’s no available package for my python (version 2.7).

    Anyway, I’ve installed pyevolve-0.6 by using the Ubuntu repository.

  18. This is an awesome project, in my PhD I need use GP, and I’ll use this lib. I make some tests and relay works great.

    Congratulations for the wonderful job!

  19. I’m unable to install pyevolve on Ubuntu 12.04.4 LTS with python 2.7.3. I get the following error:

    sudo easy_install pyevolve
    Searching for pyevolve
    Reading http://pypi.python.org/simple/pyevolve/
    No local packages or download links found for pyevolve
    error: Could not find suitable distribution for Requirement.parse(‘pyevolve’)

  20. I’m new to Python and GP and I’am trying to print the best individual’s expression in order to evaluate it and compare the result with the target. Is there a built in function of Pyevolve that does this? because as I try to import the result to a file.csv, I get the tree expression which is unsuitable for later evaluation.
    Any help would be greatly appreciated

    1. Hello Sabrina, there are two methods: getSExpression() and getPreOrderExpression(), there is also the method getCompiledCode() that will return a Python compiled function of that individual expression.

Leave a Reply

Your email address will not be published.