Home > Graphics, Python, Strange Attractors > Strange Attractors

## Strange Attractors

Lately I’ve experimented with finding strange attractors — A complex mathematical creature generated by a simple repetitive rule. To generate these images, an “x, y” point is first chosen at random and the corresponding pixel is colored white (in a simplified case). Two functions then decide the next “x, y” point:

$x = f(x,y)\\ y = g(x,y)$

Which just means that each new x position is determined by some formula incorporating the current x and/or y position, and each new y position is determined by some other formula incorporating the current x and/or y position. Depending on the formulae used, after many thousands of repetitions this may or may not generate an image of a strange attractor.

So it seems that the trick to finding these strange attractors is to simply try out  many formulae hoping to generate some interesting patterns. So what formula should I use? According to ThinkQuest, the most common attractor is the quadratic attractor. The formulae used for a quadratic attractor take the general form:

$new\enspace x=ax^2+bxy+cy^2+dx+ey+f$

To generate infinite equations of that form I need only tweak the coefficients a, b, c, d, e and f. I can leave out any of the terms (ie. the coefficient can be 0,) or I can leave in a term with no coefficient (ie. a coefficient of 1 is allowed.) For example if I decide on the coefficients 1.4, 0, 1, 2, 1 and -1.2 then the equation will look like:

$new\enspace x=1.4x^2+y^2+2x+y-1.2$

I put together a Python class to generate these equations:﻿

```class Formula(object):
def __init__(self):
# generate the random coefficients
self.coefficients = [random.choice([random.random()*4-2,
0,
1])for x in range(6)]

def __call__(self, x, y):
a, b, c, d, e, f = tuple(self.coefficients)
return a*(x**2) + b*x*y + c*(y**2) + d*x + e*y + f
```

This class generates Formula objects which can be called as if they were functions. An example usage would be:

```f = Formula()
g = Formula()
newx = f(oldx, oldy)
newy = g(oldx, oldy)
```

This first attempt is naïve in places but it succeeded in generating the first real results:

Not bad for a first attempt I think. Full Python source follows:

```import Image
import random
from math import floor

SIZE = 200 # image size

img_index = 0

class Formula(object):
def __init__(self):
self.coefficients = [random.choice([random.random()*4-2,
0,
1])for x in range(6)]
#print self.coefficients

def __call__(self, x, y):
a, b, c, d, e, f = tuple(self.coefficients)
return a*(x**2) + b*x*y + c*(y**2) + d*x + e*y + f

while True:

random.seed()
seed = int(random.random() * 1000000000)
random.seed(seed)

f = Formula()
g = Formula()

x, y = random.random(), random.random()

img = Image.new("RGB", (SIZE, SIZE))

for i in range(100000):
#print x, y
plotx = int(floor(x*SIZE/2))+SIZE/2
ploty = int(floor(y*SIZE/2))+SIZE/2
#print plotx, ploty
try:
img.putpixel((plotx, ploty), (255, 255, 255))
except IndexError:
break
x, y = f(x, y), g(x, y)

if not x or not y:
break # break out of pattern that has diminished to zero

if x > 1 or x < -1 or y > 1 or y < -1:
break # break out if growing too big

else:
img.save("a_%06d_%d.jpg" % (img_index, seed), "JPEG")
img_index += 1
```
1. December 16, 2009 at 10:50 pm

Does it work in 3D?

• December 16, 2009 at 10:59 pm

As far as I know it will work if you add a z component ie:
x = f(x, y, z)
y = g(x, y, z)
z = h(x, y, z)
That’s on my to do list!
There are also plenty of different equations types that produce different results, so plenty of scope to experiment while my attention span holds out.

I’ve greatly improved and optimised my current 2d code, and coded some image manipulation stuff. I’ll be posting that soon.