{"id":800,"date":"2018-11-30T23:30:45","date_gmt":"2018-12-01T04:30:45","guid":{"rendered":"http:\/\/aristotle2digital.blogwyrm.com\/?p=800"},"modified":"2021-11-25T19:53:40","modified_gmt":"2021-11-26T00:53:40","slug":"chaos-game-part-1-the-basics","status":"publish","type":"post","link":"https:\/\/aristotle2digital.blogwyrm.com\/?p=800","title":{"rendered":"Chaos Game Part 1 &#8211; The Basics"},"content":{"rendered":"<p>As is typical of many of the best things in life, discovery of this month\u2019s topic involved quite a bit of serendipity.\u00a0 It all started with a search for a quick reminder on how to solve a numerical set of coupled ODEs using scipy\/Python and it ended with the results seen here on the chaos game.<\/p>\n<p>Since it is possible that the reader is unfamiliar with this term (as was the author), a quick introduction is warranted.\u00a0 In short, the <a href=\"https:\/\/en.wikipedia.org\/wiki\/Chaos_game\">chaos game<\/a> is a random method for producing a deterministic fractal shape.\u00a0 Its operation is in sharp contrast to the more traditional way of drawing a fractal deterministically by hand in that the chaos game teases out the fractal\u2019s attractor by iteratively applying a set of affine transformations, each chosen randomly, to a series of points starting with a randomly chosen initial point.<\/p>\n<p>Mathematically, the chaos game falls under the broader heading of an <a href=\"https:\/\/en.wikipedia.org\/wiki\/Iterated_function_system\">Iterated Function System (IFS)<\/a> where the ith point in the plane $q_i$ is given by<\/p>\n<p>\\[ q_i = M^{(p)} q_{i-1} + f^{(p)} \\; \\]<\/p>\n<p>or, in terms of arrays<\/p>\n<p>\\[ \\left[ \\begin{array}{c} x_i \\\\ y_i \\end{array} \\right] = \\left[ \\begin{array}{cc} a^{(p)} &amp; b^{(p)} \\\\ c^{(p)} &amp; d^{(p)} \\end{array} \\right] \\left[ \\begin{array}{c} x_{i-1} \\\\ y_{i-1} \\end{array} \\right] + \\left[ \\begin{array}{c} f^{(p)} \\\\ g^{(p)} \\end{array} \\right] \\; .\\]<\/p>\n<p>The index $p$ is an integer to label the various affine transformations available, and is chosen at random at each step according to some pre-defined probability distribution.<\/p>\n<p>Before getting to the Python code, which is easy to implement, it is instructive to compare and contrast the traditional method and the chaos game in generating the well-known <a href=\"https:\/\/en.wikipedia.org\/wiki\/Sierpinski_triangle\">Sierpinski Triangle<\/a> fractal.<\/p>\n<p>The traditional way to draw the Sierpinski Triangle starts with an equilateral triangle.<\/p>\n<p><a href=\"http:\/\/aristotle2digital.blogwyrm.com\/wp-content\/uploads\/2018\/11\/Sierpinski_Triangle_Stage0.jpg\"><img loading=\"lazy\" decoding=\"async\" class=\"aligncenter size-full wp-image-799\" src=\"http:\/\/aristotle2digital.blogwyrm.com\/wp-content\/uploads\/2018\/11\/Sierpinski_Triangle_Stage0.jpg\" alt=\"\" width=\"857\" height=\"736\" srcset=\"https:\/\/aristotle2digital.blogwyrm.com\/wp-content\/uploads\/2018\/11\/Sierpinski_Triangle_Stage0.jpg 857w, https:\/\/aristotle2digital.blogwyrm.com\/wp-content\/uploads\/2018\/11\/Sierpinski_Triangle_Stage0-300x258.jpg 300w, https:\/\/aristotle2digital.blogwyrm.com\/wp-content\/uploads\/2018\/11\/Sierpinski_Triangle_Stage0-768x660.jpg 768w, https:\/\/aristotle2digital.blogwyrm.com\/wp-content\/uploads\/2018\/11\/Sierpinski_Triangle_Stage0-810x696.jpg 810w\" sizes=\"auto, (max-width: 857px) 100vw, 857px\" \/><\/a><\/p>\n<p>A similar triangle half in size (or a quarter in area) is removed from the middle of the larger triangle leaving an arrangement of three smaller triangles.<\/p>\n<p><a href=\"http:\/\/aristotle2digital.blogwyrm.com\/wp-content\/uploads\/2018\/11\/Sierpinski_Triangle_Stage1.jpg\"><img loading=\"lazy\" decoding=\"async\" class=\"aligncenter size-full wp-image-798\" src=\"http:\/\/aristotle2digital.blogwyrm.com\/wp-content\/uploads\/2018\/11\/Sierpinski_Triangle_Stage1.jpg\" alt=\"\" width=\"857\" height=\"738\" srcset=\"https:\/\/aristotle2digital.blogwyrm.com\/wp-content\/uploads\/2018\/11\/Sierpinski_Triangle_Stage1.jpg 857w, https:\/\/aristotle2digital.blogwyrm.com\/wp-content\/uploads\/2018\/11\/Sierpinski_Triangle_Stage1-300x258.jpg 300w, https:\/\/aristotle2digital.blogwyrm.com\/wp-content\/uploads\/2018\/11\/Sierpinski_Triangle_Stage1-768x661.jpg 768w, https:\/\/aristotle2digital.blogwyrm.com\/wp-content\/uploads\/2018\/11\/Sierpinski_Triangle_Stage1-810x698.jpg 810w\" sizes=\"auto, (max-width: 857px) 100vw, 857px\" \/><\/a><\/p>\n<p>The process can then be applied to these smaller triangles yielding another stage of refinement.\u00a0 This in turn results in a larger set of smaller triangles to which the process can be applied yet again.<\/p>\n<p><a href=\"http:\/\/aristotle2digital.blogwyrm.com\/wp-content\/uploads\/2018\/11\/Sierpinski_Triangle_First_Five_Stages.jpg\"><img loading=\"lazy\" decoding=\"async\" class=\"aligncenter size-full wp-image-797\" src=\"http:\/\/aristotle2digital.blogwyrm.com\/wp-content\/uploads\/2018\/11\/Sierpinski_Triangle_First_Five_Stages.jpg\" alt=\"\" width=\"857\" height=\"465\" srcset=\"https:\/\/aristotle2digital.blogwyrm.com\/wp-content\/uploads\/2018\/11\/Sierpinski_Triangle_First_Five_Stages.jpg 857w, https:\/\/aristotle2digital.blogwyrm.com\/wp-content\/uploads\/2018\/11\/Sierpinski_Triangle_First_Five_Stages-300x163.jpg 300w, https:\/\/aristotle2digital.blogwyrm.com\/wp-content\/uploads\/2018\/11\/Sierpinski_Triangle_First_Five_Stages-768x417.jpg 768w, https:\/\/aristotle2digital.blogwyrm.com\/wp-content\/uploads\/2018\/11\/Sierpinski_Triangle_First_Five_Stages-810x439.jpg 810w\" sizes=\"auto, (max-width: 857px) 100vw, 857px\" \/><\/a><\/p>\n<p>Continuing on indefinitely gives the Sierpinski Triangle in all its glory.<\/p>\n<p>However, there is a fundamental limit on how much can be drawn by hand or by computer, and the amount of work to obtain a successively more exact approximation in level of detail becomes increasingly more immense.<\/p>\n<p>In the chaos game, the programing is much simpler and, due to the random nature of the system, all levels of detail are present simultaneously.\u00a0 Central to the chaos game approach are the three affine transformations:<\/p>\n<p>\\[ T1: \\left[ \\begin{array}{c} x_i \\\\ y_i \\end{array} \\right] = \\left[ \\begin{array}{cc} 0.5 &amp; 0 \\\\ 0 &amp; 0.5 \\end{array} \\right] \\left[ \\begin{array}{c} x_{i-1} \\\\ y_{i-1} \\end{array} \\right] + \\left[ \\begin{array}{c} 1 \\\\ 1 \\end{array} \\right] \\; ,\\]<\/p>\n<p>\\[ T2: \\left[ \\begin{array}{c} x_i \\\\ y_i \\end{array} \\right] = \\left[ \\begin{array}{cc} 0.5 &amp; 0 \\\\ 0 &amp; 0.5 \\end{array} \\right] \\left[ \\begin{array}{c} x_{i-1} \\\\ y_{i-1} \\end{array} \\right] + \\left[ \\begin{array}{c} 1 \\\\ 50 \\end{array} \\right] \\; , \\]<\/p>\n<p>and<\/p>\n<p>\\[ T3: \\left[ \\begin{array}{c} x_i \\\\ y_i \\end{array} \\right] = \\left[ \\begin{array}{cc} 0.5 &amp; 0 \\\\ 0 &amp; 0.5 \\end{array} \\right] \\left[ \\begin{array}{c} x_{i-1} \\\\ y_{i-1} \\end{array} \\right] + \\left[ \\begin{array}{c} 50 \\\\ 50 \\end{array} \\right] \\; .\\]<\/p>\n<p>At each stage of the iteration, one of these transformations is selected with probability 1\/3; that is to say that each is equally likely to be selected.<\/p>\n<p>Four basic pieces of code are used in the implementation.<\/p>\n<p>The first is a table that encodes the selection probability and the parameters for each affine transformation used in the game (i.e., each row of the table encodes the likelihood and the numbers associated with $T1$, $T2$, and so on).\u00a0 The table encoding for the Sierpinski Triangle is:<\/p>\n<div class=\"myQuoteDiv\">\n<pre>sierpinski_triangle = np.array([[0.33,0.5,0,0,0.5, 1, 1],\n                                [0.66,0.5,0,0,0.5, 1,50],\n                                [1.00,0.5,0,0,0.5,50,50]])<\/pre>\n<\/div>\n<p>Second is the Transform iteration function that takes as input the current point, the table describing the game, and a random number simulating the probability at each step.<\/p>\n<div class=\"myQuoteDiv\">\n<pre>def Transform(point,table,r):\n    x0 = point[0]\n    y0 = point[1]\n\n    for i in range(len(table)):\n        if r &lt;= table[i,0]:\n            N = i\n            break\n\n    x = table[N,1]*x0 + table[N,2]*y0 + table[N,5]\n    y = table[N,3]*x0 + table[N,4]*y0 + table[N,6]\n\n    return np.array([x,y])<\/pre>\n<\/div>\n<p>Third is looping code that carries out the chaos game through successive applications.\u00a0 The code, which, for convenience, wasn\u2019t encapsulated in a function, looks like<\/p>\n<div class=\"myQuoteDiv\">\n<pre>N\u00a0\u00a0\u00a0\u00a0 = 100000\nshape = np.zeros((N,2))\nprobs = np.random.random(N)\ngame\u00a0 = sierpinski_triangle\n\nfor i in range(1,N):\n    shape[i,:] = Transform(shape[i-1,:],game,probs[i])<\/pre>\n<\/div>\n<p>The parameter N sets the number of desired iterations; the numpy array shape pre-allocates the space for the resulting points from the iterations and initializes the starting point to the origin.\u00a0 The probabilities are also precomputed since a call to the numpy (np) random is more quickly performed when in bulk than at each step.\u00a0 The game object points at the particular table encoding the transformations, here the sierpinski_triangle table defined above.\u00a0 The for loop could be done faster using a list comprehension but at the loss of clarity.\u00a0 Since N = 100000 takes less than a second of computation there wasn\u2019t a compelling reason to lose the clarity.<\/p>\n<p>The final step is a plot of the results.\u00a0 The code that performs this is given by<\/p>\n<div class=\"myQuoteDiv\">\n<pre>start = 0\n\nfig_shape = plt.figure(figsize=(6,6))\nax_shape\u00a0 = fig_shape.add_subplot(1,1,1)\nax_shape.scatter(shape[start:,0],shape[start:,1],marker='.',color='k',s=0.01)\nax_shape.axes.set_frame_on(False)\nax_shape.xaxis.set_visible(False)\nax_shape.yaxis.set_visible(False)<\/pre>\n<\/div>\n<p>The parameter start sets the number of initial points to ignore.\u00a0 This is sometimes useful to suppress the initial stray n points until the game converges to the fractal attractor.<\/p>\n<p>All of these pieces were put together in a Jupyter notebook.\u00a0 The resulting image is<\/p>\n<p><a href=\"http:\/\/aristotle2digital.blogwyrm.com\/wp-content\/uploads\/2018\/11\/Sierpinski_Triangle_1.jpg\"><img loading=\"lazy\" decoding=\"async\" class=\"aligncenter size-full wp-image-796\" src=\"http:\/\/aristotle2digital.blogwyrm.com\/wp-content\/uploads\/2018\/11\/Sierpinski_Triangle_1.jpg\" alt=\"\" width=\"857\" height=\"839\" srcset=\"https:\/\/aristotle2digital.blogwyrm.com\/wp-content\/uploads\/2018\/11\/Sierpinski_Triangle_1.jpg 857w, https:\/\/aristotle2digital.blogwyrm.com\/wp-content\/uploads\/2018\/11\/Sierpinski_Triangle_1-300x294.jpg 300w, https:\/\/aristotle2digital.blogwyrm.com\/wp-content\/uploads\/2018\/11\/Sierpinski_Triangle_1-768x752.jpg 768w, https:\/\/aristotle2digital.blogwyrm.com\/wp-content\/uploads\/2018\/11\/Sierpinski_Triangle_1-810x793.jpg 810w, https:\/\/aristotle2digital.blogwyrm.com\/wp-content\/uploads\/2018\/11\/Sierpinski_Triangle_1-54x54.jpg 54w\" sizes=\"auto, (max-width: 857px) 100vw, 857px\" \/><\/a><\/p>\n<p>Note that the Sierpinski Triangle is rotated 45 degrees from the more usual \u2018artistic\u2019 expression.\u00a0 That minor issue is easily rectified using a simple rotation matrix<\/p>\n<div class=\"myQuoteDiv\">\n<pre>c45 = 1.0\/np.sqrt(2.0)\ns45 = 1.0\/np.sqrt(2.0)\nA   = np.array([[c45,s45],[-s45,c45]])\n\nnew_shape = np.array([A.dot(shape[i,:]) for i in range(len(shape))])<\/pre>\n<\/div>\n<p>where the parameters c45 and s45 are shorthand for $\\cos(45 {}^{\\circ}) = 1\/\\sqrt{2}$ and $\\sin(45 {}^{\\circ}) = 1\/\\sqrt{2}$, respectively.<\/p>\n<p>The resulting image is now more aesthetically pleasing.<\/p>\n<p><a href=\"http:\/\/aristotle2digital.blogwyrm.com\/wp-content\/uploads\/2018\/11\/Sierpinski_Triangle_2.jpg\"><img loading=\"lazy\" decoding=\"async\" class=\"aligncenter size-full wp-image-795\" src=\"http:\/\/aristotle2digital.blogwyrm.com\/wp-content\/uploads\/2018\/11\/Sierpinski_Triangle_2.jpg\" alt=\"\" width=\"857\" height=\"852\" srcset=\"https:\/\/aristotle2digital.blogwyrm.com\/wp-content\/uploads\/2018\/11\/Sierpinski_Triangle_2.jpg 857w, https:\/\/aristotle2digital.blogwyrm.com\/wp-content\/uploads\/2018\/11\/Sierpinski_Triangle_2-150x150.jpg 150w, https:\/\/aristotle2digital.blogwyrm.com\/wp-content\/uploads\/2018\/11\/Sierpinski_Triangle_2-300x298.jpg 300w, https:\/\/aristotle2digital.blogwyrm.com\/wp-content\/uploads\/2018\/11\/Sierpinski_Triangle_2-768x764.jpg 768w, https:\/\/aristotle2digital.blogwyrm.com\/wp-content\/uploads\/2018\/11\/Sierpinski_Triangle_2-810x805.jpg 810w, https:\/\/aristotle2digital.blogwyrm.com\/wp-content\/uploads\/2018\/11\/Sierpinski_Triangle_2-54x54.jpg 54w\" sizes=\"auto, (max-width: 857px) 100vw, 857px\" \/><\/a><\/p>\n<p>Making it an equilateral triangle is left as an exercise for the reader.<\/p>\n<p>Note that I\u2019ve played with the color scheme freely and inconsistently from image to image.\u00a0 Picking and playing with colors is one of the most fun things about exploring the chaos game.<\/p>\n<p>Future columns will look more closely at the chaos game, why it works the way it does and some of the beautiful images that can be produced.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>As is typical of many of the best things in life, discovery of this month\u2019s topic involved quite a bit of serendipity.\u00a0 It all started with a search for a&#8230; <a class=\"read-more-button\" href=\"https:\/\/aristotle2digital.blogwyrm.com\/?p=800\">Read more &gt;<\/a><\/p>\n","protected":false},"author":2,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[1],"tags":[],"class_list":["post-800","post","type-post","status-publish","format-standard","hentry","category-uncategorized"],"_links":{"self":[{"href":"https:\/\/aristotle2digital.blogwyrm.com\/index.php?rest_route=\/wp\/v2\/posts\/800","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/aristotle2digital.blogwyrm.com\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/aristotle2digital.blogwyrm.com\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/aristotle2digital.blogwyrm.com\/index.php?rest_route=\/wp\/v2\/users\/2"}],"replies":[{"embeddable":true,"href":"https:\/\/aristotle2digital.blogwyrm.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=800"}],"version-history":[{"count":0,"href":"https:\/\/aristotle2digital.blogwyrm.com\/index.php?rest_route=\/wp\/v2\/posts\/800\/revisions"}],"wp:attachment":[{"href":"https:\/\/aristotle2digital.blogwyrm.com\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=800"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/aristotle2digital.blogwyrm.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=800"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/aristotle2digital.blogwyrm.com\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=800"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}