Monday, February 14, 2011

Jiffle meets Mandelbrot

The Jiffle scripting language has been getting some new bells and whistles recently. While the idea is still to keep the language small and simple, by adding a few extra constructs it becomes much more flexible.

Above is the JiffleDemo application showing a script that uses two of these new constructs, scoped variables and loops, to generate a binary image of the Mandelbrot set. Below is the script itself (it is one of the examples distributed with JAI-tools).

The "init" block is where you declare variables that you want to remain in scope throughout processing. Jiffle calls these image-scope variables. Variables declared outside this block are termed pixel-scope, ie. their values are discarded after each pixel is processed. In the Java runtime class that the Jiffle compiler creates, the image-scope variables are class fields while the pixel-scope variables are local to the evaluate method called to process each destination image pixel. The runtime class is also provided with a getter method for the image-scope variables so you can retrieve them after running the script. You could use this, for instance, to count pixels that are in a certain value range.

The script below uses an until-loop (lifted from Ruby) for the iterative calculation. Jiffle also offers a while-loop and I'm musing about adding some kind of for-loop syntax as well.

* An example Jiffle script: draws a binary
* image of the Mandelbrot set. Adapted from
* C code at
* Author: Michael Bedward

/* We declare variables that we want to remain
* in scope between pixels in the 'init' block.
* The functions width() and height() return
* the dimensions of the destination area.
init {
MaxIter = 30;
MinRe = -2.0;
MaxRe = 1.0;
MinIm = -1.2;
MaxIm = MinIm + (MaxRe-MinRe) * height() / width();
Re_scale = (MaxRe-MinRe)/(width()-1);
Im_scale = (MaxIm-MinIm)/(height()-1);

/* Calculations performed for each pixel.
* The functions x() and y() return current
* pixel coordinates.
c_im = MaxIm - y()*Im_scale;
c_re = MinRe + x()*Re_scale;

Z_re = c_re;
Z_im = c_im;

outside = 0;
n = 0;

/* Jiffle has an 'until' loop construct */
until (n >= MaxIter || outside) {
Z_re2 = Z_re*Z_re;
Z_im2 = Z_im*Z_im;
outside = if (Z_re2 + Z_im2 > 4);
Z_im = 2*Z_re*Z_im + c_im;
Z_re = Z_re2 - Z_im2 + c_re;
n++ ;

/* The variable 'result' represents the
* destination image (you can use any name
* you like in your own scripts).
result = outside;

As an aside, I recall using much the same algorithm, though in FORTRAN, to generate Mandelbrot set images on an 80286 PC last century. Some people never change...

1 comment: