CuPy Fractal
import cupy
import numpy
import math
import matplotlib.pyplot as plt
Wait until conda gets 5.0 if you want RawKernel. Not fun to setup CUDA with libraries and build. All credit for original code codes to Jim Pivarski here: https://github.com/jpivarski/python-numpy-mini-course/blob/evaluated/7-gpu.ipynb
cupy.__version__
import numpy
def prepare(height, width, numpy=numpy):
y, x = numpy.ogrid[-1 : 0 : height * 1j, -1.5 : 0 : width * 1j]
c = x + y * 1j
fractal = numpy.zeros(c.shape, dtype=numpy.int32)
return c, fractal
def run(c, fractal, maxiterations=20):
fractal *= 0 # set fractal to maxiterations without replacing it
fractal += maxiterations
z = c
for i in range(maxiterations):
z **= 2
z += c
diverge = z.real ** 2 + z.imag ** 2 > 2 ** 2
z[diverge] = 2
diverge &= fractal == maxiterations
fractal[diverge] = i
return fractal
c, fractal = prepare(8000, 12000, numpy)
%%timeit
_ = run(c, fractal)
c, fractal = prepare(8000, 12000, cupy)
%%timeit
_ = run(c, fractal)
cupy.cuda.Stream.null.synchronize()
cupy_single = cupy.ElementwiseKernel(
"complex128 cpx, int32 maxiterations",
"int32 res",
"""
res = maxiterations;
complex<double> z = cpx;
for (int i=0; i<maxiterations; i++) {
z = z*z + cpx;
if(z.real()*z.real() + z.imag()*z.imag() > 4) {
res = i;
break;
}
}
""",
"fract_el",
)
c, _ = prepare(8000, 12000, cupy)
%%timeit
fractal = cupy_single(c, 20)
cupy.cuda.Stream.null.synchronize()
cupy_kernel = cupy.RawKernel(
"""
extern "C"
__global__ void fractal(double* c, int* fractal, int height, int width, int maxiterations) {
const int x = threadIdx.x + blockIdx.x*blockDim.x;
const int y = threadIdx.y + blockIdx.y*blockDim.y;
double creal = c[2 * (x + height*y)];
double cimag = c[2 * (x + height*y) + 1];
double zreal = creal;
double zimag = cimag;
fractal[x + height*y] = maxiterations;
for (int i = 0; i < maxiterations; i++) {
double zreal2 = zreal*zreal - zimag*zimag + creal;
double zimag2 = 2*zreal*zimag + cimag;
zreal = zreal2;
zimag = zimag2;
if (zreal*zreal + zimag*zimag > 4) {
fractal[x + height*y] = i;
break;
}
}
}
""",
"fractal",
)
def run_pycuda(height, width, maxiterations=20):
y, x = cupy.ogrid[-1 : 0 : height * 1j, -1.5 : 0 : width * 1j]
grid = (int(math.ceil(height / 32)), int(math.ceil(width / 32)))
c = x + y * 1j
fractal = cupy.empty(c.shape, dtype=cupy.int32) + maxiterations
cupy_kernel(
grid,
(32, 32, 1),
[
c.view(cupy.double),
fractal,
cupy.int32(height),
cupy.int32(width),
cupy.int32(maxiterations),
],
)
return c, fractal
%%timeit
_, fractal = run_pycuda(8000, 12000)
cupy.cuda.Stream.null.synchronize()
_, fractal = run_pycuda(8000, 12000)
plt.imshow(fractal.get())