dries.page /DIY /art /dev

Python and the Meaning of Life

Dec 22, 2020

The evolution of life fascinates to no end. Around 90 chemical elements form more than 9 million known organic molecules, created from processes written in thousands to billions DNA base pairs reproducing themselves. Most lifeforms are unicellular, but humans have 30 trillion cells. Evolution is an untiring creative algorithm that creates order from chaos without planning. The creatures it produces mold their environment, which in turn influences the course of evolution. If you could look at earth's history as a fast-forward time lapse, the surface would look like a rippling liquid on which life explodes in sudden stutters, like a noisy, ever-changing expressionist painting.

A grid of green squares and an open space with a few purple ones.

Simulating life on a computer means throwing overboard almost all complexity. The interesting exercise is in choosing what to keep, like trying to summarize a book in one sentence. Some of my favorite life experiments which you can try online are:

  • Conway's Game of Life, where cells sprout in and out of existence according to the number of neighbouring cells. From these most simple mathematical rules emerge larger structures. There is no evolution and only one 'cell type' but it laid the foundation for many other cellular automata.
  • The Life Engine, which simulates evolution and ecosystems. Cells come in a discrete number of functions to form functioning multicellular lifeforms. Intelligent design is recommended to speed things up.
  • The minutelabs evolution simulator, if only because it was based on a youtube channel called Primer, which wonderfully explains what is going on.

I started making evolution simulators based on my casual interest in evolution and ecology, without knowing what else is out there. It's one of those ideas where many people do sort of the same thing without knowing about eachother. As a teenager, I made my simulations in a tool called Game Maker, which was a lot of fun. I made one simulation for optimal eye placement on some swimming circle creatures, one for group selection and social behavior, and a few with the goal of creating lush ecosystems.

Using an old game engine was however a dead end if I want to share my work, optimize it, run it on a server, or feed it into a neural net. I could barely even access the old experiments, since they require unsupported old versions of Game Maker, and executables don't work on my Linux and somehow became anti-aliased on Windows 10. So when learning how to code in something slightly more serious like python, I naturally wanted to remake a basic evolution simulator instead of 'hello world'.

Some of my early evolution experiments.

My simulation

I tried to keep it simple. It is easy to get interesting results by introducing a lot of variation in creatures and environment. The goal however, is not to code the complexity, but to have it emerge from the simplest possible rules. Still, I know it's a succesful simulation of life because the main features (Birth, Growth, Fighting and Death) are all chapters in Monty Python's "The Meaning of Life". And that's as good a definition as any.

There is a single environment, a 50*50 grid which wraps around the sides. Every square on the grid can hold one cell. Every cell has 3 genes: speed, diet and power. Each gene does one thing only and is expressed by one base color (red, green and blue). This way, the mixed rgb color of the cell tells you exactly what its genes are.

There is one more value: energy, which is spent by moving, being strong, living and gained by feeding. It's represented as the size of the cell. Reproduction happens if there is an adjacent free spot, asexually when reaching a certain energy treshold, and transfers part of this energy to a new organism with the same genes but slightly mutated.

I am not a mathematician in the slightest, but the mathematical name of this kind of grid with gradual values turns out to be 'coupled map lattice'. The term 'cellular automaton' or 'iterative array' is more famous, but is used for grids where the cells have a finite amount of states. Coupled map lattices have apparently been used to model biological system and population dynamics, though I imagine that academic ecologists use less computationally expensive models by relying on more simplified formulas like heat equations.

You can find the code here. The phenomena that can arise from these simple rules are already very interesting. Let's run it and see what happens.

On the left we see the grid or matrix, full of cells. The green cells could be considered plants - the greener a cell is, the more resources it can produce autotrophically, that is without eating other lifeforms. Blue-green plants move around, which can be useful to colonize new areas but requires energy. Yellow plants have more power, which can be useful for defending in a collision with another creature.

On the right we see a 3D scatterplot. This is just another way of representing the same creatures you see on the left. Except this time, it is not their physical location but their genes that determine their position. The higher up in the cube (blue) the faster they are. The right side (green) is about how autotrophic they are. The opposite side is for creatures which get energy from eating other creatures. The red side on the left is for power, power is needed to damage other creatures and if they survive they can strike back with their power. This way, energy can be transferred from one creature to another.

What is going on in the video is that from a situation of only 'plants', some plants figure out that by moving and having power at the same time, they can take energy from eating other plants. It may take a while for this evolution to occur, because it requires the plant to become mobile, heterotrophic and moving all at the same time. The reason that herbivores can evolve at all is because there is plenty of time to evolve, and there are so many plants so the strategy can be very succesful. Once there is a single succesful herbivore, the process picks up exponentially and herbivores evolve further and further away from plants.

The plant/herbivore split is the most basic process of speciation that I noticed even with wildly different parameters. However, by tinkering with the parameters of the simulation more niches can be created, like plants that run away which then results in herbivores that sit still and wait. There is also a much larger diversity in plants than in herbivores. This doesn't mean that there are different ecological niches, it could also mean that the environment is more forgiving for suboptimal strategies.

We can see a predator-prey cycle, where more plants causes more herbivores, which in turn means less plants. And so the populations of both species go up and down in waves, where the herbivores peak later.

In this longer simulation, we changed the parameters to make speed and power less costly. The 'plants' evolve two defensive strategies, one is to move and disperse and the other is to fight back when hit. Once the second strategy evolves, the first one goes extinct, since there is no more open space for the moving plants.

There is no intelligence in the movement, creatures just move around randomly. This is also why the herbivores only live inside corridors between the plants - once the corridor becomes too wide they run around in the empty space and starve.

Besides adding intelligence or other interesting features, a next step could be to use a neural network to find out which parameters create the highest biodiversity. I think we have tweaked them well for this experiment, but when dealing with more parameters and genes this would become challenging since the number of possible creatures grows exponentially. A trap would be that a total lack of evolutionary pressures would cause the largest genetic drift and as such the most biodiversity, but this concept of biodiversity would be ecologically meaningless. So the question becomes: how to measure and then optimize the number of ecological niches? That's for another time.