SATori logo: a red bar and a green bar, the two polarities of a literal

SATori

version 50 · single-file CDCL SAT solver

A tiny, dependency-free CDCL SAT solver — about 2,000 lines of C++ in one file — specialised for the binary-clause-heavy CNFs of automated planning and for resource-constrained hardware.

By Massimo Di Gruso · Independent Researcher, Cologne, Germany · ORCID 0009-0005-7684-2145

What it is

SATori is a conflict-driven clause-learning solver that fits in a single source file and compiles with no external libraries — from an x86 workstation down to a small embedded board, unchanged. It is not built to win competitions; it is built to be the most reliable solver in the tiny class on its target domain, while staying small enough to deploy where the heavyweight solvers cannot comfortably go.

Its headline component is a clause-span branching heuristic that orders decisions by each variable's structural reach across the clause sequence — favouring the "bridge" variables that connect distant parts of a planning formula. Every UNSAT verdict can be emitted as a DRAT proof and checked independently with drat-trim.

Performance

Evaluated under PAR-2 (timeouts charged at 2× the 100 s budget) against two tiny baselines and two state-of-the-art references. Lower PAR-2 is better.

x86_64 — 112 instances

SolverPAR-2geo. (nt)Timeouts
SATori5,8864652
MiniSat11,3073736
PicoSAT10,4415795
Kissat (SOTA)6,4713413
CaDiCaL (SOTA)4,9854472

Best PAR-2 of any tiny solver — ahead of Kissat — with only the far larger CaDiCaL lower. Its two timeouts are a strict subset of Kissat's; it never fails alone.

armv6l embedded — 36 instances

SolverSolvedgeo. (ms)PAR-2
SATori35 / 365147,935
PicoSAT35 / 365019,839
MiniSat32 / 364,32431,184

On the embedded target SATori is the most reliable tiny solver — roughly 8× faster than MiniSat in geometric mean, and it solves large planning instances on which MiniSat times out.

Download & build

The solver is a single source file, satori-50.cpp, which compiles to the satori binary.

1 — x86_64 build (performance)
$ g++ -O2 -fno-exceptions -fno-rtti -DNDEBUG satori-50.cpp -o satori
2 — Self-contained static binary (deployment)
$ g++ -O2 -fno-exceptions -fno-rtti -DNDEBUG -static -s satori-50.cpp -o satori
3 — armv6l / embedded (native on Alpine, musl)
# stock toolchain, no cross-compilation, no patches $ g++ -O2 satori-50.cpp -o satori
Run
$ ./satori problem.cnf # emit a DRAT proof for an UNSAT verdict and check it $ ./satori --proof proof.drat problem.cnf $ drat-trim problem.cnf proof.drat

-O3 and -march=native give no benefit over -O2 within the noise floor. -Os trades 25–45% of solving speed for a 38% smaller binary. The benchmarks used the dynamic build; -static -s is for deployment.