The mandelbrot set is a pretty neat looking fractal that is one of the first examples that you see when you start to learn about fractals. It looks quite cool so I figured I would try my hand at having a computer render it.
The mandelbrot set is defined using the following function: $$ f(x) = x^2 + c $$ Where \( c \) is the point of interest represented as a complex number. For example, if we are dealing the pixel at cordinate \((x, y)\), that woud be converted into the complex number \(x+yi\). A given number (or equivalently, a point on the screen) is in the Mandelbrot set so long as if you iterate the function the series that it produces is bounded. For example, if you take the point \(1+2i\), you have the series $$ \begin{align} x_0 &= f(0) = 0^2 + c = c \\ x_1 &= f(x_0) = c^2 + c \\ x_2 &= f(x_1) \\ &...\\ x_n &= f(x_{n-1}) \end{align} $$ If \(x_n\) blows up toward infinity as \(n\) increases, then \(c\) is not in the mandelbrot set, otherwise it is. In order to generate the image you see above, I used the Julia programming language.
using Images, ImageInTerminal
function mandelbrot(c)
return (f(x) = x*x + c)
end
n = 3
A = 0.6
squeeze(x) = max((x^n / (A + x^n))+0.25, 0.25)
function get_point_color(x, y)
n = 30
f = mandelbrot(x+(y)im)
cur = 0.0+0.0im
iter = [cur]
for i in 1:n
cur = f(cur)
if abs(cur) > 10000
return RGB{Float64}(0.0, 0.0, squeeze(i/n))
end
push!(iter, cur)
end
return RGB{Float64}(0.0, 0.0, 0.0)
end
function remap(value, old_min, old_max, new_min, new_max)
t = (value-old_min) / (old_max - old_min)
return (t * (new_max - new_min)) + new_min
end
height = 500
width = 1000
colors = Array{RGB{Float64}}(undef, height, width)
for x in 1:width
for y in 1:height
colors[y,x] = get_point_color(remap(x, 1, width, -3.0, 1), remap(y, 1, height, -1.2, 1.2))
end
end
colorview(RGB, colors)
Breaking down the code a bit,
Images
and ImageInTerminal
are simply libraries
that allow me to display our array of colors in the terminal we are running the program in.
mandelbrot(c)
function takes a complex number as input and returns the function that
we will iterate to see if \(c\) is or isn't in the mandelbrot set. This would be an example of a higher order function
because it is a function that returns another function as a result.
squeeze(x)
function takes in a single value between zero and one and ramps it up in
a certain way so that we get the nice edge glowing effect that you see. It is modeled after the Hill Equation. You can
read about this type of equation here if you are interested.
get_point_color(x, y)
takes in a screen coordinate \((x,y)\) and first converts
it to a complex number \(c=x+yi\). Then, it iterates the function that we get from mandelbrot(c)
.
After each iteration, it checks to see that the resulting value is not too large, if it is to large, then it calculates the pixel color
and returns that. If it gets to the end of the loop and the iterated value is still reasonably small, then we can assume it converges to
a single value or a cycle and just return a black pixel. The intensity of the blue color is calculated by taking the proportion of the
iterations that it got thorough and passing that to the squeeze(x)
function.