A Weekly Rust🦀 Pill #3
Tags: rust, programming
Published: 2023-08-05 05:45:25

A Weekly Rust🦀 Pill is a post series where on a weekly base, I share some implementations of the most popular algorithms and data structures to share my learnings on Rust 🦀.

# What is the Mandelbrot Set?
The Mandelbrot Set is a set of complex numbers defined by iterating a simple mathematical formula. Given a complex number **c**, we start with an initial value of **z** (typically set to 0) and then repeatedly apply the formula **z = z \* z + c**. If the value of **z** diverges to infinity (i.e., its magnitude exceeds a certain threshold), the complex number **z** is not part of the Mandelbrot Set. Otherwise, it is considered part of the set. The points that belong to the set are coloured distinctly, forming the breathtaking fractal pattern we all recognise.

# Implementation
Once you have Rust set up, create a new Rust project and add the required dependencies to your `Cargo.toml`:

```toml
[dependencies]
image = "0.24.1"
nalgebra = "0.24.1"
```
The `image` crate will help us save the generated image of the Mandelbrot Set, while `nalgebra` will provide the necessary complex number functionality.

Let's start by defining the function to determine if a given complex number 'c' belongs to the Mandelbrot Set. We'll call this function `mandelbrot`:

```rust
use nalgebra::{Complex, Normed};

fn mandelbrot(x: f64, y: f64) -> u8 {
    let c = Complex::new(x, y);
    let mut z = Complex::new(0.0, 0.0);

    for i in 0..255 {
        if z.norm() > 2.0 {
            return i as u8;
        }

        z = z * z + c;
    }

    255
}
```

The `mandelbrot` function takes two coordinates, 'x' and 'y', as inputs and returns a color value represented by a `u8`. The function uses the 'x' and 'y' values to create a complex number 'c'. It then iterates the formula 'z = z * z + c' until the magnitude of 'z' exceeds 2.0 or until the maximum number of iterations (255) is reached. The colour value returned represents how quickly the sequence diverges to infinity.

Now that we have the `mandelbrot` function, let's visualise the Mandelbrot Set using the `image` crate. We'll define a function called `generate_mandelbrot_set` to create and save the image:

```rust
use image::{ImageBuffer, Rgb};

fn generate_mandelbrot_set(width: u32, height: u32) {
    let scale_x = 3.0 / width as f64;
    let scale_y = 3.0 / height as f64;

    let mut img = ImageBuffer::new(width, height);

    for (x, y, pixel) in img.enumerate_pixels_mut() {
        let r = (0.3 * x as f32) as u8;
        let b = (0.3 * y as f32) as u8;
        *pixel = image::Rgb([r, 0, b]);

        let cx = x as f64 * scale_x - 2.0;
        let cy = y as f64 * scale_y - 1.5;

        let value = mandelbrot(cx as f64, cy as f64);

        *pixel = Rgb([r, value, b]);
    }

    let _ = img.save("mandelbrot.png");
}
```

The `generate_mandelbrot_set` function takes the width and height of the image as inputs and proceeds to generate the Mandelbrot Set visualization. It creates a blank image of the specified dimensions and then iterates over each pixel, calculating the corresponding complex number 'c' using the pixel coordinates. The `mandelbrot` function is called to determine the color value for that pixel, and the resulting color is assigned to the pixel.

The colors of the pixels are based on the 'r' (red) and 'b' (blue) values, with the green channel set to the computed color value from the `mandelbrot` function. The result is an aesthetically pleasing and captivating visualization of the Mandelbrot Set.

## References
- [image crate](https://docs.rs/image/latest/image/)
- [nalgebra crate] (https://docs.rs/nalgebra/latest/nalgebra/)