cpool-c191-b6
A policy/value network for Quantik, 1,780,253 parameters.
Quantik is a two-player game on a 4x4 board with four piece shapes. A player may not place a shape in a row, column or 2x2 zone where that shape already appears, whoever played it β so a move can be blocked by your own piece. The first player to complete a line or zone holding all four distinct shapes wins. There are no draws.
This model predicts, for a given position, which move an exact solver would play (policy) and who is winning (value).
About this project
Quantik began as a holiday rivalry and became an engineering project. Before building an AI to play β or teach β the game, the game itself had to be represented precisely: an exact notation, a canonical form under the board's 192 symmetries, and a bitboard the rules can be computed on cheaply.
That foundation is what these models are trained on. Every label is exact, produced by a solver rather than by self-play, so the network fits ground truth instead of its own earlier opinions. The engineering is written up as a series on The Full-Stack Mind: first-principles representation, then Monte-Carlo search, beam search, exact endgame proof, and a tournament where the engines finally played each other.
Architecture
Pools over Quantik's twelve constraint groups β four rows, four columns, four 2x2 zones β so the rule that decides the game is wired into the architecture rather than learned from data.
flowchart LR
IN["board<br/>(B,9,4,4)"] --> STEM["stem<br/>Linear 9βC per cell Β· LayerNorm"]
STEM --> BLK
subgraph BLK["constraint block Γ B"]
direction LR
P["pool over the 12 groups<br/>4 rows Β· 4 columns Β· 4 zones"] --> M["mix<br/>Linear Β· GELU"]
M --> S["scatter back to cells"]
S --> R["+ residual Β· LayerNorm"]
end
BLK --> PH["policy head<br/>Linear Cβ4 per cell<br/>transpose β 64"]
BLK --> VH["value head<br/>mean over cells Β· MLP Β· tanh"]
PH --> POL["policy logits (B,64)"]
VH --> VAL["value (B,)"]
| blocks | 6 |
| channels | 191 |
| expansion | 2 |
| value_hidden | 64 |
| parameters | 1,780,253 |
Every architecture in this family is matched to within 1.2% on parameter count, so a comparison between them is about the design and not about capacity.
Results
| metric | value |
|---|---|
| Held-out optimal-move accuracy, plies 4-6 | 0.9295 |
| Held-out optimal-move accuracy, plies 7-12 | 0.9919 |
| Arena win rate vs the field (1800 games) | 57.2% |
Held-out accuracy is measured on exactly solved positions sharing no canonical key with the training corpus, up to the 192 board symmetries β so it measures generalisation, not recall. It is reported split rather than pooled because the corpus contains nothing at the shallowest plies, and a pooled figure is dominated by deep positions where every model is near perfect.
Input and output contract
input (B, 9, 4, 4) float32 tensor-board.v1, mover-relative
output (B, 64) policy logits action_index = shape * 16 + position
(B,) value in [-1, 1] +1 = good for the side to move
Planes 0-3 are the side to move, 4-7 the opponent, 8 a ply indicator. position = row * 4 + col.
Legality masking happens outside this model
It emits logits over all 64 actions, including illegal ones. Applying the legal-move mask before the softmax is the caller's job. An unmasked argmax from this model will play illegal moves β silently, because an illegal move looks like a bad move rather than like a bug.
This is by design. Quantik's rules are exact and cheap to compute in quantik-core, so the network is never asked to approximate them and never spends capacity on legality.
Usage
There is no AutoModel for this architecture β the Hub cannot reconstruct it from weights alone. Two supported paths.
With quantik-models
Reads manifest.json and rebuilds the network from architecture_spec, and gives you the legality masking for free.
# quantik-models is not on PyPI yet; install it from source.
pip install 'quantik-models[torch] @ git+https://github.com/mberlanda/quantik-models-py'
pip install huggingface_hub
from huggingface_hub import snapshot_download
from quantik_models.arena.registry import load_evaluator
from quantik_models.env import fastboard as fb
evaluator = load_evaluator(snapshot_download("brpoplpush/quantik-cpool-c191-b6"), "cpu")
boards = fb.empty_boards(1) # (1, 8) uint16
policy, value = evaluator.evaluate(boards) # masking applied
With ONNX Runtime, and neither torch nor this package
pip install onnxruntime numpy huggingface_hub
import numpy as np, onnxruntime as ort
from huggingface_hub import hf_hub_download
path = hf_hub_download("brpoplpush/quantik-cpool-c191-b6", "model.onnx")
session = ort.InferenceSession(path)
# (B, 9, 4, 4) float32, mover-relative β see the contract above.
tensors = np.zeros((1, 9, 4, 4), dtype=np.float32)
policy, value = session.run(None, {"board": tensors})
# The mask is yours to apply. `legal` is a (B, 64) bool array;
# quantik_models.env.fastboard.legal_masks computes it, and so
# does quantik-core in Rust.
# policy = np.where(legal, policy, -np.inf)
The rules engine
Legality, symmetry and the exact solver live in quantik-core, which is published for both languages and is what generated the training labels.
pip install quantik-core # Python, >=3.12
cargo add quantik-core # Rust, 2021 edition
How it was trained
| corpus | exact-sampled.npz |
| architecture preset | medium |
| epochs | 16 |
| batch size | 1024 |
| learning rate | 0.0006 (cosine to 1e-05) |
| weight decay | 0.0001 |
| seed | 20260828 |
| symmetry augmentation | yes |
| ply-balanced sampling | yes |
Labels are exact, not bootstrapped: every training target comes from a solved position, so the network is fitting ground truth rather than its own earlier opinions.
The learning rate is a property of the architecture rather than a project-wide default. A single shared rate is not equal treatment between architectures β it privileges whichever one it was chosen for β and correcting that in this project reversed several conclusions rather than merely shifting decimals. Ply-balanced sampling gives every game stage equal attention instead of attention proportional to how many positions it happens to contribute. The corpus is dominated by late positions; the match is decided early.
Limitations
Accuracy is not uniform across the game. Deep positions are nearly forced and every model in this family is close to perfect there; the shallow openings are where they differ and where they are weakest.
| ply | accuracy on provably won positions |
|---|---|
| 4 | 0.8780 |
| 5 | 0.9324 |
| 6 | 0.9746 |
| 7 | 0.9915 |
| 8 | 0.9835 |
| 9 | 0.9904 |
| 10 | 0.9937 |
| 11 | 0.9977 |
| 12 | 1.0000 |
Weakest at ply 4 (87.8%), strongest at ply 12 (100.0%).
The evaluation is against solved positions and other engines, not against people. Nothing here says how it plays against a human.
One training seed. Every number on this card comes from a single run of this architecture.
Files
model.safetensorsβsha256:fc9849d14ea415f5d2f616981bfbd78eaa546e7557effb48c9fa6e4b9160bc23model.onnxβ opset 18,sha256:54b3040d8e4ae62654c7ddacbc70d5b74252006de722c8e870a6155665d42515, dynamic batch dimensionconfig.jsonβ the architecture spec, readable without loading anythingmanifest.jsonβ themodel-checkpoint.v1record this repo was staged fromtraining-report.jsonβ the epoch that produced these weights, and its metrics
Contract version 1.2.0. Exported 2026-08-29.
Other models in this family
Same contract, same corpus, same training protocol β interchangeable at the interface, so they can be compared directly.
Source
- Model code and training: https://github.com/mberlanda/quantik-models-py
- Rules engine (Python): https://github.com/mberlanda/quantik-core-py
- Rules engine (Rust): https://github.com/mberlanda/quantik-core-rust
- Shared schemas: https://github.com/mberlanda/quantik-core-contracts
Licence
The weights in this repository are CC BY-NC 4.0. Free to use, share and adapt for research, teaching and any other non-commercial purpose, with attribution. Commercial use requires a separate agreement β open an issue on the source repository or contact the author.
This is deliberately not an OSI-approved open-source licence. Every OSI licence permits royalty-free commercial use, which is the one thing this reserves.
The code is separate and more permissive. quantik-models and quantik-core are MIT, so the training pipeline, the rules engine and the evaluation harness carry no such restriction β only these weights do.
- Downloads last month
- 15
Evaluation results
- Held-out optimal-move accuracy, plies 4-6 on exact-sampledself-reported0.929
- Held-out optimal-move accuracy, plies 7-12 on exact-sampledself-reported0.992
- Arena win rate vs the field (1800 games) on exact-sampledself-reported0.572