Mandelplot: Mathematical Printer Art

Author(s): Fred Nachbaur
Publication: SyncWare News
Pub Details: SyncWare News v3 n5 (Volume 3, Issue 5)
Date: May-June 1986
Pages: 11-14

The purpose for writing this article is to show you how easily you can get beautiful math-art creations using a minimum of hardware. The program presented is for the ZX81/TS1000 or TS1500, but can readily be extended to virtually any computer ever built.

A few years ago, it seemed that one of the prime uses for line-printers on the early mainframes was the production of Snoopy calendars and Playboy centerfolds. The principle behind “Printer Art” is that different alphabetic characters have different optical densities, depending on the number of dots making up the character. The idea behind printer art is to select characters to give a multi-level grey scale. These characters are then used to make a picture. When viewed from a reasonable distance, the result is a very believable representation of the original picture.

As time went on, and printers became capable of dot-addressed graphics, this original form of printer art began to fall into obscurity. (The exception is the “computer portrait” outfits that frequent shopping malls, charging a couple bucks to dump your picture from a video camera to a dot-matrix printer.) The drawback to the dot-addressed approach is that it is very difficult to get more than a couple different degrees of shading.

Now, with the easy availability of high-quality reducing photocopiers, the original kind of printer art might once again become popular. The images depicted with this article should give you an idea of the potentials. The pictures here were made with a ZX81/TS1000 and 64K RAM, running the simple program shown. The first image was done with the TS2040. So if your 2040 is currently performing service as a book-end, dust it off and put it back onto the active duty roster.

The other picture was done with a Gemini 10 dot-matrix printer and Tasman interface, using the UPD utility published in an earlier issue (see SWN Vol. 2:6-ed.). The constraints of this medium required that the images be reduced considerably more than optimum; in somewhat larger sizes these are both very appealing, almost spectacular.

Mandelbrot Art

Both pictures here are of a mathematical object known as the Mandelbrot set, after Benoit B. Mandelbrot, the developer of the field of Fractal Geometry. I strongly suggest that you read the article on the Mandelbrot set by A. K. Dewdney in Scientific American, August 1985. In addition to an easily understood description of this fascinating mathematical construct, there are several beautiful colour plates of selected “places of interest” around the set.

Mandelbrot art is based on a behavior of “complex numbers” when subjected to an iterative process. Most locations will eventually diverge (increase without bound), but a certain set of points will just bounce around within a finite limit, no matter how many times the iterative process is continued. This group of points is called the Mandelbrot set. Locations near the set are right on the verge of such stability, and provide an unlimited field for exploration and aesthetic enjoyment.

The program here closely follows Dr. Dewdney’s “blueprint,” to make it easy to understand. The idea is to sequentially examine each point (pixel) in a selected region of the complex plane. We start with a complex number (z) and initialize it at zero. This number is squared, and added to the point being examined. This sum becomes the new value of z, and the process is repeated. A count is kept of the number of iterations. If at any time the sum of the squares of the two parts (real and imaginary) of z exceeds 4, we know that the series is about to go screaming off into infinity.

The final value of the count variable then becomes the value assigned to that pixel in an integer array (string array on the ZX/TS machines). If the square of the size does not exceed 4 after a pre-determined large number of iterations, we assume that it lies inside the Mandelbrot set and will never diverge. After this has been repeated for every pixel in the plane, the final result can be plotted.

TS2040 Mandel-Plot
TS2040 Mandel-Plot
Centronics (Gemini) Mandel-Plot
Centronics (Gemini) Mandel-Plot

Plotting is done by assigning a color or grey level to each range of numbers in the “picture” array. The picture therefore graphically represents the degree of stability of each point in the plane. Dark areas are close to stability, with black being the perfect stability of the Mandelbrot set. Lighter areas are increasing unstable, with the lightest shades representing points that “run away” almost immediately.

Exploring the vicinity of the Mandelbrot set can be very addictive. As you may have guessed by now, it is also very time-consuming. (For the computer, that is; all you have to do is let ‘er crank, and check on progress once or twice a day.) The program here evaluates a 192×192 square region, for a total of 36864 (36K) points. As listed, each point may take up to about eight seconds to evaluate; the maximum running time (if the entire picture is inside the Mandelbrot set) is therefore on the order of 82 hours. Typically, pictures as those shown here will take about two days to “develop.” If higher resolution is required, the time required to run will be even greater. To reproduce the resolution of the SciAm article, the run time could be up to 3 months (!) on the ZX81 or TS2068, or a couple weeks on the QL.

Entering the Program

The program listing is for the ZX81/TS1000 and 64K RAM. The 2068 doesn’t quite have enough free memory to run the program as-is; you’ll have to reduce the size of the picture array to, say, 160×160 unless you have additional RAM memory in the dock or elsewhere, or if you figure out how to put part of the data array into the display file. Similarly, 16K T/S machines will require that the picture array be, say, 96×96. (You could break a 192×192 area into four quadrants, and evaluate each one separately.)

   1 REM MANDEL-PLOT FOR TS2040          F.NACHBAUR MAR.86
10 LET MENU=1000
20 GOTO 500
100 FAST
102 IF M<192 AND N<192 THEN GOTO 120
105 PRINT AT 10,0;"ALL DONE.",,,,
110 GOTO MENU+10
120 FOR M=M TO 191
130 FOR N=N TO 191
140 IF INKEY$=CHR$ 118 THEN GOTO 400
150 LET CR=N*GAP+AC
160 LET CI=M*GAP+BC
170 LET ZR=0
180 LET ZI=0
190 LET C=0
200 LET R=ZR*ZR-ZI*ZI+CR
210 LET ZI=2*ZR*ZI+CI
220 LET ZR=R
230 LET SZ=ZR*ZR+ZI*ZI
240 IF SZ>4 THEN GOTO 270
250 LET C=C+1
260 IF C<128 THEN GOTO 200
270 LET P$(M+1,N+1)=CHR$ C
280 NEXT N
290 LET N=0
300 NEXT M
310 GOTO 100
400 CLS
410 PRINT "WORKING ON:",,"ROW ";M,,"COL ";N,,,,"""M"" FOR MENU",,"""ENTER"" TO CONT "
420 PAUSE 4E4
430 IF INKEY$="M" THEN GOTO MENU
440 CLS
450 GOTO 150
500 CLS
510 SLOW
520 PRINT " INPUT CO-ORDS OF SW CORNER OF PROPOSED MANDELBROT PLANE:",,,"A-CORNER (REAL PART)=";
530 INPUT AC
540 PRINT AC,,,"B-CORNER (IMAG PART)=";
550 INPUT BC
560 PRINT BC,,,"LENGTH OF EACH SIDE =";
570 INPUT S
580 PRINT S
590 PRINT ,,"OK?"
600 INPUT Y$
610 IF Y$<>"Y" THEN RUN
620 LET GAP=S/192
630 DIM P$(192,192)
640 LET M=0
650 LET N=0
660 GOSUB 100
1000 CLS
1010 SLOW
1020 PRINT AT 0,0;" MAIN MENU",,,,"1: START A NEW RUN ","2: SAVE CURRENT PROGRAM STATE","3: RESUME CURRENT RUN ","4: PREVIEW",,"5: SET LIMITS",,"6: FINAL HARD COPY "
1030 LET Z$=INKEY$
1040 IF Z$="" THEN GOTO 1030
1060 IF Z$="1" THEN RUN
1070 IF Z$="2" THEN SAVE "MANDELPLO▒"
1080 IF Z$<"3" OR Z$>"6" THEN GOTO MENU
1090 GOSUB MENU*VAL Z$
1100 GOTO MENU
3000 GOTO 100
4000 CLS
4010 PRINT " INPUT MAX. VALUE FOR LIT PIXELS"
4020 INPUT MX
4030 LET M$=CHR$ MX
4040 FAST
4050 CLS
4060 FOR M=1 TO 188 STEP 4.4
4070 LET Y=M/4.4
4080 FOR N=1 TO 189 STEP 4
4090 IF P$(M,N)>M$ THEN PLOT N/4,Y
4100 NEXT N
4110 NEXT M
4120 PAUSE 4E4
4130 RETURN
5000 LET F$=" .*▒▒▒▒▒▒▒▒"
5001 REM SPACE,PERIOD,ASTERISK, GR.3, GR.T, GR.Q, INV.SPACE INV.ASTERISK, INV.SLASH, GR.H, INV.SPACE
5010 DIM A(2,LEN F$)
5020 CLS
5030 PRINT " INPUT MIN/MAX FOR EACH CHAR:",,,"CHARACTER","MIN MAX",,,
5040 FOR I=1 TO LEN F$
5050 PRINT F$(I);
5060 IF F$(I)=" " THEN PRINT "(SPACE)";
5070 INPUT A(1,I)
5080 PRINT ,A(1,I);TAB 22;
5090 INPUT A(2,I)
5100 PRINT A(2,I)
5110 NEXT I
5120 PRINT ,,"OK?"
5130 INPUT Y$
5140 IF Y$="Y" THEN RETURN
5150 GOTO 5000
6000 FAST
6005 FOR I=0 TO 5
6010 FOR N=192 TO 1 STEP -1
6020 FOR J=0 TO 31
6030 LET K=32*I+J
6040 LET A=CODE P$(N,K+1)
6050 FOR L=1 TO LEN F$
6060 IF A>=A(1,L) AND A<=A(2,L) THEN GOTO 6100
6070 NEXT L
6075 SLOW
6080 PRINT ,,"RANGING ERROR"
6090 GOTO 5130
6100 LPRINT F$(L);
6110 NEXT J
6120 NEXT N
6130 LPRINT
6140 LPRINT "--------------------------------"
6150 LPRINT
6160 NEXT I
6170 RETURN

When entering RUN, you are taken to the main menu. Press “1” to start out. Enter the co-ordinates of the “southwest” corner of the area to be examined, and the length of each side. After verifying your data, the program will start crunching away. To see how far along you are, hold the ENTER key; you’ll get a report of the row and column currently being worked on. Press “M” to go to the menu, any other key to continue crunching.

You might want to return to the menu to SAVE what you have so far to tape using option 3. (This will be handy if you have only one machine, and use it to do Mandelbrot work while you sleep, work, eat, etc.) You can return to the project by pressing “2” from the menu.

Line 260 specifies the maximum number of iterations before the program “gives up” and assumes that the point is inside the Mandelbrot set. The number shown (128) is, by my experience, quite adequate for low to medium magnifications. For higher magnifications (length of side < .001 or so) you will have to increase this to avoid loss of detail. If you increase this beyond 255, you’ll have to scale the result before placing it into the picture array; for example, if your maximum is 1000, you’ll have to change line 270 to read LET P$(M+1,N+1)=CHR$ (C/4)

Option 4 gives you a rough idea of how your picture turned out, and is helpful in determining the limits for your final plot. You are asked to enter the maximum number for “lit” pixels; any locations that took more iterations than this will be plotted black. This is sort of a “bare-bones” subroutine; you’ll probably want to be able to specify a starting range as well to get a better idea of your ranges (hint: see line 6060). Better yet, write a frequency histogram routine that plots the relative frequency of occurrence of each number.

Option 5 sets the range of numbers assigned to each character representing the various grey scale levels. Line 5000 defines the characters, starting with the lightest (space) and ending with the darkest (inverse space). Feel free to change them, add more levels, etc. Choosing ranges is a matter of taste, experimentation, and experience.

Option 6 prints out your final result. As shown for the TS2040, the picture is printed in six vertical panels, which you then paste side-by-side and take to the local photocopy shop for reduction. If you use a “big” printer and UPD (or other driver), the alternate listing might help. In this case, since 64 columns are possible, the job can be done in three panels.

Mandel-Plot Modified Listing for Gemini & Universal Printer Driver

   1 REM MANDEL-PLOT FOR U.P.D.          F.NACHBAUR MAR.86
5 LET LPR1=(YOUR USR ADDRESS)
6 LET LPR3=(YOUR USR ADDRESS)
5000 LET F$=" '.:x%▒*#▒▒▒"
6000 FAST
6001 REM SET 1/12" SPACING. THEN ENHANCED + DOUBLESTRIKE
6002 LET A$= CHR$ 27+ CHR$ 51+ CHR$ 12+ CHR$ 27+ CHR$ 69+ CHR$ 27+ CHR$ 71+ CHR$ 10+ CHR$ 13
6003 RAND CODE "A"
6004 IF USR LPR3 THEN
6005 FOR I=0 TO 2
6010 FOR N=192 TO 1 STEP -1
6015 LET A$=""
6020 FOR J=0 TO 63
6030 LET K=64*I+J
6040 LET A= CODE P$(N,K+1)
6050 FOR L=1 TO LEN F$
6060 IF A >= A(1,L) AND A <= A(2,L) THEN GOTO 6100
6070 NEXT L
6075 SLOW
6080 PRINT ,,"RANGING ERROR"
6090 GOTO 5130
6100 LET A$=A$+F$(L)
6110 NEXT J
6111 REM FOR UPD V1.02 ADD 6112
6112 REM LET A$=A$+ CHR$ 118
6115 IF USR LPR1 THEN
6120 NEXT N
6125 PAUSE 4E4
6130 FOR N=1 TO 5
6140 IF USR LPR1 THEN
6150 NEXT N
6160 NEXT I
6170 RETURN

Should you wish to duplicate the pictures shown, here are the parameters I used to create them:

1: TS2040 PICTURE
   A-Corner = -2
   B-Corner = -1.25
   Side = 2.5
   RANGES: (10 levels):
   0-0 : 1-1 : 2-2 : 3-3 : 4-4 :
   5-5 : 6-14 : 15-29 : 30-127 : 128-128

2: GEMINI-10 PICTURE
   A-Corner = .268
   B-Corner = .00375
   Side = .00172
   RANGES (12 levels):
   0-23 : 24-25 : 26-42 : 43-47 : 48-57 : 58-68 :
   69-81 : 82-92 : 93-104 : 105-114 : 115-127 : 128-128

Here are a couple other areas you might find interesting:

3: A-Corner = .26
   B-Corner = -.0042708333
   Side = .01
   Suggested Ranges (12 levels):
   19-20 : 21-21 : 22-22 : 23-23 : 24-24 : 25-25 :
   26-28 : 29-35 : 36-50 : 51-75 : 76-127 : 128-128

4: A-Corner = -.0721875
   B-Corner = .96354167
   Side = 0.17
   Suggested Ranges (12 levels):
   3-4 : 5-5 : 6-6 : 7-7 : 8-8 : 9-10 :
   11-13 : 14-16 : 17-25 : 26-50 : 51-127 : 128-128

Note: Type-in program listings on this website use ZMAKEBAS notation for graphics characters.