Coding Example: The Mandelbrot Set (Python approach)
Understand the pure Python implementation of the Mandelbrot set and its iterative function. Learn about the challenges in optimizing such code and prepare to explore how NumPy can enhance computational efficiency in simulations.
We'll cover the following...
We'll cover the following...
Python Implementation
A pure python implementation is written as:
Python 3.5
# -----------------------------------------------------------------------------# From Numpy to Python# Copyright (2017) Nicolas P. Rougier - BSD license# More information at https://github.com/rougier/numpy-book# -----------------------------------------------------------------------------import numpy as npdef mandelbrot_python(xmin, xmax, ymin, ymax, xn, yn, maxiter, horizon=2.0):def mandelbrot(z, maxiter):c = zfor n in range(maxiter):if abs(z) > horizon:return nz = z*z + creturn maxiterr1 = [xmin+i*(xmax-xmin)/xn for i in range(xn)]r2 = [ymin+i*(ymax-ymin)/yn for i in range(yn)]return [mandelbrot(complex(r, i),maxiter) for r in r1 for i in r2]def mandelbrot(xmin, xmax, ymin, ymax, xn, yn, itermax, horizon=2.0):# Adapted from# https://thesamovar.wordpress.com/2009/03/22/fast-fractals-with-python-and-numpy/Xi, Yi = np.mgrid[0:xn, 0:yn]Xi, Yi = Xi.astype(np.uint32), Yi.astype(np.uint32)X = np.linspace(xmin, xmax, xn, dtype=np.float32)[Xi]Y = np.linspace(ymin, ymax, yn, dtype=np.float32)[Yi]C = X + Y*1jN_ = np.zeros(C.shape, dtype=np.uint32)Z_ = np.zeros(C.shape, dtype=np.complex64)Xi.shape = Yi.shape = C.shape = xn*ynZ = np.zeros(C.shape, np.complex64)for i in range(itermax):if not len(Z): break# Compute for relevant points onlynp.multiply(Z, Z, Z)np.add(Z, C, Z)# Failed convergenceI = abs(Z) > horizonN_[Xi[I], Yi[I]] = i+1Z_[Xi[I], Yi[I]] = Z[I]# Keep going with those who have not diverged yetnp.logical_not(I,I)Z = Z[I]Xi, Yi = Xi[I], Yi[I]C = C[I]return Z_.T, N_.Tif __name__ == '__main__':from matplotlib import colorsimport matplotlib.pyplot as pltfrom tools import timeit# Benchmarkxmin, xmax, xn = -2.25, +0.75, int(3000/3)ymin, ymax, yn = -1.25, +1.25, int(2500/3)maxiter = 200timeit("mandelbrot_python(xmin, xmax, ymin, ymax, xn, yn, maxiter)", globals())# Visualizationxmin, xmax, xn = -2.25, +0.75, int(3000/2)ymin, ymax, yn = -1.25, +1.25, int(2500/2)maxiter = 20horizon = 2.0 ** 40log_horizon = np.log(np.log(horizon))/np.log(2)Z, N = mandelbrot(xmin, xmax, ymin, ymax, xn, yn, maxiter, horizon)# Normalized recount as explained in:# http://linas.org/art-gallery/escape/smooth.htmlM = np.nan_to_num(N + 1 - np.log(np.log(abs(Z)))/np.log(2) + log_horizon)dpi = 72width = 10height = 10*yn/xnfig = plt.figure(figsize=(width, height), dpi=dpi)ax = fig.add_axes([0.0, 0.0, 1.0, 1.0], frameon=False, aspect=1)light = colors.LightSource(azdeg=315, altdeg=10)plt.imshow(light.shade(M, cmap=plt.cm.hot, vert_exag=1.5,norm = colors.PowerNorm(0.3), blend_mode='hsv'),extent=[xmin, xmax, ymin, ymax], interpolation="bicubic")ax.set_xticks([])ax.set_yticks([])plt.savefig("output/mandelbrot.png")plt.show()
Output
The output of the above code would ...