This is part of a project to explore the Mandelbrot set. The code to graphically navigate the complex plane and allow the user to adjust the colormap and number of iterations is all written in Python, because that sort of user interface work is easiest in a scripting language. However, Python is not very good at inner loops that run hundreds of times for each pixel, so I wrote a C program that does the actual computation. The python function runs the C executable in a separate process that passes the result back from C to python as a human-readable string. Parsing the string back to integers is slow. What is a more pythonic way of creating the interface between C and python? Also, any general tips for writing faster, better C are appreciated, I'm new to the language.
Python code:
import numpy as np
from subprocess import Popen
import subprocess
def getcounts(xmin, xmax, ymin, ymax, dim, depth):
"""render a view of the mandelbrot set on the given rectangle of the
complex plane, by calling a C script and interpreting stdout as a
series of integers
output is a numpy array reshaped into a dim*dim square"""
p = Popen(["./a.out", repr(xmin), repr(xmax), repr(ymin),
repr(ymax), str(dim), str(depth)], stdout=subprocess.PIPE)
counts = np.fromstring(p.stdout.readline()[:-1], dtype = np.int, sep = ' ')
return counts.reshape([dim, dim]).transpose()
C code:
#include <stdio.h>
#include <stdlib.h>
int main(int argc, char *argv[]){
int dim = 100; /*defaults produce a nice overview of the mandelbrot set*/
int depth = 300;
double minx = -2;
double maxx = 2;
double miny = -1.5;
double maxy = 1.5;
if(argc > 6){
minx = atof(argv[1]);
maxx = atof(argv[2]);
miny = atof(argv[3]);
maxy = atof(argv[4]);
dim = atoi(argv[5]);
depth = atoi(argv[6]);
}
double xstep = (maxx - minx)/dim;
double ystep = (maxy - miny)/dim;
int i, j;
for(i = 0; i < dim; i++){
double c_real = minx + i * xstep;
for(j = 0; j < dim; j++){
double c_imag = miny + j * ystep;
int count = 0;
double z_real = 0;
double z_imag = 0;
double zreal_temp;
while((z_real * z_real + z_imag * z_imag < 4) && count < depth){
count ++;
zreal_temp = z_real * z_real - z_imag * z_imag + c_real;
z_imag = z_real * z_imag * 2 + c_imag;
z_real = zreal_temp;
}
printf("%d ", count);
}
}
}
Finally, here's a python script to test the above function: I've cut out all the bits for moving around and adjusting settings since this question is about the C - Python interface
import numpy as np
import matplotlib.pyplot as plt
xmin = -2
xmax = 2
ymin = -2
ymax = 2
depth = 60
dim = 600
counts = getcounts(xmin, xmax, ymin, ymax, dim, depth)
plt.imshow(counts, extent = [xmin, xmax, ymax, ymin], interpolation = 'nearest')
plt.show()