Messing with messy mutation
I’ve been experimenting with mutating some of the populations I had saved. To do such experiments, I had to implement mutation in the first place. I got the first form of mutation implemented on Tuesday night. It had been an interesting and long day, so I climbed into bed, ready to start experimenting in the morning.
I spent months doing all this very careful coding, keeping things as clean and well documented as I could. That was to implement the core system. Then I set it up so that the downstream programmer, which has been just me so far, could be as quick and dirty as they like. I can be as sloppy as I want, just hack things together, and the core system stays safe.
All that preparation is paying off. Implementing the first form of mutation didn’t take much more than half an hour or so. That’s good, because it meant that the next form of mutation was just as quick and easy to create. And that’s good, because the first form was far, far too deadly.
I set it up so that there would be a variable, mutation rate, that would determine the chance for each figure, each turn, to be mutated. 0.0 would mean there is no chance for mutation. 0.01 would be a one percent chance. 1.0 means that every figure is mutated every turn, and just for fun, with a population of 200 figures, that’s the first thing I tried.
Needless to say, with each figure, each digital creature being mutated every turn every one of them had, I expected the population to die in a burst of chaos. Instead, it just kept on going. It took a while to figure out what was going on… Are they actually mutating? Is something wrong…?
With commands being called totally at random, enough commands that created new figures were called to keep the population going. None of the figures being created were viable, not one of any being written or any of them that were alive could make a copy of itself; but the continuous random shuffle was enough, as long as you had 200 figures to start with, to keep a stream of figures being born. With smaller populations, say around 20 or less, a 1.0 mutation rate killed them off as expected.
Next, I tried a more reasonable rate of 0.01, a one percent chance that a figure will mutate during any given turn. I thought that was a kind and gentle rate, but, all 200 figures died. Okay, how about a tenth of a percent, 0.001? Everyone died. 0.0001, a percent of a percent? Everyone died! Okay, let’s try something ridiculous, how about a percent of a percent of a percent, 0.000001, a one in a million chance of mutation. Everyone died!
I had generated a 200 figure population from 8.pop, described in the last post. Named ml.pop, that’s the population I was using for testing. The test was for the 200 figure population to try and have 1,000,000 figures born. If they reached the one-million goal, the program would beep three times and pause. If they all died, I heard one beep, and the program stopped. At a rate of 0.000001, most runs resulted in death, but some of them reached the goal instead. Still, obviously mutation was too devastating, so I did a few tests to get an idea of what might be going on.
What if we test it by mutating a single figure, and then letting the system run without anymore mutation? That way I can figure out how many mutations a given figure can take. I took one figure, from 8.pop, and mutated it. It survives. Throw two mutations at it. It survives. What happens with three mutations at a time? It survives. How about 4? It survives!
In most runs, the figure from 8.pop did what 8.pop does—she expanded to fill all available space, and then continued to make new figures until the goal was reached. At least for one figure, several mutations usually resulted in a viable creature. At four mutations before running, it seemed to be split about half and half. half the time the goal was reached and the other half the time the figure died without having any children. I think death happened a bit more than half the time with 4, but I didn’t do enough runs to find out for certain.
Testing with one figure being mutated made the form of mutation seem much gentler, but when run with the entire 200 figure population, things were different. While one figure could often make it passed 4 mutations at once, I saw 200 figures get killed with only 5, and those mutations were spread out across the entire population, and over millions and millions of turns!
I changed the mutation so that the system wouldn’t mutate a figure that had already been mutated. It made little to no difference… everyone died!
I was on the porch, thinking about what was going on, and the basic ideas behind evolution. It requires some pattern that persists by making copies of itself, but that’s not quite it. The pattern shouldn’t make perfect copies, or no evolution will happen. What we need is a self-replicating pattern that makes sloppy copies of itself, copies that are slightly different than the original. Oh… wait…
Instead of mutating a figure by randomly changing one of its numbers, what if we implement copy errors? Each time a figure attempts to write to another figure, there is a one in a million chance that instead of the number it was about to write, a random number is written instead. Note that the “random” number is constrained to be within a certain range, depending upon the size of the figure. In theory, copy errors would mean that a given figure would have a chance to write an unmutated copy, along with the occasional mutated child.
Now, most runs could make a million babies. I pushed the goal up to 2,000,000 and sometimes they’d make it, sometimes they didn’t. I couldn’t tell whether the improvement in performance was because mutations were copy errors, or if it was because there were just fewer mutations. I did many runs with both types of mutation, and gathered all sorts of information to see which change was making the difference. I’ve yet to analyze the data, so the question is still open. Even after analysis, I’ll likely need to run some tests to double check my conclusions.
In a way it doesn’t matter. I’ve suspected for some time that I’d need to change around some probabilities. I can change things so that certain commands are much more likely to be called than others. That should make populations able to handle more mutations, and self-replication to emerge from randomness much more quickly. However, before getting into that, I decided to experiment with what I have, and see if I could get some evolution to happen. That’s when things got really interesting.