File size: 4,547 Bytes
d594310
b745e8c
d594310
 
 
 
 
 
 
 
 
 
 
 
 
 
 
65c605b
d594310
 
c1dc3b9
 
7f41a3c
c1dc3b9
d594310
c1dc3b9
d594310
 
 
 
 
 
 
 
 
 
 
 
 
 
 
62fd5e6
 
 
d594310
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
65c605b
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
d594310
 
62fd5e6
d594310
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
7f41a3c
d594310
 
b745e8c
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
---
license: mit
library_name: pytorch
tags:
  - rubiks-cube
  - search
  - value-iteration
  - reinforcement-learning
pipeline_tag: other
---

# tiny-cube-solver

A 33.6M-parameter network that guesses how many moves a Rubik's Cube is from
solved, plus a search that uses the guess to find the moves. It was trained from
nothing: no solver, no example solutions, no human data.

- Solves **95%** of fully scrambled cubes (142 of 150, scrambles of 20 to 100 moves)
- Solves **every** cube scrambled with 10 moves or fewer
- Built as a control for [RubiksBench](https://brianbriscoe.dev/lab/rubiksbench),
  where language models must write the whole answer in one reply. On the same
  full scrambles the best of them, GPT-6 Astra, solves 9 of 10 with answers
  averaging over 100 moves; this model's answers average about 22. It is not the
  same test: this model gets a search loop, the language models get one reply.

Write-up and replays: https://brianbriscoe.dev/lab/tiny-cube-solver

## Try it

```sh
pip install torch transformers safetensors huggingface_hub
python solve.py --scramble "R U F' D2 L B'"
```

or with a cube state in the `kociemba` layout (faces U R F D L B, nine stickers
each):

```sh
python solve.py --facelets <54 characters>
```

Use `--beam 1024` for full scrambles, which needs a GPU. The default, 64, is
fast enough for a laptop, but it only solves short scrambles.

`solve.py` has no other dependencies. It downloads `config.json` and
`model.safetensors` from this repo the first time.

## How it works

The network does not write moves. It reads the 54 stickers of one cube and
returns one number: its guess of the distance to solved.

`solve.py` then searches:

1. Apply each of the 18 moves to every position it is keeping.
2. Ask the network to score all the new positions.
3. Keep the best `--beam` of them, and repeat.
4. Stop when one of them is the solved cube.

Every move is applied by ordinary code, and the answer is checked before it is
printed. The network only decides which positions are worth keeping.

### Training: the model makes its own answers

The model was trained by approximate value iteration (the method behind
[DeepCubeA](https://www.nature.com/articles/s42256-019-0070-z)). It starts from
one free fact: the solved cube is 0 moves from solved. A cube is then 1 more
than its best neighbour. The network learns from its own previous guesses, and
the correct answers spread outward from the solved cube, one move further each
round. No solver is involved at any point.

An earlier version with the identical network was trained on distances from the
Kociemba solver instead. It solved only 16% of full scrambles. Kociemba returns
good solutions, not the shortest, and 47% of random cubes got the label "21", so
there was nothing to learn from above distance 15. Changing only the labels took
full scrambles from 16% to 96%.

## Results

Canonical RubiksBench scrambles (the same cubes every language model on the
board is tested on), 25 cubes per scramble length:

| Scramble length | Solved (beam 1024) | Average answer |
|---|---|---|
| 3 | 25/25 | 3.0 moves |
| 6 | 25/25 | 6.0 |
| 10 | 25/25 | 10.0 |
| 15 | 25/25 | 20.4 |
| 20 | 24/25 | 22.0 |
| 25 | 24/25 | 21.9 |
| 30 | 25/25 | 21.6 |
| 40 | 23/25 | 23.0 |
| 50 | 23/25 | 21.9 |
| 100 | 23/25 | 21.5 |
| **all** | **242/250 (96.8%)** | |

Measured 2026-09-24 on one RTX A6000. Every cube and answer is replayable at
https://brianbriscoe.dev/lab/tiny-cube-solver.

Past about 15 moves, every scramble is fully mixed, so 25, 50 or 100 moves are
no harder than 20. A full scramble takes about 80 to 90 seconds on one RTX A6000.

## Model

- A Llama-shaped encoder, trained from scratch: 8 layers, width 512, 8 heads.
  The architecture only; no Llama weights.
- Input: `[BOS]` + 54 sticker tokens + `[SEP]`. Output: the mean of the final
  layer, through one linear layer, to one number.
- 33,577,985 parameters, float32.

## Things that give much lower numbers

| What you did | What you get at 20 moves |
|---|---|
| Always take the best-scored move, no search | 34% even at 10 moves |
| Judge the network by its average error | about 1.5 moves, which looks poor; the search only needs the correct ranking of the 18 neighbours |

## Limits

- It is not fast. The Kociemba two-phase solver solves any cube in milliseconds.
  This model exists to show that a small network can learn the task at all.
- Solutions are not guaranteed to be shortest. Full scrambles average about 22
  moves.
- 3x3x3 only.

## License

MIT. See `LICENSE`.