Using numba on naive implementations#

So all we have to to is to wrap our code into a function, which we already did, and decorate the function with @numba.jit.

import numba

@numba.jit
def mandelbrot(x_min, x_max, y_min, y_max, max_iterations, resolution):
    x = [
        x_min + (x_max - x_min) / (resolution - 1) * index
        for index in range(resolution)
    ]
    y = [
        y_min + (y_max - y_min) / (resolution - 1) * index
        for index in range(resolution)
    ]

    iterations = []
    for _y in y:
        row = []
        for _x in x:
            c = complex(_x, _y)
            c0 = c
            for iteration in range(max_iterations):
                c = c**2 + c0
                if abs(c) > 2.0:
                    break
            row.append(iteration)
        iterations.append(row)
    return iterations

This is the most basic approach and will work with code of less complexity quite well. We’re using the most naive implementation here with its three nested for loops and the effect will be stunning.

The reason for this is that the code can be analysed quite simply. numba will recognize the not changing data types, and independent outer for loops. As a result numba can parallelize the for loops and take advantage of all available cores in the machine. That’s neat!

Applying numba to more advanced approaches, such as numpy based algorithms will have a less dramatic effect, as its hard to optimize something very efficient further more.