For all its infinite complexity, I was surprised to learn how simple it is to generate the Mandelbrot set. All it requires is complex addition, multiplication, distance, and some iteration. Here's a worked example.
We'll represent complex numbers as two-element vectors, where the first element is the real part and the second is the imaginary part. Complex addition is simply componentwise addition:
(defn complex-add [a b] (mapv + a b))
Complex multiplication is more elaborate, but not difficult:
(defn complex-multiply [[r1 i1] [r2 i2]] [(- (* r1 r2) (* i1 i2)) (+ (* r1 i2) (* r2 i1))])
The distance from a point in the complex plane to the origin is regular Euclidean distance:
(defn distance-to-origin [[r i]] (Math/sqrt (+ (* r r) (* i i))))
Now for the hard work. The mathematical definition of the Mandelbrot set is f(z) = z2 + c, but that omits a lot of the actual algorithm. To create the traditional image of the Mandelbrot set, we need to call that function over and over and see how quickly the result diverges from its starting point:
(defn mandelbrot [c] (loop [i 0 z [0 0]] (if (and (< i 20) (< (distance-to-origin z) 2)) (recur (inc i) (complex-add c (complex-multiply z z))) i)))
The above function loops up to 20 times, or quits as soon as the point moves more than two units from its starting point. To draw the set, we'll color points in an image based on how quickly they diverged past a two-unit radius. Here's a list of hexadecimal RGB colors that walk up through blues, then add increasing amounts of green, then red:
(def color [nil 0x00002a 0x000055 0x00007f 0x0000aa 0x0000d4 0x0000ff 0x0025ff 0x0049ff 0x006eff 0x0092ff 0x00b7ff 0x00dbff 0x00ffff 0x25ffff 0x49ffff 0x6effff 0x92ffff 0xb7ffff 0xdbffff 0x000000])
Mapping each pixel in an image to the complex plane with corners -2 - i and 1 + i produces this:
While the bright, complex edge is what usually draws our attention in images like these, the colored points above don't actually belong to the Mandelbrot set. Only those points that don't diverge to infinity when iterated through f(z) = z2 + c are part of the set; that is, the points shown in black. The Mandelbrot set is usually illustrated as negative space.