Search
PyBind11 and Numba
%load_ext ipybind
import numpy
import numba
%%pybind11

#include <complex>
#include <vector>
#include <pybind11/numpy.h>

py::array_t<int> quick(int height, int width, int maxiterations) {
    
    py::array_t<int> fractal({height, width});
    
    auto fractal_uc = fractal.mutable_unchecked<2>();
    
    for (int h = 0;  h < height;  h++) {
        for (int w = 0;  w < width;  w++) {
            
            std::complex<double> ci{
                double(h-1)/height - 1,
                1.5 * (double(w-1)/width - 1)};
            
            std::complex<double> z = ci;
            fractal_uc(h,w) = maxiterations;
            for (int i = 0;  i < maxiterations;  i++) {
                z = z * z + ci;
                if (std::abs(z) > 2) {
                    fractal_uc(h, w) = i;
                    break;
                }
            }
        }
    }
    
    return fractal;
}

PYBIND11_MODULE(py11fractal, m) {
    m.def("quick", quick);
}
%%time
quick(8000, 12000)
@numba.vectorize
def as_ufunc(c, maxiterations):
    z = c
    for i in range(maxiterations):
        z = z**2 + c
        if abs(z) > 2:
            return i
    return maxiterations

def run_numba_2(height, width, maxiterations=20):
    y, x = numpy.ogrid[-1:0:height*1j, -1.5:0:width*1j]
    c = x + y*1j
    return as_ufunc(c, maxiterations)
%%time
run_numba_2(8000, 12000)
@numba.njit
def run_numba(height, width, maxiterations):
    fractal = numpy.empty((height, width), dtype=numpy.int32)
    for h in range(height):
        for w in range(width):
            c = ((h-1)/height - 1) + 1.5j*((w-1)/width - 1)
            z = c
            fractal[h, w] = maxiterations
            
            for i in range(maxiterations):
                z = z**2 + c
                if abs(z) > 2:
                    fractal[h, w] = i
                    break
    return fractal
%%time
run_numba(8000, 12000, 20)
@numba.njit(parallel=True)
def run_numba_p(height, width, maxiterations):
    fractal = numpy.empty((height, width), dtype=numpy.int32)
    for h in numba.prange(height):
        for w in range(width):
            c = ((h-1)/height - 1) + 1.5j*((w-1)/width - 1)
            z = c
            fractal[h, w] = maxiterations
            
            for i in range(maxiterations):
                z = z**2 + c
                if abs(z) > 2:
                    fractal[h, w] = i
                    break
    return fractal
%%time
run_numba_p(8000, 12000, 20)
%%time
run_numba_p(8000, 12000, 20)