https://github.com/ndrean/mandelbrot
Mandelbrot set and orbits with Zig, Zigler and Elixir Nx in a Livebook
https://github.com/ndrean/mandelbrot
elixir livebook mandelbrot-set mandelbrot-viewer nx zig zigler
Last synced: about 1 month ago
JSON representation
Mandelbrot set and orbits with Zig, Zigler and Elixir Nx in a Livebook
- Host: GitHub
- URL: https://github.com/ndrean/mandelbrot
- Owner: ndrean
- License: mit
- Created: 2024-11-03T09:49:02.000Z (over 1 year ago)
- Default Branch: main
- Last Pushed: 2024-12-10T08:08:16.000Z (over 1 year ago)
- Last Synced: 2025-02-23T10:43:25.896Z (over 1 year ago)
- Topics: elixir, livebook, mandelbrot-set, mandelbrot-viewer, nx, zig, zigler
- Language: Zig
- Homepage: https://ndrean.github.io/zig-assembly-test/
- Size: 46 MB
- Stars: 1
- Watchers: 1
- Forks: 0
- Open Issues: 0
-
Metadata Files:
- Readme: README.md
- License: LICENSE
Awesome Lists containing this project
README
# Orbits and Mandelbrot set explorer with Numerical Elixir and Zig
## Introduction
Source:
- [Mandelbrot set](https://en.wikipedia.org/wiki/Mandelbrot_set)
- [Plotting algorithm](https://en.wikipedia.org/wiki/Plotting_algorithms_for_the_Mandelbrot_set)
This repo is about visualising the orbits of points in the 2D-plane under the map `z -> z*z + c` known as Julia or Mandelbrot sets.
We are looking whether the iterates stay bounded are not. When we associate a colour that reflects this stability, this gives rise to Mandelbrot images.
These images are therefor a colourful representation of where the sequence is stable and how fast does these sequences diverge.

This repo contains:
- a pur `Zig` computation
- two `Livebook` to explore the orbits of points and to zoom into the Mandelbrot set.
The two Livebooks are:
- one proposing a pur `Elixir` orbit explorer. You click and it displays the orbit of any point.
- the other proposing a Mandelbrot set explorer with a clickable image to zoom in (and out):
- we have a pur `Elixir` implementation using Numerical Elixir with `EXLA` backend of the Mandelbrot set.
- we have an enhanced version where the heavy computations are made with running embedded `Zig` code thanks to the library `Zigler`.
The `Zig` code is compiled to `WebAssembly` to demonstrate quickly how this renders:
## Orbit explorer
Given a complex number `c` and the polynomial `p_c(x)=x^2+c`, we compute the sequence of iterates:
```
p(0)=c
p(p(0))=p(c)=c^2+2
p(p(c)) = c^4+2c^3+c^2+c
...
```
The set of this sequence is the _orbit_ of the number `c` under the map `p`.
For example, for `c=1`, we have the orbit `O_1 = { 0, 1, 2, 5, 26,...}` but for `c=-1`, we have a cyclic orbit, `O_{-1} = {−1, 0, −1, 0,...}`.
The code below computes "orbits". You select a point and a little animation displays the orbit.
[](https://livebook.dev/run?url=https%3A%2F%2Fgithub.com%2Fndrean%2Fmandelbrot%2Fblob%2Fmain%2Flivebook%2Forbits.livemd)

## Mandelbrot set explorer
### The algorithm
Given an image of size W x H in pixels,
- loop over 1..H rows, `i`, and over 1..W columns, `j`
- compute the coordinate `c` in the 2D-plane projection corresponding to the pixel `(i,j)`
- compute the "escape" iterations `n`,
- compute the RGB colours for this `n`,
- append to your final array.
### A Livebook
[](https://livebook.dev/run?url=https%3A%2F%2Fgithub.com%2Fndrean%2Fmandelbrot%2Fblob%2Fmain%2Flivebook%2Fmandelbrot.livemd)
You can explore the fractal by clicking into the 2D-plane.
This happens thanks to `KinoJS.Live`.
We have a pur `Elixir` version that uses `Nx` with the `EXLA` backend, and another one that uses embedded `Zig` code for the heavy computations. The later is 3-4 magnitude faster mostly because we are running compiled Zig code versus interpreted Elixir code in a Livebook running uncompiled on a BEAM.

## Details of the mandelbrot set
[Needs latex]
In fact, this set is contained in a disk
$ D_2$ of radius 2. This does not mean that
$ 0_c$ is bounded whenever
$|c|\leq 2$ as seen above. Merely
$0_c$ is certainly unbounded - the sequence of
$z_n$ is divergent whenever
$|c| > 2$.
We have a more precise criteria: whenever the absolute value $` |z_n| `$ is greater that 2, then the absolute values of the following iterates grow to infinity.
The **Mandelbrot set** $M$ is the set of numbers $c$ such that its sequence $O_c$ remains bounded (in absolute value). This means that $` | z_n (c) | < 2 `$ for any $` n `$.
When the sequence $` O_c `$ is _unbounded_, we associate to $c$ the first integer $N_c$ such that $` |z_N (c)| > 2 `$.
Since we have to stop the computations at one point, we set a limit $m$ to the number of iteration. Whenever we have $` |z_{n}|\leq 2 `$ when $n=m$, then point $` c `$ is declared _"mandelbrot stable"_.
When the sequence $O_c$ remains bounded, we associate to $` c `$ a value $` max `$.
So to each $` c `$ in the plane, we can associate an integer $n$, whether `null` or a value between 1 and $m$.
Furthermore, we decide to associate each integer $` n `$ a certain RGB colour.
With this map:
```math
c \mapsto n(c) \Leftrightarrow \mathrm{colour} = f\big(R(n),G(n),B(n)\big)
```
we are able to plot something.
By convention it is **black** when the orbit $O_c$ remains bounded.
When you represente the full Mandelbrot set, you can take advantage of the symmetry; indeed, if $c$ is bounded, so is its conjugate.
#### Math details:
Firstly consider some $` |c| \leq 2 `$ and suppose that for some $` N `$, we have $` |z_N|= 2+a `$ with $` a > 0 `$. Then:
```math
|z_{N+1}| = |z_N^2+c|\geq |z_N|^2 -|c| > 2+2a = |z_N|+a
```
so $` |z_{N+k}| \geq |z_N| +ka \to \infty `$ as $` k\to \infty `$.
Lastly, consider $|c| > 2$. Then for every $n$, we have $|z_n| > |c|$. So:
```math
|z_{n+1}| \geq |z_n|^2 -|c| \geq |z_n|^2-|z_n| = |z_n|(|z_n|-1) \geq |z_n|(|c|-1) > |z_n|
```
so the term grows to infinity and "escapes".
The _mandelbrot set_ $M$ is **compact**, as _closed_ and bounded (contained in the disk of radius 2).
It is also surprisingly _connected_.
> Fix an integer $n\geq 1$ and consider the set $M_n$ of complex numbers $c$ such that there absolute value at the rank $n$ is less than 2. In other words, $ M_n=\{c\in\mathbb{C}, \, |z_n(c)|\leq 2\} $. Then the complex numbers Mandelbrot-stable are precisely the numbers in all these $ M_n$, thus $M = \bigcap_n M_n$.
> We conclude by remarking that each $M_n$ is closed as a preimage of the closed set $ [0,2]$ by a continous function, and since $M$ is an intersection of closed sets (not necesserally countable), it is closed.