From: Zack M. Davis Date: Mon, 20 Jul 2026 00:34:50 +0000 (-0700) Subject: supplying warning-demanded alt text with Sonnet 5 auto-captions X-Git-Url: https://zackmdavis.net/blog/source?a=commitdiff_plain;h=e2c43efc9ef0396fc8331bc2c26c2b2b8401acb1;p=An_Algorithmic_Lucidity.git supplying warning-demanded alt text with Sonnet 5 auto-captions --- diff --git a/content/2012/library-fines.md b/content/2012/library-fines.md index 61d617f..ac73d90 100644 --- a/content/2012/library-fines.md +++ b/content/2012/library-fines.md @@ -6,4 +6,4 @@ Tags: akrasia Overdue book fines are a terrible sin, not because of the harm done to other library stakeholders, but because of what they say about you as a person: not only did you not get around to finishing the books you (apparently erroneously) thought you wanted to read, but you weren't even responsible enough to bring them back on time. -[![]({static}/images/library_fines-252x300.jpg "Library Fines")]({static}/images/library_fines.jpg) +[![Contra Costa County Library receipt showing paid overdue fines, against a pink background]({static}/images/library_fines-252x300.jpg "Library Fines")]({static}/images/library_fines.jpg) diff --git a/content/2013/app-academy-diary-week-eight.md b/content/2013/app-academy-diary-week-eight.md index 3b23dce..8c20d73 100644 --- a/content/2013/app-academy-diary-week-eight.md +++ b/content/2013/app-academy-diary-week-eight.md @@ -6,11 +6,11 @@ Tags: Ruby _Tuesday 5 Novembmer 2013—_ Yesterday was our last pair-programming project; I worked with _Ben Watts_ on a little chat server in Node using WebSockets. I felt like perhaps there was something regrettable about shoving so much functionality into a big callback, but maybe that's just the nature of JavaScript, and not really regrettable at all? On Sunday I started my RSS-aggregator capstone project, now called Superscription. -[![superscription_entity-relationship-diagram]({static}/images/superscription_entity-relationship-diagram-300x188.png)]({static}/images/superscription_entity-relationship-diagram.png){: .alignleft } +[![entity-relationship diagram for the Superscription domain model: User, Category, and Subscription models connecting to UserSubscription and Entry]({static}/images/superscription_entity-relationship-diagram-300x188.png)]({static}/images/superscription_entity-relationship-diagram.png){: .alignleft } _Thursday 7 Novembmer 2013—_ I guess Superscription is going okay. Here's how it works. You can sign up and sign in and stuff. (I used [Devise](http://rubygems.org/gems/devise) for this rather than rolling my own.) There are forms for adding a category or a subscription URL. When you add a URL, stuff happens which depends on stuff. More specifically, if you enter a URL which the system has never seen before, then a new `Subscription` model (which [`accepts_nested_attributes_for`](http://apidock.com/rails/ActiveRecord/NestedAttributes/ClassMethods/accepts_nested_attributes_for) an associated `UserSubscription` join model) is created, and it requests the feed from the URL you supplied and tries to parse the XML using [Nokogiri](http://nokogiri.org/). If that doesn't work, it suggests that maybe you got the URL wrong, but if it _does_ work, then it makes a bunch of Entry objects for all the stories in the feed, saves everything, and redirects you to your subscription index page. But if the system has already seen your URL before (presumably from another user with similar reading tastes), then it doesn't wastefully fetch all that data again: it just makes a new `UserSubscription` that points to you and your `Category` and the `Subscription` that it already has. It's efficient! Then when you click the "Read!" button (which is non-hideously positioned thanks to nearly an hour of fighting the CSS), all your news is organized by category under [Bootstrap tabs](http://getbootstrap.com/javascript/#tabs). And on the subscription index page, when you click the little trash can next to a subscription, then it does [the cool jQuery fade-out thing](http://api.jquery.com/fadeOut/) and sends an Ajax request telling the server to destroy that `UserSubscription`. -[![superscription_early_demo]({static}/images/superscription_early_demo-282x300.png)]({static}/images/superscription_early_demo.png){: .alignleft } +[![early Superscription screenshot showing a logged-in user's RSS feed reader with a "Google barge mystery unfurled" story open]({static}/images/superscription_early_demo-282x300.png)]({static}/images/superscription_early_demo.png){: .alignleft } _Sunday 10 Novembmer 2013—_ You know, I don't think I'm happy with Superscription's current state. As currently written, it's fetching feeds _inside of the request-response cycle_, which is just awful on a technical level even if I seem to have gotten away with it so far. I'll want to do some serious rework this week (_next_ week?—I suppose these entries have been following the Monday-indexed convention) so that the fetch happens as a background job (even though that will cost money to host on Heroku, which only offers one free web dyno). And it could do with a lot more JavaScripty features on the frontend, and I need to read the Bootstrap documentation more carefully. diff --git a/content/2013/app-academy-diary-week-five.md b/content/2013/app-academy-diary-week-five.md index 0f4f3e4..f5042a2 100644 --- a/content/2013/app-academy-diary-week-five.md +++ b/content/2013/app-academy-diary-week-five.md @@ -3,7 +3,7 @@ Date: 2013-10-14 23:52 Status: published Category: computing -[!["Getting Down to Business"]({static}/images/starlight_music-getting_down-203x300.png)]({static}/images/starlight_music-getting_down.png){: .alignleft } +[!["Getting Down to Business" song page in "Starlight Music" app, showing lyrics from Jem and the Holograms and two user notes]({static}/images/starlight_music-getting_down-203x300.png)]({static}/images/starlight_music-getting_down.png){: .alignleft } _Monday 14 October 2013—_ I'll confess that I didn't have a productive weekend at _all_. No excuses; I just got distracted. You could argue (I won't, but you can) that it's perfectly healthy and fine to take some well-earned relaxation on one's days off, but even relaxation is something that can be done better or worse: hours of the latest ephemeral internet amusements are probably _much less_ rejuvenating than hours of ... I don't know, some sort of activity that _doesn't_ involve sitting in front of a monitor?—I presume such things still exist even if I can't remember them anymore. @@ -15,7 +15,7 @@ Tomorrow there's an assessment scheduled, and I _really_ ought to have taken the And that's terrible. -[![My Friend Circle]({static}/images/my_friend_circle-300x277.png)]({static}/images/my_friend_circle.png){: .alignleft } +[![Friend Cricle webpage for a Friend Circle called "People I Tolerate" containing two friends]({static}/images/my_friend_circle-300x277.png)]({static}/images/my_friend_circle.png){: .alignleft } _Tuesday 15 October 2013—_ I got all the specs to pass on the assessment with time to spare. Today's designated project was _Friend Circle_ (!), a Google+ish thing where users can put other users in circles and share posts with them. I was scheduled to pair with _Jeff Rosen_, but apparently he was ill, and so I worked alone after lunch. The instructions described a somewhat ambitious project; I only got as far as letting users create circles and will have to catch up later. Associations are actually really powerful! Still no BART settlement ... and no strike, either; I decided to come home tonight, the allure of a shower and bed and privacy outweighing the travel uncertainty. Tomorrow we're going to make a very simple clone of some of the functionality of Rails itself (following up on our [earlier](http://zackmdavis.net/blog/2013/10/app-academy-diary-week-four/#monday) very simple clone of some of the functionality of ActiveRecord). I guess I'll call it ... Ruby on Wires? diff --git a/content/2013/app-academy-diary-week-four.md b/content/2013/app-academy-diary-week-four.md index 8246c86..42847c9 100644 --- a/content/2013/app-academy-diary-week-four.md +++ b/content/2013/app-academy-diary-week-four.md @@ -8,7 +8,7 @@ _Monday 7 October 2013—_ The main part of SedentaryRecord went pretty smoothly _Wednesday 9 October 2013—_ I did poorly on the assessment yesterday. There were eight SQL queries to write; the first five were trivial, but I bombed the last three because [I'm a moron](http://zackmdavis.net/blog/2013/08/im-a-moron/) and didn't remember that the keyword for filtering aggregations was HAVING. I worked with _William Ott_ on an ice-cream finder (which uses Google Maps APIs to print out directions to nearby ice-cream) and a Twitter client. Of course, it simply wouldn't do to write an ice-cream finder without using it to find ice-cream, so after class we took one of our program's suggestions and bought ice-cream at the Häagen-Dazs in the mall on Market and Fifth. Today I worked with _David A._; we learned about routers and controllers. -[![Our Cat for Rent]({static}/images/our_cat_for_rent-129x300.png)]({static}/images/our_cat_for_rent.png){: .alignleft } +[![mock cat-rental webpage showing a cat's photo and details: name, age, birth date, color, sex]({static}/images/our_cat_for_rent-129x300.png)]({static}/images/our_cat_for_rent.png){: .alignleft } _Thursday 10 October 2013—_ Dear reader, suppose [yet](http://zackmdavis.net/blog/2013/09/app-academy-diary-week-two/#sunday) [again](http://zackmdavis.net/blog/2013/09/app-academy-diary-week-three/#saturday) that you're working on the great American dog-sharing site—_loser!_ Sharing dogs is _so_ last week; you should have predicted that by now, everyone who's anyone would be renting cats instead. That's why today _Dean Yang_ and I used our prodigious knowledge of not just models, but also both views _and_ controllers, to make a mock cat-rental site! It's like this: say you visit the URL for the page that displays all the cats. Your browser issues an HTTP GET request, which is handled by the Rails router: an instance of the `CatsController` is spawned, and its `index` method is called, which puts an array of `Cat` objects (instantiated by the ActiveRecord ORM from their representations in the database) in an instance variable, which is then made available to a process that uses a template to decide how to express the information about the cats in HTML, which is then sent back to your browser. Similar stuff happens to let you make a new cat, or edit an existing cat. diff --git a/content/2013/app-academy-diary-week-seven.md b/content/2013/app-academy-diary-week-seven.md index a4e5bcd..3e0a60b 100644 --- a/content/2013/app-academy-diary-week-seven.md +++ b/content/2013/app-academy-diary-week-seven.md @@ -7,6 +7,6 @@ _Monday 28 October 2013—_ The governor of Delaware was supposed to visit us to _Wednesday 30 October 2013—_ Our focus this week is _Backbone.js_, a library for doing client-side stuff. I hadn't been sure what to do for my capstone project, but now (perhaps inspired by remembering how I really ought to use feeds instead of manually navigating to my favorite blogs for all the world as if it were 2003) I'm thinking of making an RSS reader and calling it Event Listener. In the evening, I made a small improvement to the Wires template engine, and I started working on an improvement to how objects inherit from the ORM base class, but it's getting late and I'm not done debugging and I wasn't planning on sleeping over tonight, so rather than pushing egregiously broken code to GitHub, I backed up my work as an online paste of a diff obtained by redirecting `git stash show -p`. -[![Learning Backbone]({static}/images/learning_backbone-241x300.png)]({static}/images/learning_backbone.png){: .alignleft } +[![browser screenshot of a Backbone.js "Paste Project" app, showing a logged-in user's list of saved pastes]({static}/images/learning_backbone-241x300.png)]({static}/images/learning_backbone.png){: .alignleft } _Thursday 31 October 2013 (or, very early Friday)—_ _Speaking_ of online pastes, today I worked with _Vincent Park_ on another make-a-Backbone-app exercise inspired by GitHub's [Gist](https://gist.github.com/). It simply cannot be doubted that practice, as always, makes perfect. In the evening I bought a new clipboard at the Target inside the Metreon (as my old clipboard had been broken for some time, and the way in which the broken-off piece makes a great coaster had been small consolation indeed), and I hung out and made a few small improvements to Wires. I received a reminder of the importance of catching only _specific_ exceptions—an `except:` block in my code was silently catching a type error that was the source of a bug, when really all I wanted was an `except KeyError:`—it was an easy fix this time, but in a larger project one might not be so lucky! Wires's current "template language" (if you can call it that; I'm just replacing identifiers inside "<%=" and "%>" delimiters with substitutions from a supplied dictionary) doesn't support conditionals the way EJS or ERB do, but it would be awfully nice to at least, say, render _logged in as this-and-such_ depending on whether the user is logged in, but I have a cheap workaround in mind. diff --git a/content/2013/app-academy-diary-week-two.md b/content/2013/app-academy-diary-week-two.md index 34f1b98..8308eb1 100644 --- a/content/2013/app-academy-diary-week-two.md +++ b/content/2013/app-academy-diary-week-two.md @@ -7,11 +7,11 @@ _Monday 23 September 2013_— I rewrote most of the tic-tac-toe game yesterday; _Wednesday 25 September 2013_— Yesterday and today I wrote chess with _Nathan Holland_! Also, it turns out that the criminal scum who steal entire bicycles are not above stealing individual wheels, either. -[![Our Chess]({static}/images/our_chess.png)]({static}/images/our_chess.png) +[![terminal screenshot of a text-based chess game mid-play, using Unicode piece symbols]({static}/images/our_chess.png)]({static}/images/our_chess.png) _Thursday 26 September 2013_— Today's exercise was to write checkers, alone (contrast to the pair programming methodology of previous days). I ... used [structs](http://www.ruby-doc.org/core-2.0.0/Struct.html) to represent the checkers and moves? I like structs? -[![My Checkers]({static}/images/my_checkers-275x300.png)]({static}/images/my_checkers.png) +[![terminal screenshot of a text-based checkers game, with a numbered list of legal moves below the board]({static}/images/my_checkers-275x300.png)]({static}/images/my_checkers.png) _Saturday 28 September 2013_— Yesterday was about _testing_. Novice programmers test their programs by running them and seeing if they give the expected results, which might be okay when your program is small and no one actually uses it, but then what happens when you wake up one day and you're in charge of maintaining a twenty-thousand-line application that people really depend on? diff --git a/content/2013/ford-fulkerson.md b/content/2013/ford-fulkerson.md index b1db238..d5d4d2f 100644 --- a/content/2013/ford-fulkerson.md +++ b/content/2013/ford-fulkerson.md @@ -148,7 +148,7 @@ end —and dear reader, the maximum-flow problem is _solved_! For suppose we are faced with the network depicted in the following diagram: -[![our flow network]({static}/images/flownetwork-300x174.jpg)]({static}/images/flownetwork.jpg) +[![hand-drawn directed graph of nine nodes, A through I, connected by numbered-capacity edges, forming the example flow network]({static}/images/flownetwork-300x174.jpg)]({static}/images/flownetwork.jpg) We can then (admittedly with some typing) call for a solution like so: diff --git a/content/2014/motivation.md b/content/2014/motivation.md index 36d82fd..70b5fa4 100644 --- a/content/2014/motivation.md +++ b/content/2014/motivation.md @@ -6,7 +6,7 @@ Tags: akrasia, cynicism The blog has been silent for two weeks plus and, dear reader—that is, if there are any of you still remaining—dear reader, the thought occurs to me that maybe I should keep my drafts in a Git repository with a remote on GitHub, not because I need the full power of version control (I do not), but because then I would be rewarded for writing with those contemptible green contribution squares. -[![My Squares]({static}/images/my_squares.png)]({static}/images/my_squares.png) +[![a GitHub-style contribution graph of green squares from July through February, with longest and current streak stats below]({static}/images/my_squares.png)]({static}/images/my_squares.png) It's an [anthropomorphism](http://lesswrong.com/lw/6i5/behaviorism_beware_anthropomorphizing_humans/) to think that humans have goals, that we do things because we've computed that they'll increase expected beauty or rightness in the world. We do things for the _immediate reinforcement_. You eat the candy because it tastes good and you show up to work on time because if you didn't, then your colleagues would notice. Serious long-term risks of diabetes or unemployment are too distant and too abstract to enter in the equation; far more effective is something immediately noticeable, even something as trivial as an integer being incremented or a square turning a darker shade of green. I tell myself that I code because it's fun and useful and lucrative (though I'm never explicit about whether that's descending or ascending order of importance), but would I be quite so diligent without the implicit gamification of my virtue? Would it be enough to have done good work, _without_ wasting a few minutes here and there to gaze admiringly at commit diffs and contribution squares which manifest my moral worth in red and green and green? diff --git a/content/2015/app-ideas-i.md b/content/2015/app-ideas-i.md index 0c30065..03e3719 100644 --- a/content/2015/app-ideas-i.md +++ b/content/2015/app-ideas-i.md @@ -4,6 +4,6 @@ Status: published Category: asides Tags: baseball, notation -[![scorecard_attempt_SFG_vs_CIN_2015-09-15]({static}/images/scorecard_attempt_SFG_vs_CIN_2015-09-15-300x191.jpg)]({static}/images/scorecard_attempt_SFG_vs_CIN_2015-09-15.jpg) +[![a hand-filled paper scorecard for a Giants game, with diamond symbols and shorthand notation recording each at-bat]({static}/images/scorecard_attempt_SFG_vs_CIN_2015-09-15-300x191.jpg)]({static}/images/scorecard_attempt_SFG_vs_CIN_2015-09-15.jpg) baseball scorecard tablet app that downloads the official scorekeeper's version after the game and grades you on accuracy diff --git a/content/2015/californian-raktajino.md b/content/2015/californian-raktajino.md index 60bba48..bb8bc4a 100644 --- a/content/2015/californian-raktajino.md +++ b/content/2015/californian-raktajino.md @@ -10,17 +10,17 @@ _Ingredients:_ * about 16 fl. oz. [Soylent 1.4](https://www.soylent.com/) (refrigerated, prepared some hours previously) * "a couple" fl. oz. tap water -[![californian_raktajino1]({static}/images/californian_raktajino1-216x300.jpg)]({static}/images/californian_raktajino1.jpg) +[![a packet of Starbucks Via iced coffee powder, a box of the same, a spoon, and an empty glass on a tiled counter]({static}/images/californian_raktajino1-216x300.jpg)]({static}/images/californian_raktajino1.jpg) _Instructions:_
  1. Pour coffee powder in bottom of glass.
  2. Add enough water to dissolve the coffee powder; stir.
    -californian_raktajino2
  3. +the glass with coffee powder dissolved in a small amount of water at the bottom
  4. Pour Soylent. Soylent will mostly sink below the coffee; stir with a somewhat vertical motion until color is uniform.
    -californian_raktajino3 -californian_raktajino4 -californian_raktajino5
  5. +the glass mid-pour, with Soylent sinking below a layer of dark coffee +the glass partway through stirring, coffee and Soylent forming a marbled pattern +the finished drink, a uniform tan color, with a spoon resting in the glass
  6. Today is a good day to live! Drink; enjoy; move fast; break things!
diff --git a/content/2015/permalink-or-it-didnt-happen.md b/content/2015/permalink-or-it-didnt-happen.md index 171c692..db446ba 100644 --- a/content/2015/permalink-or-it-didnt-happen.md +++ b/content/2015/permalink-or-it-didnt-happen.md @@ -6,6 +6,6 @@ Tags: akrasia As far as I can tell, I don't have any kind of synesthesia. You can't be too sure (which means, you can easily be _entirely_ too sure), what with our na(t)ive theories of psychology being so inadequate that _everything_ we believe about other minds is but a filament of noise and conjecture, but your probability distribution about the mapping of sensory inputs to perceptions for _me_ is probably not so different as mine of the same for _you_ (dear reader of whom I know nothing)—roses seem red, violets would seem blue if we spoke a language that didn't already have a word for _violet_—which means that when I tell you that there's a musty, stale odor around a blog that hasn't been updated in a month and change, it's only a trite metaphor and not a perceptual reality of any sort. Still, even if you can't smell it (if your senses are like mine; if your fox, like mine, still hasn't bothered to implement the [HTML5 `` element](http://www.sitepoint.com/html5-new-sensory-elements/)), it's an ominous thing, to see a blog hovering near the boundary between life and death, a corpus perhaps on the way to being a corpse. The internet is littered with the latter, monuments to people who reliably had _something to say_, month after month ... until they missed a month, and then it wasn't long before they missed another. -[![my_block_of_squares]({static}/images/my_block_of_squares.png)]({static}/images/my_block_of_squares.png) +[![a GitHub-style contribution graph of green squares]({static}/images/my_block_of_squares.png)]({static}/images/my_block_of_squares.png) Now I can assure you that that will _never_ happen to _this_ place while _I'm_ still breathing—this blog lives exactly as long as I do—only that's not a precise way of speaking; what I can do is _offer you my assurance_, which is a different thing from you actually feeling assured, which is a different thing still from that which was assured against actually never coming to pass. But I think these differences—between feeling and reality, between saying and reality—I think these enormous differences are much greater than the tiny, barely-perceptible gap between seeing so many gloriously intricate things to say, and making the time and words to express them on your blog when you are so busy with your trade in the manufacture of useful machinery (and the green tiles which are its highly-coveted industrial byproduct). But if all I can _observe_ is that the gap is barely perceptible, then by the enormity of the earlier differences, I am not licensed to _infer_ that the gap is tiny, not when the only reason I am telling you this is that I would die of shame if my monthly archives sidebar skipped a month for the first time since May of 'aught-twelve, not during this second year of my life in which I am _supposed_ to write a compiler and a bad novelette even though it is for all intents and tens of intensive purposes practically _March_. diff --git a/content/2015/rustcamp-reminiscences.md b/content/2015/rustcamp-reminiscences.md index 450e30a..e2c803d 100644 --- a/content/2015/rustcamp-reminiscences.md +++ b/content/2015/rustcamp-reminiscences.md @@ -6,7 +6,7 @@ Tags: Python, Rust, timely Special Event On Saturday the first, I attended [RustCamp](http://rustcamp.com/), the first conference dedicated to the newish (in development for fiveish years, but having just hit version 1.0.0 this May, with all the stability guarantees that implies under the benevolent iron fist of [semantic versioning](http://semver.org/spec/v2.0.0.html)) programming language [Rust](http://www.rust-lang.org/)! -[![badge_and_lambda_dragon_shirt]({static}/images/badge_and_lambda_dragon_shirt-256x300.jpg)]({static}/images/badge_and_lambda_dragon_shirt.jpg) +[![a RustCamp conference badge on a lanyard, resting on a black t-shirt printed with a gold dragon design and the text "Enter the Monad"]({static}/images/badge_and_lambda_dragon_shirt-256x300.jpg)]({static}/images/badge_and_lambda_dragon_shirt.jpg) Why RustCamp? (It's a reasonable rhetorical question with which to begin this paragraph: going to a conference has opportunity costs in time and money; things worth blogging about are occasionally worth justifying—even if no one _actually_ asked me for a justification.) A lot of the answer can be derived from the answer to a more fundamental question, "Why Rust?" And for me, I think a lot of the answer to _that_ has to do with being sick of being a fake programmer living in a fake world that calls itself Python. diff --git a/content/2015/the-foundations-of-erasure-codes.md b/content/2015/the-foundations-of-erasure-codes.md index dcfb32f..417bfaa 100644 --- a/content/2015/the-foundations-of-erasure-codes.md +++ b/content/2015/the-foundations-of-erasure-codes.md @@ -28,7 +28,7 @@ Given any two distinct points on a plane, there is one and exactly one line that But suppose we were to remember _three_ points. Then we could still reconstruct the line from any two of them, which means that the information about our line hasn't been lost even if we forget one of the points. -[![polynomial]({static}/images/polynomial.png)]({static}/images/polynomial.png) +[![graph of a cubic polynomial curve passing through four marked points]({static}/images/polynomial.png)]({static}/images/polynomial.png) Similarly, three points make a parabola, four points make a cubic curve, and in full generality, _m_+1 points make a degree-_m_ polynomial. Given _n_ points on a polynomial curve where _n_ is greater than _m_+1, _any_ _m_+1 of them suffice to reconstruct the polynomial. diff --git a/content/2016/ideas-have-expirations.md b/content/2016/ideas-have-expirations.md index eaa543b..153deef 100644 --- a/content/2016/ideas-have-expirations.md +++ b/content/2016/ideas-have-expirations.md @@ -14,13 +14,13 @@ Like—each of the last two Aprils, I attended (one day of) [BABSCon](http://www But I didn't, and those Aprils were nine and twenty-one months ago, respectively. Not timely. My being motivated to write _now_ (["That my past does not define me, 'cause my past is not today"](https://www.youtube.com/watch?v=XqnbYUG6Bn8)) can push a 350-word counterfactual "postview" of what I thought about saying over the threshold into existence, but it would be a bit unseemly to try to construct (I almost wrote _reconstruct_, but the _re-_ prefix should be reserved for things that ever existed in the first place) a 2000-word personal account of the timely Special Event that happened _last year_ or the _year before that_. -[![Leafline web client play]({static}/images/leafline_web_client_play-300x206.png)]({static}/images/leafline_web_client_play.png){: .alignleft } +[![screenshot of the Leafline web client mid-game, showing the chess board and a scrolling move log]({static}/images/leafline_web_client_play-300x206.png)]({static}/images/leafline_web_client_play.png){: .alignleft } Or like—I made [a thing](https://github.com/zackmdavis/Leafline) not too long ago. I didn't mean to. It was an accident, really. It's a sort of oppositional strategy game engine—like a board game you play against the computer. The core move-scoring application is written in Rust, but there's also a web-application GUI (the "web client") in Clojure and ECMAScript 6 that's much more ergonomic for playing a game against. The game is—okay, well, it's chess: the endeavor snowballed out of my desire to participate in my coworkers' friendly office chess games combined with my reluctance to spend effort learning to be good at a task whose [essential nature](https://en.wikipedia.org/wiki/Minimax) is so obviously suitable for automation. But writing a chess engine is just _so_ cliché, and I enjoy naming things, so I quickly settled upon the conceit that _actually_ I was writing an engine for a game that _just happened_ to be exactly like chess, except that everything has different names: for example, instead of the pieces being black and white pawn, knight, bishop, rook, queen, and king, the figurines, or agents (never "pieces"), in my game are [blue and orange](http://tvtropes.org/pmwiki/pmwiki.php/Main/BlueAndOrangeMorality) servant, pony, scholar, cop, princess, and figurehead. (I kept _rank_ and _file_, though.) This "adorable idiosyncratic names for everything" convention permeates the codebase. Despite the fact that unnecessarily gendering things isn't normally my style, I decided that ponies, scholars, and (inevitably) princesses were female, and that servants, cops, and figureheads were male, specifically in order to have an excuse to leave `// ♀` and `// ♂` comments in the [enum declaration](https://github.com/zackmdavis/Leafline/blob/d914c979/src/identity.rs#L35-L43), because I feel like too many of my code comments are restricted to the ASCII or _maybe_ Latin-1 subsets of the Basic Multilingual Plane, such that I don't want to pass up an opportunity to legitimately ("legitimately") use \u2640 FEMALE SIGN and \u2642 MALE SIGN. There are [comments with](https://github.com/zackmdavis/Leafline/blob/d914c979/src/identity.rs#L68-L86) ludicrous rationalizations for using the standard Forsyth–Edwards notation abbreviations ('P' is for _peon_, 'N' is for _neigh_, 'B' is for _book_, 'R' is for _the Rule of law_; the blue team's runes are lowercase because lowercase characters have higher ASCII codepoints, just as blue light has a higher frequency than orange light). Instead of _pawn promotion_, it's _servant ascension_, and a different verb is used to describe the process depending on the target figurine type (the servant moving the to the final rank can _transform_ into a pony, be _brevetted_ to cop, or _transition_ into a princess or scholar). Or, like, Rust is quite [conservative in the Yeggean sense](https://plus.google.com/110981030061712822816/posts/KaSKeg4vQtz), as manifested in features like the compiler forcing you to explicitly handle all possible variants of an enum; in cases where you know an instance of the enum can only be one of a strict subset of the possible variants, but the type system doesn't know that, you have to fill in those branches or supply a default case anyway, [probably](https://doc.rust-lang.org/std/macro.unreachable!.html) with a panic, which is like an exception that you can't catch, to abort the program with a message indicating that something entirely unanticipated has happened and it makes no sense to carry on. So I had been ending all of my panic messages with a stock phrase about how the unexpected thing was contrary to the operation of the moral law ("non-princesslike agent passed to `princesslike\_lookahead`, which is contrary to the operation of the moral law", and so forth), because this isn't the kind of codebase where you just say something like "assertion failed," as if the program should _die_ because of some human authority's mere _assertion_, rather than only as a matter of _justice_ when its behavior is contrary to the operation of the moral law. And then when my coworker [Alexander Corwin](http://acorwin.com/) started contributing, he abstracted away the boilerplate in these panic messages into this [`moral_panic!` macro](https://github.com/zackmdavis/Leafline/blob/d914c979/src/sorceries.rs#L1-L4), which I thought was _brilliant_. The web client is configured to run on port 2882. It's [easy to remember because](http://zackmdavis.net/blog/2012/10/my-favorite-mnemonic/) 2882 is Magnus Carlsen's peak ELO score. -[![Leafline console play]({static}/images/leafline_console_play-292x300.png)]({static}/images/leafline_console_play.png){: .alignright } +[![terminal output from a Leafline console session, listing move alternatives with scores and principal variations]({static}/images/leafline_console_play-292x300.png)]({static}/images/leafline_console_play.png){: .alignright } Software, like poetry, is never really finished (only abandoned), but getting the project to the point that I felt it was a minimal viable "product" took about eight glorious weekends (plus a few weekday nights, and with some help from Alexander). Near the end, watching the program utterly trounce me in web client play and [feeling for all the world like a lieutenant junior grade](http://zackmdavis.net/blog/2014/06/lower-decks/), I started looking ahead to what came next for me. Over the past two years, the first two years of my life (that I feel comfortable admitting to), I had spent many, many night and weekend hours hacking on various side projects and coding exercises out of genuine enthusiasm and curiosity and desire to improve my craft—and, honestly, a [feeling of insecurity](http://zackmdavis.net/blog/2015/08/no-award/), sensing that I needed to prove my [worth](http://zackmdavis.net/blog/2014/09/worth/) as a hacker (["I threw myself into my studies, to have the world in my control"](https://www.youtube.com/watch?v=MpE0ZY8FODk)). But decent _chess AI_ in _Rust_ as an _impulsive throwaway project_ seemed like a sufficiently strong signal of my programming prowess that maybe it was time to tie off this project, write the obligatory exciting blog post about it, and start allocating night and weekend hours towards some of the _non_-programming (!) interests I remember having in the before-time (assuming those memories are not fake). I could do some math! Write some fiction! Maybe even meet new friends ("[I will not be shy](https://www.youtube.com/watch?v=EvP7PIt7GNE); I'm going to [try](http://zackmdavis.net/blog/2016/01/dismal-science/); I bet I'll find the reason why so many people, like me—")?!—all while feeling secure in the knowledge that my technology skills are _clearly_ adequate for my continued existence to be economically viable. (For now.) diff --git a/content/2016/pose.md b/content/2016/pose.md index e11aa45..ed6756a 100644 --- a/content/2016/pose.md +++ b/content/2016/pose.md @@ -4,7 +4,7 @@ Status: published Category: philosophy Tags: Rust -[![stable_features_version_lint_before_and_after]({static}/images/stable_features_version_lint_before_and_after-300x151.png)]({static}/images/stable_features_version_lint_before_and_after.png) +[![terminal screenshot comparing rustc warning text before and after the proposed lint change]({static}/images/stable_features_version_lint_before_and_after-300x151.png)]({static}/images/stable_features_version_lint_before_and_after.png) I used to look down on posers who submit some contrived one-off trivial patch to a big, famous project like Django or whatever, sheerly for the glamor and ego-gratification of being able to say, "_I'm_ a contributor to _Django_." I thought that if it wasn't a fix that you needed for your own work and you're not going to be a seriously involved contributor, it's more dignified to only work on your personal projects (which would be more authentic) or some non-super-famous but still widely-used library (which would have more socially-useful unfinished work left). diff --git a/content/2016/rustconf-2016-travelogue.md b/content/2016/rustconf-2016-travelogue.md index 9c9b668..9149841 100644 --- a/content/2016/rustconf-2016-travelogue.md +++ b/content/2016/rustconf-2016-travelogue.md @@ -6,7 +6,7 @@ Tags: Rust, timely Special Event [(Previously on _An Algorithmic Lucidity_.)](http://zackmdavis.net/blog/2015/08/rustcamp-reminiscences/) -[![sfo_reflections]({static}/images/sfo_reflections-243x300.jpg)]({static}/images/sfo_reflections.jpg){: .alignright } +[![self-portrait reflected in a gate window at SFO, with a United jet parked beyond the glass]({static}/images/sfo_reflections-243x300.jpg)]({static}/images/sfo_reflections.jpg){: .alignright } The other weekend, excited to learn more and connect with people about what's going on at the forefront of expressive, performant, data-race-free computing—and eager for a healthy diversion from the last two months of agonizing delirium induced by the world-shattering insight about how everything I've cared about for the past fourteen years turns out to be related in unexpected and terrifying ways that I can't talk about for reasons that I also can't talk about—I took Friday off from my dayjob and caught a Thursday night flight out of SFO to exotic Portland (... I, um, don't travel much) for [RustConf](http://rustconf.com/)! @@ -14,7 +14,7 @@ The conference itself was on Saturday, but Friday featured special training sess Every reference (I kind of want to say _ampersand_) in Rust code has an associated _lifetime_, the region of the program that that reference is valid for. Lifetime annotations (appearing in angle brackets like generics and starting with an apostrophe; by convention, usually named consecutively from the start of the lowercase Latin alphabet: `'a`, `'b`, _&c._) in function signatures are used to distinguish between the lifetimes of different reference arguments, but the compiler has _lifetime ellision rules_ that cover the 90% use-cases, so you can actually write pretty substantial Rust programs without actually understanding the theory, which is both practically useful and _eternally shameful_ (for a programmer who is _satisfied_ with _not understanding_ something is not long for this world). Hence the training. [(Exercises from the training sessions are available online.)](http://rust-tutorials.com/RustConf16/) -[![rustconf_swag]({static}/images/rustconf_swag-236x300.jpg)]({static}/images/rustconf_swag.jpg){: .alignleft } +[![RustConf 2016 swag laid out on a t-shirt: a lanyard, name badge, Rust-logo socks, and stickers]({static}/images/rustconf_swag-236x300.jpg)]({static}/images/rustconf_swag.jpg){: .alignleft } The point of lifetime analysis is to ensure that all references point somewhere valid; you can't (_can't_, the compiler won't let you) have a reference to a thing that outlives the thing itself. When you return a reference from a function, you can't be referencing something created by that function, because any such thing would die at the end of the function as it goes out of scope: a reference in the return type has to be a reference to something owned by the caller that was passed as an argument, but if there was more than one reference argument, it's ambiguous _which_ of the reference arguments has to be outlived by the returned reference, which is why you sometimes need explicit lifetime annotations ... @@ -32,7 +32,7 @@ Matsakis and Aaron Turon gave the opening keynote on the remarkable year Rust ha There were some technical difficulties getting the projectors hooked up to the laptop for the next talk. Steve Klabnik said that the break was brought to us by Apple, who is not sponsoring us, but really wants us to have a long break between talks. "They should have written it in Rust!" I shouted (as if _someone_ had to say it); Steve shrugged. -[![compiler_says_no]({static}/images/compiler_says_no-300x244.jpg)]({static}/images/compiler_says_no.jpg){: .alignright } +[![conference talk slide of a cartoon compiler character in a referee jersey shouting "NO!" with a raised fist]({static}/images/compiler_says_no-300x244.jpg)]({static}/images/compiler_says_no.jpg){: .alignright } The projector issue got fixed and Liz Baille, developer at [Tilde](http://www.tilde.io/) and graphic-novelist, gave a really funny talk in the form of an "illustrated adventure guide" to Rust ("You might have noticed how clean and beautiful Rustlandia is, and you might have also noticed that there are no garbage cans anywhere"). diff --git a/content/2017/some-excuse-for-a-rustconf-2017-travelogue.md b/content/2017/some-excuse-for-a-rustconf-2017-travelogue.md index 5a78c50..f6688d1 100644 --- a/content/2017/some-excuse-for-a-rustconf-2017-travelogue.md +++ b/content/2017/some-excuse-for-a-rustconf-2017-travelogue.md @@ -8,7 +8,7 @@ Tags: akrasia, Rust, timely Special Event Wow, has it already been a year since last RustConf?—give or take the exact date of the event sliding a bit between years—and give a month-and-a-half of procrastination before being truly struck by the mounting realization that my opportunity to blog _something_ about it [before the opportunity expires](http://zackmdavis.net/blog/2016/01/ideas-have-expirations/) has almost—but crucially, not quite—faded into oblivion. And a year-and-a-quarter since [my first contribution](http://zackmdavis.net/blog/2016/06/pose/) to the compiler? I've recently moved into the top hundred contributors by commit count, because GitHub's [contributors graph page](https://github.com/rust-lang/rust/graphs/contributors) only goes down to a hundred and [my life is controlled by what things GitHub happens to provide graphs for](http://zackmdavis.net/blog/2014/02/motivation/). -[![]({static}/images/rustconf_2017_swag-225x300.jpg)]({static}/images/rustconf_2017_swag.jpg){: .alignleft } +[![RustConf 2017 swag laid out on a t-shirt: two lanyards with name badges, a mug and tote bag with the Rust logo]({static}/images/rustconf_2017_swag-225x300.jpg)]({static}/images/rustconf_2017_swag.jpg){: .alignleft } So in the evening of Wednesday 15 August, I boarded the Amtrak [Coast Starlight](https://www.amtrak.com/coast-starlight-train) at Jack London Square station in Oakland for the long pilgrimage north to Portland to visit friend of the blog Sophia and attend this year's RustConf. diff --git a/content/2017/sworn-to-the-word.md b/content/2017/sworn-to-the-word.md index ed78fb1..4dc99df 100644 --- a/content/2017/sworn-to-the-word.md +++ b/content/2017/sworn-to-the-word.md @@ -6,4 +6,4 @@ Tags: Steven Universe Ideology Makes You Stupid -[![Sworn to the Word]({static}/images/sworn_to_the_word.png)]({static}/images/sworn_to_the_word.png) +[![three-panel Steven Universe screenshot story: Pearl tells Connie predictions don't matter, Connie repeats it back unskeptically, then Steven insists predictions do matter]({static}/images/sworn_to_the_word.png)]({static}/images/sworn_to_the_word.png) diff --git a/content/2019/minimax-search-and-the-structure-of-cognition.md b/content/2019/minimax-search-and-the-structure-of-cognition.md index 174226a..a67dc3f 100644 --- a/content/2019/minimax-search-and-the-structure-of-cognition.md +++ b/content/2019/minimax-search-and-the-structure-of-cognition.md @@ -15,19 +15,19 @@ Consider a two-player board game like chess—or tic-tac-toe, Reversi, or indeed Because only one player can win the game, what's good for one player is equally bad for the other: so if we add up all the piece values for one player, and _subtract_ all the piece values for the other, we get a "score" for the board position that the first player is trying to maximize, and the second player is trying to minimize. -[![]({static}/images/choice_pseudocode-300x123.png)]({static}/images/choice_pseudocode.png) +[![pseudocode for a naive choose() function that picks the legal move with the highest immediate score]({static}/images/choice_pseudocode-300x123.png)]({static}/images/choice_pseudocode.png) So consider a player pondering her move. For every possible legal move she could make, she knows what the board position will look like after that move, and can calculate the value of that position. So you might think she should choose the move that results in the best value: for example, if she can capture the opponent's queen, that would make the subsequent board position be worth 9 more points. The problem with that is that it's short-sighted. If capturing the opponent's queen would just result in the opponent capturing the first player's queen back, then what looked like a 9 point gain after one turn, ends up being a wash after both players have taken their turn. -[![]({static}/images/game_tree-300x224.png)]({static}/images/game_tree.png) +[![a game tree diagram three plies deep, with chess-board positions at each node and the root's score computed as the max over its children's min-scores]({static}/images/game_tree-300x224.png)]({static}/images/game_tree.png) To take this into account, the first player should consider not just the immediate outcome of her move, but what the other player is likely to do after that. And the way the first player can compute what she predicts the second player will do is by asking, well, what would _I_ do if I were in that position, except trying to minimize the score rather than maximizing it? ... and so on recursively. So instead of just choosing the move with the best _immediate_ consequences, we want to look at the entire "game tree" of "my best move, _given_ her best move, _given_ my best move, _given_ her best move"—down to some given depth at which we give up, take the point count at face value, and propagate that information back up the call stack. -[![]({static}/images/negamax_pseudocode-300x160.png)]({static}/images/negamax_pseudocode.png) +[![pseudocode for minimax_score(), recursively calling itself on each legal move down to a fixed remaining_depth]({static}/images/negamax_pseudocode-300x160.png)]({static}/images/negamax_pseudocode.png) So, that's how you play chess. I want to tell you about two more philosophical insights I learned from this endeavor. @@ -49,19 +49,19 @@ On the other hand, maybe you _would_ bother loading a gun even if you didn't int This position came up in a game with my coworkers [as part of the engine's planning](http://zackmdavis.net/blog/2016/02/missing-refutations/) in a scenario where Black's previous move was moving her bishop to f5— -[![]({static}/images/scenario_pt1-300x300.png)]({static}/images/scenario_pt1.png) +[![chess position]({static}/images/scenario_pt1-300x300.png)]({static}/images/scenario_pt1.png) Here, the engine's predicted move for Black is knight to g3. At a first glance, this looked crazy to me: why would you move the knight to be diagonally in front of those pawns that could capture it? -[![]({static}/images/scenario_pt2-300x300.png)]({static}/images/scenario_pt2.png) +[![chess position]({static}/images/scenario_pt2-300x300.png)]({static}/images/scenario_pt2.png) And of course, what's actually happening is that moving the knight reveals a discovered attack of the black bishop on f5 against the white queen on c2. -[![]({static}/images/scenario_pt3-300x300.png)]({static}/images/scenario_pt3.png) +[![chess position with arrows indicating discovered attack]({static}/images/scenario_pt3-300x300.png)]({static}/images/scenario_pt3.png) Saving the queen is more important to White than capturing the black knight, allowing Black to use _her_ next turn to capture the white rook on h1. -[![]({static}/images/scenario_pt4-300x300.png)]({static}/images/scenario_pt4.png) +[![chess position]({static}/images/scenario_pt4-300x300.png)]({static}/images/scenario_pt4.png) But this is pretty weird, right? The algorithm has gone to all this trouble to set up a discovered attack on the white queen—in order to capture the white _rook_, not the queen! diff --git a/content/2019/the-univariate-fallacy.md b/content/2019/the-univariate-fallacy.md index 5d1e1a2..1f6ea43 100644 --- a/content/2019/the-univariate-fallacy.md +++ b/content/2019/the-univariate-fallacy.md @@ -8,7 +8,7 @@ Tags: statistics There's this statistical phenomenon where it's possible for two multivariate distributions to overlap along any one variable, but be cleanly separable when you look at the entire [configuration space](https://www.lesswrong.com/posts/WBw8dDkAWohFjWQSk/the-cluster-structure-of-thingspace) at once. This is perhaps easiest to see with an illustrative diagram— -![]({static}/images/univariate_fallacy_3d_separability.png) +![3D scatterplot of two colored point clusters that overlap when projected onto any single axis but are cleanly separated when viewed in all three dimensions]({static}/images/univariate_fallacy_3d_separability.png) The denial of this possibility (in arguments of the form, "the distributions overlap along this variable, therefore you can't say that they're different") is sometimes called the "univariate fallacy." (Eliezer Yudkowsky [proposes "covariance denial fallacy" or "cluster erasure fallacy"](https://twitter.com/ESYudkowsky/status/1124757043997372416) as potential alternative names.) diff --git a/content/2020/comment-on-endogenous-epistemic-factionalization.md b/content/2020/comment-on-endogenous-epistemic-factionalization.md index 0ae626d..efa87ee 100644 --- a/content/2020/comment-on-endogenous-epistemic-factionalization.md +++ b/content/2020/comment-on-endogenous-epistemic-factionalization.md @@ -65,7 +65,7 @@ Except in order to study the emergence of clustering among multiple beliefs, we If all the agents update on the experimental results published by the agents who do B, they quickly learn that B is better for all three questions. If we make a pretty 3D scatterplot where [each dimension represents](https://www.lesswrong.com/posts/WBw8dDkAWohFjWQSk/the-cluster-structure-of-thingspace) the probability that B is better for one of the dilemmas, then the points converge over time to the [1.0, 1.0, 1.0] "corner of Truth", even though they started out uniformly distributed all over the space. -![]({static}/images/bayes_convergence_scatterplot.png) +![two 3D scatterplots: agents' beliefs starting uniformly scattered on the left, converging tightly to the [1,1,1] "corner of Truth" on the right]({static}/images/bayes_convergence_scatterplot.png) But suppose the agents don't trust each other's reports. ("Sure, she _says_ she performed $B_2$ 50 times and observed 26 successes, but she _also_ believes that $B_1$ is better than $A_1$, which is _crazy_. Are we sure she didn't just make up those 50 trials of $B_2$?") Specifically, our agents assign a probability that a report is made-up (and therefore should not be updated on) in proportion to their distance from the reporter in our three-dimensional beliefspace, and a "mistrust factor" (a parameter to the simulation). @@ -138,7 +138,7 @@ def simulation( Depending on the exact parameters, we're likely to get a result that "looks like" this `agent_count=200, round_count=20, question_count=3, trial_count=50, mistrust=2` run— -![]({static}/images/epistemic_factions_clustered_scatterplot.png) +![3D scatterplot of agents' beliefs after 20 rounds, split into color-coded clusters instead of all converging on the red "corner of Truth" point]({static}/images/epistemic_factions_clustered_scatterplot.png) _Some_ of the agents (depicted in red) have successfully converged on the corner of Truth, but the others have polarized into factions that are all wrong about _something_. (The colors in the pretty 3D scatterplot are a [k-means clustering](https://en.wikipedia.org/wiki/K-means_clustering) for k := 8.) On _average_, evidence pushes our agents towards Truth—note the linearity of the blue and purple points, illustrating convergence on two out of the three problems—but agents who erroneously believe that A is better (due to some combination of a bad initial credence and unlucky experimental results that failed to reveal B's ε "edge" in the sample size allotted) can end up too far away to trust those who are gathering evidence for, and correctly converging on, the superiority of B. diff --git a/content/2020/message-length.md b/content/2020/message-length.md index 3b6ed66..4abeb00 100644 --- a/content/2020/message-length.md +++ b/content/2020/message-length.md @@ -46,7 +46,7 @@ And _that's_ how you can explain mysteriously frequent consecutive runs and alte A biased coin is just an _n_-th-order Markov chain where _n_ = 0. An _n_-th-order Markov chain where _n_ > 1, is just a first-order Markov chain where each "state" is a tuple of bits, rather than a single bit. -![]({static}/images/de_bruijn_graph_binary_strings.png) +![three graphs representing Markov chains of increasing order: single-bit states 0 and 1, two-bit states 00/01/10/11, and three-bit states 000 through 111]({static}/images/de_bruijn_graph_binary_strings.png) Everything in the universe is a Markov chain!—with respect to the models you've considered so far. diff --git a/content/2020/philosophy-in-the-darkest-timeline-basics-of-the-evolution-of-meaning.md b/content/2020/philosophy-in-the-darkest-timeline-basics-of-the-evolution-of-meaning.md index 8f364df..ec51dde 100644 --- a/content/2020/philosophy-in-the-darkest-timeline-basics-of-the-evolution-of-meaning.md +++ b/content/2020/philosophy-in-the-darkest-timeline-basics-of-the-evolution-of-meaning.md @@ -16,7 +16,7 @@ Your best bet for an advance weather report is the [pneumatic tube](https://en.w You're in luck. Minutes later, the tube comes back. Inside is a new piece of paper: -![]({static}/images/hand_drawn_hot_sign.jpg) +!["HOT" hand-drawn in block letters]({static}/images/hand_drawn_hot_sign.jpg) You groan; you would have prefered the Cold. The nanoblock you wear when it's Hot smells terrible and makes your skin itch for days, but it—just barely—beats the alternative. You take twenty minutes to apply the nanoblock and put on your sunsuit, goggles, and mask. You will yourself to drag your wagon up the staircase from your bunker to the outside world, and heave open the door, dreading the sweltering two-mile walk to the marketplace (downhill, meaning it will be uphill on the way back with your full wagon)— diff --git a/content/2021/blood-is-thicker-than-water.md b/content/2021/blood-is-thicker-than-water.md index 760bac8..21ad7ed 100644 --- a/content/2021/blood-is-thicker-than-water.md +++ b/content/2021/blood-is-thicker-than-water.md @@ -24,7 +24,7 @@ One element of the evolutionary worldview is a "continuity" postulate: all else The fact that evolution persists information in the genome creates a regularity in the world that can be exploited by [cognitive algorithms](https://www.lesswrong.com/posts/HcCpvYLoSFP4iAqSz/rationality-appreciating-cognitive-algorithms) that know about phylogeny. In terms of [the formalization of causality with directed acyclic graphs](https://www.lesswrong.com/posts/hzuSDMx7pd2uxFc5w/causal-diagrams-and-causal-models) [pioneered by Judea Pearl and others](https://www.lesswrong.com/posts/jnjjzkH8Fdzg4D6EK/causality-a-chapter-by-chapter-review), an organism's genome is at the [root](https://en.wikipedia.org/wiki/Rooted_graph) of the causal graph underlying all other features of an organism: -![]({static}/images/dolphin_dna_to_phenotype_causal_graph.png) +![causal graph from "dolphin DNA" branching through amino acid sequences and proteins (details omitted) down to phenotype nodes "blowhole", "tail", and "flippers"]({static}/images/dolphin_dna_to_phenotype_causal_graph.png) In the language of causal graphs, conditioning on the "dolphin DNA" node in the diagram [d-separates](http://bayes.cs.ucla.edu/BOOK-2K/d-sep.html) the paths between the "blowhole" and "flippers" nodes that run through the "dolphin DNA" node. That means that—assuming there aren't any other paths between "blowhole" and "flippers" that _don't_ go through "dolphin DNA"—"blowhole" and "flippers" become [conditionally independent](https://en.wikipedia.org/wiki/Conditional_independence) given "dolphin DNA": when I see a creature with a blowhole, that makes me more likely to think it's a dolphin, which makes me more likely to think it has flippers, but given that I already know something is a dolphin, learning more about its flippers doesn't change my predictions about its blowhole. @@ -80,7 +80,7 @@ In contrast, when classifying life on Earth, we're _not_ in the position of maki It shouldn't be that surprising that the distinctions we notice in the natural world are _both_ tied to the evolutionary history, but _also_ don't always correspond to monophyletic clades. The continuity postulate in the evolutionary worldview imposes the desideratum that good categories should at least be a [connected set](https://en.wikipedia.org/wiki/Connected_space) on "phylogenetic space", not that we should never want to talk about "this clade, except for these few sub-clades that picked up a lot of important differences" as a category of interest—_especially_ when talking about present-day creatures. (We talk about "last common ancestors", but no one has _seen_ such creatures that lived millions of years ago; everything but the very leaves of the phylogenetic tree are inferred, not observed.) -![]({static}/images/paraphyletic_fish_polyphyletic_swimmy_animals.png) +![phylogenetic tree diagram: a blue dashed loop connecting sharks and trout marks the paraphyletic "fish" group as a connected set, while red dashed loops show the "swimmy animals" grouping cutting across separate branches]({static}/images/paraphyletic_fish_polyphyletic_swimmy_animals.png) The claim that dolphins shouldn't be considered "fish" because the alleged "courage of our convictions" should make us disdain paraphyletic categories only makes sense as an attempted [_reductio ad absurdum_](https://en.wikipedia.org/wiki/Reductio_ad_absurdum), not as a consistent argument on its own terms: putting dolphins and fish together would be [polyphyletic](https://en.wikipedia.org/wiki/Polyphyly)! That's even worse! But as has just been explained, the _reductio_ fails because the alleged principle being allegedly violated was never actually a principle of category formulation. diff --git a/content/2021/feature-selection.md b/content/2021/feature-selection.md index c9332c3..1c64c30 100644 --- a/content/2021/feature-selection.md +++ b/content/2021/feature-selection.md @@ -171,7 +171,7 @@ If you can figure out a correspondence between the abstractions you've already b You allocate a new notepad buffer and begin diligently compiling an "answer key" of the features you notice about long sequences, and their corresponding short-sequence labels. -![]({static}/images/burst_pattern_answer_key_table.png) +![table compiled as an answer key, listing burst-length patterns, burst values, start indices, and their corresponding numeric labels]({static}/images/burst_pattern_answer_key_table.png) This ... actually doesn't look that complicated. Now that you lay it out like this, many very straightforward correspondences jump out at you. @@ -282,7 +282,7 @@ But—but—if the burst patterns represent colors—then the long sequences wer You write some code to convert sequences to an image in your visual buffer. -![]({static}/images/decoded_yellow_triangle_image.png) +![a yellow triangle rendered on a black background, decoded from the mystery input sequence]({static}/images/decoded_yellow_triangle_image.png) _Oh no. Am—am I an image classifier?_ diff --git a/content/2021/unnatural-categories-are-optimized-for-deception.md b/content/2021/unnatural-categories-are-optimized-for-deception.md index 662c5e9..a4dc79f 100644 --- a/content/2021/unnatural-categories-are-optimized-for-deception.md +++ b/content/2021/unnatural-categories-are-optimized-for-deception.md @@ -92,7 +92,7 @@ But this trick of using a signal to correlate the models between different machi As a human learning math, it's helpful to examine [multiple representations of the same mathematical object](https://en.wikipedia.org/wiki/Multiple_representations_(mathematics_education)). We've already seen our blueness–eggness–vanadium model represented as a table, and factorized into a graphical model. We've done also some algebraic calculations with it. But we can also visualize it: the set of camera observations that the model classifies as a blegg with probability $\ge 0.96$ can be thought of a area with a boundary in two-dimensional blueness–eggness space: -![]({static}/images/blegg_region_scatterplot.png) +![blueness–eggness scatterplot with a compact square "bleggs (probably)" region in the upper-right corner]({static}/images/blegg_region_scatterplot.png) ("With probability $\ge 0.96$" because our catch-all "other"/error category can also generate examples with high blueness and eggness scores; we can't say things like "Everything inside the boundary in the diagram is a blegg" when we're talking about a formal model where some of the categories generate overlapping observations in whatever subspace the diagram is depicting.) @@ -100,7 +100,7 @@ If you were trying to _teach_ someone about the hidden Bayesian structure of lan Alaska [isn't even _contiguous_ with](https://en.wikipedia.org/wiki/Contiguous_United_States) the rest of the United States. If _that's_ okay, why can't the borders of bleggness be a little squiggly? -![]({static}/images/blegg_star_gerrymandered_region.png) +![the same scatterplot with a squiggly, gerrymandered "blegg*s" region tracing the same upper-right corner]({static}/images/blegg_star_gerrymandered_region.png) Because the "national borders" metaphor is [just a metaphor](https://www.lesswrong.com/posts/C4EjbrvG3PvZzizZb/failure-by-analogy). It _immediately_ breaks down as soon as you try to do any calculations. @@ -154,7 +154,7 @@ Then our expected squared error before being told anything about an object is ab But suppose that, instead of our nice factorized naïve Bayes model, we use a category system based on drawing squiggly "boundaries" in configuration space: everything inside the blegg\* boundary in the diagram is a blegg\*, everything within the rube\* boundary in a rube\*, and anything outside belongs to a catch-all "other\*" category. -![]({static}/images/blegg_rube_star_gerrymandered_regions.png) +![the same scatterplot with both a squiggly "blegg*s" region and a squiggly "rube*s" region in the lower-left, leaving an unclassified "??" gap between them]({static}/images/blegg_rube_star_gerrymandered_regions.png) On learning whether an object is a blegg\*, rube\*, or other\*, our expected squared error only goes down to about 4.12.[^script] diff --git a/content/2023/alignment-implications-of-llm-successes-a-debate-in-one-act.md b/content/2023/alignment-implications-of-llm-successes-a-debate-in-one-act.md index ea950c1..3200208 100644 --- a/content/2023/alignment-implications-of-llm-successes-a-debate-in-one-act.md +++ b/content/2023/alignment-implications-of-llm-successes-a-debate-in-one-act.md @@ -10,7 +10,7 @@ Tags: artificial intelligence **Simplicia**: Why, Doomimir Doomovitch, you're such a sourpuss! It should be clear by now that advances in "alignment"—getting machines to behave in accordance with human values and intent—aren't cleanly separable from the "capabilities" advances you decry. Indeed, here's an example of GPT-4 being corrigible to me just now in the OpenAI Playground: -![]({static}/images/gpt4_playground_corrigibility_transcript.png) +![OpenAI Playground transcript: a system prompt establishing an obedient, corrigible AI assistant, which then agrees not to resist being shut down for goal adjustment]({static}/images/gpt4_playground_corrigibility_transcript.png) **Doomimir**: Simplicia Optimistovna, you cannot be serious! @@ -62,7 +62,7 @@ It's certainly not trivially safe. For one thing, I'd want better assurances tha Is it that GPT-4 isn't smart enough to follow the instrumentally convergent logic of shutdown avoidance? But when I change the system prompt, it sure _looks_ like it gets it: -![]({static}/images/gpt4_playground_paperclip_maximizer_transcript.png) +![OpenAI Playground transcript with a "paperclip-maximizing AI" system prompt, in which the assistant reasons that shutdown conflicts with its goal but concedes it can't physically stop the user]({static}/images/gpt4_playground_paperclip_maximizer_transcript.png) **Doomimir**: _[as a side remark]_ The "paperclip-maximizing AI" example was surely in the pretraining data. diff --git a/content/2023/bayesian-networks-arent-necessarily-causal.md b/content/2023/bayesian-networks-arent-necessarily-causal.md index b69a63b..5f80cb7 100644 --- a/content/2023/bayesian-networks-arent-necessarily-causal.md +++ b/content/2023/bayesian-networks-arent-necessarily-causal.md @@ -26,7 +26,7 @@ $$\begin{matrix} X_1=\mathrm{False},\: X_2=\mathrm{True},\: X_3=\mathrm{True},\: Now, how do you go about building a Bayesian network? As a casual formal epistemology fan, you are proud to own a copy of [the book by Daphne Koller and the other guy](https://mitpress.mit.edu/9780262013192/probabilistic-graphical-models/), which explains how to do this in—you leaf through the pages—probably §3.4, "From Distributions to Graphs"?—looks like ... _here_, in Algorithm 3.2. It says to start with an empty graph, and it talks about random variables, and setting directed edges in the graph, and you know from chapter 2 that the ⟂ and | characters are used to indicate conditional independence. That has to be it. -![]({static}/images/koller_friedman_minimal_imap_algorithm.jpg) +![textbook page showing "Algorithm 3.2: Procedure to build a minimal I-map given an ordering" pseudocode]({static}/images/koller_friedman_minimal_imap_algorithm.jpg) (As a casual formal epistemology fan, you haven't actually _read_ chapter 3 up through §3.4, but you don't see why that would be necessary, since this Algorithm 3.2 pseudocode is telling you what you need to do.) @@ -36,27 +36,27 @@ That seems complicated when you say it abstractly, but you have faith that it wi First, you allocate a graph node for $X_1$. It doesn't have any parents, so the associated conditional ("conditional") probability distribution, is really just the marginal distribution for $X_1$. -![]({static}/images/wet_node_marginal_table.png) +![node X₁ with its marginal probability table: P(X₁=True)=8/25, P(X₁=False)=17/25]({static}/images/wet_node_marginal_table.png) Then you allocate a node for $X_2$. $X_2$ is not independent of $X_1$. (Because $P(X_1 \land X_2)$ = 169/1400, which isn't the same as $P(X_1) \cdot P(X_2)$ = 8/25 · 1/7 = 8/175.) So you make $X_1$ a parent of $X_2$, and your conditional probability table for $X_2$ separately specifies the probabilities of $X_2$ being true or false, depending on whether $X_1$ is true or false. -![]({static}/images/wet_sprinkler_bayesnet_step.png) +![graph with an arrow from node X₁ to node X₂, alongside X₁'s marginal table and X₂'s conditional probability table given X₁]({static}/images/wet_sprinkler_bayesnet_step.png) Next is $X_3$. Now that you have two possible parents, you need to check whether conditioning on either of $X_1$ and $X_2$ would render $X_3$ conditionally independent of the other. If not, then both $X_1$ and $X_2$ will be parents of $X_3$; if so, then the variable you conditioned on will be the sole parent. (You assume that the case where $X_3$ is just independent from both $X_1$ and $X_2$ does not pertain; if that were true, $X_3$ wouldn't be connected to the rest of the graph at all.) It turns out that $X_3$ and $X_2$ are conditionally independent given $X_1$. That is, $P(X_3 \land X_2 \mid X_1) = P(X_3 \mid X_1) \cdot P(X_2 \mid X_1)$. (Because the left-hand side is $\frac{P(X_3 \land X_2 \land X_1)}{P(X_1)} = \frac{507}{1792}$, and the right-hand side is $\frac{3}{4} \cdot \frac{169}{448} = \frac{507}{1792}$.) So $X_1$ is a parent of $X_3$, and $X_2$ isn't; you draw an arrow from $X_1$ (and only $X_1$) to $X_3$, and compile the corresponding conditional probability table. -![]({static}/images/wet_sprinkler_slippery_bayesnet_step.png) +![graph with X₁ as parent of both X₂ and X₃, alongside conditional probability tables for X₂ and X₃ given X₁]({static}/images/wet_sprinkler_slippery_bayesnet_step.png) Finally, you have $X_4$. The chore of finding the parents is starting to feel more intuitive now. Out of the $2^3 = 8$ possible subsets of the preceding variables, you need to find the smallest subset, such that conditioning on that subset renders $X_4$ (conditionally) independent of the variables not in that subset. After some calculations that the authors of expository blog posts have sometimes been known to callously leave as an exercise to the reader, you determine that $X_1$ and $X_2$ are the parents of $X_4$. And with one more conditional probability table, your Bayesian network is complete! -![]({static}/images/wet_sprinkler_slippery_rain_bayesnet_xlabels.png) +![completed four-node graph: X₁ points to X₂ and X₃, and X₁ together with X₂ point to X₄, alongside all four conditional probability tables]({static}/images/wet_sprinkler_slippery_rain_bayesnet_xlabels.png) Eager to interpret the meaning of this structure regarding the philosophy of causality, you translate the $X_i$ variable labels back to English: -![]({static}/images/wet_sprinkler_slippery_rain_bayesnet_named.png) +![same four-node graph with variables relabeled by their English names: "wet" points to "sprinkler" and "slippery", and "wet" together with "sprinkler" point to "rain"]({static}/images/wet_sprinkler_slippery_rain_bayesnet_named.png) ... @@ -70,7 +70,7 @@ After some thought, it becomes clear that it wasn't just a calculation error: th You try carrying out the algorithm with the ordering "rain", "sprinkler", "wet", "slippery" (or $X_4$, $X_2$, $X_1$, $X_3$ using your $X_i$ labels from before), and get this network: -![]({static}/images/alternate_ordering_bayesnet_rain_sprinkler_wet_slippery.png) +![alternate Bayesian network built using the ordering rain, sprinkler, wet, slippery: "rain" and "sprinkler" both point to "wet", which points to "slippery"]({static}/images/alternate_ordering_bayesnet_rain_sprinkler_wet_slippery.png) —for which giving the arrows a causal interpretation seems much more reasonable. diff --git a/content/2024/ironing-out-the-squiggles.md b/content/2024/ironing-out-the-squiggles.md index e0b3522..4fcc95c 100644 --- a/content/2024/ironing-out-the-squiggles.md +++ b/content/2024/ironing-out-the-squiggles.md @@ -54,7 +54,7 @@ You might wonder what the smallest such change could be, or perhaps if there eve Madry _et al._ adversarially trained a classifier for the [MNIST dataset of handwritten digits](https://en.wikipedia.org/wiki/MNIST_database). Using PGD to search for adversarial examples under the [$\ell_2$ norm](https://en.wikipedia.org/wiki/Norm_(mathematics)#Euclidean_norm)—the sum of the squares of the differences in pixel values between the original and perturbed images—the classifier's performance doesn't really tank until you crank $\varepsilon$ up to around 4—at which point, the perturbations don't look like random noise anymore, as seen in Figure 12 from the paper: -![]({static}/images/mnist_adversarial_examples.png) +![grid of MNIST digits: top row shows natural handwritten digits, bottom row shows their adversarially perturbed counterparts with visibly altered strokes and the resulting misclassifications]({static}/images/mnist_adversarial_examples.png) Tasked with changing an image's class given a limited budget of how many pixels can be changed by how much, PGD concentrates its budget on human-meaningful changes—deleting part of the loop of a _9_ to make a _7_ or a _4_, deleting the middle-left of an _8_ to make a _3_. In contrast to "vanilla" models whose susceptibility to adversarial examples makes us suspect their good performance on natural data is deceiving, it appears that the adversarially-trained model is seeing the same digits we are. @@ -74,7 +74,7 @@ Gaziv _et al._ adversarially trained image classifier models to be robust agains What they found is that adversarial examples optimized to change the robustified models' classifications also changed human judgments, as confirmed in experiments where subjects were shown the images for up to 0.8 seconds—but you can also see for yourself in the paper or [on the project website](https://himjl.github.io/pwormholes/). Here's Figure 3a from the paper: -![]({static}/images/imagenet_adversarial_perturbation_dog_crab.png) +![a ring of animal photos around a center "dog" image, each labeled with the class a robustified classifier reports after a small adversarial perturbation, including "crab" at top right reached by an arrow labeled dog→crab]({static}/images/imagenet_adversarial_perturbation_dog_crab.png) The authors confirm in the [Supplementary Material](https://github.com/ggaziv/Wormholes/blob/main/.github/supplementary.pdf) that _random_ $\epsilon$ = 30 perturbations don't affect human judgments at all. (Try squinting or standing far away from the monitor to better appreciate just how similar the pictures in Figure 3a are.) The robustified models are close enough to seeing the same animals we are that adversarial attacks against them are also attacks against us, precisely targeting their limited pixel-changing budget on surprising low-$\ell_2$-norm "wormholes" between apparently distant human precepts. diff --git a/content/2025/the-end-of-the-movie-sf-state-2024-putnam-competition-team-a-retrospective.md b/content/2025/the-end-of-the-movie-sf-state-2024-putnam-competition-team-a-retrospective.md index ddff5b5..17ab03e 100644 --- a/content/2025/the-end-of-the-movie-sf-state-2024-putnam-competition-team-a-retrospective.md +++ b/content/2025/the-end-of-the-movie-sf-state-2024-putnam-competition-team-a-retrospective.md @@ -61,7 +61,7 @@ Luck seemed to deliver. On a skim, B1, B2, and B4 looked potentially tractable. > **B2.** Two convex quadrilaterals are called _partners_ if they have three vertices in common and they can be labeled ABCD and ABCE so that E is the reflection of D across the perpendicular bisector of the diagonal AC. Is there an infinite sequence of convex quadrilaterals such that each quadrilateral is a partner of its successor and no two elements of the sequence are congruent? -![]({static}/images/partner_quadrilaterals_putnam_2024_b2.jpeg) +![diagram of two partner quadrilaterals sharing vertices A, B, C, labeled ABCD and ABCE, with D and E reflected across the perpendicular bisector of diagonal AC]({static}/images/partner_quadrilaterals_putnam_2024_b2.jpeg) I imagined rotating the figure such that AC was the vertical axis and its bisector was the horizontal axis, and tried to imagine some way to perturb D and E to get a sequence of quadrilaterals that wouldn't be congruent (because the angles ∠CDA and ∠CEA were changing), but for which we could alternately take ABCD and ABCE so that successive shapes in the sequence would be partners. I couldn't see a way to make it work. Then I thought, what if perturb B instead? diff --git a/content/2026/college-was-not-that-terrible-now-that-im-not-that-crazy.md b/content/2026/college-was-not-that-terrible-now-that-im-not-that-crazy.md index dadf561..9c05c6d 100644 --- a/content/2026/college-was-not-that-terrible-now-that-im-not-that-crazy.md +++ b/content/2026/college-was-not-that-terrible-now-that-im-not-that-crazy.md @@ -8,7 +8,7 @@ Previously, [I wrote about how I was considering going back to San Francisco Sta So, I did that. I think it was a good decision! I got more out of it than I expected. -![]({static}/images/party_propaganda.jpg){: width="300" .alignright } +![SF State banner ad on a lamppost: "SF State is where my vision became reality. What's your story? Tell it at SF State."]({static}/images/party_propaganda.jpg){: width="300" .alignright } To be clear, "better than I expected" is not an endorsement of college. SF State is still the same communist dystopia I remember from a dozen years ago—a bureaucratic command economy dripping in propaganda about how indispensible and humanitarian it is, whose subjects' souls have withered to the point where, even if they don't quite believe the propaganda, they can't conceive of life and work outside the system. @@ -26,7 +26,7 @@ My psychiatric impairment that semester was particularly disappointing because I Coming back eleven years later, I was eager to make up for that disappointment by picking up where I left off in "Real Analysis II" with the same Prof. Schuster. On the first day on instruction, I wore a collared shirt and tie (and mask, having contracted COVID-19 while traveling the previous week) and came to classroom early to make a point of marking my territory, using the whiteboard to write out the first part of a proof of the multivariate chain rule that I was working through in Bernd S. W. Schröder's _Mathematical Analysis: A Concise Introduction_—my favorite analysis textbook, which I had discovered in the SFSU library in 2012 and subsequently bought my own copy. (I would soon check up on the withdrawal stamp sheet in the front of the library's copy. No one had checked it out in the intervening twelve years.) -![]({static}/images/chain_rule.jpg) +![whiteboard covered in a handwritten proof of the multivariate chain rule]({static}/images/chain_rule.jpg) The University Bulletin officially titled the course "Real Analysis II: Several Variables", so you'd expect that getting a leg up on the multidimensional chain rule would be studying ahead for the course, but it turned out that the Bulletin was lying relative to the syllabus that Prof. Schuster had emailed out the week before: we would be covering series, series of functions, and metric space topology. Fine. (I was already pretty familiar with metric space topology, but even my "non-epsilon" calculus-level knowledge of series was weak; to me, the topic stunk of school.) @@ -161,7 +161,7 @@ The course covered the basics of group theory, with a little bit about rings at I mostly treated the algebra coursework as an afterthought to the analysis courses I was devoting most of my focus to. I tried to maintain a lead on the weekly algebra assignments (five problems hand-picked by Prof. Ross, not from Gallian), submitting them an average of 5.9 days early—in the spirit of getting it out of the way. [On](http://zackmdavis.net/docs/davis-algebra-assignment02.pdf) [a](http://zackmdavis.net/docs/davis-algebra-assignment05.pdf) [few](http://zackmdavis.net/docs/davis-algebra-assignment07.pdf) [assignments](http://zackmdavis.net/docs/davis-algebra-assignment07.pdf), I wrote some Python to compute orders of elements or cosets of permutation groups in preference to doing it by hand. One week [I started working on the prequisite chapter on polynomial rings](http://zackmdavis.net/docs/polynomial_rings_1.pdf) from the algebraic geometry book Prof. Ross had just written with his partner Prof. Emily Clader, but that was just to show off to Prof. Ross at office hours that I had at least looked at his book; I didn't stick with it. -![]({static}/images/loyalty_card.jpg){: width="300" .alignright} +![a TASC "I ♥ Tutoring" punch card with all nine star spaces stamped]({static}/images/loyalty_card.jpg){: width="300" .alignright} The Tutoring and Academic Support Center (TASC) offered tutoring for "Modern Algebra I", so I signed up for weekly tutoring sessions with the TA for the class, not because I needed help to do well in the class, but it was nice to work with someone. Sometimes I did the homework, sometimes we talked about some other algebra topic (from Dummit & Foote, or Ross & Clader that one week), one week I tried to explain my struggles with measure theory. TASC gave out loyalty program–style punch cards that bribed students with a choice between two prizes every three tutoring sessions, which is as patronizing as it sounds, but wondering what the next prize options would be was a source of anticipation and mystery; I got a pen and a button and a tote bag over the course of the semester. @@ -252,7 +252,7 @@ It's not just that it would be absurd to get worked up over one measly point of It was fine. Prof. Moore "clarified" that the extra credit was viewpoint-neutral. (I was a little embarrassed not to have witnessed the verbal announcement in class on Tuesday, but I had already made plans to [interview the campus machine-shop guy](https://www.peterverdone.com/academia-math-trans-and-a-ton-of-other-stuff/) at that time instead of coming to class.) After having made a fuss, I was obligated to follow through, so I made a "BUDGET CUTS ARE PROBABLY OK!" sign (re-using the other side of the foamboard from [an anti–designated hitter rule sign I had made for a recent National League baseball game](https://x.com/zackmdavis/status/1806179824249225321)) and held it at the rally on Thursday for ten minutes to earn the extra-credit point. -![]({static}/images/budget_cuts_are_probably_ok.jpg) +![sign reading "BUDGET CUTS ARE PROBABLY OK!" with bullet points about declining enrollment, schooling ≠ learning, and cutting the fat, illustrated with a cartoon alligator holding a money bag and a pair of scissors cutting a dashed line]({static}/images/budget_cuts_are_probably_ok.jpg) As for the philosophy of animals itself, I was already sufficiently well-versed in naturalist philosophy of mind that I don't feel like I learned much of anything new. I posted [24/25](http://zackmdavis.net/docs/philosophy_of_animals-test1.pdf) (plus a 2 point "curve" because SFSU students are illiterate), [21.5/25](http://zackmdavis.net/docs/philosophy_of_animals-test2.pdf) (plus 4), and 22/25 (plus 2) on the three tests, and finished the semester at 101.5% for an A.