February 22, 2009

Chaos in WPF

feigenbaum_2I’ve been reading up on math lately. Mostly chaos theory and nonlinear dynamics. I still don’t get why they don’t teach stuff like this in school, I might have even found math fun if they had done so, part of the fun of these areas of mathematics are the cool graphics they produce. Everyone knows the Mandelbrot set, but in this post I want to focus more on chaos theory. And to make it interesting for my usual readers lets draw some pictures with WPF

But first some math to scare off all the wanna-be geeks out there. We’re going to have a look at the logistic map.

xn+1 = xnr(1 – xn)

This function was thought up by the mathematician Pierre François Verhulst to model population growth. The function models two things, bigger populations grow faster until they get too big, then growth will be limited by competition for resources. When you look at the function you will see that it’s a non-linear difference equation.

The fun starts when you start playing with r. For small values of r the x will quickly go to zero and stay there. Things get more interesting for r > 1, first x will stabilize on some value. The stable value for x gets bigger as r gets bigger, but for values of r bigger than 3 x will actually start to oscillate, first between 2 values, then between 4 values, then 8 and then the behaviour of x will become chaotic. You can plot this out and you will get a nice fractal-image. If you zoom in on part of the image you will see the same image repeated.

I wanted to see if I could plot this. My previous toy project was done with WinForms but I found drawing pixels a bit cumbersome. This time I wanted to try out WPF. I found that drawing single pixels in WPF is not trivial either but with a little help from the WriteableBitmap component I could access single pixels in a bitmap. I’d like to have a simple panel component that I can reuse for simple toy projects like this so I quickly built a nice BitmapPanel. Here’s the interface definition. The source code for it is included in the project files if you want to see how it works.

   1: public interface IBitmapPanel
   2: {
   3:     int PixelWidth { get; }
   4:     int PixelHeight { get; }
   6:     event Action Redraw;
   8:     void SetPixel(int x, int y, byte color);
   9:     byte GetPixel(int x, int y);
  10: }

You get redraw events every time the panel changes shape. You can retrieve the size of the panel and you can get and set pixels. Simple enough but usable.

I now could put the bitmap panel on a window and build a presenter object around it. The presenter is where all the interesting stuff happens, it looks like this:

   1: public class ChaosPresenter
   2: {
   3:     public IBitmapPanel View { get; set;}
   5:     public void Initialize()
   6:     {
   7:         View.Redraw += RedrawHandler;
   8:     }
  10:     private void RedrawHandler()
  11:     {
  12:         var width = View.PixelWidth;
  14:         for (var i = 0; i < width; i++)
  15:         {
  16:             var factor = i*3f/width + 1;
  17:             Iterate(i, factor);
  18:         }
  19:     }
  21:     void SetPixelScaleY(int x, float y)
  22:     {
  23:         var ycoordinate = (int)((1.0f - y) * View.PixelHeight);
  24:         var index = x + ycoordinate * View.PixelWidth;
  25:         View.SetPixel(x, ycoordinate, (byte)((View.GetPixel(x, ycoordinate) + 0xFF) / 2));
  26:     }
  28:     private void Iterate(int x, float factor)
  29:     {
  30:         var number = .2f;
  32:         for(var i = 0; i < 100; i++)
  33:         {
  34:             number = GetNextIteration(factor, number);
  35:         }
  37:         for(var i = 0; i < 1000; i++)
  38:         {
  39:             SetPixelScaleY(x, number);
  40:             number = GetNextIteration(factor, number);
  41:         }
  42:     }
  44:     private float GetNextIteration(float factor, float value)
  45:     {
  46:         return factor*value*(1f -value);
  47:     }
  48: }

It wraps the IBitmapPanel and redraws the complete diagram every time it resizes. The RedrawHandler is where stuff happens. It maps different values for r between 1 and 4 on the x axis of the bitmap panel and calls Iterate for all those values of r. Iterate starts at x = 0.2 and throws away the first 100 iterations. This allows x to stabilize into the typical behavior for that value of r. Then it iterates through the next 1000 values and plots them.  GetNextIteration is my implementation of the logistic function. You can play with the values in Iterate if you like. By changing the number of iterations on line 32 you can see how quicly x settles in it’s typical behaviour for different values of r for example. I got the image at the start of this post by iterating 10 times before starting to plot. You can see that x settles pretty quick for most values of r, but near r = 1 and r = 3 it takes more iterations for x to settle down.

The executable can be downloaded here: ChaosExecutable.zip (5.43 kb)

And code is available here: Chaos.zip (10.36 kb)

No comments:

Post a Comment