Some time ago I stumbled across a paper entitled ‘Beyond the Null Ritual: Formal modelling of Psychological Processes‘ (Marewski & Olsson, 2009). As the title suggests the paper is a strong argument for formal modelling of psychological phenomenon. Marewski and Olsson argue that there are two kinds of models – formal models (mathematical and computational models) and informal models (descriptions of phenomena using language). Formal models are superior to informal models because a) they afford better comparisons for different theories describing the same phenomenon, b) they ‘sharpen’ research questions by reducing ambiguity in informal models by forcing researchers to quantify and make explicit their assumptions, and c) they better illuminate real-world problems. Further, our current statistical tools already beget assumptions about the underlying rules of our chosen phenomenon which ought to be checked (ANOVA’s are a linear tool, for example, and not all phenomenon can be treated with them). Certainly improved statistical understanding improves our understanding of both our data and our real-world phenomena, but this doesn’t mean modelling has no place. On the contrary, modelling is just another tool for understanding, describing, and making predictions about the world.
I was easily persuaded. How could they be wrong? And given that I’m interested in evolutionary phenomenon, I’m already bought-in on the idea that the process by which a mechanism of behavior emerges is important.
And so, after a little bit of research, I came to NetLogo, a Java-based modelling language used to model agent-based phenomena. I initially pieced together an informal education using youtube, but hita hard limit pretty quickly. Needing something more comprehensive, I found ‘An Introduction to Agent-Based Modelling‘ by Wilenski and Rand. It’s not great for my questions, but it is thorough on teaching skills more broadly (so far, anyway). And so here I share a very basic model I’ve created.
Sidenote: Netlogo does have a Web app for embedding programs. Unfortunately, it doesn’t have complete functionality, and some of the commands I used were not available.
Below: My Evolutionary Model has been running for about a minute (Click to embiggen)
The model is quite simple. It’s a horizontally wrapped world populated by ‘dumb’ THINGS (the agents or ‘turtles’ of the model). Initally, Things move randomly collecting FOOD which is spawned by patches according to [Food-Regen] probability set in the interface. Movement costs 1-unit of [Life-Force]. If a Thing runs out of Life-Force it dies.
The SUN moves predictably through the world at a rate of .3-units per tick. Things accrue [UV-Damage] as a function of distance from the Sun (according to the inverse-square-law). When UV-Damage exceeds the [UV-Kill] threshold the Thing dies.
When Things reach a threshold of Life-Force they reproduce asexually (according to the [min-energy-to-reproduce] value in the interface). The Life-Force of parents is reduced by [Cost-of-reproduction] and they hatch a single other Thing, which inherits a life-force (the value of [Birth-Energy]) and inherits no UV-Damage. Offspring also inherit parental values of Melanin and Light-Detect (if switched on). Mutations occurs according to the [Mutation-Rate] variable in the interface. If both traits are on, then mutations occur in one trait only (if only one is one, mutations only occur in this trait). If a mutation does occur, the value of the trait-inherited is changed according to a randomly picked floating value in a normal distribution with a mean of 0 and a standard deviation of 1 (this value is then divided by 10). Thus any mutations are (usually) very small, and equally like to be adaptive or maladaptive.
The trait of MELANIN initially has a value of 0 (when the model is initialized). A Thing’s Melanin score is added to the UV-kill value, which means that a Thing with a high melanin value has an increased tolerance to UV-Damage before it dies.
Light-Detect initializes at 1. A Thing can detect light if the UV-damage it accrues in a single tick is equal to or greater than the value of it’s light-detect. Thus, to detect light with a value of 1 requires the Thing to occupying the same space as the Sun. The smaller the value gets, the better a Thing’s ability to discriminate it’s proximity to the Sun. Once detected, the Thing faces away from the Sun and moves.
Below: Yellow patches (not featured in the previous image) indicate that a Thing has died at that location due to UV-Damage. It’s distribution is what you would expect given how UV-Damage is accrued. Note also that after (maximum) of 276 generations Melanin has evolved. Light-sensitivity has improved, but is not stable. (Current model has Thing speed = 1/tick… a point that becomes relevant in the next paragraph).
I have made a few observations: Melanin is immediately selected for and seems to linearly improve over time (the red squiggle in the right corner; red square-lines map the size of the trait for the individual with the most melanin). Light-sensitivity is far more fickle. Initially I had the Sun move at a rate of .3 units per tick and Things moving at a rate of 1.0 per tick. Light-sensitivity never evolved. Initially there is no capacity to detect damage, and I surmise that a random walk that’s 3x faster than the source of the damage is better than the ability to detect the Sun, which initially, can only be done if you’re literally right on top of it. When I slowed the Things movement down to .5 units per tick, light-sensitivity evolved (but not always; and in the instance below, did evolve but disappeared)
Below: An image capture at (max) 1,970 generations. Melanin has evolved such that the initial base threshold for death was 1-unit, but now, on average, a Thing dies once it accrues more than 2.376 units of UV-damage. Light-sensitivity evolved, remained stable for about 600 – 700 generations, then disappeared. During this period of stability, a Thing was able to detect UV-Damage at a range indicated by the red splotches. Other crazy things: On average, each Thing has generated 1,565 offspring (but the max number generated is 1,577 so presumably the distribution is quite tight). (Thing speed = .5/tick, apparently allowing for the emergence evolution of light-sensitivity).
There is no logically upper limit to Melanin, and I would have thought that there ought to be a stable and optimal capacity for light-sensitivity. I anticipated that given that the world is finite and wrapped horizontally, this value would be less than half the width of the world (because after that a Thing will get stuck avoiding the Sun exactly halfway between the ‘East’ and it’s re-occurrence in the ‘West’), because it still likely needs some amount of freedom to execute it’s random walk in search of food. For reasons not clear to me, Light-Sensitivity was stable for about 600 – 700 generations at between .8 and .85 (a range corresponding roughly to the red-splotches). As can be seen from the graph (below), after remaining stable, it began to decline. After nearly 2000 generations, the mean capacity for light-sensitivity was worse than the initial values. In fact, even the ‘best’ Thing has absolutely no capacity to detect light. I have no idea why this occurred (if there is a reason that isn’t chance or drift). But this is the value of models.
All in all, this a great exercise, and a valuable step forward in learning how to code evolutionary phenomenon. I will re-run this model a number more times. If the appearance/disappearance of light-sensitivity recurs, then it demonstrates the value of Agent-Based Modeling – some outcomes are not predictable a priori. I’m currently working on other toy problems, including quantifying the contagiousness of yawns. Long term, I hope to model a variety of social problems relating the cultural evolution, learning, and transmission.
Code below the fold