Version 27 of Simple Chaos Theory with Tcl

Updated 2005-03-22 21:04:03 by RHS

Chapter 3 of James Gleick's book on chaos (Chaos - Making a New Science, 1987, [L1 ]) discusses how very simple equations can exhibit chaotic behavior when particular parameters are manipulated. The example equation he provides is a model for population growth in a fish pond, which looks like this:

http://jrankin.ath.cx/tclerswiki/equation.png

Meaning that the population for the next iteration (year, month, day, whatever) equals the rate of population growth r multiplied by the current population x multiplied by a term that keeps the population within bounds (e.g. as the population increases, food becomes increasingly scarce and some of our fish die or move to less crowded ponds).

The parameter manipulated is the rate of growth r, and Mr. Gleick discusses in depth what happens to the population as r is increased. He also provides several graphs that show how the fish population oscillates in regular patterns over multiple iterations and eventually becomes chaotic, i.e., no regular pattern is readily apparent.

For a fun exercise, and to help explain these concepts to myself, I scripted this model in Tcl to see if I could get similar results. I also wanted to output the data in such a way that I could import it into Excel to create graphs.

Well, fortunately the math was within my reach so generating the data was easy, and instead of using Excel I was able to use the emu_graph package to generate the graph on the fly.

Here's the script:

 #!/usr/local/ActiveTcl/bin/wish

 # Rate of population growth
 # Nice values 2, 2.75, 3, 3.25, 3.5, 4 (chaos ensues!)
 set r 2.75

 # Starting population
 set x .4
 set init_x $x

 # Number of iterations
 set iterations 50


 for {set i 1} {$i <= $iterations} {incr i} {
     set x [expr $r * $x * [expr 1 - $x]]
     lappend data $i
     lappend data $x
 }

 package require emu_graph
 wm title . "Simple Chaos Theory (r=$r, x=$init_x, $iterations\
         iterations)"

 canvas .c -width 500 -height 300
 pack .c 

 emu_graph::emu_graph graph -canvas .c -width 400 -height 225
 graph data d2 -colour red -points 0 -lines 1 -coords $data

Setting r to 2.75 results in the following graph, where the population oscillates for a while before settling down to a steady state.

http://jrankin.ath.cx/tclerswiki/2.75.png

Setting r to 3.25 results in a regular pattern that oscillates between levels each iteration, known as Period 2.

http://jrankin.ath.cx/tclerswiki/3.25.png

Setting r to 3.5 results in more complex, yet still regular, behavior known as Period 4.

http://jrankin.ath.cx/tclerswiki/3.5.png

Finally, increasing r to 4 results in apparent chaos. However, as Gleick writes, regularities will still appear now and then, only to give way to more chaotic behavior. My impression from the book thus far is that these regularities would not necessarily be visualized in graphs like these, but would be apparent through other means of visualizations (fractals, perhaps?).

http://jrankin.ath.cx/tclerswiki/4.png

Notes:

On my workstation, setting r to anything above 4 results in this error:

 Error in startup script: floating-point value too large to represent
     while executing
 "expr $r * $x * [expr 1 - $x]"

AM This is because then the iterate will grow in size indefinitely. Another chaotic function is presented at The Q function

DKF: The classic way of visualising the Simplified Malthusian fractal is to plot r (on a scatter graph) against the points in the "cycle", running the thing for some number of iterations (perhaps 100?) to let it settle. In general, this produces x points for each value of r, where x is the cycle length. Look out for cycles of length 3...

WJR The above as a Tcl script:

 #!/usr/local/ActiveTcl/bin/wish

 # Rate of population growth
 # Nice values 2, 2.75, 3, 3.25, 3.5, 4 (chaos ensues!)
 set r [list 1 1.25 1.5 1.75 2 2.25 2.5 2.75 3 3.25 3.5 3.75 4]

 # Starting population
 set x .4
 set init_x $x

 # Number of iterations
 set iterations 100

 foreach r_value $r {
     for {set i 1} {$i <= $iterations} {incr i} {
         set x [expr $r_value * $x * [expr 1 - $x]]
         lappend data $r_value
         lappend data $x
     }
 }

 package require emu_graph
 wm title . "Simple Chaos Theory"

 canvas .c -width 500 -height 300
 pack .c

 emu_graph::emu_graph graph -canvas .c -width 400 -height 225
 graph data d2 -colour red -points 1 -lines 0 -coords $data

The results are shown below. Again, as r increases we see the data points split as they alternate between different levels, and eventually become chaotic.

http://jrankin.ath.cx/tclerswiki/r-scatter.png

Lars H: It would probably be better to record values 101-200 than 1-100. What one is interested in in this latter kind of plot are the points on the attractor (set towards which the values of the process are attracted), and the first couple of values are very "tainted" by the (completely irrelevant) $init_x value. Also, to get plots like the ones in Gleick's Chaos (where one can actually see the period-doubling), one would need a much smaller r step size than the 0.25 in the above script.

Concerning the book Chaos, I'd like to share a quaint observation of mine: Next to it (on the science shelf in my home-town library), one finds a book entitled Cosmos (when I first observed this combination, it was a book by George Gamow, but right now it is a book by Stephen Hawking), which is kind of fun considering that Cosmos (at least in Greek mythology) was the direct opposite of Chaos. None of which has anything to do with Tcl, though.


Here's a slightly improved version of the script above:

 #!/usr/local/ActiveTcl/bin/wish

 # Starting population
 set x .4

 # Number of iterations
 set iterations 100

 for {set r_value 1} {$r_value <= 4} {set r_value [expr $r_value + .01]} {
     for {set i 1} {$i <= $iterations} {incr i} {
         set x [expr $r_value * $x * [expr 1 - $x]]
          lappend data $r_value
          lappend data $x
     }
 }

 package require emu_graph
 wm title . "Simple Chaos Theory"

 canvas .c -width 500 -height 300
 pack .c 

 emu_graph::emu_graph graph -canvas .c -width 400 -height 225
 graph data d2 -colour red -points 1 -lines 0 -coords $data

The bifurcations in the resulting graph are much clearer and strongly resemble the graph on page 71 of the Gleick book:

http://jrankin.ath.cx/tclerswiki/r-scatter-2.png

DKF: Is there a way to get emugraph to use real points and not those splodges? For this fractal (and anything else where you're plotted iterated function systems, of which there is an enormous family) pixels are far more appropriate.

WJR: I can't see a way to do it in the package. Maybe another graphing package would allow this. I chose emu_graph because of it's simplicity. Any suggestions?

(pbo): You can type this after display (quick, fast & dirty, with a small shift)

 foreach i [.c find withtag point] {
         foreach {a b c d} [.c coord $i] break
         .c create line $a $b [expr {$a+1}] [expr {$b+1}] -fill blue -tag ppoint
         .c delete $i
 }

By the way, is there a special raison to use a recursive "expr" call? and not using {} braces inside? (the display is then slightly different but keep the spirit of the thing).

Lars H: The recursive expr and lack of braces does indeed look like a waste of clock cycles. Does anyone have an example of how to make these graphs as images instead?

WJR: By all means feel free to make whatever improvements to the code you like, that why it's here. I suspect that the recursive expr is an artifact of earlier versions of the script I was playing with.

RHS To see a pattern in the chaos, change the chart you're drawing from x/t axis to x(n)/x(n+1). Ie, the x position is the current x, and the y position is the previous x. Below is code that does this:

 proc main {} {
    buildGUI

 }

 proc buildGUI {} {
    set ::formula {3 * $x * (1 - $x)}

    canvas .canvas
    frame  .bottombar

    button .bottombar.calc -text "Calculate" \
        -command {doFormula .canvas ::formula}
    label  .bottombar.x    -text "X(t+1) ="
    entry  .bottombar.formula -textvariable ::formula

    pack .bottombar.x -side left -expand false
    pack .bottombar.formula -side left -fill x -expand true
    pack .bottombar.calc -side left -expand false

    pack .canvas .bottombar -side top -fill both -expand true
 }

 proc doFormula {window var} {
    set formula [set $var]

    set width [$window cget -width]
    set height [$window cget -height]


    set x [expr {rand()}]
    .bottombar.calc configure -state disabled
    drawPoints $window $width $height $formula $x 0 10 1000
 }

 proc drawPoints {window width height formula x currCount interval maxCount} {
    for {set i 0} {$i < $interval} {incr i} {
        if { [incr currCount 1] >= $maxCount } {
            .bottombar.calc configure -state normal
            return
        }
        # puts "X=$x"
        set x2 [expr $formula]
        $window create oval [getLine $width $height $x $x2] -width 1 -fill black
        set x $x2
    }

    after idle [list drawPoints $window $width $height \
            $formula $x $currCount $interval $maxCount]
 }

 proc getLine {width height x y} {
    set x2 [set x1 [expr {$x * $width}]]
    set y2 [set y1 [expr {$y * $height}]]
    list $x1 $y1 $x2 $y2

 }

main


[ Category Mathematics | Category Plotting ]