Reso: Rewritten in Rust and now 20000x faster!!
tldr: Reso has been re-implemented in Rust, deprecating the Python original. The underlying datastructure is new, with an incidence-map based algorithm. This makes Reso very fast, at about 20000x faster than the original in some cases.
Reso is a logic circuit language and simulator, first written in Python and now revived in Rust. It's a visual language, where inputs and outputs are both .png
images, making MS Paint a totally appropriate IDE. :)
This post assumes you already know the idea behind Reso. You can check Reso out on GitHub and crates.io. You can install it with cargo install reso
.
The story behind Reso
TLDR: I made Reso out of the desire to have a Redstone-like circuit tool.
In 2015, I took a digital logic design course, and I finally started to understand how those magnificent Minecraft redstone computers were built. But Minecraft was such an unwieldy tool for making circuits, and the existing digital logic design tools felt too stuffy and un-fun. I wanted something quick and direct.
In 2017, I started working on Reso, inspired by redstone, piet, and other esolangs. Rather than a simple cellular-automata based system, the language would be made from a series of connected components. The first release was in 2018, with this dinky logo, which doubles as a functional Reso circuit:
In the first iteration, there were red and blue wires, AND nodes and XOR nodes (on the cyans), and input/output nodes (to force directionality on logic flow, on the magnetas). To make wiring easier, wires can be contiguous in eight directions, allowing them to cross, but the other components are contiguous in only four.
In 2019, I started using Rust for the first time, and I made my first attempts to tackle a Rust port of the language.
In 2021, I presented reso at !!con (bangbangcon)! Reso stayed mostly unchanged, but the the palette was shifted from RGB/CYM to the tertiary colors (for more consistent brightness), and a third color wire color was added. It got a brand new logo, which also is a functioning Reso circuit:
It's ugly as hell, but I like it, and it showcases the basic language features: Three wires (underlining the r
, e
, s
characters) feed into the three basic logic gates in the o
character: From top to bottom, AND, OR, and XOR. These output to three new wires, arranged as diamonds. But stuck in Python, Reso was still slow. It took about 40 seconds per iteration of this logo, even after a decent amount of profiling and optimization.
So in 2022 and 2023, I started learning Rust in earnest and and porting Reso. In early 2022, ashirviskas also wrote a Rust port of Reso, but I didn't know enough to understand or extend this port. I ultimately took a different direction with the Rust port I made, with a roadmap of new features in mind.
In the latter parts of 2023, I wrote a number of projects along the way to learn, like this fantasy assembly language. During this time, I had to deprecate the original Python reso because of some breaking changes on dependencies. I didn't care to fix it, in favor of the new Rust port.
In December 2023, I finally ran my first Reso cycle in Rust. With all exports and printing disabled, and using the logo as a test case, I got to about two milliseconds per iteration! Recall the original logo took about 40 seconds per iteration. That means we see a 20000x performance boost!
I expected swapping to Rust alone would yield a 10x to 100x performance boost, as would the algorithmic changes, so a 10000x boost was the upper limit of what I expected. A very welcome surprise :)
The big algorithmic change is in the logic graph
tldr: The Python version uses an adjacency list based on a dictionary (hashmap) to identify which nodes are adjacent to one another. The Rust rewrite uses an incidence list based on dense indices to identify which nodes are adjacent to one another, using no hashmaps to maintain relationships.
Generally, direct integer indexing is faster than using a hashmap.
Both versions only maintain "relevant" adjacencies: Wire-to-inputs, input-to-logics, input-to-outputs, logic-to-outputs, and output-to-wires. We don't care about some adjacencies, like wires adjacent to logic nodes.
Reso works by compiling down to a list of nodes and their adjacencies. A minimal "AND" has six elements: Two input wires, an input node, the "AND" node, the output node, and an output wire.
The key thing here is that every region has a global "region index" integer which identifies it, as well as a "dense index" which identifies it among a class. (Wires, inputs, outputs, and logic nodes each have their own indices.) So, a wire might be the 10th region, but the 3rd wire.
The code is the best description of the algorithms, check Reso out on GitHub.
Here's to a bright 2024
I have so many ideas, and so little time. I want to make Reso more colorblind-friendly, I want to build tooling to make it easier to build in Reso, I want to make prefab components (i.e. sprites), I want to build a circuit in Reso, I want to make it easy to run a Reso circuit on a microcontroller, to make it easy to connect Reso wires to real-world GPIO pins, etc.
The main thing is I want Reso to be a toy people can use to make cool things. The ideal end state is a web editor with a bunch of tools builtin.
I'm on a roll with Reso, but I'm pausing to do genuary in Rust. You can see my progress here.
So, here's a list of what's coming the next time I get a chance to fixate on this:
A computer made in Reso: I started writing Reso at a time when I held all the knowledge in my head to build a computer, or even Tetris, from logic gates. Now that Reso is written in Rust, such a
Onion-skin algorithm walkthrough: While working on Reso, I drew an example input circuit, and added "onion skin" layers explaining every step of the way: The mapping from pixel to Resel
, the compilation to a Vec<Vec<Resel>>
to a ReselBoard
, the results from RegionMap
, then from IncidenceMap
, and then eventually the steps ResoCircuit
takes to iterate. I really want to make this step-by-step onionskinner, and this is probably an easy-ish trick of SVG. But that kind of stuff is far outside the perview of my webdev skills.
A cool new logo :) The current one is ugly :)
Docs: Right now, there are no docs outside of what's contained in the code. This is probably a huge barrier to contributing, but I really want to make a tool that walks you through how Reso compiles.
Better ASCII support: Right now, Reso only operates on images, but is pretty close to ASCII support. Right now, I imagine it'd be hard to make Reso circuits while colorblind.
Palette support: The default colors are chosen to be nice and easy to remember, but they're not the prettiest. An optional palette.png
mapping should be simple to add.
A Reso editor: I want to make an editor specifically for Reso circuits, with no reliance on color, and in-editor compilation and running.
GPIO support, allowing you to connect Reso wires to GPIO, allowing you to run your circuits on a Raspberry Pi.