mandelbrotset

mandelbrotset preview image

1 collaborator

Hobbes286x286 Rik Blok (Author)

Tags

mathematics 

Tagged by Rik Blok over 10 years ago

Visible to everyone | Changeable by everyone
Model was written in NetLogo 5.0.4 • Viewed 579 times • Downloaded 32 times • Run 0 times
Download the 'mandelbrotset' modelDownload this modelEmbed this model

Do you have questions or comments about this model? Ask them here! (You'll first need to log in.)


The Mandelbrot Set

A [NetLogo] model by Rik Blok.

http://www.zoology.ubc.ca/~rikblok/wiki/doku.php?id=science:popmod:mandelbrot_set:start

Explore the Mandelbrot Set and these related fractals:

Mappings

Each fractal is defined by a function in the complex plane. Starting with an initial value z=0, each point c in the plane is repeatedly iterated through the map, z → f(z,c). The mapping function is characterized by an exponent, d (d-multibrot-exp slider in the simulation), as follows:

  • Mandelbrot: f(z,c) = z2 + c (same as Multibrot with d=2)
  • Multibrot: f(z,c) = zd + c
  • Mandelbar: f(z,c) = Conj(z)d + c
  • Burning ship: f(z,c) = (|Re(z)| + i |Im(z)|)d + c

A point c is excluded from the set if the value z diverges after repeated iteration. In the simulation, excluded points are painted a color indicating how many iterations were required to decide they have diverged. Black points indicate undecided candidates that may belong to the set.

Other implementations and examples

This implementation of the Mandelbrot set is neither fast nor beautiful -- it's just a proof of concept and a demonstration of how to code in [NetLogo]. If you're interested in the Mandelbrot set or similar fractals, check out these excellent pages:

Comments and Questions

Please start the discussion about this model! (You'll first need to log in.)

Click to Run Model

globals [ 
  xmin ymin xmax ymax 
  was-mouse-down? was-mouse-xcor was-mouse-ycor
  was-record-mov was-record-png 
  png-file-prefix png-file-index
  was-multibrot-exp was-generalization
  was-going
  tick-last-change
  max-detectable-period
  was-zoom-power
]

patches-own [ x y real imag was-real was-imag]

to startup
  clear-all
  ; defaults
  set record-mov false set was-record-mov false
  set record-png false set was-record-png false
  set was-mouse-down? false
  set was-going false
  set jump-size 25
  set mouse-zooms-in true
  set max-detectable-period 3
  set was-zoom-power 0
  reset
  ; hint
  output-print "Explore the Mandelbrot set\nand related fractals.\nPress go to get started."
end 

to reset
  ; range
  set xmin -2
  set xmax  2
  set ymin -2
  set ymax  2
  zoom
end 

to zoom
  if (movie-status != "No movie.") [ movie-grab-view ]
  if (record-png) [
    export-view ( word png-file-prefix " " was-zoom-power " " png-file-index ".png" ) 
    set png-file-index png-file-index + 1
    set was-zoom-power zoom-power
  ]
  reset-ticks
  set tick-last-change 20 * ticks-per-zoom ; don't auto-zoom for at least 20 ticks-per-zoom if all black
  set was-multibrot-exp d-multibrot-exp
;  set was-conjugate conjugate
  set was-generalization generalization
  let xslope width  / ( max-pxcor - min-pxcor )
  let yslope height / ( max-pycor - min-pycor )
  ask patches [
    set pcolor black 
    set x (pxcor - min-pxcor) * xslope + xmin
    set y (pycor - min-pycor) * yslope + ymin
    set real 0
    set imag 0
    set was-real []
    set was-imag []
  ]
  ask patch max-pxcor 4 [ set plabel zoom-power ]
end 

to go
  ; check for changed parameters
  if (not was-going) [
    output-print "\nDrag the mouse to move or\npress the W/A/S/D keys."
    output-print "Click to zoom or\npress the +/- keys."
    set was-going true
  ]
  if (d-multibrot-exp     != was-multibrot-exp    ) [ 
    zoom 
    output-print "\nChange the multibrot\nexponent d, z->z^d+c."
  ]
  if (generalization != was-generalization) [ 
    zoom 
    output-print "\nChoose a generalization\nof the Mandelbrot set."
  ]
  ; check for changed record switches
  if (record-png and not was-record-png) [
    ; start recording to png
    ifelse (netlogo-applet?) [
      output-print "\nSorry, can't record from applet."
      output-print "Download the .nlogo file to allow recording."
      set png-file-prefix false
    ][
      set png-file-prefix user-new-file
    ]
    ifelse (png-file-prefix != false) [
      ; strip file extension
      set png-file-prefix remove ".PNG" png-file-prefix
      set png-file-prefix remove ".png" png-file-prefix
      set was-record-png true
      set was-zoom-power zoom-power
      output-print "\nStarted recording to png files."
    ][
      ; cancelled
      set record-png false
    ]
  ]
  if (record-mov and not was-record-mov) [
    let mov-file false
    ifelse (netlogo-applet?) [
      output-print "\nSorry, can't record from applet."
      output-print "Download the .nlogo file to allow recording."
    ][
      set mov-file user-new-file
    ]
    ifelse (mov-file != false) [
      ; strip file extension
      set mov-file remove ".MOV" mov-file
      set mov-file remove ".mov" mov-file
      ; add extension
      set mov-file word mov-file ".mov"
      ; start recording to mov
      movie-start mov-file
      set was-record-mov true
      output-print "\nStarted recording to mov file."
    ][
      ; cancelled
      set record-mov false
    ]
  ]
  if (was-record-mov and not record-mov) [
    ; stop recording mov
    if (movie-status != "No movie.") [ movie-close ]
    output-print "\nStopped recording to mov file."
  ]
  ; check for mouse activity
  if (mouse-down? and not was-mouse-down?) [
    ; mouse press
    set was-mouse-down? true
    set was-mouse-xcor mouse-xcor
    set was-mouse-ycor mouse-ycor
  ]
  ; check for auto-zoom
  if (was-mouse-down? and not mouse-down?) [
    ; mouse release
    let xslope width  / ( max-pxcor - min-pxcor )
    let yslope height / ( max-pycor - min-pycor )
    if-else (mouse-xcor = was-mouse-xcor and mouse-ycor = was-mouse-ycor) [
      ; click, zoom centered on mouse
      output-type "\nMouse click: zoom "
      let xc (mouse-xcor - min-pxcor) * xslope + xmin
      let yc (mouse-ycor - min-pycor) * yslope + ymin
      let xrad 0
      let yrad 0
      ifelse mouse-zooms-in [
        set xrad  width  * (1 - jump-size / 100) / 2
        set yrad  height * (1 - jump-size / 100) / 2
        output-type "in "
      ][
        set xrad  width  / (1 - jump-size / 100) / 2
        set yrad  height / (1 - jump-size / 100) / 2
        output-type "out "
      ]
      output-type jump-size output-print "%"
      set xmin xc - xrad
      set xmax xc + xrad
      set ymin yc - yrad
      set ymax yc + yrad
    ][
      ; drag
      output-print "\nMouse drag: move"
      let xshift (was-mouse-xcor - mouse-xcor) * xslope
      let yshift (was-mouse-ycor - mouse-ycor) * yslope
      set xmin xmin + xshift
      set xmax xmax + xshift
      set ymin ymin + yshift
      set ymax ymax + yshift
    ]
    set was-mouse-down? false
    zoom
  ]
  
;  let hue ticks mod 256
;  let sat 255 - 20 * int ( ticks / 256 )
  let slow-ticks 1.25 * ticks ^ 0.8 ; increases slower than ticks for large ticks
  let hue slow-ticks mod 256
  let sat 255 - int ( slow-ticks / 12.8 )
  let conjugate      ( generalization = "Mandelbar, complex conjugate" )
  let absolute-value ( generalization = "Burning ship, absolute value" )
  let changes 0
  ask patches with [pcolor = black] [
    ; iterate z_{n+1} = z_n^2 + (x + i y)
    if (conjugate)      [ set imag ( - imag ) ]
    if (absolute-value) [ set real abs real  set imag abs imag ]
    let oldreal real
    set real x + re-pow real    imag d-multibrot-exp ; Re(z_{n+1}) = x + Re(z_n^multibrot-exp)
    set imag y + im-pow oldreal imag d-multibrot-exp ; Im(z_{n+1}) = x + Im(z_n^multibrot-exp)
    ifelse (real * real + imag * imag) > 4 [ 
      ; diverges
      set pcolor hsb hue sat 255
      set changes changes + 1
    ][
      ; hasn't diverged.  Check if periodic
      let period position real was-real
      ifelse (period != false and period = position imag was-imag) [
        set period period + 1 ; so not zero
        set pcolor rgb period period period
        ; don't track changes here...makes run too long
        ; set changes changes + 1
      ][
        ; not periodic.  Add new (real, imag) to history
        set was-real fput real was-real
        set was-imag fput imag was-imag
        while [length was-real > max-detectable-period] [
          ; trim
          set was-real but-last was-real
          set was-imag but-last was-imag
        ]
      ]
    ]
  ]
  if (changes > 0) [ 
;    if (ticks > tick-last-change + 1) [ print ticks ]
    set tick-last-change ticks
  ]
  tick
end 

to zoom-in
  ; zoom in by factor 1 - jump-size
  let newwidth  width  * (1 - jump-size / 100)
  let newheight height * (1 - jump-size / 100)
  let xcrop ( width  - newwidth  ) / 2
  let ycrop ( height - newheight ) / 2
  set xmin xmin + xcrop
  set xmax xmax - xcrop
  set ymin ymin + ycrop
  set ymax ymax - ycrop
  output-type "\nZoom in " output-type jump-size output-print "%"
  zoom
end 

to zoom-out
  ; zoom in by factor 1 - jump-size
  let newwidth  width  / (1 - jump-size / 100)
  let newheight height / (1 - jump-size / 100)
  let xcrop ( newwidth  - width  ) / 2
  let ycrop ( newheight - height ) / 2
  set xmin xmin - xcrop
  set xmax xmax + xcrop
  set ymin ymin - ycrop
  set ymax ymax + ycrop
  output-type "\nZoom out " output-type jump-size output-print "%"
  zoom
end 

to move-up
  ; shift by jump-size
  let move jump-size / 100 * height
  set ymin ymin + move
  set ymax ymax + move
  output-type "\nMove up " output-type jump-size output-print "%"
  zoom
end 

to move-left
  ; shift by jump-size
  let move jump-size / 100 * width
  set xmin xmin - move
  set xmax xmax - move
  output-type "\nMove left " output-type jump-size output-print "%"
  zoom
end 

to move-down
  ; shift by jump-size
  let move jump-size / 100 * height
  set ymin ymin - move
  set ymax ymax - move
  output-type "\nMove down " output-type jump-size output-print "%"
  zoom
end 

to move-right
  ; shift by jump-size
  let move jump-size / 100 * width
  set xmin xmin + move
  set xmax xmax + move
  output-type "\nMove right " output-type jump-size output-print "%"
  zoom
end 

to-report width
  report xmax - xmin
end 

to-report height
  report ymax - ymin
end 

to toggle-mouse-zoom
  set mouse-zooms-in not mouse-zooms-in
  output-type "\nMouse clicks now zoom " output-print ifelse-value (mouse-zooms-in) [ "in." ][ "out." ]
end 

to-report re-pow [ zr zi d ]
; returns Re(z^d) = Re((zr + i zi)^d) via recursion.  Assumes d>=2 is an integer.
  ifelse (d = 2) [
    ; Re(z^2) = zr^2 - zi^2
    report zr * zr - zi * zi
  ][
    ; Re(z^d) = Re(z z^(d-1)) = zr Re(z^(d-1)) - zi Im(z^(d-1))
    report zr * ( re-pow zr zi (d - 1)) - zi * ( im-pow zr zi (d - 1))
  ]
end 

to-report im-pow [ zr zi d ]
; returns Im(z^d) = Im((zr + i zi)^d) via recursion.  Assumes d>=2 is an integer
  ifelse (d = 2) [
    ; Im(z^2) = 2 zr zi
    report 2.0 * zr * zi
  ][
    ; Im(z^d) = Im(z z^(d-1)) = zi Re(z^(d-1)) + zr Im(d^(n-1))
    report zi * ( re-pow zr zi (d - 1)) + zr * ( im-pow zr zi (d - 1))
  ]
end 

to coords
  ; report coordinates
  output-print "center:"
  output-type  "x = " output-print ( xmin + xmax ) / 2
  output-type  "y = " output-print ( ymin + ymax ) / 2
  let scale xmax - xmin
  output-type  "scale = " output-print ifelse-value (scale <= 0) [ 0 ][ rel-precision scale 2 ]
end 

to-report rel-precision [ number places ]
  ; like precision but only for mantissa
  let pow floor log number 10
;  report ( 10 ^ pow ) * precision ( number / 10 ^ pow ) places
  report ( word precision ( number / 10 ^ pow ) places "E" pow )
end 

to zoom-every
  if (ticks > ( tick-last-change + ticks-per-zoom ) ) [ 
    ifelse mouse-zooms-in [ 
      zoom-in
      output-print "\nAutomatically zoomed in"
    ][
      zoom-out 
      output-print "\nAutomatically zoomed out"
    ]
    output-type "after " output-type ticks-per-zoom output-print " unchanged ticks."
  ]
end 

to-report zoom-power
  report precision ( 0 - log width 10 ) 2
end 

There is only one version of this model, created over 10 years ago by Rik Blok.

Attached files

File Type Description Last updated
mandelbrotset.png preview Preview for 'mandelbrotset' over 10 years ago, by Rik Blok Download

This model does not have any ancestors.

This model does not have any descendants.