Julia Sets

Caleb Sturges


In [1]:
class JuliaSet:
    def __init__(self, c, n=100):   
        self.c = c
        self.n = n
        self._d=.001
        self._complexplane = []
        for i in (0, 4/self._d):
            for k in (0, 4/self._d):
                self._complexplane.append(complex(-2+i*self._d,-2j+k*self._d))

    def juliamap(self, z):
        return self.c+z**2
    
    def iterate(self, z):
        m = 1
        runningz = z
        while True:
            juliamap(self, z)
            if abs(runningz)>2:
                return m
            elif m>=n:
                return 0
            else:
                m+=1

    def set_spacing(self, _d):
        self._d = _d
        self._complexplane = []
        for i in frange(-2, 2, self._d):
            for j in frange(-2, 2, self._d):
                self._complexplane.append(complex(i, j))
        return self._complexplane       
    
    def generate(self):
        self._d
        self.set=[]
        for i in frange(-2, 2, self._d):
            for j in frange(-2, 2, self._d):
                self.set.append(complex(i,j))
        return self.set
    
def frange(start, stop, step):
    i = start
    while i < stop:
        yield i
        i += step   
        

myJuliaSet=JuliaSet(0, 100)

In [ ]:


In [2]:
from random import uniform, randint
from math import sqrt
from nose import with_setup

###
# Test Suite for specified JuliaSet interface
#
# Run with the command: "nosetests juliatests.py"
###


# Custom random numbers

def rand_range():
    """Return a random complex number bounded by real and imaginary axes [-2, 2]"""
    return (uniform(-2,2) + uniform(-2,2)*1j)

def rand_circle():
    """Return a random complex number within the unit circle"""
    r = uniform(-1,1)
    dr = sqrt(1 - r**2)
    i = uniform(-dr, dr)
    return (r + i*1j)

# Test classes for several cases
    
class TestRandomC:
    """Define a julia set with a random c seed value, test interface"""
    
    def setup(self):
        """Setup fixture is run before every test method separately"""
        self.c = rand_range()
        self.n = randint(2,100)
        self.j = JuliaSet(self.c, self.n)
        
    def test_c_value(self):
        """Test that c is an attribute"""
        assert self.j.c == self.c
    
    def test_n_value(self):
        """Test that n is an attribute"""
        assert self.j.n == self.n
    
    def test_juliamap(self):
        """Test that juliamap is implemented properly"""
        z = rand_range()
        print "z = ", z
        print "z**2 = ", z**2
        zcorrect = z**2 + self.c
        print "z**2 + c = ", zcorrect
        znew = self.j.juliamap(z)
        print "juliamap(z) = ", znew
        assert znew == zcorrect
    
    def test_set_spacing(self):
        """Test that changing spacing works"""
        print "Test original spacing _d = 0.001"
        assert self.j._d == 0.001
        print "Test new spacing of _d = 0.1"
        self.j.set_spacing(0.1)
        print "_d = ", self.j._d
        assert self.j._d == 0.1
        print "Test that complex plane is regenerated"
        print "len(_complexplane) = ", len(self.j._complexplane)
        print "int(4.0 / 0.1)**2 = ", int(4.0 / 0.1)**2
        assert len(self.j._complexplane) == int(4.0 / 0.1)**2
    
    def test_generate(self):
        """Test that generating the julia set works"""
        self.j.set_spacing(0.1)
        self.j.generate()
        print "Test that j.set exists, and is of the same length as j._complexplane"
        assert (len(self.j.set) == len(self.j._complexplane))

class TestTrivial:
    """Test that a seed value of c=0 leaves the unit circle invariant"""
    
    @classmethod
    def setup_class(cls):
        cls.j = JuliaSet(0)
    
    def test_trivial_seed(self):
        def check_z(z):
            """Test all z inside unit circle return 0"""
            m = TestTrivial.j.iterate(z)
            print "m = ", m
            assert m == 0
        # A generator like this runs a test for every yield
        for _ in xrange(100):
            z = rand_circle()
            yield check_z, z

class TestHuge:
    """Test that a huge seed always causes a divergence after 1 iteration"""
    
    @classmethod
    def setup_class(cls):
        cls.j = JuliaSet(16)
    
    def test_huge_seed(self):
        def check_z(z):
            """Test all z escape after 1 iteration"""
            print "z = ", z
            print "z**2 = ", z**2
            print "z**2 + c = ", z**2 + 16
            print "juliamap(z) = ", TestHuge.j.juliamap(z)
            assert TestHuge.j.iterate(z) == 1
        # Again, a generator runs a test for every yield
        for _ in xrange(100):
            z = rand_range()
            yield check_z, z


testRandC = TestRandomC()

In [3]:
testRandC.setup()
testRandC.test_juliamap()


testRandC.test_c_value()
testRandC.test_set_spacing()
testRandC.test_generate()


z =  (0.862442194936-0.853580381244j)
z**2 =  (0.0152070723625-1.47232747511j)
z**2 + c =  (0.512187307836-2.78400069935j)
juliamap(z) =  (0.512187307836-2.78400069935j)
Test original spacing _d = 0.001
Test new spacing of _d = 0.1
_d =  0.1
Test that complex plane is regenerated
len(_complexplane) =  1600
int(4.0 / 0.1)**2 =  1600
Test that j.set exists, and is of the same length as j._complexplane

In [ ]:


In [7]:
testTriv = TestTrivial()
testHuge = TestHuge()

In [5]:
testTriv.setup_class()
testTriv.test_trivial_seed()


Out[5]:
<generator object test_trivial_seed at 0x7fd03d5c8a00>

In [6]:
testHuge.setup_class()
testHuge.test_huge_seed()


Out[6]:
<generator object test_huge_seed at 0x7fd0440f43c0>

In [ ]:


In [ ]: