Understanding Randomness
Genetic Algorithms in Elixir — by Sean Moriarity (88 / 101)
👈 Chapter 12 Writing Tests and Code Quality | TOC | Writing Property Tests with ExUnit 👉
One challenge to writing tests for genetic algorithms is their stochastic nature. When something is stochastic, it’s dictated by random processes — usually with some associated probability. For example, if you examine how you implemented flip mutation in Chapter 7, Preventing Premature Convergence, it looks like this:
def flip(chromosome, p) do
genes =
chromosome.genes
|> Enum.map(
fn g ->
» if :rand.uniform() < p do
g ^^^ 1
else
g
end
end
)
%Chromosome{genes: genes, size: chromosome.size}
endRemember this function performs a bit-flip with probability p on the genes in a chromosome. Notice the highlighted if-condition. The condition :rand.uniform < p represents a coin-flip that is true with probability p and false with probability 1 — p. If you were to test this function with a probability of 0.5, on average, 50% of the genes in your chromosome would be flipped. If you tried to test this, you’d quickly run into problems because the behavior of the function is stochastic. You could run this function on the same chromosome 100 times and get a different outcome every time.
Testing with randomness is difficult because testing often relies on you being able to dictate and understand the outcome of a function. Because most of the functions in your genetic algorithm rely on randomness, you’re unable to predict exactly what the output of a function is, which in turn makes it difficult to write tests. Fortunately, there are ways to address the challenge of randomness to effectively test your functions.
In this chapter, you’ll learn how to use property-based testing to test the functions in your framework. You’ll learn more about property-based testing in the next section. For now, you’ll learn about two alternative approaches to testing with randomness: seeding and mocking.
Seeding relies on the need for random number generators to be initialized with a random seed from which they generate new random numbers. The :rand module you’ve been using implements pseudo-random number generation (PRNG) algorithms. This means that the algorithms aren’t truly random but give the illusion of randomness. An algorithm is truly random if it can generate numbers infinitely many times without repeating itself. The PRNGs implemented in the :rand module have periods of around 2⁶⁴, which means they repeat themselves after 2⁶⁴ calls. Essentially, you’ll never have to worry about your algorithms not being truly random.
You can provide a random seed to :rand before you generate numbers to control the behavior of the numbers generated. To see this in action, open iex and try the following:
iex(1)> :rand.seed(:exsss, 1)
...
iex(2)> :rand.uniform(100000000000000)
82609428762732
iex(3)> :rand.seed(:exsss, 2)
...
iex(4)> :rand.uniform(100000000000000)
4
iex(5)> :rand.seed(:exsss, 1)
...
iex(6)> :rand.uniform(100000000000000)
82609428762732If you repeat that process forever, you’ll continue to get the same numbers every time. You could use this same strategy to seed the PRNG before running your tests to guarantee the behavior of your random functions is the same every time. One of the flaws of this approach is you have to trace through the behavior of your function by hand to determine what the outcome of your function is with your chosen seed.
Another approach to testing with randomness is by using mocking. Mocking refers to creating an imitation module to replace the behavior of :rand with something predictable. For this approach, you’d have to create a module to replace :rand at test time with predictable behaviors. This approach is common when testing the behaviors of functions that interact with some API offline. It doesn’t work as well with randomness.
👈 Chapter 12 Writing Tests and Code Quality | TOC | Writing Property Tests with ExUnit 👉
Genetic Algorithms in Elixir by Sean Moriarity can be purchased in other book formats directly from the Pragmatic Programmers. If you notice a code error or formatting mistake, please let us know here so that we can fix it.

