Monday, September 5, 2011

A Practical Use for the 'complex' Type

In a recent programming competition, a question asked competitors to generate certain fractals (Julia sets, to be precise). This task requires understanding of the mathematics behind fractals; specifically, complex numbers. The judges assumed that most competitors would be unfamiliar with complex numbers and how to manipulate them programmatically. Hence, about half of the problem statement documented the different operations that could be done with complex numbers: polar/Cartesian conversions, getting the modulus and the angle, how the arithmetic operators worked, etc.

Luckily, I recalled that Python has built-in support for complex numbers. All I had to do was plug in the given formulae and the problem basically solved itself.

In celebration, here's a short piece of Python code which generates a 200x200 Mandelbrot set in ASCII, using Python's complex number support and the cmath library. cmath is to complex numbers as math is to real numbers: it provides loads of helpful functions you might need when dealing with complex numbers. Here, I use cmath to get the modulus of z.

import math, cmath
RX, RY = (-2.5,1), (-1,1)

# maps a pixel (x,y) into a (x,y) point on the Mandelbrot canvas
def lmap(n, (a,b)): return n/200.0 * (b-a) + a

def value(x,y):
    z, c = 0, complex(lmap(x, RX), lmap(y, RY))
    iters = 0
    while cmath.polar(z)[0] < 4 and iters < 1000:
        z = z*z + c
        iters += 1
    return int(math.log(iters)/math.log(1000) * 10.0)
        
out = open('out.txt', 'w')
for r in xrange(200):
    for c in xrange(200):
        out.write(' .:;*0&%@$#'[value(r,c)])
    out.write('\n')

A small portion of the generated fractal: