8.5 KiB
Chaos
In mathematics chaos is a phenomenon that makes it extremely difficult to predict, even approximately, the result of some process even if we completely know how the process works and what state it starts in. In more technical terms chaos is a property of a nonlinear deterministic system in which even a very small change in input creates a great change in the output, i.e. the system is very sensitive to initial conditions. Chaos is a topic studied by the field called chaos theory and is important in all science. In computer science it is important for example for the generation of pseudorandom numbers or in cryptography. Every programmer should be familiar with the existence of chaotic behavior because in mathematics (programming) it emerges very often, it may pose a problem but, of course, it may be taken advantage of as well.
Perhaps the most important point is that a chaotic system is difficult to predict NOT because of randomness, lack of information about it or even its incomprehensible complexity (many chaotic systems are defined extremely simply), but because of its inherent structure that greatly amplifies any slight nudge to the system and gives any such nudge a great significance. This may be caused by things such as feedback loops and domino effects. Generally we describe this behavior as so called butterfly effect -- we liken this to the fact that a butterfly flapping its wings somewhere in a forest can trigger a sequence of events that may lead to causing a tornado in a distant city a few days later.
Examples of chaotic systems are the double pendulum, weather (which is why it is so difficult to predict it), dice roll, rule 30 cellular automaton, logistic map, Baker's map, gravitational interaction of N bodies or Lorenz differential equations. Langton's ant sometimes behaves chaotically. Another example may be e.g. a billiard table with multiple balls: if we hit one of the balls with enough strength, it'll shoot and bounce off of walls and other balls, setting them into motion and so on until all balls come to stop in a specific position. If we hit the ball with exactly the same strength but from an angle differing just by 1 degree, the final position would probably end up being completely different. Despite the system being deterministic (governed by exact and predictable laws of motion, neglecting things like quantum physics) a slight difference in input causes a great different in output.
A simple example of a chaotic equation is also the function sin(1/x) for x near 0 where it oscillates so quickly that just a tiny shift along the x axis drastically changes the result. See how unpredictable results a variant of the function can give:
x | 1000 * sin(10^9 / x) |
---|---|
4.001 | 455,... |
4.002 | 818,... |
4.003 | -511,... |
4.004 | -974,... |
4.005 | -335,... |
Logistic map is often given as the typical example of a chaotic system. It is the series defined as x[n + 1] = r * x[n] * (1 - x[n]), which for some constant r (interpreted as speed of population increase) says how a population evolves from some starting value x[0]; for low x[n] the population will be increasing proportionally by the rate of r but once it reaches a higher value, it will start decreasing (as if by starvation), resulting in oscillation. Now if we only start to be interested in changing the value r and then seeing at what value the population stabilizes (for a big n), we make some interesting discoveries. This is best seen by plotting the stable values (let's say x[1000]) depending on r. For r approximately between 3.57 and 4 we start to see a chaotic behavior, with results greatly depending on the initial population value (x[0]). This demonstrates chaotic behavior.
The following is a fixed point C implementation of the above:
#include <stdio.h>
#define FP_UNIT 256
#define DOWNSCALE_X 4
#define DOWNSCALE_Y 25
#define LINE_LENGTH (FP_UNIT / DOWNSCALE_X)
#define GENERATIONS 1000
char stablePoints[LINE_LENGTH + 1];
int main(void)
{
stablePoints[LINE_LENGTH] = 0; // string terminator
for (int i = 0; i <= FP_UNIT * 4; i += DOWNSCALE_Y) // for different rs
{
for (int j = 0; j < LINE_LENGTH; ++j)
stablePoints[j] = ' ';
for (int j = 0; j < FP_UNIT; ++j) // for different starting population sizes
{
int population = j;
for (int k = 0; k < GENERATIONS; ++k)
population = (i * population * (FP_UNIT - population)) / (FP_UNIT * FP_UNIT);
population /= DOWNSCALE_X;
if (population >= 0 && population < LINE_LENGTH)
stablePoints[population] = '*';
}
printf("%.3f| %s\n",i / ((float) FP_UNIT),stablePoints);
}
return 0;
}
It outputs the following:
0.000| *
0.098| *
0.195| *
0.293| *
0.391| *
0.488| *
0.586| *
0.684| *
0.781| *
0.879| *
0.977| *
1.074| *****
1.172| ** ***
1.270| ** **
1.367| * **
1.465| * *
1.562| * **
1.660| * *
1.758| * *
1.855| * *
1.953| * *
2.051| * *
2.148| * *
2.246| * *
2.344| * *
2.441| * *
2.539| * *
2.637| * *
2.734| * *
2.832| * *
2.930| * **
3.027| * *********
3.125| * * * *
3.223| * * * *
3.320| * * **
3.418| * ** * **
3.516| * ** * * ** * *****
3.613| * **** *** * * ** * * * ********
3.711| * ** ** ** ***** * **
3.809| * * ** * * * * * * * *** *
3.906| * * * *** * * * * * *** *
Vertical axis is the r parameter, i.e. the population growth speed. Horizontal axis shows stable population size after 1000 generations, starting with different initial population sizes. We can see that up until about r = 3 the stable population size always stabilizes at around the same size, which gradually increases with r. However then the line splits and after around r = 3.56 the stable population sizes are quite spread out and unpredictable, greatly depending on the initial population size. Pure CHAOS!