Status: Floating Point Escapes Me, and Carving Seams
This week I've been involved in two different things: the first is giving up on the Buddhabrot generator.
There were two implementations. The first is the "Naive" implementation, which works okay, but is, well, naive. Ultimately, we want to render an image, and in the naive implementation I assumed (incorrectly) that what I wanted was to find a pixel, map it to a point on the complex plane, iterate that, and then map the result back to the image. The problem is that the pixel plane is too crude to give me all the really useful points. I ended up with a cloud that was recognizably the Buddha, but had significant asymmetries due to the imprecision of the map/map pair.
The second was named the "Cupe" implementation, after Johann "Cupe" Korndoerfer's lisp implementation. This one was terrible, and I think I've reached the point where I've stared at it so long the details are starting to gloss over in my head and it's time to walk away from it for a while and let it rest, then come back with a fresh attempt at an implementation, perhaps some slam of the Naive and the Cupe.
One interesting detail of the Cupe version is that he asserts, and I'm not currently math-savvy enough to know why, that the only interesting "starting points" for Buddha-related orbits are those within a very small distance of the border of the Mandelbrot set, those pixels that live right on the edge of the black zone. I was able to generate a gorgeous image of the border (no, really, it was my best work), but could not turn that information into a working Buddhabrot implementation.
The good news is that for the last two days I've been knocking together a basic seam-carving algorithm based on Rust's image library. I'm trying to keep the algorithm separate from the image processing part of the library, as my hope is to eventually port this to C (yes, sucker: C) and then submit it to NetPNM as an alternative resizing feature. I've got the energy processor and seam recognizer worker, now I just need to proof-of-concept an image-to-image resizer.
The other thing that happened this week is that I went to the used bookstore closest to the Microsoft campus. Someone there had just unloaded all of their database development textbooks, and for some reason I've been obsessed with them. The ugliest part appears to be the transaction manager, and I've been kinda wondering something.
I believe, perhaps irrationally, that at some point every program should be written as a library. I write most of my rust programs that way, as a library with a 'src/bin' for the final executable, which is often little more than an implementation of a command line parser and an invocation to one of the library's main entrance points.
I also believe that many things which are command-line programs ought to be client/server. That is, that the library/executable pattern in which I write my binaries is just a strong variant of a basic client/server model. For example, the Unix commands 'find', 'mlocate', and 'gdmap' are all the same routine under the covers, a file-system tree-walker algorithm ruled by a collection of predicates. So I have basic questions, like "Why is there no library API for mlocate?" and "Why do you have to leave GDMap up and running to get the map?"
So now I intend to try an answer some of those questions. I don't know if 'find', 'mlocate', and 'gdmap' need to be client-server, but it seems to me that a file-system tree-walking routine into which you inject the expected outcome, or perhaps from which you extract the expected outcome as an iterator, would be an ideal separation of concerns, and then accessing mlocate can be a library, and gdmap won't need to be running in order to generate the map itself.
I've been looking deep into the storage manager for Postgres, and as I'm reading through it, and looking at various announcements of features added and bugs fixed throughout the Postgres ecosystem, I'm seeing two things: there is a lot of Postgres code that basically exists because C cannot make the same promises as Rust, and many big fixes involves touching many different parts of the code. I'm wondering how much smaller some parts of Postgres could be made using the native features of Rust and the better-built libraries around it, and how different its internals would be if, somehow, the relationship between all the different parts could be teased apart.
Like my belief in the client/server-ness (or library/cli-ness) of the programming universe, I've long suspected that a lot of programming comes down to just a few moving parts. Go, for example, is a runtime with a fast garbage collector and a smart concurrency model, on top of which is built a syntactically ugly language. There's no reason it couldn't be a library and we'd build other things on it, as if it were a VM. A traditional database is a query language with a fast optimizer built on top of a smart manager for moving data from warm storage (disk & spindles). A spreasheet is a functional, reactive programming language with a funky display mechanism.
Anyway, I'm obsessing about transaction managers and storage engines right now. Not sure how that'll pan out.