Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Mandelbrot numba examples #44

Open
wants to merge 6 commits into
base: master
Choose a base branch
from
Open
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
Numpy Array Implementtion
animator committed Aug 11, 2022
commit 2c80fe3de63546328b88f4c113dd7e51f140f6eb
20 changes: 20 additions & 0 deletions examples/maths/mandelbrot_set_numpy/bench.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
name: Mandelbrot Set (NumPy)
description: |
Compute the Mandelbrot Set, a set of points on the complex plane which always remain bounded by a threshold value while solving the quadratic recurrence equation. It is an iterative problem which is also compute intensive and visual in nature.
Author - <a href="https://github.com/animator">Ankit Mahato</a>
input_generator: numpy_array.py:input_generator
xlabel: Max iteration
validator: numpy_array.py:validator
implementations:
- name: numpy_array
description: Implementation where a 3-dimensional numpy array is used to store the computed RBG pixel values.
function: numpy_array.py:mandelbrot
- name: numba_numpy_array
description: numba.njit decorator is applied on the NumPy implementation.
function: numba_numpy_array.py:mandelbrot
- name: numba_prange_numpy_array
description: numba.njit decorator is applied on the NumPy implementation. Numpy is primarily array designed to be as fast as possible on a single core, whereas numba automatically compiles a version which can run in parallel utilizing multiple threads if it contains reduction functions, array math functions and many more functions or assignments or operations. Explicit for loop parallelization is also performed using numba.prange().
function: numba_prange_numpy_array.py:mandelbrot

baseline: numpy_array
22 changes: 22 additions & 0 deletions examples/maths/mandelbrot_set_numpy/numba_numpy_array.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
import math
import numba as nb

@nb.njit
def mandelbrot(iters, pixels, bbox, width, max_iter):
for y in range(width):
for x in range(width):
c0 = complex(bbox[0] + (bbox[2]-bbox[0])*x/width,
bbox[1] + (bbox[3]-bbox[1])*y/width)
c = 0
i = 1
while i < max_iter:
if abs(c) > 2:
log_iter = math.log(i)
pixels[y, x, 0] = 255*(1+math.cos(3.32*log_iter))//2
pixels[y, x, 1] = 255*(1+math.cos(0.774*log_iter))//2
pixels[y, x, 2] = 255*(1+math.cos(0.412*log_iter))//2
break
c = c * c + c0
i += 1
iters[y, x] = i
return iters, pixels
22 changes: 22 additions & 0 deletions examples/maths/mandelbrot_set_numpy/numba_prange_numpy_array.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
import math
import numba as nb

@nb.njit(parallel = True)
def mandelbrot(iters, pixels, bbox, width, max_iter):
for y in nb.prange(width):
for x in range(width):
c0 = complex(bbox[0] + (bbox[2]-bbox[0])*x/width,
bbox[1] + (bbox[3]-bbox[1])*y/width)
c = 0
i = 1
while i < max_iter:
if abs(c) > 2:
log_iter = math.log(i)
pixels[y, x, 0] = 255*(1+math.cos(3.32*log_iter))//2
pixels[y, x, 1] = 255*(1+math.cos(0.774*log_iter))//2
pixels[y, x, 2] = 255*(1+math.cos(0.412*log_iter))//2
break
c = c * c + c0
i += 1
iters[y, x] = i
return iters, pixels
46 changes: 46 additions & 0 deletions examples/maths/mandelbrot_set_numpy/numpy_array.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
import numpy as np

#### BEGIN: numpy
import math

def mandelbrot(iters, pixels, bbox, width, max_iter):
for y in range(width):
for x in range(width):
c0 = complex(bbox[0] + (bbox[2]-bbox[0])*x/width,
bbox[1] + (bbox[3]-bbox[1])*y/width)
c = 0
i = 1
while i < max_iter:
if abs(c) > 2:
log_iter = math.log(i)
pixels[y, x, 0] = 255*(1+math.cos(3.32*log_iter))//2
pixels[y, x, 1] = 255*(1+math.cos(0.774*log_iter))//2
pixels[y, x, 2] = 255*(1+math.cos(0.412*log_iter))//2
break
c = c * c + c0
i += 1
iters[y, x] = i
return iters, pixels
## END: numpy

WIDTH = 600
PLANE = (-2.0, -1.5, 1.0, 1.5)

def validator(input_args, input_kwargs, impl_output):
actual_iters, actual_pixels = impl_output
expected_iters, expected_pixels = mandelbrot(*input_args, **input_kwargs)
np.testing.assert_allclose(expected_iters, actual_iters)
np.testing.assert_allclose(expected_pixels, actual_pixels)

def make_arrays(width):
iters = np.zeros((width, width), dtype=np.uint16)
pixels = np.zeros((width, width, 3), dtype=np.uint8)
return iters, pixels

def input_generator():
for maxiter in [100, 200, 500, 1000]:
iters, pixels = make_arrays(WIDTH)
yield dict(category=("",),
x=maxiter,
input_args=(iters, pixels, PLANE, WIDTH, maxiter),
input_kwargs={})