Time to catch you up on a project of mine.

A short while ago I got interested in adaptive design. The broad idea is to apply an evolutionary or fitness maximising algorithm to the design of some object.

Whenever I want to learn about something I like to build a small project of my own. For this I decided to model how roots grow through soil.

I start with a 100 x 100 grid. The squares are either empty soil or occupied by a root cell. The plant wants to maximise its surface area (number of adjacent soil cells) to volume (number of plant cells) ratio. From here on let’s have


The algorithm does this:

  1. Identify all unoccupied squares next to the plant.
  2. Choose a square from step 1.
  3. Calculate how much the plant’s fitness would change by adding the new square.
  4. Decide whether to add the square or not.

Step 1 is done using a convolution which I may detail in another post. Step 2 is just a random selection. Step 4 uses this code:

def shouldTransition(self, changeInFitness):

        #threshold value
        #changeInFitness += 5.0

        #changeInFitness *= 10

        activation = expit(changeInFitness)

        dice = random.uniform(0.0, 1.0)

        return dice <= activation

The expit function looks like this:


The idea is that the plant should favour new growth that would increase its fitness so the probability gets closer to 1 to the right. conversely if a change lowers the fitness it gets a probability closer to zero. We can have lots of fun by tweaking the shape of this graph: we can

  1. Make the plant more ambitious; it only accepts big increases to its fitness.
  2. Make the plant more adventurous; it will more happily add growth that harms its fitness. this can be useful to prevent the plant getting stuck in a rut.

Let have a look at some results. Animated for your viewing pleasure. Here 1 second corresponds to 100 time steps.

And another


Th eagle eyed among you may notice a few interesting things about these animations: Do all the root cells spawn new growth? No but more on that in another post. What happens if we modify the expit function? Coming soon…

Thanks for reading I’ll follow up with more detail soon.