Making of-the-logistic-map-bifurcation-diagram
-
Upload
martsberger -
Category
Software
-
view
580 -
download
1
description
Transcript of Making of-the-logistic-map-bifurcation-diagram
Making of:
The logistic mapbifurcation diagram
Brad Martsberger
What is this talk about?Making a pretty picture
Squeezing performance out of python
PyPy, Cython, C extensions
With a toy physics model (chaos!)
Fun with fractals
Cool, but...Where did that come from?Can you show me some python already?
The logistic mapMap a value, x, from [0, 1] to [0, 1] according to:
r * x * (1 - x)
Let's play...
x = 0.25 r = 2.5 for j in range(limit): print "x:", x x = r * x * (1 - x)
What do we need to make thatsweet graph?
Python
Matplotlib
Patience ... lots of patience
Simplified version bif_diag = [[0.0] * height] * width
for k in range(width): # histogram of how frequently each pixel is visited. h = logmap_histogram(r, x_len, x1, x2, height)
# Normalize the histogram to go from 0 to 1. h = divide_list(h, 1.0 * max(h))
# stick it in upside down to the image bif_diag[k - 1] = h[::-1]
plot_bif_diag(bif_diag, plt, cm, (x1, x2), (r_lower, r_upper))
Inner loop def logmap_histogram(r, x_len, x1, x2, height): result = [0] * height dx = 1.0 * (x2 - x1) / (height - 1)
transient = 500 x = 0.25 for k in xrange(transient): x = x * r * (1 - x) for k in xrange(x_len): x = x * r * (1 - x) incr = int((x - x1) / dx) if incr >= 0 and incr < M: result[incr] += 1
return result
Matplotlib bitdef plot_bif_diag(bif_diag, plt, cm, xlim, rlim): width, height, = len(bif_diag), len(bif_diag[1])
to_plot = [[1 - pix for pix in col] for col in bif_diag] to_plot = map(list, zip(*to_plot))
plt.imshow(to_plot, cm.gray, clim=(0.7, 1))
font = {'family': 'serif', 'size': 24} plt.xlabel('r', fontdict=font) plt.ylabel('x*', fontdict=font) plt.xticks(linspace(1, N, 9), ['%.2g' % r for r in linspace(rlim[0], rlim[1], 9)]) plt.yticks(linspace(1, M - 1, 5), ['%.2g' % x for x in linspace(xlim[1], xlim[0], 5)])
ax = plt.gca() ax.set_position([80. / (width + 100.), 80. / (height + 100.), width / (width + 100.), height / (height + plt.gcf().canvas.manager.window.geometry("{0}x{1}+30+30".format(width + 100, height +
plt.show()
Let's run thisthing already...
That was a little disappointingNot horrible, but too slow to do some cool stuff.
Options for doing better0. Quit using python
1. PyPy
2. C extension
3. Cython
4. There are others (numpy with numexpr)
PyPyStraight from pypy.org:
Fast, compliant alternative implementation of the Pythonlanguage (2.7.6 and 3.2.3) with several advantages:
Speed, due to Just-In-Time compiler
Takes less memory
Supports a number of third party libraries:
ctypes, django, sqlalchemy, twisted, etc.
Does not require any change to your code!
Unfortunately, matplotlib is not supported.
Numpy is partially supported.
C extensionsWrite functions in C that are callable from python
Pass python objects as arguments that must be converted to Cvalues
Returns a python object, e.g., a list
Compiled and fast
Do this at least once
Let's have a lookstatic PyObject *logmap_attractor_histogram(PyObject *self, PyObject *args) { double r1, r2, x, x1, x2; int xxlen, rrlen, M; int transient = 500; // Short transient for each r.
if (!PyArg_ParseTuple(args, "ddiiddi", &r1, &r2, &rrlen, &xxlen, &x1, &x2, &M)) { return NULL; }
// Store our histogram in an int array, copy it to a python list and return // the list as a PyObject* int array[M]; PyObject* list = PyList_New(M); // Initialize array to all zeros int j, k; for (j = 0; j < M; ++j) { array[j] = 0; }
double r, dr, dx; int incr;
// Set the amount we will step to get from r1 to r2 in rrlen-1 steps dr = 0; if (rrlen > 1) { dr = (r2 - r1)/(rrlen-1); }
// Histogram bin size dx = (x2 - x1)/(M - 1);
// loop over r (perhaps change to for (r=r1; r<=r2; r += dr) )
Compiling to an importable moduleCreate a setup.py file, e.g:
from distutils.core import setup, Extension
setup(name='logmap', version='1.0', ext_modules=[Extension('logmap', ['logmapmodule.c'])])
Then install it
>>> python setup.py install
And it can be imported and called
import logmap
h = logmap.attractor_histogram(...)
Let's see it already...
CythonDirectly from cython.org:
Static compiler for python
Makes writing C extensions for python as easy as writingpython
Generates C code from your python code
Has the potential to deliver the speed gains that we get from a Cextension with less hassle
How to make it workCreate setup.py file:
Build like this:
Then you can import fromlogistic_map_bifurcation_diagram_cython
from distutils.core import setupfrom Cython.Build import cythonize
setup( name = 'logmap_cython', ext_modules = cythonize("logistic_map_bifurcation_diagram_cython.pyx"),)
%>python setup.py build_ext --in_place
Making cython fasterCython's code generation is helped by providing it hints in the
form of type declarations
def logmap_histogram(float r1, float r2, int rrlen, int xxlen, float x1, float x2, int M) result = [0] * M cdef float dx dx = 1.0 * (x2 - x1) / (M - 1)
transient = 500 cdef float x cdef float r cdef float k for r in linspace(r1, r2, rrlen): x = 0.25 for k in range(transient): x = x * r * (1 - x) for k in range(xxlen): x = x * r * (1 - x) incr = int((x - x1) / dx) if incr >= 0 and incr < M: result[incr] += 1
return result
Questions...Comments, etc.