I recently needed to use a microcontroller to estimate the pose (translation and orientation) of an object using readings from six different sensors. Since the readings were non-linear and coupled with each other, an explicit analytical solution was out of the question.
I figured I’d have a go at using a simple neural network to approximate it:
Since neural networks have been around since the 1980’s, I figured it’d be straightforward. A quick background search uncovered lots of promising leads too, especially regarding “quantization”, which I wanted to do as my microcontroller doesn’t have hardware support for floating point operations.
However, this turned out to be much more difficult than I’d anticipated. It seems like my use case — end-to-end training of a simple dense neural network with integer-only inference — is quite uncommon.
The vast majority of papers and software libraries I found turned out to be complex, heavyweight (in terms of inference code size), and have lots of unstated assumptions and background requirements.
To make a web design analogy: It felt like I kept falling into npm create-react-app
rabbit holes rather than what I wanted: The moral equivalent of opening index.html
with notepad.exe and typing <h1>Welcome to my Homepage</h1>
.
I’m writing up my notes to:
Mathematics won’t render properly in an email, so if you’re interested you’ll have to click over to my website to see my plan for making the cutest neural network.
Back in 2022 I explored a pen/gesture-based user interface for 2D drawing with constraint solvers and recently I decided to make a more general 3D, BRep-based system.
I’d ultimately like something graphical, but since I’ll be building the system with textual code, I’ll need some textual notation to use for debugging, recording test cases, etc. I don’t want to spend the next few months/years reading screenfuls of EDN, JSON, or (have mercy) that incomplete, unparsable stuff Rust’s Debug prints.
So that’s how I ended up starting to design a programming language. After all, I’ve got to come up with semantics for my system anyway, and if I’ve got to do that and have to come up with a concise notation, I might as well put them together into a language, right?
The closest prior art I’m aware of is Build123d, a Python library that provides “builder-style” and “algebra-style” APIs to the OpenCascade BRep kernel.
The primary differentiators I’ll be focusing on are:
For the language itself, I’m leaning towards Julia-style multiple dispatch based on types, with optional argument names for disambiguation.
My hope is that this mechanism will allow for concise specifications. For example, a cylinder could be specified with either a diameter or a radius:
(defn cylinder
([diameter: Length
height: Length]
(extrude height (sketch (circle diameter))))
([radius: Length
height: Length]
(cylinder :diameter (* radius 2)
height)))
Lots of details to sort out here.
For example, both of these methods have the same type arity (length, length), so for an invocation like (cylinder 1mm 2mm)
, should I:
Multiple dispatch could also be used to simplify the “happy path” by having some methods define necessary conversions. E.g., a solid extrusion requires a closed profile, but in the general case a sketch may not have exactly one closed profile. So the extrude invoked by the first cylinder method above would only make sense if extrude was defined something like:
(defn extrude
([distance: Length
sketch: Sketch]
(extrude distance (get-unique-closed-profile-or-throw sketch)))
([distance: Length
profile: Profile]
...))
That said, I haven’t implemented a language with multiple dispatch and type inference, and I expect there are tons of tricky interactions — if you have any recommendations, advice, or just want to get into trouble with me on this, please drop me a line!
Last newsletter I was wondering about graph-directed autocomplete as a way to have the computer “do what I mean” and figure out how to compose functions to map provided arguments to a desired type.
My motivating example was “figure out how to make an axis from a circular face”, and I’m happy to report that such a system can be implemented in a few lines of Clojure:
(def fns
"A list of [function-name arg-types return-type]"
[["plane, three point" [:point :point :point] :plane]
["axis, normal to plane through point" [:plane :point] :axis]
["point, edge start" [:edge] :point]
["point, edge mid" [:edge] :point]
["point, edge end" [:edge] :point]
["plane, containing edge" [:edge] :point]
["point, arc centerpoint" [:arc] :point]
["point, circle centerpoint" [:circle] :point]
["edge, from points" [:point :point] :edge]
["plane, circle" [:circle] :plane]
["plane, arc" [:arc] :plane]])
(def all-types
(->> (flatten fns) (filter keyword?) set))
(def all-fns
(concat fns
;; add fns which construct a type from id
(for [t all-types]
[(name t) [:id] t])))
(def fn-name->type
(into {} (for [[name _ return-type] all-fns]
[name return-type])))
(defn possible-arglists
"For a given function signature and possible expressions indexed by type, find all possible args"
[signature type->exprs]
(->> (apply clojure.math.combinatorics/cartesian-product (map type->exprs signature))
;;don't allow an expression to be used multiple times
(filter (fn [args] (= (count args) (count (set args)))))))
(defn expand
"expand set of exprs by applying all possible fns with all possible permutations of args"
[exprs]
(let [type->exprs (->> exprs
(group-by (comp fn-name->type first)))]
(into exprs
(for [[name signature _] all-fns
args (possible-arglists signature type->exprs)]
(into [name] args)))))
(comment
;; what can you do with two points?
(expand #{["point" 1] ["point" 2]})
;; => #{["point" 1]
;; ["point" 2]
;; ["edge, from points" ["point" 1] ["point" 2]]
;; ["edge, from points" ["point" 2] ["point" 1]]}
;; leave them as is or make two different directed edges
)
(defn autocomplete
([exprs target-type]
(autocomplete exprs target-type 3))
([exprs target-type max-iterations]
(->> (iterate expand exprs)
(take max-iterations)
last
(filter #(= target-type (fn-name->type (first %)))))))
(comment
;; the motivating problem: how can you get an arc from an axis?
(autocomplete #{["arc" 1]} :axis)
;; => (["axis, normal to plane through point"
;; ["plane, arc" ["arc" 1]]
;; ["point, arc centerpoint" ["arc" 1]]])
;; just one solution: use the arc to get a plane and a point, then use those to get an axis.
)
We all know computers can search graphs like this, but it’s still fun to actually write it out.
The next step would be to extend this with:
["length" :edge :length]
["edge-to-profile" :edge :profile]
for open edgesAlso: shout out to newsletter reader Xavier who suggested I look at OnShape’s Mate Connector concept as another way to solve this selection problem. My programmer interpretation of mate connectors is that they’re reified interfaces for parts, such that rather than relating specific geometry (faces, edges, etc.) between parts, you define and relate mate connectors so that the relationship is robust to later changes to the underlying “implementation” (geometry/topology) of the parts.
Several people wrote after my last newsletter to ask where I find so many articles and esoteric YouTube videos. Well, over the winter I moved my 3x weekly 90 minute cardio routine onto a stationary bike in a gym.
The gym has wifi.
An interactive-speed Linux computer on a tiny board you can easily build with only 3 8-pin chips
How I use LLMs - Awesome overview from a boss.
“turns out coca-cola people model the back emf of the dispensor’s flow control module by taylor expansion of pressure into 26 terms of 6 features (time, voltage etc.), and got ~90% accuracy +- 10 psi.” x.com post
The Spade Programming Language is a nice lookin’ hardware description language — their Blinky (for software people) makes me want to have a go at programming an FPGA sometime…
GARF: Learning Generalizable 3D Reassembly for Real-World Fractures. The computer figures out how to put broken stuff back together.
Haptick is a Stewart platform spacemouse built using SMD resistors as strain gauges.
If You’re So Smart, Why Can’t You Die? What does AI tell us about the word “intelligence?”