back to index

Rubik's Snake — Formally Verified

Coq (Rocq) and TLA+ specifications of the Rubik's Snake state space — 4^23 configurations, formally

repo: https://github.com/EricSpencer00/rubix-snake-puzzle


GitHub Repo

I bought a Rubik's Snake at some point and spent way too long folding it into a ball, a dog, and then back into a stick. It is 24 right-triangular prisms strung together on a chain, with 23 joints between them, and each joint clicks into one of four positions (0°, 90°, 180°, 270°). That gives you 4^23 = 70,368,744,177,664 possible configurations if you ignore physics, and somewhere around 13.4 trillion if you actually require that the wedges not pass through each other. Peter Aylett did the exhaustive backtracking search in C in 2011 (and patched it in 2022). I wanted to ask the same question with formal methods instead of brute force, partly because I've been pulling on the AI-for-formal-methods thread for a while and partly because nobody had done it.

This repo is the first formal verification of the Rubik's Snake puzzle in any proof assistant — Coq, Lean, Isabelle, Alloy, TLA+, none of them. That was honestly the most surprising thing I found while writing the related-work section. The puzzle has a Wikipedia page and a small academic literature (Hou/Chen/Li wrote a couple of papers on it in J. Mechanisms and Robotics, and the Luxembourg group has a nice characterization of which Eulerian paths give you planar configurations), but the formal-methods community had not touched it.

What's in the repo

Two specifications and a Python reference enumerator:

The Coq file opens with this, which I think is the cleanest summary of what's going on:


(* Each joint has 4 possible rotations: 0°, 90°, 180°, 270° around the shared edge. *)
Inductive Rotation : Type :=
  | R0   (* 0°   — straight *)
  | R90  (* 90°  — right angle *)
  | R180 (* 180° — folded back *)
  | R270 (* 270° — left angle *).

The whole thing is built on a 3D integer grid with 6 axis-aligned directions, which means I do not have to deal with floating-point rotation matrices in the proof — everything is Z-arithmetic, and Lia can close most of the arithmetic obligations.

What I did not do (yet)

I have not proved the count. Aylett's number (13,446,591,920,995 valid configurations) is established by exhaustive search, and proving it formally in Coq would require either reflecting the enumerator into Gallina and computing it (impractical — the search took weeks of CPU time in C) or finding a clever combinatorial argument that nobody has found yet. What I have is the formal specification of what a valid configuration is. The bridge from spec to count is still empirical.

I also have not fully worked out the symmetry quotient (mirror + cyclic) that Aylett applies to drop the count from 13.4T to 6.7T. The TLA+ spec does not have it at all; the Coq side has a stub.

Why this exists

It's a hobby-scale formal verification project. Small enough to actually finish, weird enough to be the first of its kind, and connected to the AI-for-formal-methods (ai4fm) work I've been doing on the side. If you wanted a project to learn Coq on that is not yet another "verify insertion sort," the geometry of a physical puzzle is a nice change of pace. The state space is huge but every individual piece of reasoning is concrete — you can hold the puzzle in your hand and check the math.

If you want to play with it, the README has build instructions for Coq 8.18+ / Rocq and the TLA+ Toolbox. PRs welcome, especially on the symmetry reduction or if you have an idea for how to prove the count without exhaustive search.


No time to write a full breakdown for everything — this description was written by an LLM.