Creating the mandelbrot set

For what happened before, consult the Oberon page In short: I wanted to create the mandelbrot pictures. The obc compiler is only black and white and some depth perception with different shades of colours are then essential. And so my x11 module is required. So I ported the obc source to modula-2. Below is the source:

MODULE mand01;

IMPORT	x11, InOut, Arguments, NumConv, RealConv, MathLib;

TYPE	Complex	= RECORD
		    real, imag	: REAL
		  END;

VAR	z, z0, c		: Complex;
	startR, startI, step	: REAL;
	count, n		: CARDINAL;
	Mx, My, task		: INTEGER;
	store			: Arguments.ArgTable;
	colours			: ARRAY [0..19] OF CARDINAL;


PROCEDURE Csq (VAR  z : Complex);

VAR	res	: Complex;

BEGIN
  res.real := z.real * z.real - z.imag * z.imag;
  res.imag := 2.0 * z.real * z.imag;
  z := res
END Csq;


PROCEDURE Cadd (VAR z : Complex;  y : Complex);

VAR	res	: Complex;

BEGIN
  res.real := y.real + z.real;
  res.imag := y.imag + z.imag;
  z := res
END Cadd;


PROCEDURE Csize (VAR z : Complex) : INTEGER;

VAR	len	: INTEGER;

BEGIN
  len := MathLib.entier (z.real * z.real + z.imag * z.imag);
  RETURN len
END Csize;


PROCEDURE Init;

VAR	args	: SHORTCARD;
	ok	: BOOLEAN;

BEGIN
  Arguments.GetArgs (args, store);
  IF  args < 4  THEN
    InOut.WriteString ("Mandel X0 Y0 count step");	InOut.WriteLn;
    startR := -0.71;
    startI := -0.36;
    count := 100;
    step := 40000.0
  ELSE
    startR := RealConv.Str2Real (store^ [1]^, ok);
    startI := RealConv.Str2Real (store^ [2]^, ok);
    NumConv.Str2Num (count, 10, store^ [3]^, ok);
    step := RealConv.Str2Real (store^ [4]^, ok);
    InOut.WriteLn
  END;
  z0.real := 0.0;
  z0.imag := 0.0
END Init;


PROCEDURE build;

VAR	X0, Y0,
	x, y, color	: INTEGER;

BEGIN
  FOR  X0 := 0 TO 799  DO
    x := X0 - 400;
    c.real := startR + MathLib.real (x) / step;
    FOR  Y0 := 499 TO 0 BY -1  DO
      y := Y0 - 250;
      c.imag := startI + MathLib.real (y) / step;
      n := 0;
      z := z0;
      REPEAT
        INC (n);
	Csq (z);
	Cadd (z, c)
      UNTIL  (Csize (z) > 4) OR (n > count);
      IF  n < count  THEN
	x11.setFgC (99 * n);
	x11.Plot (X0, Y0)
      END
    END
  END
END build;


BEGIN
  Init;
  x11.setTitle ("Mandelbrot with Mocka");
  x11.Xinit (800, 500);
  x11.SetFont ("10x20");
  task := x11.NextEvent ();
  build;
  LOOP
    task := x11.NextEvent ();
    IF  task = -1000  THEN
      build
    ELSIF  task < 0  THEN
      task := -task;
      IF  task = ORD ('q')  THEN  EXIT  END
    ELSIF  task > 0  THEN	(* Mouse click!	*)
      Mx := task DIV 10000;
      My := task MOD 10000;
    END
  END;
  x11.Xclose ()
END mand01.
   
Just use the mocka script to compile. Be sure to set the MOCKALINK environment variable to "-lx11" as explained in the x11 section. When done, this is the result. An example commandline is:
./mand01 -0.372 -0.65 25000 70000
The 25000 is some kind of quality factor.

Other colours

The colours are calculated with the 'n' count as input. And there seems to be a favor for smaller n counts. So in the RGB colour system there is a bias for blue. Which is kind of dark. So I added a function to swap the colour parts: mand02:

MODULE mand02;

IMPORT	x11, InOut, Arguments, NumConv, RealConv, MathLib;

TYPE	Complex	= RECORD
		    real, imag	: REAL
		  END;

VAR	z, z0, c		: Complex;
	startR, startI, step	: REAL;
	count, n		: CARDINAL;
	Mx, My, task		: INTEGER;
	store			: Arguments.ArgTable;
	colours			: ARRAY [0..19] OF CARDINAL;


PROCEDURE Csq (VAR  z : Complex);

VAR	res	: Complex;

BEGIN
  res.real := z.real * z.real - z.imag * z.imag;
  res.imag := 2.0 * z.real * z.imag;
  z := res
END Csq;


PROCEDURE Cadd (VAR z : Complex;  y : Complex);

VAR	res	: Complex;

BEGIN
  res.real := y.real + z.real;
  res.imag := y.imag + z.imag;
  z := res
END Cadd;


PROCEDURE Csize (VAR z : Complex) : INTEGER;

VAR	len	: INTEGER;

BEGIN
  len := MathLib.entier (z.real * z.real + z.imag * z.imag);
  RETURN len
END Csize;


PROCEDURE Init;

VAR	args	: SHORTCARD;
	ok	: BOOLEAN;

BEGIN
  Arguments.GetArgs (args, store);
  IF  args < 4  THEN
    InOut.WriteString ("Mandel X0 Y0 count step");	InOut.WriteLn;
    startR := -0.71;
    startI := -0.36;
    count := 100;
    step := 40000.0
  ELSE
    startR := RealConv.Str2Real (store^ [1]^, ok);
    startI := RealConv.Str2Real (store^ [2]^, ok);
    NumConv.Str2Num (count, 10, store^ [3]^, ok);
    step := RealConv.Str2Real (store^ [4]^, ok);
    InOut.WriteLn
  END;
  z0.real := 0.0;
  z0.imag := 0.0
END Init;


PROCEDURE SwapColour (c : INTEGER) : INTEGER;

VAR	R, G, B, res	: INTEGER;

BEGIN
  B := c MOD 256;
  G := (c DIV 256) MOD 256;
  R := c DIV 65536;
  res := 65536 * R + 256 * B + G;
  RETURN res
END SwapColour;


PROCEDURE build;

VAR	X0, Y0,
	x, y, color	: INTEGER;

BEGIN
  FOR  X0 := 0 TO 799  DO
    x := X0 - 400;
    c.real := startR + MathLib.real (x) / step;
    FOR  Y0 := 499 TO 0 BY -1  DO
      y := Y0 - 250;
      c.imag := startI + MathLib.real (y) / step;
      n := 0;
      z := z0;
      REPEAT
        INC (n);
	Csq (z);
	Cadd (z, c)
      UNTIL  (Csize (z) > 4) OR (n > count);
      IF  n < count  THEN
	x11.setFgC (SwapColour (99 * n));
	x11.Plot (X0, Y0)
      END
    END
  END
END build;


BEGIN
  Init;
  x11.setTitle ("Mandelbrot with Mocka");
  x11.Xinit (800, 500);
  x11.SetFont ("10x20");
  task := x11.NextEvent ();
  build;
  LOOP
    task := x11.NextEvent ();
    IF  task = -1000  THEN
      build
    ELSIF  task < 0  THEN
      task := -task;
      IF  task = ORD ('q')  THEN  EXIT  END
    ELSIF  task > 0  THEN	(* Mouse click!	*)
      Mx := task DIV 10000;
      My := task MOD 10000;
    END
  END;
  x11.Xclose ()
END mand02.
   
Resulting in the colours to be RBG instead of RGB. An array with 1000 colours would be best. I'll have to think of a way to generate such an array.

Mand04 : better colours, better resolution

Although the obc Oberon version was quite fast (for a JIT compiled program), it would be no match for these Mocka Mandelbrot searchers. It would take the obc version days on end to calculate]

./mand04 -0.6963047 -0.474999 1000000 10000000000
That is with 1 million colours (and the max count) and stepsize of 1.0EE-10. That is a stepsize of 1 in 10 billion. In order to get this done I had to change all REALs into LONGREALs. It is quite astonishing to see how much influence the iteration count has on picture outputs. The below pictures (which were reduced by 75% in size) show the results for max counts of 500, 1100, 2200, 11000, 22000, 60000, 100000, 400000 and 1000000. One thing: the colours are dynamically calculated so they can not be compared between pictures.

Mand04 : the source

Below is the source code of the new mand04 Mandelbrot searcher. In essence the prgram is not changed a lot. See for yourself.

MODULE mand04;

IMPORT	x11, InOut, Arguments, NumConv, RealConv, MathLib;

TYPE	Complex	= RECORD
		    real, imag	: LONGREAL
		  END;

VAR	z, z0, c		: Complex;
	startR, startI, step	: LONGREAL;
	count, n		: CARDINAL;
	Mx, My, task		: INTEGER;
	store			: Arguments.ArgTable;


PROCEDURE Csq (VAR  z : Complex);

VAR	res	: Complex;

BEGIN
  res.real := z.real * z.real - z.imag * z.imag;
  res.imag := 2.0 * z.real * z.imag;
  z := res
END Csq;


PROCEDURE Cadd (VAR z : Complex;  y : Complex);

VAR	res	: Complex;

BEGIN
  res.real := y.real + z.real;
  res.imag := y.imag + z.imag;
  z := res
END Cadd;


PROCEDURE Csize (VAR z : Complex) : INTEGER;

VAR	len	: INTEGER;

BEGIN
  len := MathLib.entierL (z.real * z.real + z.imag * z.imag);
  RETURN len
END Csize;


PROCEDURE Init;

VAR	args	: SHORTCARD;
	ok	: BOOLEAN;

BEGIN
  Arguments.GetArgs (args, store);
  IF  args < 4  THEN
    InOut.WriteString ("Mandel X0 Y0 count step");	InOut.WriteLn;
    startR := -0.71;
    startI := -0.36;
    count := 100;
    step := 40000.0
  ELSE
    startR := RealConv.Str2LongReal (store^ [1]^, ok);
    startI := RealConv.Str2LongReal (store^ [2]^, ok);
    NumConv.Str2Num (count, 10, store^ [3]^, ok);
    step := RealConv.Str2LongReal (store^ [4]^, ok)
  END;
  z0.real := 0.0;
  z0.imag := 0.0
END Init;


PROCEDURE build;

VAR	X0, Y0,
	x, y, color	: INTEGER;

BEGIN
  FOR  X0 := 0 TO 799  DO
    x := X0 - 400;
    c.real := startR + MathLib.realL (x) / step;
    FOR  Y0 := 499 TO 0 BY -1  DO
      y := 249 - Y0;
      c.imag := startI + MathLib.realL (y) / step;
      n := 0;
      z := z0;
      REPEAT
        INC (n);
	Csq (z);
	Cadd (z, c)
      UNTIL  (Csize (z) > 4) OR (n > count);
      IF  n < count  THEN
	x11.setFgC ((16000000 DIV count) * n);
	x11.Plot (X0, Y0)
      END
    END
  END
END build;


BEGIN
  Init;
  x11.setTitle ("Mandelbrot with Mocka");
  x11.Xinit (800, 500);
  x11.SetFont ("10x20");
  task := x11.NextEvent ();
  build;
  LOOP
    task := x11.NextEvent ();
    IF  task = -1000  THEN
      build
    ELSIF  task < 0  THEN
      task := -task;
      IF  task = ORD ('q')  THEN  EXIT  END
    ELSIF  task > 0  THEN	(* Mouse click!	*)
      Mx := task DIV 10000;
      My := task MOD 10000;
    END
  END;
  x11.Xclose ()
END mand04.
   
The new colour to be plotted is calculated by
x11.setFgC ((16000000 DIV count) * n);
x11 uses 24 bit colours, which is something like 16 million. Almost all colours are now used. The smaller the max count is, the bigger the change between any two colours. I did a test with an array of 6000 colours but that didn't work out satisfactorily. This one, with "the fraction of white" works great.

The commandline for producing the series of images above was:

./mand04 -0.6963047 -0.474999 1000000 10000000000
With 1 million colours, the black spots (the actual Mandelbrot set points) take quite some time to calculate. Perhaps a nex version should not use a 'Complex TYPE' but just a collection of numbers.

Interesting area's

Below is a list with interesting area's to explore:

  1. -0.75 0 100 200
  2. -0.7 -0.27 100000 250000
  3. -0.7 -0.27 100000 2500
  4. -0.7001 -0.27 2500 200000000
  5. -0.6964 -0.4752 4000 1000000
  6. -0.69630 -0.475 5000 250000000
  7. -0.6963048 -0.474999 11000 50000000
  8. -0.6963047 -0.474999 11000 10000000000
  9. -1.5 0 15000 400000000000
  10. -0.3705 -0.649 700000 200000
  11. -0.71 0.3125 100 10000
  12. 0.365 -0.24 100 12000
  13. -0.71 -0.36 100 40000
  14. -0.6735 -0.3615 125 30000
  15. -0.71 0.3125 100 10000

Downloads

Page created 4 November 2018 and