If I were to challenge you right now to do something completely random, what would you do? Perhaps you'd suddenly jump up from your seat, or maybe burst into unexpected laughter. Or, if you're the rebellious type, you might just continue reading with a smirk, thinking, "Nice try." :P But let's pause for a moment and ponder - what does it truly mean to be random?
At its core, randomness can be defined as "acting or happening without any discernible method or conscious decision." It's the unpredictability, the surprise element that catches us off guard.
So, let's translate this concept into the world of coding. Imagine you're tasked with simulating randomness. How would you go about it? Naturally, you'd need a "pool" of choices. From this pool, your code would pick an option, seemingly out of the blue. It might sound counterintuitive to use a pre-defined pool to generate randomness (I mean, using randomness to explain randomness? Sounds like a riddle!).
Let's start with a simple example: Random Walk.
Imagine you have a coin. Every time you flip it and get heads, you move forward; tails, you step backward. (Hope you're not in the middle of traffic while trying this out). This model works seamlessly in a one-dimensional space.
But what if we expand our experiment to a two-dimensional plane? Here's where it gets interesting. Now, you'd require two coins. With these, you'd have four possible outcomes, each corresponding to a specific direction — forward, backward, left, or right.
Venturing into a three-dimensional space complicates things further. To move in a positive direction on the Z-axis, for instance, you'd need three consecutive heads. For an outcome like HHT(Head, Head, Tail), you'd move in a positive direction on both the X and Y axes, but in a negative direction on the Z-axis. Conversely, flipping TTT would direct you negatively across all three axes.
To offer a visual perspective, I've created a simulation.
I created this simulation using THREE.js. However, the underlying logic is straightforward. I used JavaScript's built-in random function, which, while not representing true randomness, is pseudorandom. For generating a random number between 0 and 8, I believe it is pretty accurate.
Here is the sample code block
Upon closer inspection, you might observe that the simulation doesn't appear entirely random. The randomness is evident in direction, but not in amplitude. This type of uniformity isn't commonly seen in nature, is it? Thankfully, the fix is simple. We can introduce variability by changing the fixed amplitude of 0.05 to a random value. If you're curious about how this alteration affects the simulation, I've provided a link to the playground below where you can experiment further.
Analysing the Distribution:
If we run this simulation long enough this would be evenly distributed in all directions assuming the random function is not biased.
Biased randomness:
Speaking of bias, it's intriguing to consider that nature's randomness might inherently contain biases. Take the principle of "survival of the fittest" as an example. These biases can emerge due to various reasons. Consider bees and their flower preferences. Even when presented with flowers of the same type, bees might exhibit a preference. This selectiveness could be attributed to distinct fragrances, colors, or other subtle factors.
Similarly, when we observe human heights, we notice a range of variations. However, the distribution is not entirely random. Instead, it tends to cluster around an average, indicating an inherent bias.
Returning to our simulation, how might we incorporate this natural bias? One approach would be to adjust our random number generation. Instead of producing numbers from 0 to 8, let's extend the range to include 9. We'll design the simulation such that when a 9 is generated, it behaves identically to a 0 — prompting movement along the positive x, y, and z axes.
By introducing this change, we've effectively created a bias towards movement in the positive direction of all three axes.
Below is the simulation in action. As you'll observe, there's a distinct bias favouring movement along the positive x, y, and z axes.
Lévy flight:
Purely random movements might not be the most efficient strategy when searching for food. A significant drawback is the potential for oversampling: creatures might end up revisiting the same locations repeatedly, wasting energy without finding new food sources.
One solution to circumvent this issue is to introduce occasional large steps amidst the smaller, more frequent steps. This would allow the creature or entity to cover vast areas in a single move, potentially landing in richer food zones.
To simulate this behaviour, we can use a function that produces smaller values most of the time (representing small steps) and larger values with lower probability (representing the occasional large leap). The function I propose is:
y=r**(-1/2)
The following plot illustrates how this function behaves
and the balance it strikes between smaller, frequent steps and rare, larger ones.
This is how it would look in simulation
While this doesn't precisely replicate the intricacies of Lévy flight, it captures the fundamental concept behind it.
Does our simulation truly mirror reality? While a perfect representation of Lévy flight might bring us closer to realism, our current implementation falls short. One noticeable shortcoming is its lack of smoothness. To enhance this, we can incorporate Perlin noise, a technique renowned for its ability to produce smoother, more natural sequences.
Perlin noise:
Now, you might wonder, "What exactly is Perlin noise?" At its core, Perlin noise is a gradient noise function developed by Ken Perlin. Perlin noise gives us a sequence that flows more naturally. Imagine the difference between jagged mountain edges and the gentle, undulating curves of rolling hills. That's the kind of distinction we're discussing.
Below is our simulation, showcasing the effects of integrating Perlin noise. For a more interactive experience, I started with Lévy's flight in the playground and, after a while, activated the Perlin noise. Watch closely.
As you can observe, the movement becomes notably smoother with the introduction of Perlin noise.
It's important to note that in my Perlin noise implementation, the entity moves directly towards the food, differing from the behavior exhibited in Lévy's flight.
What's Next?
The magic of Perlin noise doesn't stop here. In our upcoming blog, we'll delve deeper into the myriad ways Perlin noise is instrumental in creating realistic digital art and simulations. From the ethereal beauty of clouds drifting across a sky to the majestic sprawl of digital landscapes, Perlin noise plays a pivotal role. Stay tuned!
For those eager to dive into the code and experience the simulation firsthand, click on the links below:
(All the controls doesn’t work for all options. This is solely created for this blog purpose there would be a lot of code repetitions and there is a plenty scope for code optimisation)
The blog is so insightful, excellent crafting of document with detail explanations, I’m very new to this topic but reading this blogs makes me feel confident.
Thank You! Jayanth!
Great Work! Keep Going!