Skip to content

Instantly share code, notes, and snippets.

@Veedrac
Last active August 29, 2015 14:05
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save Veedrac/64bd4875d1adebe0d02c to your computer and use it in GitHub Desktop.
Save Veedrac/64bd4875d1adebe0d02c to your computer and use it in GitHub Desktop.
Significantly more complicated than justified, but eeking out that last 50% felt important...
import sys
import numpy
import numexpr
numexpr.set_num_threads(2)
CHUNKS = 256
def mandel_unroll_numexpr(n, z="z", c="c"):
"""
Generate a numexpr for the core mandelbrot loop (z = z ** 2 + c)
a number of times.
"""
for _ in range(n):
z = "({} ** 2 + {})".format(z, c)
return z
def mandelbrot(h, w, xstart, xend, ystart, yend, maxit=50):
"""
Returns an image of the Mandelbrot fractal of size (h,w).
"""
y, x = numpy.ogrid[xstart:xend:h*1j, ystart:yend:w*1j]
c = x + y*1j
z = c.copy()
for i in range(maxit//6):
z = numexpr.evaluate(mandel_unroll_numexpr(6))
# Prevent overflow
z = numexpr.evaluate("where(real(z) ** 2 + imag(z) ** 2 > 2 ** 2, 2, z)")
# Finish the loops
z = numexpr.evaluate(mandel_unroll_numexpr(maxit % 6))
return numexpr.evaluate("real(z) ** 2 + imag(z) ** 2 > 2 ** 2")
width = height = int(sys.argv[1])
sys.stdout.buffer.write("P4\n{} {}\n".format(width, height).encode("ascii"))
# We need to chunk to keep memory usage down
i = -1.4
chunkheight = 2.8 / CHUNKS
for _ in range(CHUNKS):
output = mandelbrot(
width // CHUNKS, height,
xstart=i, xend=i+chunkheight,
ystart=-1.4, yend=1.4
)
# Write bytes to sys.stdout
# For some reason packbits doesn't like bools
packed = numpy.packbits(output.astype("uint8"), axis=1)
sys.stdout.buffer.write(packed.tostring())
sys.stdout.flush()
i += chunkheight
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment