Devlog – alanza.xyz

ROBBIE LYMAN

Devlog

241120 - /ai

I added a pretty punchy /ai page, in response to this manifesto. The manifesto is certainly something, but I think it is not it.

241119 - seamstress.monome

On Sunday I finished working on implementing support for monome grid and arc devices in seamstress v2. Here's a snippet from the test file that illustrates their use.

local monome = require 'seamstress.monome'
describe('seamstress.monome', function()
  local m
  it('is callable', function()
    assert.is.callable(monome)
  end)
  m = monome(8888) -- starts an OSC server on port 8888
  it('calling it returns a table', function()
    assert.is.table(m)
    assert.has(m, 'serialosc')
    assert.has(m, 'Grid')
    assert.has(m, 'Arc')
  end)
  local dev_waiting = true
  local p = seamstress.async.Promise(function()
    repeat coroutine.yield() until dev_waiting == false
  end)
  seamstress.Timer(function(self)
    if #m.Grid > 0 or self.stage >= 3 then
      dev_waiting = false
      self.running = false
    end
  end)
  p:await() -- blocks this function 
  -- until the Timer sets dev_waiting false
  if #m.Grid > 0 then
    describe('Grid', function()
      local g = m.Grid.connect()
      it(':all()', function()
        local done = false
        seamstress.Timer(function(self)
          if self.stage >= 32 then
            done = true
            self.running = false
          end
          local level = self.stage <= 16 and self.stage - 1 or 32 - self.stage
          g:all(level)
          g:refresh()
        end, 1 / 32)
        repeat coroutine.yield() until done
      end)
      it(':led() and .key()', function()
        local done = false
        local blink = true
        seamstress.Timer(function(self)
          g:led(4, 4, blink and 15 or 0)
          g:refresh()
          blink = not blink
          if done then self.running = false end
        end, 1 / 4)
        g.key = function(x, y, z)
          if x == 4 and y == 4 and z == 0 then done = true end
        end
        repeat coroutine.yield() until done
      end)
    end)
  else
    pending('Grid: not connected!')
  end
end)
An excerpt of seamstress 2’s monome device spec

If a monome grid is connected while the tests are running, the tests will first cause all the LEDs on the grid to raise and then lower through all 16 brightness levels (counting 0 as a level), and then blink the 4, 4 key until it is pressed (or released, really).

Something I love about this test is it really shows the shine of the Timer and Promise objects I dreamed up over the summer. I don’t need to assign any of the return values of seamstress.Timer to anything because each Timer is smart enough to clean itself up when it’s done by setting self.running = false (which under the hood sets off a chain of events which eventually enables the Timer to be garbage collected), even though Timer and Promise objects fundamentally have to be available to the Zig side of seamstress. Using a Promise earlier in the test block allows me to tie the execution of the test block to the execution of the Promise by using :await(). So fun!!

241026 – zOSC

Today I finished a first milestone in implementing the Open Sound Control (OSC) data format and RPC protocol in Zig: currently the repository contains what should be a complete implementation of the format at least as far as “message” objects are concerned. Next steps include implementing “bundles” of messages, and an RPC server.

Zig really is lovely for everything, but I quite liked it for this. The reference-counting mechanism and other aspects of a Message object, including the full contents of the message can be contiguous with but hidden from the user’s handle to a Message by using the following sleight of hand: when a Message is created, a large block of memory is allocated: the beginning of the memory becomes a Message.Header struct which contains the Message object as a field, as well as a reference counter, a size of the allocation, and an offset where the data of the message begins. The user never interacts with Message.Header objects; instead, methods on the Message type use Zig’s @fieldParentPtr construction (similar to the Linux kernel’s container_of macro, but doing all the pointer manipulation for you) to first turn a Message into a Header, query the Header (or even the allocation) for the relevant data, and then pass it back to the caller.

The data format is charmingly simple: strings in OSC are 0-terminated ASCII strings padded with zeros so that the string is followed in memory by at least one zeros, and the padded memory occupies a multiple of four bytes. An OSC message begins with a string whose first character is '/', and all well-formed messages should follow with a string (the “type tag” string) whose first character is ','. Each character of the type tag string corresponds to a type of an argument, which is present in what follows. Ints (32- and 64-bit 2’s-complement signed integers represented in big endian byte order), floats (32- and 64-bit, IEEE floats, also big endian), strings, and a few other “contentful” types, as well as some which occupy space only in the type tag, like “true”, “false”, “nil” and “bang” (or “infinitum”). The whole chunk of memory is 0-padded to occupy a multiple of 4 bytes, and can be transparently communicated over UDP, for instance.

241009 – Mathcha

Today in my graduate class we talked about Stallings folding, which is one of my favorite topics in all of mathematics. It’s a really lovely piece of mathematics which has these beautifully simple-to-grasp proofs.

Also today, Jose Urrea, a student in my class, showed me Mathcha, which is a truly gorgeous little site: a what-you-see-is-what-you-get little editor for mathematical diagrams that supports LaTeX, clicking and dragging, bezier curves, etc. While it does export to TikZ, I’m really enthused that it exports to SVG (as well as to PNG). I think I’m going to make an effort to try it out when the need for more figures arises.

By the way, now that Google is slowrolling the death of Jamboard (itself a very imperfect tool) this is less urgent, but if you are reading this and you happen to have suggestions for a tablet-forward multiplayer whiteboard app in the vein of Jamboard, I’d love suggestions for use in one of my collaborations. We tried out Miro briefly but found it kind of annoying. Since we’re mathematicians and not UX designers, for instance, builtin support for beautiful widgets impresses us not at all, but good support for manipulating drawings created with a stylus like an Apple Pencil and low latency for collaboration that we can all look at while talking on Zoom without needing to share screen would capture our hearts for sure. If you happen to know anything, shoot me an email.

241008 – busted

Seamstress version 2 (or rather, the branch where I’m currently working) now once again is capable of running unit tests on the functionality of seamstress when run as seamstress test. Currently the suite of tests is entirely vendored, but it seems likely that I will eventually want to extend this capability to run tests in the directory seamstress is launched from as well.

Unit tests are powered by luarocks busted. My initial go at incorporating busted used its provided runner script, but I found this difficult to grok and the default behavior didn’t suit my use cases. Therefore part of the project this go-around was to properly understand what is needed to set up a busted runner.

It turns out to be not so bad! This seems to be the bones of it:

local function runner()
  local busted = require 'busted.core' ()
  require 'busted' (busted)
  local directory = os.getenv("SEAMSTRESS_LUA_PATH") ..
      package.config:sub(1, 1) .. "test"
  local loadTestFiles =
    require 'busted.modules.test_file_loader'(busted, { 'lua' })
  loadTestFiles({ directory }, { '_spec' }, { excludes = {} })
  
  local handler = require 'busted.outputHandlers.base' ()
  handler:subscribe({ language = 'en' })

  local execute = require 'busted.execute' (busted)
  execute(1, {})
end
An excerpt of the first draft of seamstress 2’s busted runner

(Apologies for the slightly haphazard syntax highlighting style; I’ll work on it soon.)

Anyway, this snippet of code is pretty interesting: busted apparently wants to be loaded twice, once as require 'busted.core' which, as appears to be common practice among many luarocks libraries, returns a function rather than a table, and then again as require 'busted'. We’re using busted’s builtin test file loader which hooks Lua files in the specified directory with filename containing _spec up to busted’s complicated environment hijacking scheme. We’re also using (actually extending) busted’s base output handler, which is in charge of keeping track of the number of succeeded and failed tests.

In seamstress 2, this runner function is called as seamstress.async(runner)(), which is crucial for testing seamstress itself: by running the tests in an asynchronous context (which is to say, on the event loop rather than immediately) we gain the ability to yield execution from the test back to the seamstress environment, allowing us to test functions which depend on input from outside of seamstress, or are fundamentally time-based, for example.

241005

Still figuring out the right cadence for posting here. I think the answer is that I should post when I do work, rather than attempting to post, for example, every weekday.

Justin Bennett has been organizing a “Side Project Saturday” event most weekends here in Brooklyn; I’ve managed to attend two so far, the second of which was today.

I worked on seamstress version 2. Today I mostly revisited seamstress.async and seamstress.async.Promise, which are implementations of JavaScript style Promises and asynchronous functions in Lua for use with libxev. So far, the implementation is basically complete (although I’m unsure what the expectation is when you execute Promise.race() with an empty list of Promises in JavaScript: should it resolve or reject?) but I still need to add documentation for use with LuaLS, as well as README documentation and eventually actual documentation, which will live on this website but currently has no home. (So much documenting!!)

We ended the day with presentations, all of which were so so cool. Maybe my favorite was this: Owen, another attendee, shared a bit about some material design he’s been working on, thinking through placement of heatsinks, the mechanical operations behind latching drawers, distributing heat evenly throughout a machine, etc. Really an immediate clue-in about what is so cool about like 10 different things I hadn’t previously given a second glance to.

The immediate next step with seamstress is to hook up busted-powered testing. I started working on this (I think to feel like I did it properly, I need to write my own version of the busted test runner), but found myself browsing the internet instead. Since I came back from Side Project Saturday intending to do more than just this with my day, I think this is actually the signal that I was waiting for that I had hit a natural inflection point in the process. It was interesting to consider that I hadn’t noticed it initially because I was expecting a conscious “ah, we’ve hit a stopping point” instead.

241004

I clearly did not post any blog posts yesterday. Always nice to check in with collaborators when stuck; I think the lemma I’ve been obsessing over is just not quite true, which is super interesting to discover.

241003 – What day is it today?

I think I’m gonna finish out my day by writing a new blog post instead of getting trapped in porting old ones.

Spent a lot of the day going through a draft of a joint paper. Found a way closer into arguing a certain lemma that I will be the first to admit I am overly fixated on proving.

I suppose soon I’m going to have to think about how to split up my really long paper into more digestible chunks to publish. The struggle is that the paper is still pretty close to having one theme. Well, I suppose that’s one struggle. The other struggle is that the paper is a hammer in search of nails. I really liked using the paper as an opportunity to learn about tool-building, but the theorem is much more usually the organizational principle of a math paper.

241002 – Trees

Made use of some high-powered observations in class today. Probably this deserves an actual math blog post, huh, since I kind of don’t want to write LaTeX in this space, but: first the moduli space idea—given a collection of disparate interesting things, can you assemble them into one thing that parametrizes the originals and gives the whole some new structure which might be interesting to investigate. And then secondly, a cute trick: if you have uniformity but also the ability to rescale things, that uniform thing suddenly becomes nothing… Okay, yeah, I’ll go write a blog post, fine.

Fun, also, after the chaos of the past several years, to have more continuity lately to the point where I can start to see patterns. Fall is a time to focus in.

241001 – Art

Interesting observation: in (good) digital art, almost everything has a thickness. Even stuff that scans as linework is very rarely actually lines; so using the “stroke” option in Illustrator (which I spent most of the day in) is usually not the move.

I’m working on a postcard for the play I’m composing music for, hence the work in Illustrator.

240930 – Hello World

Going to start keep little microblogs of work I do here. Today I added this section to my website, prompted by this blog post by Loris Cro.

I have two laptops, one of which lives in my office at Rutgers and which used to run Asahi Linux. This morning it occurred to me that my use of Linux was holding me back. For example, while I believe I’ve managed to get Bluetooth audio and the webcam working independently, I hadn’t managed to add that together to end up with a functional Zoom experience. I need to use Zoom every week for research meetings, which meant, functionally, that I had to carry my other laptop to work every day, completely defeating the purpose of having a second one.

Today in class, we continued working through a book chapter by Mladen Bestvina about real trees. This brought us to a very heady idea: given an action of a group on a metric space by isometries, and a basepoint in that metric space which is not a global fixed point, pulling back yields a pseudometric on the group. Focusing on the pseudometric and projectivizing yields a kind of moduli space for group actions on metric spaces: indeed, if you assert that the action is continuous, you can equip this space with the (quotient of the) compact–open topology, and talk about convergence of (basepointed) group actions!

Aside from this, I worked more on my actual blog, mostly writing a first new post for it; porting old posts will be a slower process.