Julia Set
WHAT IS IT?
This model uses turtles and colored patches to generate any of a number of Julia sets. To understand a Julia set, we must first understand the following iterative relationship:
z(n+1) = z(n)^2 + c
where z(n) is the value of z after n iterations, and c is a complex constant.
For any given value of c, the set of z(0) values for which z(n) converges to a finite range of values (as n goes to infinity) is called the "filled-in" Julia set. Formally, the Julia set is the boundary of this filled-in set - the dividing line between the filled-in set and the "escaping set" (the z(0) values that result in divergent sequences - those which are unbounded as n goes to infinity). Different values of c generally have different associated Julia sets (though the Julia set associated with c = a + bi will be a mirror image of the set associated with c = a - bi).
Practically speaking, we can't iterate the sequence to infinity. Instead, we set a maximum number of iterations, and we compare the terms of the sequence with a threshold radius; for Julia sets, this threshold radius is the greater of 2 and the distance from the origin of c. If the distance between z(n) and the origin becomes greater than the threshold radius at some point in the sequence, we know that z(0) is not a member of the filled-in Julia set, and we stop iterating. On the other hand, if n exceeds the maximum number of iterations, and z(n) has not yet exceeded the threshold radius, then we assume that z(0) is within the boundary of the Julia set (i.e. is in the filled-in Julia set). (We could also keep track of the values in a sequence, to see if they are repeated at some point, indicating that the sequence is cycling, and thus finitely bounded; this isn't an approach that is well-suited to StarLogo, however.) Not surprisingly, we will get more accurate results if we select a large maximum number of iterations; however, for z(0) values which are in the filled-in Julia set, we will iterate longer before coming to that conclusion.
Besides learning which z(0) values lie inside the Julia set boundary, and which do not, it is often useful to count how many iterations it takes before a sequence exceeds the threshold radius; in the immediate neighborhood of the Julia set, there are large changes in this number of iterations for small changes in the z(0) value. If we display some subset of complex numbers graphically, by plotting their x + yi complex values on the X-Y coordinate system, and we relate the number of iterations before a sequence to the color used to plot the z(0) that begins the sequence, then we will have a graphical representation of the filled-in Julia set and the surrounding region, for the given value of c. Using colors in this fashion is sometimes referred to as "coloring by escape speed", where a lower number of iterations corresponds to a larger escape speed.
HOW IT WORKS
This model uses a number of turtles, each moving vertically along a portion of a single column, to draw the Julia set. Every time a turtle moves to a new patch, it scales the patch coordinates to a virtual coordinate system (allowing us to zoom in, to a certain extent), and begins iterating the sequence based on the scaled x and y values.
If the maximum number of iterations is exceeded, the turtle assumes that the sequence beginning with the z(0) value corresponding to its patch converges (i.e. the z(0) is in the Julia set), and it stamps the patch with the color selected by the user for the Julia set; otherwise, it stamps the patch with a color related to the number of iterations before the threshold radius was exceeded. The turtle then moves to the next patch; if that patch has already been stamped for the current Julia set, the turtle dies.
HOW TO USE IT
The "Maximum # of Iterations" slider controls the maximum number of times a sequence will be iterated by a turtle, before the turtle assumes that the sequence converges. Lower values will result in the set being rendered more quickly, but with less accuracy. With higher values, the set is rendered more slowly, but more accurately. A starting value of 100 is reasonable in most cases, though some sets (especially disconnected sets such as that in example 3) are rendered very differently with a higher iteration limit.
The next few controls have to do with the centering and scaling of the image. The "X Center" and "Y Center" monitors show the complex value (x + yi) that will be the center for the next Julia set drawn. When you press the "Set" button, it will remain pressed until you click some point in the StarLogo canvas; the point you click will be the new center. The "Reset" button sets the center to the origin, which is the default.
The "Zoom Factor" slider is used to draw the Julia set with a magnification factor. By default, a scale value of 0 will show the entirety of most Julia sets which can be drawn by this model. Each increase by one zooms in by a factor of two.
The "Interior Color" slider allows you to specify the color (using the StarLogo numeric color values) with which the turtle will stamp patches corresponding to points that are considered to be in the interior of the Julia set boundary.
The "Divergent Color" slider controls how wide the range of colors is. If a sequence exceeds the threshold radius after the first iteration, then the patch will be stamped with this color; if it takes more iterations to exceed the threshold radius, the resulting color will be scaled between this color and the interior color.
The model includes a number of different examples, which have different values of the c constant. These examples can be invoked by setting the "Examples" slider to a non-zero value.
If you want to control the c constant explicitly, you can do so by setting the "Examples" slider to 0, and setting the "10 * Real Part" and "10 * Imaginary Part" sliders to the desired values. Since StarLogo allows only integral values in sliders, the values specified here will actually be ten times the values that will be used in the model. For example, if "10 * Real Part" is set to 7, and "10 * Imaginary Part" is set to 4, then c is 0.7 + 0.4i. (Remember: To control these values directly, you must set the "Examples" slider to 0.)
The "Clear" button erases any previous Julia set from the canvas. (Note: it is not necessary to press "Clear" before pressing "Draw". Doing so will cause the drawing to be done on a black canvas; otherwise, the new drawing will slowly replace the previous one.)
Press "Draw" to draw the Julia set on the canvas, based on the parameters set in the sliders. If the process is interrupted (by pressing the "Draw" button again, bringing it to the up position), and started again, drawing will begin again from the start.
THINGS TO NOTICE
Notice that the outer regions of the canvas generally will be drawn first; this is because the sequences that start with the complex values corresponding to these patches diverge very quickly (depending on the scale and centering, of course).
When the "Zoom Factor" slider is used to zoom in close on an area that includes a portion of the Julia set boundary/interior, the sequences starting with the z(0) values corresponding to the patches on the canvas will rarely diverge in a very small number of iterations; thus, the specified "Divergence Color" will generally not be used, and the range of colors visible on the canvas may be significantly limited vs. the range specified in the sliders. On the other hand, there are some Julia sets where - depending on the maximum iterations specified - we won't see many (if any) pixels of the interior color; see example 2 for an illustration of this. Formally speaking, sets like example 2 don't have any points on the interior of the boundary; the boundary is the entirety of the filled-in set.
Notice that there will often be complexity revealed, after zooming in and redrawing, of which there was no hint at larger scales (though the features at the smaller scale will often resemble the features visible at the larger scale).
EXPLORATIONS
There is a natural relationship between the width of the color range selected (i.e. the difference between the interior color and the divergent color) and the maximum iterations. With a given maximum iterations value, there will be - at most - the same number of possible colors present in the image. So if the color range runs from 40 to 99, but the maximum iterations is 20, many of the possible color values will be unused. On the other hand, if the color range is 50 to 59, and the maximum iterations is 100, there will be some iteration values which, when plotted in color, are indistinguishable from others. These graphical relationships become trickier with different zoom levels, divergence thresholds, etc. Experiment with some combinations, to find Julia set plots which you think best use color to reveal details. (Note that the StarLogo color spectrum is actually much more detailed than the documentation might lead you to believe. Although only integral values are documented, there are actually fractional values between them which will be displayed distinctly by StarLogo. In general, the number of distinct shades of any StarLogo color is between 50 and 90. However, at the lighter end of each color's shade spectrum, the colors may be nearly indistinguishable from white.)
The five examples included in the model (selectable with the "Examples" slider) have the following values of c:
1: -0.8 2: i 3: -0.7 + 0.3i 4: -1.5 5. 0.3
Obviously, these are only a few of the possible combinations available in the model. Of course, there are an infinite number of possible values of c; the sliders allow you to specify only 200. A few of these combinations are not that interesting: for example, try setting both "10 * Real Part" and "10 * Imaginary Part" to zero, and see the set that results. Most values of c do have fractal Julia sets, however.
Try a few other combinations of the "10 * Real Part" and "10 * Imaginary Part" sliders - possibly starting by varying the values shown above slightly - to find other Julia sets that you find interesting. (Note: When experimenting with different values of c, it is sometimes best to use the lowest possible maximum iterations value, so that at least the general shape of the Julia set becomes clear more quickly.)
Notice that some of the examples show Julia sets that are broken up into many separate, disconnected portions. (If we were able to zoom in to any desired scale on these sets, we would see that even regions that look like parts of the filled-in Julia set are collections of individual points, separated by areas which do not have converging sequences.) Julia sets are related to another set, called the "Mandelbrot set". The Mandelbrot set is the set of all c values for which the associated Julia set is connected. As is the case with Julia sets, the boundary of the Mandelbrot set is very complex - and near the boundary (both inside and outside) of the Mandelbrot set is often where the c values give us the most interesting Julia sets (the limits of the "10 * Real Part" and "10 * Imaginary Part" sliders include several points in the neighborhood of the Mandelbrot set boundary). For more information on the Mandelbrot set, and its relationship to Julia sets, see the Wikipedia entry for the Mandelbrot set (http://en.wikipedia.org/wiki/Mandelbrot_set).
THINGS TO TRY
Begin by drawing example 1, with a zoom factor of 0, maximum iterations set to 50, interior color set to 50, and the divergent color set to 99.
Next, set the zoom factor slider to 1, and redraw. Notice the additional detail that is now visible: structures that were hard to see at the larger scale are now apparent - but they are also very similar to structures which were visible before.
Try some of the other examples, to see just a bit of the variety in Julia sets, with different values of c.
Try different values of the color sliders, to see how your choices can reveal or hide some of the details of the Julia set and its boundaries.
Select example 3, and start with a zoom factor of 0, maximum iterations of 100, interior color set to 0, and divergent color set to 39. Next, draw the same set with a zoom factor of 1, then 2. After seeing the results at a zoom factor of 2, increase the maximum iterations to 250. Draw the Julia set again, and see how it changes with the increased accuracy given by increasing the maximum iterations. (To see the difference clearly, it may be necessary to use the File/Export Picture/Patches menu option, to save the Julia set image created with the different iteration limits.) Some of this difference is due to color scaling differences that are a side effect of increasing the iteration limit. however, note that some portions which were black (i.e. identified as part of the filled-in Julia set) with an iteration limit of 100, are now shown in different colors; by setting the iteration limit higher, the sequences starting at these points are given a longer time to diverge - which many of them do.
EXTENDING THE MODEL
Currently, the model scales color linearly, according to the number of iterations before divergence. Of course, there are many other ways we might scale color. For example, we could take the logarithm of the number of iterations, or the inverse of the number of iterations, etc. The result could then be used to select a color on the spectrum between the color used for the interior of the Julia set and the color used for the sequences which exceed the threshold radius in a single iteration. Each of these color mapping schemes would result in different characteristics for the "colored by speed" rendering of the Julia set and the surrounding neighborhood of the complex plane.
Although this model can zoom in (and back out), doing so requires that the Julia set be redrawn from scratch. It should be possible (if a bit complicated) to extend the model so that a zoom in or zoom out could be done without having to clear and redraw the canvas completely. Similarly, it should be possible to "scroll" the view - i.e. to change the center of the view, slide the displayed Julia set accordingly, and draw only those areas which are then uncovered.
STARLOGO FEATURES
The model uses the StarLogo "mouse-down?", "mouse-xcor", and "mouse-ycor" commands to allow the user to set a new drawing center by clicking on the canvas. However, when the user clicks outside the canvas, StarLogo returns mouse-xcor and mouse-ycor as if the click was in the outermoust row or column of the canvas; the model rejects any such values, to ensure that the mouse click actually did happen in the canvas.
Multiple turtles per column are used to draw the Julia set, with each column alternating up/down direction of turtle motion. For this approach to work, a turtle must be able to tell when a patch has already been stamped; but since a patch could have a color from the previous Julia set (and since a patch can be stamped with the color black), the turtle can't simply look at the patch color to know if the patch has been stamped. So, this model declares a patch variable that holds the drawing generation in which the patch was last stamped; if this number is equal to the current generation, the turtle knows that the patch has already been stamped.
The turtle also needs to know if another turtle is currently on the patch and iterating the sequence for that patch; if so, there is no need for the new arrival to do so. This is accomplished by testing the value of "count-turtles-here"; if it is equal to one, then the turtle performing the test knows that it is the only turtle on the patch, and that it should begin the iteration of the sequence for that patch.
RELATED MODELS
As noted above, there is a relationship between Julia sets and the Mandelbrot set. There is a Mandelbrot set model in the models library, with an interface similar to this one.
CREDITS AND REFERENCES
This model was based on the Julia set model in the original StarLogo models library; the current version was executed by Nick Bennett (with suggestions from Irene Lee and Gordon McDonough) in March 2006. The basic algorithm was not changed, though variables were renamed from Spanish to English, and the detection of divergence was changed, to reflect the fact that a sequence with any |z(n)| > max(2, |c|) is guaranteed to diverge. The drawing order was changed - from a single turtle drawing one row, then moving to the next row, etc., to having several turtles per column, all moving vertically. Additional variables and sliders were included, to allow for a greater degree of control over the coloring, scaling, and centering. The example slider was also added, to give quick access to a set of very different Julia sets.
Background information on Julia sets and the Mandelbrot set was obtained from Wikipedia (http://en.wikipedia.org/wiki/Julia_set and http://en.wikipedia.org/wiki/Mandelbrot_set), and "Julia Jewels: An Exploration of Julia Sets" (http://mcgoodwin.net/julia/juliajewels.html), Michael McGoodwin, March 2000.
Turtle procedures
;; Procedure: set-starting-position
;; Called by: draw-julia-set procedure (observer)
;;
;; Hide turtle and position it on an unoccupied patch, in a column determined by
;; the who number.
;;
to set-starting-position
hide-turtle
let [:set (who mod screen-width)]
setheading (180 * (:set mod 2))
loop [
setxy (:set - screen-half-width) (random screen-height)
if (count-turtles-here = 1) [
stop
]
]
end
;; Procedure: draw
;; Called by: draw-julia-set procedure (observer)
;;
;; Get the number of iterations in the sequence that starts with the point in
;; the complex plane corresponding to the current location. Stamp the patch
;; with the color corresponding to the number of iterations. Repeat until the
;; turtle lands on a patch that is already occupied, or which has already been
;; stamped for the current Julia set.
;;
to draw
loop [
let [:iteration-count get-iterations]
ifelse (:iteration-count > max-iterations) [
stamp (base-color + color-width)
] [
stamp (base-color + (:iteration-count - 1) * color-interval)
]
set generation drawing-generation
set iterations :iteration-count
forward 1
if ((generation = drawing-generation) or (count-turtles-here > 1)) [
die
]
]
end
;; Procedure: get-iterations
;; Called by: draw procedure (turtle)
;;
;; Compute the point in the complex plane corresponding to the turtle's X and Y
;; coordinates; use this point as z(0). Iterate z(n+1) = z(n)^2 + c until the
;; threshold radius is exceeded, or until the iteration limit is reached.
;;
to get-iterations
let [:x ((xcor - x-offset) / computed-axis-scale)]
let [:y ((ycor - y-offset) / computed-axis-scale)]
dotimes [:iteration iteration-limit] [
let [:new-x (:x * :x - :y * :y + real-constant)]
let [:new-y (2 * :x * :y + imaginary-constant)]
if ((:new-x * :new-x + :new-y * :new-y) > threshold-radius-squared) [
output :iteration
]
set :x :new-x
set :y :new-y
]
output (max-iterations + 1)
end
Observer procedures
globals [
computed-axis-scale ; Scale for drawing, computed in setup
example-constants ; List of real & imaginary parts of c for examples
real-constant ; Real part of c in z(n+1) = z(n)^2 + c
imaginary-constant ; Coefficient of i in c, in z(n+1) = z(n)^2 + c
x-scaled-center ; X coordinate (in complex plane) of drawing center
y-scaled-center ; Y coordinate (in complex plane) of drawing center
x-offset ; X difference between complex and StarLogo origins
y-offset ; Y difference between complex and StarLogo origins
color-width ; Size of the color range
color-interval ; Difference in color per iteration
base-color ; Starting color
threshold-radius-squared ; Squared distance from origin for divergence
iteration-limit ; Maximum iterations in a sequence
drawing-generation ; Number of times set has been drawn (since clear)
]
patches-own [
iterations ; Iterations for sequence beginning at patch
generation ; Last generation in which patch was painted
]
;; Procedure: Clear
;; Called by: Clear button
;;
;; Clear drawing area, and set generation counter back to zero.
;;
to clear
clear-patches
set drawing-generation 0
end
;; Procedure: draw-julia-set
;; Called by: Draw button
;;
;; Clear turtles, but not globals (we need to keep the values of the X and Y
;; coordinates of the point in the complex plane that is the center of the
;; drawing). Set the value of c based on the example chosen or explicit slider
;; values. Compute the threshold radius, based on c. Compute scale, center, and
;; color values from the sliders. Set iteration limit from max-iterations slider
;; (so changing slider during execution won't have unexpected results). Create
;; turtles, and ask them to draw.
;;
to draw-julia-set
clear-turtles
set example-constants [[-0.8 0] [0 1] [-0.7 0.3] [-1.5 0] [0.3 0]]
set-constant-value
set threshold-radius-squared
(max 4 (real-constant * real-constant
+ imaginary-constant * imaginary-constant))
set computed-axis-scale
((min screen-width screen-height) * (2 ^ axis-scale) / 3)
set x-offset (0 - computed-axis-scale * x-scaled-center)
set y-offset (0 - computed-axis-scale * y-scaled-center)
set base-color divergent-color
set color-width (interior-color - divergent-color)
set color-interval (color-width / max-iterations)
set iteration-limit max-iterations
set drawing-generation (drawing-generation + 1)
create-turtles-and-do (5 * screen-width) [
set-starting-position
draw
]
end
;; Procedure: set-constant-value
;; Called by: draw-julia-set procedure (observer)
;;
;; Set the values of the real and imaginary components of c, based on the
;; example selected, or - if no example was selected - the values set explicitly
;; in the sliders.
;;
to set-constant-value
ifelse (example = 0) [
set real-constant (real-constant-tenth / 10)
set imaginary-constant (imaginary-constant-tenth / 10)
] [
let [:example-point (item example example-constants)]
set real-constant (item 1 :example-point)
set imaginary-constant (item 2 :example-point)
]
end
;; Procedure: set-center
;; Called by: Set button
;;
;; Wait for a mouse click, and - if click location is inside of outer edge of
;; patches (to protect against responding to a click outside of the canvas) -
;; sets the new center (in the complex plane) of the drawing. Wait for a short
;; interval after, to allow monitors to catch up.
;;
to set-center
wait-until [mouse-down?]
let [:click-x mouse-xcor]
let [:click-y mouse-ycor]
if (((abs :click-x) < screen-half-width)
and ((abs :click-y) < screen-half-height)) [
set x-scaled-center ((:click-x - x-offset) / computed-axis-scale)
set y-scaled-center ((:click-y - y-offset) / computed-axis-scale)
]
wait 0.2
end
;; Procedure: set-default-center
;; Called by: Reset button
;;
;; Reset center of drawing to default values. Wait for a short interval after,
;; to allow monitors to catch up.
;;
to set-default-center
set x-scaled-center 0
set y-scaled-center 0
wait 0.2
end
