|
|
1.1 ! root 1: .so ../ADM/mac ! 2: .XX anim 451 "A System for Algorithm Animation" ! 3: .EQ ! 4: delim @@ ! 5: .EN ! 6: .nr dP 1 ! 7: .nr dV 1 ! 8: .nr dT 8 \" tab stops this far apart in .P1/.P2 ! 9: .nr NH .5v \" adds extra space before NH or SH heading ! 10: .nr ds .5i \" default indent for programs ! 11: .hy 14 \" set hyphenation: 2=not last lines; 4= no -xx; 8=no xx- ! 12: .\" ! 13: .de IN \" assumes called as .INCLUDE filename ! 14: .sy compile \\$2.t ! 15: .so \\$2.o ! 16: .. ! 17: .de ge \" assumes .ge called as .get ! 18: .sy trget \\n(.$ \\$2 '\\$3' '\\$4' '\\$5' >junk.\\n($$ ! 19: .so junk.\\n($$ ! 20: .sy rm junk.\\n($$ ! 21: .. ! 22: .de ru \" assumes .ru called as .run ! 23: .sy \\$2 \\$3 \\$4 \\$5 \\$6 \\$7 \\$8 \\$9 >junk1.\\n($$ ! 24: .get junk1.\\n($$ ! 25: .sy rm junk1.\\n($$ ! 26: .. ! 27: .TL ! 28: A System for Algorithm Animation ! 29: .br ! 30: Tutorial and User Manual ! 31: .AU ! 32: Jon L. Bentley ! 33: Brian W. Kernighan ! 34: .AI ! 35: .MH ! 36: .AB ! 37: A program or an algorithm can be animated by a movie ! 38: that graphically represents its dynamic execution. ! 39: For instance, a memory allocator might be animated by lines that ! 40: appear when memory is allocated and disappear when it is freed; ! 41: a sort might be animated by a randomly scrambled ! 42: sequence of lines being permuted into order. ! 43: Such animations are useful for debugging programs, for developing ! 44: new programs, and for communicating information about how programs work. ! 45: This paper describes a basic system for algorithm animation: ! 46: the output is crude, but the system is easy to use; ! 47: novice users can animate a program in a couple of hours. ! 48: The system currently produces movies on Teletype 5620 terminals ! 49: and workstations that support the X window system, and also renders movies into ! 50: ``stills'' that can be included in ! 51: .I troff ! 52: documents. ! 53: This paper is a user manual and a tutorial introduction ! 54: to algorithm animation using the system. ! 55: .AE ! 56: .NH ! 57: Introduction ! 58: .PP ! 59: Dynamic displays are better than static displays for ! 60: giving insight into the behavior of dynamic systems. ! 61: The pictures in Figure 1, for instance, illustrate four ! 62: equal-mass bodies moving in the plane ! 63: under Newtonian attraction. ! 64: .KF ! 65: .INCLUDE stars ! 66: .sp ! 67: .ce ! 68: \f3Figure 1:\fP Bodies moving under Newtonian attraction ! 69: .KE ! 70: Time marches across the pictures left to right, ! 71: at roughly equal intervals. ! 72: Each column, called a ! 73: .I snapshot , ! 74: depicts three ! 75: .I views ! 76: of the bodies. ! 77: The top view gives the current position as a dot; the tail formed ! 78: by the last few positions hints at the velocity and the acceleration. ! 79: The middle view renders the path of each body as a line. ! 80: The bottom view depicts the history of velocities by dots ! 81: recorded at equal time intervals: ! 82: low velocities give close dots and ! 83: high velocities leave the dots far apart. ! 84: .PP ! 85: The first snapshot shows the bodies starting slowly, far apart. ! 86: In the second snapshot they have recently experienced a ! 87: high-velocity encounter near the center. ! 88: In the third snapshot the bodies are again far apart, ! 89: moving slowly toward another encounter in the fourth snapshot. ! 90: In the fifth snapshot the large time-step of our simulation program ! 91: violates conservation of energy and sends the bodies racing away ! 92: from each other. ! 93: .PP ! 94: This paper describes the animation system that produced those pictures. ! 95: A sixty-line C simulation program was augmented with eight ! 96: .I printf ! 97: statements to generate a ! 98: .I script ! 99: file describing the paths of the four bodies in the three views. ! 100: That file was processed by a program named ! 101: .I stills ! 102: to produce the pictures above, using ! 103: .I pic ! 104: and ! 105: .I troff ; ! 106: we were able to control what frames were displayed, in what size and form. ! 107: A program named ! 108: .I movie ! 109: displays the same data on a Teletype 5620 terminal or an X workstation; ! 110: the viewer can control the speed of display, ! 111: proceed forward or backward through time, ! 112: and change the screen layout to emphasize certain views. ! 113: Those components can be depicted as: ! 114: .PS ! 115: boxht = .25; boxwid = .6 ! 116: ellipseht = .25; ellipsewid = .6 ! 117: lineht = .1; linewid = .4 ! 118: down ! 119: box "generator" ! 120: line down ! 121: A: ellipse "script" ! 122: line from A.se right down ! 123: box "stills" ! 124: line down ! 125: box invis "pic | troff | ..." ! 126: line from A.sw left down ! 127: box "movie" ! 128: line down ! 129: box invis "5620, X, ..." ! 130: .PE ! 131: .PP ! 132: Several systems have been developed for algorithm animation ! 133: |reference(sedgewick brown ieee). ! 134: Most of those systems produce animations of very high quality; ! 135: unfortunately, they are expensive in both programmer time and CPU time. ! 136: Our system is at the opposite end of the spectrum: ! 137: its output is primitive, but the system is easy to use; ! 138: a new user can animate a simple program ! 139: in an hour or two by adding a few lines of code. ! 140: Although our system was designed primarily with program animation ! 141: in mind, the gravitational example shows that it can be useful ! 142: in other domains as well. ! 143: .PP ! 144: Section 2 introduces the system by animating a sorting algorithm. ! 145: Sections 3 through 5 describe the three primary components of ! 146: the system: ! 147: script ! 148: files, ! 149: .I movie , ! 150: and ! 151: .I stills . ! 152: Section 6 describes the animation of several larger programs, ! 153: and Section 7 discusses a few everyday matters about using the system. ! 154: .NH ! 155: A Simple Example \(em Sorting ! 156: .PP ! 157: Insertion sort is the method most card players use. ! 158: As each card is dealt, it is inserted into ! 159: its proper place among the existing cards. ! 160: To sort the array @X[1..N]@, insertion sort maintains the ! 161: sorted subset in @X[1..I]@ and increases @I@ from 2 to @N@. ! 162: The subarray @X[1..1]@ is sorted by definition. ! 163: The first phase of the algorithm sifts @X[2]@ down ! 164: so that @X[1..2]@ is sorted, the second phase sifts ! 165: @X[3]@ down so that @X[1..3]@ is sorted, and so on. ! 166: .PP ! 167: Here is an implementation of insertion sort in ! 168: .I awk |reference(awk book): ! 169: .P1 ! 170: .get is.awk ! 171: .P2 ! 172: The first ! 173: .CW for ! 174: statement sprinkles ! 175: .CW x[1..n] ! 176: with random integers in the range @1..25@, and the second and third ! 177: .CW for ! 178: statements perform the insertion sort. ! 179: The function ! 180: .CW swap ! 181: exchanges array elements; ! 182: .CW show ! 183: prints the current state of the array. ! 184: .PP ! 185: If we run this program with ! 186: .CW n ! 187: set to 7, we get this static display ! 188: of sorting a 7-element array of random integers: ! 189: .P1 ! 190: .run sh is.awk 7 ! 191: .P2 ! 192: .PP ! 193: The animation system provides an alternative: ! 194: by adding a few more ! 195: .CW print ! 196: statements to the program, we can produce input for the animation system, ! 197: thus providing a dynamic display ! 198: of the sorting process. ! 199: Furthermore, we can use graphics as well as text, ! 200: to give a more visual presentation of the algorithm. ! 201: .PP ! 202: For this example, we decided to present two ! 203: views. ! 204: The top view simply shows the numbers in the array as they are sorted; ! 205: it is essentially the same as the textual output above, ! 206: except that we have added a vertical bar: ! 207: elements to the left of the bar are in order. ! 208: The bottom view is graphical: the value of each element is represented ! 209: by the length of the corresponding vertical line. ! 210: .PP ! 211: These six snapshots ! 212: show the state after each phase of the sorting algorithm: ! 213: .sy make.sorts ! 214: .INCLUDE is3 ! 215: .PP ! 216: Although the two views represent the same information, ! 217: they are useful for different tasks. ! 218: The textual nature of the top view is easier for novices to follow, ! 219: and the complete information is handy for debugging small examples. ! 220: The more visual bottom view is better for displaying large sorts. ! 221: .sp 1 ! 222: .LP ! 223: .I "The Program." ! 224: .PP ! 225: Here is the complete ! 226: .I awk ! 227: program ! 228: .CW is.gen ! 229: that generated the animation depicted above. ! 230: .P1 ! 231: .get is.gen ! 232: .P2 ! 233: It is very similar to the first version, ! 234: but we have added the functions ! 235: .CW less ! 236: to make comparisons and ! 237: .CW draw ! 238: to display elements, ! 239: as well as several ! 240: .CW print ! 241: statements. ! 242: In addition to performing their sorting functions, ! 243: .CW less ! 244: and ! 245: .CW swap ! 246: record their actions by printing output ! 247: into a script file that will serve as input to ! 248: .I movie ! 249: and ! 250: .I stills . ! 251: This animation uses four commands: ! 252: .CW line , ! 253: .CW text , ! 254: .CW view ! 255: and ! 256: .CW click . ! 257: .PP ! 258: A line from @( x sub 1 , y sub 1 )@ to @( x sub 2 , y sub 2 )@ is ! 259: drawn by a command of the form ! 260: .P1 ! 261: @optional_label:@ line @x sub 1@ @y sub 1@ @x sub 2@ @y sub 2@ ! 262: .P2 ! 263: (Throughout this paper, literals are shown in ! 264: .CW typewriter ! 265: font and categories are in @italics@.) ! 266: The coordinates of the line can lie in any range; ! 267: later programs will scale them appropriately. ! 268: The label on a line is optional. ! 269: When a labeled object is drawn ! 270: the object that previously had that label is erased. ! 271: Thus for all lines that have the same label, ! 272: the act of drawing one line erases its predecessor. ! 273: (There is also an explicit ! 274: .CW erase ! 275: command.) ! 276: .PP ! 277: Text is produced at @( x , y )@ by a command of the form ! 278: .P1 ! 279: @optional_label:@ text @x@ @y@ @anything@ @at@ @all@ ! 280: .P2 ! 281: As with lines, labels are permitted; ! 282: re-use of a label erases whatever object previously had that label. ! 283: For example, the vertical bar is always printed with the label ! 284: .CW bar , ! 285: so each bar erases the previous one. ! 286: .PP ! 287: The ! 288: .CW view ! 289: command is used to place output in a particular view. ! 290: There are two views here, ! 291: .CW text ! 292: and ! 293: .CW geom : ! 294: .P1 ! 295: view text ! 296: view geom ! 297: .P2 ! 298: The ! 299: .CW draw ! 300: function draws text in the ! 301: .CW text ! 302: view ! 303: and lines in the ! 304: .CW geom ! 305: view, relying on implicit erasure to remove the previous object ! 306: before creating a new one. ! 307: Different views are independent, so a label like ! 308: .CW a1 ! 309: can be used in several views without interference. ! 310: .PP ! 311: Interesting events are marked by the ! 312: .CW click ! 313: command: ! 314: .P1 ! 315: click swap ! 316: click comp ! 317: click phase ! 318: .P2 ! 319: .I Stills ! 320: and ! 321: .I movie ! 322: can refer to each click with this mechanism, ! 323: as we will see in more detail shortly. ! 324: .PP ! 325: Labels, view names and click names are arbitrary ! 326: and unrelated to one another. ! 327: .sp 1 ! 328: .LP ! 329: .I "The Script File." ! 330: .PP ! 331: Executing the command ! 332: .P1 ! 333: is.gen 3 >is1.s ! 334: .P2 ! 335: produces the script file ! 336: .CW is1.s ! 337: containing a sort of three elements. ! 338: The basename ! 339: .CW is1 ! 340: is for ``insertion sort 1''; the suffix ! 341: .CW .s ! 342: identifies it as a script file and is required by the animation system. ! 343: Here is ! 344: .CW is1.s , ! 345: printed in two columns to save space: ! 346: .P1 ! 347: .ps 8 ! 348: .vs 8 ! 349: .ta 3i ! 350: .run 2col is1.s ! 351: .P2 ! 352: .sp ! 353: .PP ! 354: Here is a picture of all clicks in the script file ! 355: .CW is1.s , ! 356: produced by ! 357: .I stills . ! 358: .INCLUDE is1 ! 359: As before, time goes from left to right. ! 360: Both views of the current state are depicted in a snapshot at each ! 361: .CW click ; ! 362: the label below each frame tells the name and number of the click. ! 363: This detailed picture illustrates the animation system; ! 364: here is a sparser picture that illustrates insertion sort ! 365: on a 14-element array: ! 366: .INCLUDE is2 ! 367: .sp 1 ! 368: .LP ! 369: .I "Making Stills." ! 370: .PP ! 371: The last picture was included in this document by this ! 372: .I stills ! 373: description: ! 374: .P1 ! 375: .get is2.t ! 376: .P2 ! 377: The description is delimited by the lines ! 378: .CW "\&.begin stills" ! 379: and ! 380: .CW \&.end ! 381: (which correspond, for instance, to ! 382: .CW \&.EQ ! 383: and ! 384: .CW \&.EN ! 385: in ! 386: .CW eqn ! 387: or ! 388: .CW \&.TS ! 389: and ! 390: .CW \&.TE ! 391: in ! 392: .CW tbl ). ! 393: Text following the sharp character ! 394: .CW # ! 395: is a comment to be ignored. ! 396: The ! 397: .CW view ! 398: statements specify the empty string as the title for both ! 399: views of the data. ! 400: The ! 401: .CW print ! 402: statement displays snapshots at the requested ! 403: .CW click s ! 404: of ! 405: .CW phase . ! 406: .PP ! 407: The last four statements are parameter assignments of the form ! 408: .P1 ! 409: @parameter_name@ @value@ ! 410: .P2 ! 411: Assignment to the ! 412: .CW file ! 413: parameter names the script file to be displayed. ! 414: The next two assignments set the height and width of frames, ! 415: and the final statement causes ! 416: .CW medium ! 417: text (the default text size) to be set ! 418: five points smaller than the current ! 419: .I troff ! 420: point size. ! 421: .sp 1 ! 422: .LP ! 423: .I "Viewing A Movie." ! 424: .PP ! 425: To watch a movie on the 5620, ! 426: make a window of suitable size and shape ! 427: and in it type the command ! 428: .P1 ! 429: is.gen 20 | movie ! 430: .P2 ! 431: If you want to access the script later, type instead ! 432: .P1 ! 433: is.gen 20 >is.s ! 434: movie is.s ! 435: .P2 ! 436: After a pause to run ! 437: .CW is.gen ! 438: (about 15 seconds on a VAX\(tm-750 in this case), the 5620 down-loading procedure ! 439: will begin; ! 440: after that (another 30 seconds), the data for the movie itself will ! 441: begin to appear. ! 442: When this is finished (also about 30 seconds), ! 443: a message about the number of bytes ! 444: sent (about 9500) appears in the upper left corner. ! 445: .PP ! 446: At this point, the mouse buttons can be used to ! 447: redisplay the movie. ! 448: Button 3 is the main control. ! 449: It has 9 menu items: ! 450: .P1 ! 451: again ! 452: faster 1 ! 453: slower 1 ! 454: 1 step ! 455: backward ! 456: fatter 1 ! 457: thinner 1 ! 458: or mode ! 459: new file ! 460: Quit? ! 461: .P2 ! 462: To play the movie again, ! 463: select ! 464: .CW again . ! 465: (This movie takes about 6 seconds at full speed.) ! 466: You can stop it at any point by pushing any button; ! 467: a further push of button 1 continues it. ! 468: To slow the display, select ! 469: .CW slower ; ! 470: each selection halves the speed by increasing ! 471: a wait interval by a factor of two. ! 472: After three selections the menu reads ! 473: .P1 ! 474: again ! 475: faster 8 ! 476: slower 8 ! 477: \&... ! 478: .P2 ! 479: Try selecting ! 480: .CW again ! 481: to see the sort once at this speed, then select ! 482: .CW faster ! 483: three times to get back to full speed. ! 484: .PP ! 485: The items labeled ! 486: .CW fatter ! 487: and ! 488: .CW thinner ! 489: control the thickness of lines in an analogous manner. ! 490: Selecting ! 491: .CW fatter ! 492: several times results in obese lines; ! 493: you may return things to normal with ! 494: .CW thinner . ! 495: .PP ! 496: Three menu items control binary mode settings: ! 497: .CW 1 ! 498: .CW step ! 499: or ! 500: .CW run ; ! 501: .CW backward ! 502: or ! 503: .CW forward ; ! 504: and ! 505: .CW or ! 506: .CW mode ! 507: or ! 508: .CW xor ! 509: .CW mode . ! 510: For each, the label indicates the next state, ! 511: not the current state. ! 512: .PP ! 513: Normally the movie is played from beginning to end without pause. ! 514: The menu item labeled ! 515: .CW 1 ! 516: .CW step ! 517: puts it into a mode where it displays only one ``step'' ! 518: each time button 1 is pushed. ! 519: This allows you to inspect the sort a frame at a time. ! 520: This item changes to ! 521: .CW run ! 522: when ! 523: .CW 1 ! 524: .CW step ! 525: has been selected ! 526: so you can revert to continuous action. ! 527: .PP ! 528: The ! 529: .CW backward ! 530: item causes the steps to be taken in reverse order (time runs backwards); ! 531: the menu item changes to ! 532: .CW forward ! 533: when selected. ! 534: After the sort ends, select ! 535: .CW backward ! 536: and ! 537: .CW again ! 538: and watch the array scramble itself before your very eyes. ! 539: Judicious use of ! 540: .CW 1 ! 541: .CW step ! 542: and ! 543: .CW backward ! 544: and ! 545: .CW forward ! 546: make it easy to examine a few snapshots in detail. ! 547: .PP ! 548: Normally items are displayed in ``exclusive OR'' mode, ! 549: which means that a bit drawn over a previous one erases it. ! 550: If you are drawing numerous objects in a crowded area, ! 551: this can lead to unintended erasures. ! 552: The ! 553: .CW or ! 554: .CW mode ! 555: item switches to ``inclusive OR'' for drawing objects, ! 556: and erases objects by clearing. ! 557: Some movies are far better in one mode than the other. ! 558: .PP ! 559: The ! 560: .CW new ! 561: .CW file ! 562: item allows one to view a new movie without having to reload the ! 563: .I movie ! 564: program into the 5620. ! 565: We'll see how it works in Section 4. ! 566: .PP ! 567: The ! 568: .CW Quit? ! 569: menu item is the way to exit. ! 570: If selected, it displays a skull and crossbones ! 571: to warn that its effect is irreversible. ! 572: Pushing button 3 again exits; ! 573: a different button avoids quitting. ! 574: .PP ! 575: Button 2 contains menu items to control the size and shape ! 576: of the views on the screen and to control the meaning of a ! 577: ``step'' in 1-step mode. ! 578: For this sorting movie, button 2 looks like: ! 579: .P1 ! 580: view text ! 581: view geom ! 582: click comp ! 583: click swap ! 584: click phase ! 585: .P2 ! 586: When a view is selected, you can sweep a rectangle ! 587: in which that view is to be displayed; ! 588: the use is exactly like the ! 589: .CW New ! 590: menu item in ! 591: .I mux . ! 592: You can arrange the views any way you like; ! 593: try deleting the textual view by sweeping its rectangle out of the window. ! 594: .PP ! 595: When a ! 596: .CW click ! 597: is selected, 1-stepping proceeds to the next ! 598: occurrence of that click. ! 599: So, for example, to see swaps one at a time, ! 600: select ! 601: .CW click ! 602: .CW swap ! 603: on button 2 then select ! 604: .CW 1 ! 605: .CW step ! 606: on button 3. ! 607: Each hit of button 1 will pause at the next ! 608: .CW click ! 609: .CW swap ! 610: statement in the script file, in either ! 611: .CW forward ! 612: and ! 613: .CW backward ! 614: mode. ! 615: .PP ! 616: Multiple clicks may be selected. ! 617: Selecting both ! 618: .CW click ! 619: .CW comp ! 620: and ! 621: .CW click ! 622: .CW swap ! 623: will cause a pause after every comparison and every swap. ! 624: Selected clicks are marked with an asterisk in the menu; ! 625: selecting a click that already has an asterisk ! 626: removes the asterisk and turns off the click. ! 627: .PP ! 628: In ! 629: .CW run ! 630: mode, the movie runs at full speed until it encounters a selected click, ! 631: then pauses for a time proportional to the selected speed. ! 632: Selecting no clicks is equivalent to having selected an implicit ! 633: click that occurs after each geometric object ! 634: (text, line, circle, rectangle) ! 635: is drawn or erased, ! 636: so animations run faster when some clicks are turned on (with ! 637: .CW click ! 638: .CW phase ! 639: selected, for instance, the sorting movie runs nearly twice as fast). ! 640: .sp 1 ! 641: .LP ! 642: .I "Summary." ! 643: .PP ! 644: This exercise illustrates the capabilities ! 645: and limitations of our animation system. ! 646: The output of ! 647: .I movie ! 648: is a crude but useful animation. ! 649: The output of ! 650: .I stills ! 651: is handy for more detailed study and for presentation in documents ! 652: (we would like to include a movie in this document, for instance, ! 653: but paper is easier to distribute than videotape). ! 654: A sophisticated animation system might require 500 lines of ! 655: code to produce beautiful animations of insertion sort. ! 656: Our output is unpolished by comparison, but it is adequate ! 657: for many purposes and requires just a few dozen lines. ! 658: .PP ! 659: If our system is so crude, why bother using it? ! 660: Why not animate an algorithm simply by drawing geometric objects ! 661: on the output device you happen to be using? ! 662: Some of the answer lies in extra services like these: ! 663: .IP ! 664: .I "Device Independence." ! 665: A script file can be rendered as a movie on a 5620 or an X11 workstation; ! 666: the system is designed to make it easy to port to additional ! 667: output devices. ! 668: The same script file can be incorporated into a document by ! 669: .I stills . ! 670: .IP ! 671: .I "Names." ! 672: Labels allow geometric objects to be erased; ! 673: implicit erasure by re-using a label avoids ! 674: much of the tedium of bookkeeping. ! 675: Click names mark key events; ! 676: they can be used to group related events. ! 677: .IP ! 678: .I "Independent Views." ! 679: Different simultaneous views of a process ! 680: are crucial for animating algorithms. ! 681: In our system, a single statement moves from one view to another. ! 682: Within a view, the user need not be ! 683: concerned about the range of coordinates; ! 684: the system scales automatically. ! 685: Labels in different views are independent. ! 686: .IP ! 687: .I "Viewer Control." ! 688: Both ! 689: .I movie ! 690: and ! 691: .I stills ! 692: allow the viewer to select which views will be displayed ! 693: and which clicks will be recognized. ! 694: Additionally, ! 695: .I movie ! 696: allows the viewer to go forward or backward, in single ! 697: steps or running at a selected speed. ! 698: .IP ! 699: .I "An Interface To The World." ! 700: Although writing to files takes more computer time than using the ! 701: geometric primitives provided by a specific output device, ! 702: we will soon see how those files allow complicated tasks ! 703: to be easily composed out of simple software tools. ! 704: .LP ! 705: Our system does not support interactive animations, however: ! 706: once the script has been generated, ! 707: there's no way to change it ! 708: except to generate it again. ! 709: .NH ! 710: The Script Language ! 711: .PP ! 712: This section is a more complete description of the ! 713: script language in which animations are described. ! 714: A script file is processed by the heretofore unmentioned program ! 715: .I develop ; ! 716: errors in script files are reported by that program. ! 717: The output of ! 718: .I develop ! 719: feeds ! 720: .I stills ! 721: and ! 722: .I movie : ! 723: .PS ! 724: boxht = .25; boxwid = .6 ! 725: ellipseht = .25; ellipsewid = .6 ! 726: lineht = .1; linewid = .4 ! 727: down ! 728: box "generator" ! 729: line down ! 730: ellipse "fname.s" ! 731: line down ! 732: box "develop" ! 733: line down ! 734: A: ellipse "fname.i" ! 735: B: box "stills" with .w at A.e + (.2, -.4) ! 736: line down ! 737: box invis "pic | troff | ..." ! 738: C: box "movie" with .e at A.w - (.2, .4) ! 739: line down ! 740: box invis "5620, X, ..." ! 741: line from A.se to B.nw ! 742: line from A.sw to C.ne ! 743: up ! 744: line up from B.n ! 745: ellipse "docfile" ! 746: .PE ! 747: The command ! 748: .CW develop ! 749: .CW fname.s ! 750: produces the ! 751: .I intermediate ! 752: file ! 753: .CW fname.i ! 754: from the script file ! 755: .CW fname.s , ! 756: unless ! 757: .CW fname.i ! 758: already exists and is newer than ! 759: the corresponding script file. ! 760: Fortunately, most users need not be concerned with intermediate files and the ! 761: .I develop ! 762: program; both ! 763: .I movie ! 764: and ! 765: .I stills ! 766: call ! 767: .I develop ! 768: implicitly. ! 769: Appendix I defines the format of an intermediate file. ! 770: .PP ! 771: The script language provides ! 772: commands to draw geometric objects ! 773: and commands that control the pictures. ! 774: A line whose first non-blank character is ! 775: .CW # ! 776: is a comment; ! 777: comments may not appear on the line after other commands. ! 778: Blank lines are ignored. ! 779: .sp 1 ! 780: .LP ! 781: .I "Geometric Commands" : ! 782: .CW text , ! 783: .CW line , ! 784: .CW box , ! 785: .CW circle . ! 786: .PP ! 787: Geometric commands describe text, lines, rectangles, or circles. ! 788: They share the common form ! 789: .P1 ! 790: @optional_label:@ @command@ @options@ @x@ @y@ @additional@ @parts@ ! 791: .P2 ! 792: If a label is present, it names the object and will implicitly ! 793: erase any existing object with the same name in the same view. ! 794: The options are a (possibly null) list of names, ! 795: terminated by the next numeric field. ! 796: .PP ! 797: Text is placed at a position by the command ! 798: .P1 ! 799: @optional_label:@ text @options@ @x@ @y@ @string@ ! 800: .P2 ! 801: The available options are ! 802: .P1 ! 803: [center] ljust rjust above below ! 804: small [medium] big bigbig ! 805: .P2 ! 806: At most one option may be selected from each line; ! 807: if none is selected, the option in brackets is used. ! 808: The first line describes text position, and ! 809: the second line describes text size. ! 810: The text string may be quoted. ! 811: If there is no leading quote, then the string starts at the first ! 812: non-blank character and continues until the end of the line. ! 813: If there is a leading quote, subsequent leading white space is kept ! 814: and any trailing quote at the end of the line is removed; ! 815: intermediate quotes are kept. ! 816: Some strings, including ! 817: (but not necessarily limited to) ! 818: .CW bullet , ! 819: .CW dot , ! 820: .CW circle , ! 821: and ! 822: .CW times , ! 823: are recognized by later processors. ! 824: .PP ! 825: A line is drawn by ! 826: .P1 ! 827: @optional_label:@ line @options@ @x sub 1@ @y sub 1@ @x sub 2@ @y sub 2@ ! 828: .P2 ! 829: The available options are ! 830: .P1 ! 831: [-] -> <- <-> ! 832: [solid] fat fatfat dotted dashed ! 833: .P2 ! 834: The first line of options describe whether the line should ! 835: be drawn with arrowheads; the default is without arrowheads. ! 836: The option ! 837: .CW <- ! 838: puts an arrowhead at the @( x sub 1 , y sub 1 )@ end of the line, ! 839: .CW -> ! 840: puts an arrowhead at the other end, ! 841: and ! 842: .CW <-> ! 843: puts them at both ends. ! 844: The second line of options describes the body of the line. ! 845: .PP ! 846: A rectangle is drawn by ! 847: .P1 ! 848: @optional_label:@ box @options@ @xmin@ @ymin@ @xmax@ @ymax@ ! 849: .P2 ! 850: The only options are ! 851: .P1 ! 852: [nofill] fill ! 853: .P2 ! 854: Under the default ! 855: .CW nofill ! 856: only the border of the box is drawn; ! 857: a ! 858: .CW fill ed ! 859: box has a solid interior as well. ! 860: .PP ! 861: A circle is drawn by ! 862: .P1 ! 863: @optional_label:@ circle @options@ @x@ @y@ @radius@ ! 864: .P2 ! 865: The radius is measured in the @x@ dimension. ! 866: Circles will look right only if @x@ and @y@ are in about the same range. ! 867: As with rectangles, the options are ! 868: .P1 ! 869: [nofill] fill ! 870: .P2 ! 871: .sp 1 ! 872: .LP ! 873: .I "Control Commands" : ! 874: .CW view , ! 875: .CW click , ! 876: .CW erase , ! 877: .CW clear . ! 878: .PP ! 879: The current view is set by the statement ! 880: .P1 ! 881: view @name@ ! 882: .P2 ! 883: If there are no view statements in the script file, ! 884: .I develop ! 885: generates a single implicit view named ! 886: .CW def.view . ! 887: If geometric objects appear before the first view statement, ! 888: they go in that view and a warning message is generated. ! 889: .PP ! 890: A click is named by ! 891: .P1 ! 892: click @optional_name@ ! 893: .P2 ! 894: If no name is present, then the name ! 895: .CW def.click ! 896: is implicitly supplied. ! 897: .PP ! 898: A labeled geometric object can be explicitly erased by the command ! 899: .P1 ! 900: erase @label@ ! 901: .P2 ! 902: .I develop ! 903: prints a warning ! 904: if the object was never defined or has already been erased. ! 905: The various views have distinct name spaces; ! 906: the same label may be applied to two unrelated objects in two different views. ! 907: All objects in the current view can be erased by the statement ! 908: .P1 ! 909: clear ! 910: .P2 ! 911: .PP ! 912: None of these commands may have labels. ! 913: .sp 1 ! 914: .LP ! 915: .I "Summary." ! 916: .PP ! 917: The script language contains the following commands; ! 918: options are indented on a subsequent line, with defaults in brackets: ! 919: .P1 ! 920: # comment ! 921: @optional_label:@ line @options@ @x sub 1@ @y sub 1@ @x sub 2@ @y sub 2@ ! 922: [-] -> <- <-> ! 923: [solid] fat fatfat dotted dashed ! 924: @optional_label:@ text @options@ @x@ @y@ @string@ ! 925: [center] ljust rjust above below ! 926: small [medium] big bigbig ! 927: @optional_label:@ box @options@ @xmin@ @ymin@ @xmax@ @ymax@ ! 928: [nofill] fill ! 929: @optional_label:@ circle @options@ @x@ @y@ @radius@ ! 930: [nofill] fill ! 931: view @name@ ! 932: click @optional_name@ ! 933: erase @label@ ! 934: clear ! 935: .P2 ! 936: .PP ! 937: The shell command ! 938: .CW develop ! 939: .CW fname.s ! 940: makes the intermediate file ! 941: .CW fname.i ! 942: from the script file ! 943: .CW fname.s , ! 944: if ! 945: .CW fname.i ! 946: is out of date. ! 947: The purpose of the intermediate file is to trade ! 948: increased space (for storing the intermediate file) for ! 949: reduced run time (a script file is developed just once, not ! 950: each time it is used). ! 951: The ! 952: .I movie ! 953: and ! 954: .I stills ! 955: shell scripts could be rewritten to pipe their inputs through ! 956: .I fdevelop , ! 957: a filter form of ! 958: .I develop . ! 959: The ! 960: .I fdevelop ! 961: program can handle script files with at most 20,000 lines; ! 962: the argument ! 963: .CW -l\f2n\fP ! 964: changes the upper bound to ! 965: .I n ! 966: instead. ! 967: It can similarly handle at most 10,000 pieces of geometry ! 968: active at any time; ! 969: the argument ! 970: .CW -s\f2n\fP ! 971: (for ``slots'') changes that upper bound. ! 972: Error messages tell when these bounds need to be increased. ! 973: After any ! 974: .CW -l ! 975: and ! 976: .CW -s ! 977: arguments, ! 978: .I fdevelop ! 979: can have an optional file name. ! 980: If there is a name, that is the input file; otherwise, ! 981: the standard input is used. ! 982: The output is written on ! 983: the standard output. ! 984: .NH ! 985: The Movie Program ! 986: .PP ! 987: Movie production, as with most 5620 programs, ! 988: uses a host process and a terminal process. ! 989: The host sends the intermediate file produced by ! 990: .I develop ! 991: in a compact form to the terminal, ! 992: which stores it in a form suited ! 993: for forward or backward display. ! 994: As the file is shipped, the line number in ! 995: the intermediate file is displayed in the ! 996: upper-left corner of the window every 100 lines. ! 997: Afterwards, the total number of bytes ! 998: stored is displayed in that location. ! 999: The terminal process allocates 80,000 bytes ! 1000: (typically 5-10,000 objects) ! 1001: for the picture; ! 1002: the argument ! 1003: .CW -m\f2n\fP ! 1004: sets the allocation to ! 1005: .I n ! 1006: instead. ! 1007: .PP ! 1008: The button 3 menu was sketched in Section 2. ! 1009: In general, drawing can be interrupted at any point by ! 1010: pushing any button, then resumed by pushing button 1. ! 1011: .PP ! 1012: Four menu items control two variables: ! 1013: .P1 ! 1014: faster [speed] ! 1015: slower [speed] ! 1016: .P2 ! 1017: decrease (halve) and increase (double) the pause at selected clicks, and ! 1018: .P1 ! 1019: thinner [line width] ! 1020: fatter [line width] ! 1021: .P2 ! 1022: alter the width of lines. ! 1023: (If the line thickness is @n@, then ! 1024: .CW solid ! 1025: lines are @2n - 1@ bits wide; ! 1026: .CW fat ! 1027: and ! 1028: .CW fatfat ! 1029: lines are larger.) ! 1030: Three menu items control binary attributes: ! 1031: .P1 ! 1032: backward forward ! 1033: or mode xor mode ! 1034: 1 step run ! 1035: .P2 ! 1036: The mode displayed on the menu is the next state, not the current one. ! 1037: If the program is currently in ! 1038: .CW or ! 1039: .CW mode , ! 1040: for instance, then ! 1041: .CW xor ! 1042: .CW mode ! 1043: is displayed. ! 1044: .PP ! 1045: The ! 1046: .CW new ! 1047: .CW file ! 1048: item allows one to view a new movie without downloading the ! 1049: .I movie ! 1050: program again. ! 1051: After selecting that item, ! 1052: text in the upper left of the window asks for the name of the intermediate ! 1053: file to be processed. ! 1054: The ! 1055: .I movie ! 1056: program does not call ! 1057: .I develop ! 1058: to make the intermediate ! 1059: .CW .i ) ( ! 1060: file from the script ! 1061: .CW .s ) ( ! 1062: file; ! 1063: that is the responsibility of the user, ! 1064: typically in a separate window. ! 1065: .PP ! 1066: Button 2 lists views and clicks. ! 1067: Selecting a view results in an icon for sweeping a rectangle, ! 1068: as in ! 1069: .I mux . ! 1070: Views may be positioned anywhere; ! 1071: portions positioned outside the window will not be shown. ! 1072: Initially, views have a 5 percent margin at each edge; ! 1073: this margin is zero for views that have been reshaped. ! 1074: If the window itself is reshaped, all views revert to ! 1075: the default position and margin. ! 1076: .PP ! 1077: Normally, in 1-step mode, the display pauses after each ! 1078: primitive object (line, text, etc.) has been drawn or erased. ! 1079: If any clicks are defined and turned on by button 2, however, ! 1080: then the display pauses only at those points. ! 1081: Any number of clicks may be turned on. ! 1082: Clicks that are turned on are marked with an asterisk; ! 1083: they may be turned off by selecting them again. ! 1084: .PP ! 1085: As it is for the 5620, so it is for X workstations, ! 1086: although the exigencies of the X window system ! 1087: have forced us to curtail some features. ! 1088: To keep the code relatively portable, ! 1089: there are again two processes, so ! 1090: the window in which one starts the animation clones another ! 1091: window of uncontrolled size, shape and position ! 1092: where the animation itself occurs. ! 1093: .PP ! 1094: The current terminal programs support ! 1095: many, but not all, text size and line mode options. ! 1096: .PP ! 1097: If ! 1098: .I movie ! 1099: has a single argument, it must be either a ! 1100: .CW .s ! 1101: or ! 1102: .CW .i ! 1103: file; ! 1104: .I movie ! 1105: .I develop s ! 1106: a ! 1107: .CW .s ! 1108: file. ! 1109: If it has no arguments, then it will pipe ! 1110: the standard input ! 1111: through ! 1112: .I fdevelop ; ! 1113: no intermediate file is created. ! 1114: For more exotic situations, use ! 1115: .I fmovie : ! 1116: with no arguments, it projects the intermediate file ! 1117: from the standard input; ! 1118: with a single argument, it projects that intermediate file. ! 1119: .NH ! 1120: The Stills Language ! 1121: .PP ! 1122: The ! 1123: .I stills ! 1124: program is a typical ! 1125: .I troff ! 1126: preprocessor. ! 1127: Portions of its input bracketed by ! 1128: .CW .begin ! 1129: .CW stills ! 1130: and ! 1131: .CW .end ! 1132: are translated into ! 1133: .I pic ! 1134: commands, and the rest of the input is passed through untouched. ! 1135: A paper containing ! 1136: .I stills ! 1137: input is typically compiled by a command like ! 1138: .P1 ! 1139: stills paper | pic | troff >paper.out ! 1140: .P2 ! 1141: .PP ! 1142: There are three classes of statements in a ! 1143: .I stills ! 1144: description: ! 1145: .CW print , ! 1146: .CW view , ! 1147: and parameter assignments. ! 1148: Only two statements are mandatory in a particular description: ! 1149: an assignment to the ! 1150: .CW file ! 1151: parameter and a ! 1152: .CW print ! 1153: statement. ! 1154: Text following the sharp symbol ! 1155: .CW # ! 1156: is discarded as a comment; blank lines are ignored. ! 1157: .PP ! 1158: There may be any number of ! 1159: .CW print ! 1160: statements of any combination of the following forms: ! 1161: .P1 ! 1162: print all ! 1163: print final ! 1164: print @clickname@ all ! 1165: print @clickname@ @number@ @number@ @number@ ... ! 1166: .P2 ! 1167: The first statement causes a snapshot to be drawn at each ! 1168: .CW click ! 1169: statement in the script file; the second draws one at the end of the file. ! 1170: The third form prints all ! 1171: .CW click s ! 1172: of the designated name, and the fourth prints only the clicks enumerated ! 1173: in the list of numbers. ! 1174: .PP ! 1175: View statements select which views are to be printed in snapshots ! 1176: and assign titles to views. ! 1177: .P1 ! 1178: view @name@ @optional@ @title@ ! 1179: .P2 ! 1180: The views appear in the order they are named, ! 1181: either top-to-bottom if time goes ! 1182: .CW across ! 1183: the page or left-to-right if time goes ! 1184: .CW down ! 1185: the page. ! 1186: If there are no ! 1187: .CW view ! 1188: statements, each snapshot depicts all views in the script. ! 1189: If the title is enclosed in quote marks, they are stripped and ! 1190: leading space is kept. ! 1191: If no title is given for a particular view, the view name ! 1192: itself is used as a title; ! 1193: thus an empty title is needed to turn off printing. ! 1194: .PP ! 1195: Parameters can be set by assignment statements of the form ! 1196: .P1 ! 1197: @parameter_name@ @value@ ! 1198: .P2 ! 1199: All parameters are reset to their default values at each ! 1200: .CW .begin ! 1201: .I stills ! 1202: statement. ! 1203: Numeric values may be of the form ! 1204: .CW n , ! 1205: .CW +n , ! 1206: .CW -n , ! 1207: or absent (zero default). ! 1208: .IP ! 1209: .I Filename ! 1210: parameter: ! 1211: .CW file . ! 1212: The script file is named by assigning to the ! 1213: .CW file ! 1214: parameter with a statement of the form ! 1215: .CW file ! 1216: .CW basename.s . ! 1217: The ! 1218: .I stills ! 1219: program ! 1220: .I develop s ! 1221: that script file and then reads ! 1222: .CW basename.i . ! 1223: .IP ! 1224: .I "Text sizes" : ! 1225: .CW "small medium big bigbig" . ! 1226: The assignment ! 1227: .CW small ! 1228: .CW -2 ! 1229: causes text with the ! 1230: .CW small ! 1231: option to be printed two point sizes smaller than the current ! 1232: .I troff ! 1233: point size. ! 1234: Assigning ! 1235: .CW "+5" ! 1236: or ! 1237: .CW "5" ! 1238: to ! 1239: .CW "bigbig" ! 1240: increases the point size by 5 for ! 1241: .CW bigbig ! 1242: text. ! 1243: All changes are relative; there is no way to set ! 1244: absolute point size. ! 1245: .IP ! 1246: .I "Line widths" : ! 1247: .CW "solid fat fatfat" . ! 1248: Relative size changes for line widths, exactly as for text sizes. ! 1249: .IP ! 1250: .I "Direction" : ! 1251: .CW "across down" . ! 1252: By default, snapshots proceed across the page in time. ! 1253: The assignment ! 1254: .CW down ! 1255: .CW 5 ! 1256: causes time to proceed down the page for 5 snapshots before ! 1257: starting a new column; ! 1258: .CW down ! 1259: .CW 0 ! 1260: or ! 1261: .CW "down" ! 1262: yields as many snapshots as will fit on an 8-inch page. ! 1263: The assignment ! 1264: .CW across ! 1265: .CW 7 ! 1266: gives 7 snapshots in a row before starting a new row; ! 1267: .CW across ! 1268: .CW 0 ! 1269: or ! 1270: .CW across ! 1271: adapts to a 6-inch width. ! 1272: .IP ! 1273: .I "Frame parameters" : ! 1274: .CW "frameht framewid margin" . ! 1275: The height and width of frames are given in inches; defaults are 1.5. ! 1276: The margin of a frame is the white space surrounding the data; ! 1277: the default is 0.05, or a five percent border. ! 1278: .IP ! 1279: .I "Optional parts" : ! 1280: .CW "frames times" . ! 1281: Frames are the solid borders around pictures; ! 1282: times are the click name and number that triggered a snapshot. ! 1283: Both have the default value ! 1284: .CW vis ! 1285: and are shown; they may be suppressed by assigning them the value ! 1286: .CW invis . ! 1287: .PP ! 1288: In summary, ! 1289: .I stills ! 1290: input consists of these commands: ! 1291: .P1 ! 1292: print all ! 1293: print final ! 1294: print @clickname@ all ! 1295: print @clickname@ @number@ @number@ @number@ ... ! 1296: view @name@ @optional@ @title@ ! 1297: @parameter_name@ @value@ ! 1298: .P2 ! 1299: .LP ! 1300: At least one ! 1301: .CW print ! 1302: statement and a ! 1303: .CW file ! 1304: assignment are mandatory; ! 1305: other statements are optional. ! 1306: The parameter names in the right column may appear on the left side of a ! 1307: name/value assignment: ! 1308: .P1 ! 1309: .ta 1.1i ! 1310: \f2Filename\fP file ! 1311: \f2Text sizes\fP small medium big bigbig ! 1312: \f2Line widths\fP solid fat fatfat ! 1313: \f2Direction\fP across down ! 1314: \f2Frame parameters\fP frameht framewid margin ! 1315: \f2Optional parts\fP frames times ! 1316: .P2 ! 1317: ......... ! 1318: .NH ! 1319: Larger Animations ! 1320: .PP ! 1321: The examples in this section illustrate algorithms on several ! 1322: classes of data structures, including arrays, trees and graphs. ! 1323: The graphical style is simple; this is easy for the animator and ! 1324: effective for the viewer. ! 1325: The programs in this section are not presented as paradigms of ! 1326: good programming style; rather, they show how succinct programs ! 1327: can yield useful animations. ! 1328: .PP ! 1329: In the paper cited earlier, Brown and Sedgewick employ ! 1330: several conceptual levels in animating an algorithm. ! 1331: .IP ! 1332: .I Execution. ! 1333: At one extreme is the program to be animated, ! 1334: executing on the data of interest. ! 1335: .IP ! 1336: .I "History of ``Interesting Events.'' ! 1337: What events in a computation should be depicted in the animation? ! 1338: The simple animation of insertion sort in Section 2 used augmented ! 1339: .CW less ! 1340: and ! 1341: .CW swap ! 1342: routines to capture two primitives of most sorting programs: ! 1343: comparisons and data movements. ! 1344: It also explicitly recorded information associated with the ! 1345: interesting event of finishing a phase. ! 1346: .IP ! 1347: .I "Geometric interpretation of events. ! 1348: One must next decide how to represent ! 1349: the interesting events pictorially. ! 1350: An array of integers, for instance, might be represented by ! 1351: a sequence of numbers, a scatterplot of bullets, or a sequence ! 1352: of vertical bars. ! 1353: .IP ! 1354: .I "Rendering on a device. ! 1355: In our system, this is the job of ! 1356: .I movie ! 1357: and ! 1358: .I stills . ! 1359: .LP ! 1360: The sample program ! 1361: .CW is.gen ! 1362: identified interesting events and gave them ! 1363: a geometric interpretation in separate procedures ! 1364: within a single program. ! 1365: Alternatively, it may be more convenient ! 1366: to implement the various tasks as a pipeline of two programs: ! 1367: a generator program writes interesting events that ! 1368: are given a geometric interpretation by a program that writes ! 1369: a script file. ! 1370: .PP ! 1371: One usually prints a ! 1372: .CW click ! 1373: statement immediately after the event it marks. ! 1374: Sometimes, though, one draws additional objects to ! 1375: highlight the event, which are erased immediately after the ! 1376: .CW click . ! 1377: In that case, one uses a sequence like ! 1378: .P1 ! 1379: @draw@ @event@ @E@ ! 1380: @highlight@ @E@ ! 1381: click E ! 1382: @remove@ @highlights@ ! 1383: .P2 ! 1384: .sp 1 ! 1385: .LP ! 1386: .I "Sorting, Again." ! 1387: .PP ! 1388: We will return to the subject of ! 1389: sorting with a more interesting animation: ! 1390: a race of insertion sort versus quicksort. ! 1391: We will use the same insertion sort we saw earlier, ! 1392: and a quicksort described in Section 10.2 of |reference(programming pearls). ! 1393: The two sorting routines and their supporting functions ! 1394: are contained in this ! 1395: .I awk ! 1396: program: ! 1397: .P1 ! 1398: .get race.gen ! 1399: .P2 ! 1400: Quicksort is called as ! 1401: .CW "qsort(l,u)" ! 1402: to sort the subarray ! 1403: .CW x[l..u] . ! 1404: The function ! 1405: .CW draw ! 1406: represents the numbers to be sorted as vertical lines. ! 1407: The ! 1408: .CW BEGIN ! 1409: block sets ! 1410: .CW n , ! 1411: initializes the array, ! 1412: draws the initial representation, ! 1413: and then calls a sort routine. ! 1414: As it stands, the code depicts a 50-element quicksort. ! 1415: .PP ! 1416: Some algorithm animation systems present races of programs ! 1417: by implementing a simple form of time slicing. ! 1418: To create a race in our system, we first ran the program into the file ! 1419: .CW qs.s . ! 1420: We then changed the final line in the ! 1421: .CW BEGIN ! 1422: section to call ! 1423: .CW isort , ! 1424: and ran that into the file ! 1425: .CW is.s . ! 1426: Finally, we merged the two scripts into one with this ! 1427: .I awk ! 1428: program: ! 1429: .P1 ! 1430: .get race.splice ! 1431: .P2 ! 1432: The loop copies the script of insertion sort until it encounters a ! 1433: .CW click ! 1434: .CW comp ! 1435: statement; it then copies quicksort until it encounters the corresponding ! 1436: .CW click , ! 1437: at which points it prints the ! 1438: .CW click ! 1439: statement. ! 1440: The variables ! 1441: .CW s1 ! 1442: and ! 1443: .CW s2 ! 1444: store the status of the most recent ! 1445: .CW getline s ! 1446: of the two files; the status is one if a record was found and ! 1447: zero if an end-of-file was encountered. ! 1448: When one file is exhausted, the remainder of the other is copied. ! 1449: (A production splicer should ! 1450: have a more graceful interface for naming the files and views.) ! 1451: .PP ! 1452: The resulting script file is an execution of the ! 1453: sorts in two parallel views, synchronized by comparisons: ! 1454: .INCLUDE race ! 1455: As before, insertion sort sifts each element into place in turn. ! 1456: This picture only hints at the operation of quicksort; ! 1457: insight into that algorithm requires the identification ! 1458: of interesting events beyond comparisons and swaps. ! 1459: Quicksort finishes after 240 comparisons, while insertion ! 1460: sort takes almost three times as long. ! 1461: For completeness, here is the ! 1462: .I stills ! 1463: input that produced the picture: ! 1464: .P1 ! 1465: .get race.t ! 1466: .P2 ! 1467: .sp 1 ! 1468: .LP ! 1469: .I "Trees." ! 1470: .PP ! 1471: Here are pictures of a (nonbalanced) binary search tree after inserting ! 1472: 5, 10, 15 and 20 random integers in the range 0..999: ! 1473: .INCLUDE bst ! 1474: In the last two frames, the labels for node 3 ! 1475: and 13 are squeezed too close together. ! 1476: The script was generated by this ! 1477: .I awk ! 1478: program: ! 1479: .P1 ! 1480: .get bst.gen ! 1481: .P2 ! 1482: The animation code consists of just three lines in the ! 1483: .CW insert ! 1484: procedure. ! 1485: .PP ! 1486: The pictures give insight into random binary search trees ! 1487: in spite of being rather ugly. ! 1488: The trees have two distinct failings: the depiction of ! 1489: individual nodes, and the layout of the entire tree. ! 1490: .PP ! 1491: A node is represented by its numeric value; ! 1492: each node is connected to its parent. ! 1493: If the shape of the tree is more important than ! 1494: the values it contains, one can delete the values entirely. ! 1495: We will shortly see a tree with more graceful edges. ! 1496: .PP ! 1497: The other aesthetic issue is the layout of the tree. ! 1498: The @y@-value is the depth of the node in the tree, ! 1499: which is a very robust choice ! 1500: (one could also use the time at which the node was inserted). ! 1501: The @x@-value in this example is simply the randomly generated value itself; ! 1502: there are many alternative choices. ! 1503: One could instead use the number of the node in an inorder traversal, ! 1504: which involves a multiple-pass algorithm: ! 1505: the tree is first built, then traversed and numbered, and the ! 1506: insertions are then reported with knowledge of the numbers. ! 1507: For this representation, it is crucial to separate the ! 1508: interesting events from their geometric representation; ! 1509: it is convenient to calculate these in two filters in a pipeline. ! 1510: .PP ! 1511: This animation of heapsort uses an alternative representation of trees. ! 1512: It was generated by a 50-line ! 1513: .I awk ! 1514: program. ! 1515: .INCLUDE heap ! 1516: Each snapshot shows the result of a ! 1517: .CW sift ! 1518: operation. ! 1519: The first four ! 1520: .CW sift s ! 1521: build the heap; subsequent ! 1522: .CW sift s ! 1523: maintain the unsorted elements as a heap. ! 1524: Arrows point from lesser elements to greater elements. ! 1525: .PP ! 1526: A node in the heap is represented by its value; ! 1527: lines between nodes have a single arrowhead and ! 1528: are chopped by twenty percent at each end. ! 1529: The root of the heap is at @(1/2,~-1)@, ! 1530: its two children are at @(1/4,~-2)@ and @(3/4, ~-2)@, their four ! 1531: children are at @(1/8,~-3)@, @(3/8,~-3)@, @(5/8,~-3)@, @(7/8,~-3)@, etc. ! 1532: .PP ! 1533: Other tree layouts proved useful in animating ! 1534: two algorithms dealing with parse trees. ! 1535: In both cases, a node's @x@-value was the minimum of the ! 1536: @x@-values among the node's descendants (equivalently, ! 1537: the @x@-value of its leftmost child); all edges were therefore ! 1538: either vertical or slanting down to the right. ! 1539: A random sentence generator built the tree left-to-right and top-down; ! 1540: just as in the binary search tree, ! 1541: the height of a node was one less than its parent. ! 1542: A parser built the tree in postorder and bottom-up: ! 1543: the height of a node was one greater than the ! 1544: maximum of the heights of its children. ! 1545: .sp 1 ! 1546: .LP ! 1547: .I "A Graph Algorithm." ! 1548: .PP ! 1549: Prim's algorithm for computing the minimum spanning tree (MST) ! 1550: of a graph starts with a fragment consisting of a single vertex. ! 1551: It increases the fragment by adding the nearest vertex until all ! 1552: vertices are in the fragment, at which point it is the MST ! 1553: of the entire graph. ! 1554: This picture shows Prim's algorithm on the complete ! 1555: graph induced by a set of 50 planar points; ! 1556: the weight of an edge between two points is ! 1557: defined to be their Euclidean distance. ! 1558: .INCLUDE mst2 ! 1559: The snapshots are taken every ten stages. ! 1560: .PP ! 1561: The obvious implementation of Prim's algorithm on an @N@-point ! 1562: set requires time proportional to @N sup 3@. ! 1563: Dijkstra discovered an elegant implementation of the algorithm ! 1564: with running time proportional to @N sup 2@: ! 1565: every point not in the fragment keeps a pointer ! 1566: to its nearest neighbor in the fragment. ! 1567: Here is Dijkstra's implementation on a ten-node planar graph: ! 1568: .INCLUDE mst1 ! 1569: In this animation, nodes in the fragment are bullets, nodes ! 1570: not in the fragment are crosses, edges in the MST are ! 1571: .CW fat ! 1572: lines, and the nearest neighbors are pointed to by arrows. ! 1573: .PP ! 1574: These two sequences illustrate two ! 1575: styles of drawing graphs with our system. ! 1576: Dots and lines are sufficient for simple algorithms, ! 1577: while various symbols and line options can depict subtle processes. ! 1578: .PP ! 1579: The geometric nature of the above graphs made them easy to lay out. ! 1580: Laying out a general graph is very hard. ! 1581: If the graphs in your applications are specialized (such as trees), ! 1582: you might exploit that structure to compute an effective layout. ! 1583: A graph of @N@ vertices can be easily represented ! 1584: by an @N times N@ matrix in which the @i,j@-th element ! 1585: represents the edge from vertex @i@ to vertex @j@; ! 1586: that is useful for insight into some graph algorithms. ! 1587: If you have access to a program that produces good layouts of general graphs, ! 1588: you might use that program to compute positions of vertices, ! 1589: and then feed those into our system. ! 1590: .sp 1 ! 1591: .LP ! 1592: .I "A Memory Allocator." ! 1593: .PP ! 1594: The ! 1595: .I develop ! 1596: program uses the ! 1597: .I malloc ! 1598: memory allocator for several of its data structures. ! 1599: We augmented ! 1600: .I develop 's ! 1601: calls to the allocator with data gathering ! 1602: routines to produce an animation; ! 1603: here is the final snapshot. ! 1604: .KF ! 1605: .INCLUDE malloc ! 1606: .KE ! 1607: The left frame is the arena of storage from which memory is allocated. ! 1608: Memory blocks are represented by lines, ! 1609: low addresses are at the bottom of the picture, and ! 1610: the picture is 1024 bytes wide. ! 1611: The right frame is a histogram of the sizes of memory currently ! 1612: allocated; there is a dot for each element, a vertical bar every ten ! 1613: positions to help counting, and the maximum value is in the lower right corner. ! 1614: .PP ! 1615: This snapshot was taken at the end of execution of ! 1616: .I fdevelop . ! 1617: The histogram shows two large blocks ! 1618: of 20,000 and 40,000 bytes, 96 blocks of size 16, and 96 ! 1619: slightly larger blocks (the blocks of size 16 are symbol table records; ! 1620: each points to an allocated string). ! 1621: The arena shows the two huge pieces (the larger is higher) ! 1622: and a gap above the smaller (memory allocated by ! 1623: procedures that didn't call our augmented ! 1624: .I malloc ). ! 1625: The remainder of the arena is allocated efficiently. ! 1626: .PP ! 1627: A movie like this helped us find a bug in ! 1628: .I fdevelop : ! 1629: an early version allocated the symbol table nodes but did not ! 1630: .I free ! 1631: them. ! 1632: This problem manifested itself in an overloaded arena and a huge ! 1633: spike in the histogram at size 16. ! 1634: .PP ! 1635: The ! 1636: .I fdevelop ! 1637: program interacts with the storage allocator only through ! 1638: the two routines ! 1639: .I emalloc ! 1640: and ! 1641: .I efree . ! 1642: We animated the storage allocator by modifying those routines: ! 1643: .P1 ! 1644: .get malloc.c ! 1645: .P2 ! 1646: They write on the named file output lines of two types: ! 1647: .P1 ! 1648: m @address@ @length@ ! 1649: f @address@ ! 1650: .P2 ! 1651: The first line denotes that a ! 1652: .I malloc ! 1653: of the given length returned the given address; ! 1654: the second marks a ! 1655: .I free . ! 1656: .PP ! 1657: The resulting history file contains the interesting events; ! 1658: they are given a geometric interpretation by a subsequent program. ! 1659: Here is a simple program that generates only the arena view ! 1660: from the script file: ! 1661: .P1 ! 1662: .get malloc.awk ! 1663: .P2 ! 1664: The ! 1665: .CW BEGIN ! 1666: block initializes variables, ! 1667: the actions for ! 1668: .CW m ! 1669: lines draw memory, and those for ! 1670: .CW f ! 1671: lines erase memory. ! 1672: The variable ! 1673: .CW s ! 1674: is the starting byte of a block; ! 1675: .CW e ! 1676: is the ending block. ! 1677: The variables ! 1678: .CW sx ! 1679: and ! 1680: .CW sy ! 1681: are the @x@ and @y@ positions of the starting byte, and ! 1682: similarly for ! 1683: .CW ex ! 1684: and ! 1685: .CW ey . ! 1686: If the block fits on one line, then only a single line fragment ! 1687: need be drawn; otherwise, fragments of three types are needed. ! 1688: .PP ! 1689: The complete program for generating scripts ! 1690: from history files is 56 lines of ! 1691: .I awk . ! 1692: To ease tracing the action in the arena, it marks a ! 1693: .I malloc ! 1694: with an ! 1695: .CW x ! 1696: and a ! 1697: .I free ! 1698: with an ! 1699: .CW o . ! 1700: The histogram view is embellished with bars and the maximum value. ! 1701: There is room for further elaborations; ! 1702: one might, for instance, want to put either or both of ! 1703: the axes of the histogram on logarithmic scales. ! 1704: .sp 1 ! 1705: .LP ! 1706: .I "Dynamic Statistical Displays." ! 1707: .PP ! 1708: Rick Becker constructed this display of air pollution ! 1709: in the Northeast United States: ! 1710: .INCLUDE ozone ! 1711: The data was gathered hourly on ! 1712: a single summer day in the early 1970's. ! 1713: The radius of each circle is proportional to the ozone ! 1714: reading (a common measurement of air pollution) ! 1715: at one of 32 stations in New Jersey, ! 1716: New York, Connecticut, and Massachusetts. ! 1717: The radius of the clock denotes the maximum ozone level prescribed ! 1718: by the Environmental Protection Agency; ! 1719: its hour hand goes from 7:00 AM to midnight. ! 1720: .PP ! 1721: This display shows how New York City's ! 1722: air pollution is blown to the northeast. ! 1723: Becker and his colleagues prepared a similar movie in the ! 1724: early 1970's using the technology of the day; ! 1725: it required several weeks of programming time, then ! 1726: a weekend with a movie camera to make the final film. ! 1727: He built this display from the same data in a couple of hours, ! 1728: then prepared a video tape of the ! 1729: resulting movie in under thirty minutes. ! 1730: The original movie was a bit nicer (it drew the background ! 1731: map and the circles in two different colors), ! 1732: but the new movie is just as useful, and provides stills for free. ! 1733: ...... ! 1734: .NH ! 1735: Living With The System ! 1736: .PP ! 1737: The system that we have described is the ! 1738: bare bones of an animation environment. ! 1739: We have found that the most fruitful way of enhancing the ! 1740: environment is not by modifying the primary programs, ! 1741: but rather by using small filters that interact with the ! 1742: various files in the system. ! 1743: .PP ! 1744: We showed earlier, for instance, a race of two sorting algorithms. ! 1745: While other animation systems implement races with ! 1746: a general mechanism for time sharing, ! 1747: we did the job with a small ! 1748: .I awk ! 1749: program that merges two files. ! 1750: Our system does not have a facility for counting clicks; ! 1751: rather, we use filters such as ! 1752: .P1 ! 1753: grep 'click comps' | wc ! 1754: .P2 ! 1755: to see how many comparisons were made. ! 1756: We will even admit to using text editors to make minor changes ! 1757: to both script and intermediate files. ! 1758: .PP ! 1759: We have built several useful filters in addition to ! 1760: .I merge . ! 1761: The program ! 1762: .I view.clicks ! 1763: prints a summary of the views and clicks used in a script file; ! 1764: it is helpful as one is preparing a ! 1765: .I stills ! 1766: file. ! 1767: Its implementation uses the intermediate file described ! 1768: in Appendix I: ! 1769: .P1 ! 1770: .get view.clicks ! 1771: .P2 ! 1772: The first step of the shell script is to develop the script file; ! 1773: the subsequent ! 1774: .I awk ! 1775: program then reads the resulting intermediate file. ! 1776: The first pattern/action pair prints for each view its ! 1777: name and the @x@ and @y@ ranges in the script file. ! 1778: The second pair builds a string of all clicks from the ! 1779: define click statements, and the third pair prints that ! 1780: string and exits at the first non-define statement. ! 1781: .PP ! 1782: The program ! 1783: .I show.clicks ! 1784: takes a script file as input; ! 1785: its output is a new script file containing all information in ! 1786: the input and, in addition, a new view named ! 1787: .CW click.count ! 1788: in which the various clicks are counted. ! 1789: This is useful for preparing ! 1790: .I stills ! 1791: files and for debugging. ! 1792: Its input is a script file, ! 1793: either named explicitly or as the standard input. ! 1794: Here is the code: ! 1795: .P1 ! 1796: .get show.clicks ! 1797: .P2 ! 1798: The second pattern/action pair stores the name of the current view, ! 1799: and the fourth action copies each line onto the output file. ! 1800: The first pattern/action pair supplies a default view name, if needed. ! 1801: .PP ! 1802: The work is done when the third pattern recognizes a ! 1803: .CW click ! 1804: statement. ! 1805: The ! 1806: .CW if ! 1807: statement puts the click name in ! 1808: .CW cname , ! 1809: and the ! 1810: .CW print ! 1811: statement switches to the new view. ! 1812: The second ! 1813: .CW if ! 1814: statement is executed when a new ! 1815: .CW click ! 1816: statement is seen; it assigns it a number and prints out the ! 1817: click name, once and for all. ! 1818: The two following statements rewrite the appropriate count ! 1819: and place a bullet next to it. ! 1820: The final statement returns to the current view. ! 1821: .PP ! 1822: One can use the ideas in ! 1823: .I show.clicks ! 1824: to process lines in the script file of the form ! 1825: .P1 ! 1826: @name@ = @value@ ! 1827: .P2 ! 1828: The output script file has a new view named ! 1829: .CW variables ; ! 1830: it contains the name of each variable mentioned and its current value. ! 1831: .PP ! 1832: Larger filters have also proven useful. ! 1833: For instance, we built a set of tools to render animations ! 1834: of three-dimensional lines and text ! 1835: (circles and rectangles were not supported). ! 1836: The primary program translated a three-dimensional script into a ! 1837: standard script that contained two two-dimensional views for ! 1838: each three-dimensional view; the resulting ! 1839: .I movie ! 1840: and ! 1841: .I stills ! 1842: were suitable for viewing with standard stereo viewers. ! 1843: Support programs included a filter for rotating a view ! 1844: around a given line. ! 1845: .PP ! 1846: The ! 1847: .I movie ! 1848: and ! 1849: .I develop ! 1850: programs are in fact simple shell scripts that call filter ! 1851: versions named ! 1852: .I fmovie ! 1853: and ! 1854: .I fdevelop . ! 1855: You may find it convenient to rewrite those shell scripts for ! 1856: your environment. ! 1857: .SH ! 1858: Acknowledgements ! 1859: .PP ! 1860: We are deeply indebted to Howard Trickey; ! 1861: he gave us invaluable advice for getting a minimal ! 1862: animation facility working in the Sun environment, ! 1863: then finished the job properly. ! 1864: He subsequently made it all work under the X window system. ! 1865: Andrew Hume and Jane Elliott made possible ! 1866: our first experiments with animation. ! 1867: Our early users, Rick Becker and Chris Van Wyk, ! 1868: gave us bug reports and suggestions for improvements. ! 1869: Eric Grosse, John Linderman, Doug McIlroy, ! 1870: Steve Mahaney, Howard Trickey, and Chris Van Wyk ! 1871: made helpful comments on this paper. ! 1872: .SH ! 1873: References ! 1874: .LP ! 1875: |reference_placement ! 1876: .sp 100 ! 1877: .BP ! 1878: .SH ! 1879: Appendix I \(em Intermediate Files ! 1880: .PP ! 1881: This appendix defines the intermediate files produced by ! 1882: .I develop . ! 1883: The files are easier to process than the corresponding script files. ! 1884: For instance, ! 1885: names are converted to small integers, ! 1886: floating point numbers are scaled to integers in 0..9999, ! 1887: and commands are abbreviated to single letters. ! 1888: .PP ! 1889: A line whose first non-blank character is ! 1890: .CW # ! 1891: is a comment. ! 1892: .PP ! 1893: An intermediate file begins with define statements ! 1894: that give the names of the views and the clicks: ! 1895: .P1 ! 1896: d v @vnum@ @viewname@ @minx@ @miny@ @maxx@ @maxy@ ! 1897: d c @cnum@ @clickname@ ! 1898: d p @any@ @text@ ! 1899: d p e ! 1900: .P2 ! 1901: Fields are separated by tab characters. ! 1902: Both views and clicks are numbered 0, 1, 2, .... ! 1903: The four final numbers on a view line tell the ! 1904: range of the coordinates in the original script file. ! 1905: A line that begins with ! 1906: .CW "d p" ! 1907: is a ``pragma''; both ! 1908: .I movie ! 1909: and ! 1910: .I stills ! 1911: currently ignore all such lines. ! 1912: The defines appear at the front of the file in ! 1913: the order views, clicks, pragmas, then ! 1914: the ``end of defines'' pragma ! 1915: .CW "d p e" . ! 1916: .PP ! 1917: The geometric commands for lines, boxes, circles and text ! 1918: are mapped to the following: ! 1919: .P1 ! 1920: g @slotnum@ l @vnum@ @opts@ @x sub 1@ @y sub 1@ @x sub 2@ @y sub 2@ ! 1921: g @slotnum@ b @vnum@ @opts@ @x sub 1@ @y sub 1@ @x sub 2@ @y sub 2@ ! 1922: g @slotnum@ c @vnum@ @opts@ @x@ @y@ @rad@ ! 1923: g @slotnum@ t @vnum@ @opts@ @x@ @y@ @text@ @string@ ! 1924: .P2 ! 1925: Objects that are never erased have slot number 0; ! 1926: other objects are placed in ``slots'' that can hold at most one object. ! 1927: The third field is the type of geometric object; ! 1928: the fourth field is the view number. ! 1929: All @x@ and @y@ values are normalized to integers in the range 0..9999. ! 1930: There is a single separating tab before the (unquoted) text string. ! 1931: Options are given as a string of characters, ! 1932: whose length and interpretation are summarized as: ! 1933: .P1 ! 1934: .ps -2 ! 1935: .vs -3 ! 1936: OBJECT POS NAME ABBREV ! 1937: text 1 center c ! 1938: ljust l ! 1939: rjust r ! 1940: above a ! 1941: below b ! 1942: 2 medium m ! 1943: small s ! 1944: big b ! 1945: bigbig B ! 1946: line 1 solid s ! 1947: fat f ! 1948: fatfat F ! 1949: dotted o ! 1950: dashed a ! 1951: 2 - - ! 1952: -> > ! 1953: <- < ! 1954: <-> x ! 1955: box 1 nofill n ! 1956: fill f ! 1957: circle 1 nofill n ! 1958: fill f ! 1959: .vs +3 ! 1960: .ps +2 ! 1961: .P2 ! 1962: For instance, the options for a text string are described ! 1963: by two characters giving its position and its size; ! 1964: .CW small ! 1965: .CW center ! 1966: text has the option string ! 1967: .CW cs . ! 1968: Further options may be added at the right end of the string; ! 1969: subsequent programs should ignore letters they don't expect. ! 1970: .PP ! 1971: A click statement is represented as ! 1972: .P1 ! 1973: c @cnum@ ! 1974: .P2 ! 1975: .PP ! 1976: An erase statement is translated into ! 1977: .P1 ! 1978: e @line@ @repeated@ @here@, @except@ e @italic "for"@ @leading@ g ! 1979: .P2 ! 1980: A processor may choose to implement this statement using ! 1981: either the geometric description or the slot number. ! 1982: .PP ! 1983: A ! 1984: .CW clear ! 1985: statement (which erases all objects in a view) ! 1986: is translated into a pair of starting and ending ``blank'' ! 1987: commands that bracket a sequence of erase statements: ! 1988: .P1 ! 1989: b s @vnum@ ! 1990: b e @vnum@ ! 1991: .P2 ! 1992: The erase statements together clear the view. ! 1993: A processor may choose to implement the ! 1994: .CW clear ! 1995: either by ignoring the ! 1996: .CW b ! 1997: commands and letting the erase statements ! 1998: take their course or by explicitly processing the start ! 1999: command and then ignoring ! 2000: .CW e ! 2001: commands until encountering the ! 2002: .CW "b e" ! 2003: line. ! 2004: .PP ! 2005: As an example, running ! 2006: .CW develop ! 2007: on this trivial script file ! 2008: .P1 ! 2009: line 1 2 3 4 ! 2010: text small above 5 6 "Hello, world." ! 2011: click stage ! 2012: clear ! 2013: .P2 ! 2014: produces this intermediate file: ! 2015: .P1 ! 2016: d v 0 def.view 1 2 5 6 ! 2017: d c 0 stage ! 2018: d p e ! 2019: g 1 l 0 s- 0 0 4999 4999 ! 2020: g 2 t 0 as 9999 9999 Hello, world. ! 2021: c 0 ! 2022: b s 0 ! 2023: e 1 l 0 s- 0 0 4999 4999 ! 2024: e 2 t 0 as 9999 9999 Hello, world. ! 2025: b e 0 ! 2026: .P2 ! 2027: .PP ! 2028: Here is a summary of the commands in the intermediate language: ! 2029: .P1 ! 2030: # @comment@ ! 2031: b s @vnum@ ! 2032: b e @vnum@ ! 2033: c @cnum@ ! 2034: d v @vnum@ @viewname@ @minx@ @miny@ @maxx@ @maxy@ ! 2035: d c @cnum@ @clickname@ ! 2036: d p @any@ @text@ ! 2037: d p e ! 2038: e @line@ @repeated@ @here@, @except@ e @italic "for"@ @leading@ g ! 2039: g @slotnum@ l @vnum@ @opts@ @x sub 1@ @y sub 1@ @x sub 2@ @y sub 2@ ! 2040: g @slotnum@ b @vnum@ @opts@ @x sub 1@ @y sub 1@ @x sub 2@ @y sub 2@ ! 2041: g @slotnum@ c @vnum@ @opts@ @x@ @y@ @rad@ ! 2042: g @slotnum@ t @vnum@ @opts@ @x@ @y@ @text@ @string@ ! 2043: .P2
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.