May 14, 2018

euclids proof in-line

I started working through Mathematical Illustrations by Bill Casselman. It hits several interests: drawing with PostScript, improving my math skills, and getting better at using a computer as my “math environment” (as opposed to using a whiteboard or pen and paper).

Here is my repo for PostScript and other code pertaining to the book: https://github.com/mdashx/math-illustrations.

After showing you how to draw a red square and fill it with a color, the first exercise in the book asks “how would you set the current color to green? Pink? Violet? Orange?” I decided to fill a page with a grid of squares, with given colors in the top row, and lighter squares in each row, with the colors calculated by modifying the HSL values.

Using Python

UPDATE: I've switched to working through the book using Python/SVG exclusively

At this point, 4 pages into the book, the author has barely introduced the PostScript language, there is definitely no information about variables or functions. To make up for not knowing any PostScript, I wrote a Python script to do all of the calculations and write out PostScript instructions.

There's a bunch of code that looks like this:

def fill_square(start_x, start_y, width):
    square_code = []
    square_code.append('newpath')
    square_code.append(f'{start_x} {start_y} moveto')
    square_code.append(f'{width} 0 rlineto 0 {width} rlineto -{width} 0 rlineto')
    square_code.append(f'closepath fill')
    return '\n'.join(square_code)

Now I know that it's easier to just define that procedure in PostScript, but I didn't want to start jumping too far ahead right from exercise one.

I spent too much time trying to calculate colors. It didn't feel right to add a 3rd party dependency for a basic book exercise, so I found dubious directions for converting from RGB to HSL and implemented them in Python. The HSL to RGB conversion was looking kind of tedious and I was running out of time to work on it, so I thought I might as well see what Python libraries are out there. And then I discovered Python's built-in color system library. With much cringing and remorse, I deleted all of my color conversion code and replaced it with calls to the standard library.

I need to complicate the first exercise so much, but it kept me interested as I got through the process of actually creating and viewing a basic PostScript file.

Laziness, Impatience, And Hubris And Math

The last exercise in chapter one is to draw Euclid's Pythagorean Proof from Book I of Elements. The author still hasn't introduced variables or procedures, but I want to actually write this program in PostScript instead of generating it with Python.

Trying to write the program without procedures triggered my laziness, impatience, and hubris. There's no way I was going to responsible for creating that code. Instead, I downloaded all of Adobe's PostScript manuals to help me use a little more of the language. The goal wasn't to write perfect PostScript code yet, but at least something reasonable. Armed with procedures, local variables, and some array operations, I felt much better about finishing the exercise.

I definitely got to brush up my math skills. I might have learned Euclid's proof in 9th grade, but I definitely didn't remember it. Now I'm fully confident in the proof, so I can pat myself on the back for my grasp of elementary geometry. Figuring out how to draw the first triangle took me way longer than I'm going to admit. I'll just say that it feels great dust off really basic knowledge.

Stack-based Programing And Building PostScript Code

One of the PostScript books I found shows how you can load a file inside of a PostScript program, and then evaluate the file contents. That's the closest thing I could find for a way to include PostScript libraries. You can also embed Encapsulated PostScript files, but I'm pretty sure that does not accomplish what I want to do. I considered creating an import function based on the example in the book, but it felt brittle and unnecessary.

It makes sense that PostScript doesn't have an include keyword, given the goals and design of the language. Once I considered this, it was obvious that I could split up my code however I want and then concatenate the files. So I pulled code out into modules like vector-procedures.ps, added a Makefile, and everything went great.

I suspect that the ease of concatenating files into a working program is related to PostScript being a stack-based language. For example, you couldn't do the same thing with a bunch of Python files, it would produce nonsense most of the time.

Stack-based programming is pretty interesting once you get in the flow of it. One of the really gratifying things about programming is folding code into more abstract and meaningful expressions. Stack-based languages make this really easy to do.

Because the variables just get pushed to the stack, instead of explicitly passed between functions, and because it feels natural to keep moving groups of statements into procedures, it's easy to end up with code like:

getSquare drawPath fillGreen

I spent some time learning Factor 5 or 6 years ago, and I remember it being a lot of fun, but unfortunately, it's not a language I have many opportunities to use. On the otherhand, PostScript is a language I can get a lot of use out of.

The Finished Product

The exercise suggested using colors in an intelligent way to help exlain Euclid's proof. I think I did a pretty good job of that, and I think my illustration looks a lot better than the author's. I've really enjoyed the book so far, I'm definitely interested in continuing to work through it, and I'm optimistic about eventually using PostScript as my go to vector graphics tool.

Learning some PostScript was fun, but ultimately it's not a productive environment…

I'm going to do the rest of the book with Python and SVG:

Mathematical Illustrations Chapter One

---

If you want to read more, subscribe to my personal newsletter.