Category: Uncategorized

  • Playing With The Mandelbrot Set

    Playing With The Mandelbrot Set

    Prologue

    I have been fascinated with fractals ever since I was little. My first experience with them was at the Renaissance Fair where a vendor was selling prints of his artist renditions of fractals.

    I have been thinking that I kind of want one of those prints now, but since I am extra I wanted to do it myself. After all a little math isn’t that scary.

    The Math

    Iteration

    The first thing to understand is iteration. Imagine you have a sequence of numbers, where each number depends on the number that came before it, that’s the idea.

    Lets imagine our function takes two inputs, n which describes the “nth” place and a constant c. Our function would return it’s previous state squared plus the constant.

    f(n+1) = n^2 + c

    For a c of 1 you would get: 0, 1, 2, 5, 26… a sequence that continues to infinity.
    For a c of -1 you would get: 0, −1, 0, −1, 0… a sequence that does not continue to infinity.

    Exit Conditions

    I won’t pretend to know the math behind it, but we know that if a sequence ever reaches the absolute value of 2 then it will continue to infinity forever.

    Lets use this criteria to define a new function. This new function will take a constant c and return the length of the sequence of numbers that stays below 2. Since this could repeat forever, lets define a maximum number of iterations.

    The Code

    There are many iterations (heh) of the code. But lets start with what we have covered so far:

    // Define a sequence given a starting constant
    function sequence($constant)
    {
        $next = $constant;
        while (true) {
            yield $next;
            $next = $next**2 + $constant;
        }
    }
    
    // Count the iterations in a given sequence
    function iterations()
    {
        foreach (sequence() as $nth => $value) {
            if ($nth > MAX_ITERATIONS) {
                break;
            }
            if ($value >= 2) {
                return $nth;
            }
        }
    
        return 0;
    }

    It’s Never That Easy

    We are not working with your regular numbers here. We are working with complex numbers. A complex number is a number that has both a real and an imaginary component. For example, 1+2i is a complex number.

    So let’s rewrite our function to take complex numbers instead. To accomplish this I am using the markbaker/complex-functions library.

    function sequenceWithComplexNumbers($real, $imaginary) {
        $next = $test = new Complex\Complex($real, $imaginary);
        while (true) {
            yield $next;
            $next = $next->pow(2)->add($test);
        }
    }
    
    function countIterationsOfSequence($sequence) {
        foreach ($sequence as $nth => $value) {
            if ($nth >= MAX_ITERATIONS) {
                break;
            }
            if ($value->getReal() >= 2 || $value->getImaginary() >= 2) {
                return $nth;
            }
        }
    
        return 0;
    }

    Let’s Use OOP

    We are starting to work with enough code that encapsulating it into a class is starting to make sense. Let’s create a class that takes an input real and imaginary number, as well as a maximum number of iterations for the sequence. This class should represent both the sequence of numbers and the iteration count of the sequence. This isn’t the whole code but describes the interface:

    interface Mandelbrot
    {
        public function __construct(
            private float $real,
            private float $imaginary,
            private int $maxIterations,
        ) {}
    
        public function iterations(): int;
    
        public function sequence(): Generator;
    }

    Generating The Image

    Since we are working with complex numbers we can fill in the complex number plane. We can say that the X axis is the real component, and the Y axis is the imaginary component. For each X and Y, we:

    1. Create a Mandelbrot class instance for the given coordinate.
    2. Generate the sequence given our positions complex c constant.
    3. Count the iterations in the sequence.
    4. Color the pixel in depending on the number of iterations.

    For point #4 there, that’s the only real challenging part. I am using 256 iterations, or counting up to 0xff in hex. We can convert the number to grayscale by converting the iteration count from decimal to hexadecimal, then concatenating itself three times. This gives us 0x000000 to 0xffffff to work with, which is the entire gray color spectrum.

    There may be a follow-up blog post about adding color, but for now lets stick with gray. Oh, and I am using the intervention/image library for generating images.

    $width = $input->getArgument('width');
    $height = $input->getArgument('height');
    $realStart = -2;
    $realEnd = 1;
    $imaginaryStart = -1;
    $imaginaryEnd = 1;
    $filename = $input->getArgument('filename');
    
    $canvas = ImageManagerStatic::canvas($width, $height, '#ffffff');
    
    foreach (range(0, $width) as $x) {
        foreach (range(0, $height) as $y) {
            $mandelbrot = new Mandelbrot(
                $realStart + ($x / $width) * ($realEnd - $realStart),
                $imaginaryStart + ($y / $height) * ($imaginaryEnd - $imaginaryStart),
                MAX_ITERATIONS,
            );
            $iterations = $mandelbrot->iterations();
            $color = $iterations > 0 ? dechex(MAX_ITERATIONS - $iterations) : "00";
            $colorCode = "#$color$color$color";
            $canvas->pixel($colorCode, $x, $y);
        }
    }
    
    $canvas->save($filename, 100, 'png');

    Wrapping Things Up

    The code presented here is just one iteration that got me to the end result. The actual code uses the symfony/console component to handle inputs and outputs for generating a customizable image. This isn’t my finest work yet, I may publish the full code someday.

    The featured image on this post is a 4k-resolution image of the set, generated by this code. It took an hour or two to generate. My real goal for the project was a print-quality poster version, which unfortunately is a little too large for distribution on a blog, but that took a few days to generate.

  • Mushroom In December

    Mushroom In December

    It rained for a few days and these appeared apparently out of nowhere. Wild that they can grow so late in the year.

    Also featured, puppy snoots.

  • Yellow Mushroom

    Yellow Mushroom

    While out with my family gathering firewood, I stumbled upon some real nifty mushrooms.

    There must have been a hundred or more all growing out of one dead tree.

  • Tiny Mushroom

    Tiny mushroom.

    Tiny mushroom
  • Mushroom Picking

    It’s springtime and that means it is time to go pick mushrooms.

    Morels are my personal favorite. They grow anywhere (in North Idaho at least) where a wildfire burned through a forrest the previous year, and typically pop up once it hits 70F outside.
    If you ever wondered why people keep such a close eye on wildfires during fire season, well now you know. Mushrooms are the answer, they will grow there next year.

    Ironically enough, I didn’t get a single picture of a Morel in the wild. I got a few other good pictures to share though. Enjoy!

    Finally, the haul. Not much, maybe a dozen, but it’s still early in the season.

    Mushroom haul