Triumviratus 6.0 — release notes
A strong UCI chess engine in C++ — NNUE evaluation · SPSA-tuned alpha-beta search · Syzygy
tablebases. GPLv3, by Francesco Torsello, in collaboration with Maurizio Platino.
Every number below is measured, not estimated. Full development log, footnotes and corrections:
DEVELOPMENT_6.0.md · network
training: NETWORKS.md · source:
github.com/Tors3/Triumviratus.
Headline
+52.98 ± 12.25 Elo over 5.1 — 40+0.4, 760 games, LOS 100%, nElo +108.57, SPRT [0,5] passed
(LLR 2.95). Release binary vs release binary (AVX-512), each loading its own network
(6.0 → rubicon-alea-v3, 5.1 → rubicon-alea-v1), 1 thread, 256 MB, UHO 2024 book, resign/draw
adjudication on. Score 57.6%, pentanomial [0, 47, 173, 158, 2], pairs ratio 3.40.
This gate was run on the shipped binaries, at the longest time control used anywhere in this
release, and it includes every change listed below. Roughly half of the margin is search work, half
the network.
An earlier gate measured +33.18 ± 9.86 at 20+0.2 with 64 MB on 2026-07-16. It predates eight
further changes and is superseded, not contradicted — the two are separate measurements at
different time controls and hash sizes. The incremental gains listed further down are not
additive: each is measured against the state immediately before it, and they overlap.
Verification: bench on the shipped binary prints 205566 nodes.
What's new over 5.1
New network architecture — TRANN1
The inference machinery is Stockfish's SFNNv13 (GPLv3), extended with two input feature blocks
SFNNv13 does not have:
- PawnPair (4560 features) — pawn-structure geometry: phalanxes, chains, doubled and isolated
pawns, which threat features cannot see (two pawns side by side attack nothing). This feature
design is not ours: it is shared with Stormphrax, Viridithas and Pawnocchio, and is credited to
them. Our implementation and weights are our own. - PassedPawns (96 features) — one per passed pawn. Deciding "is this pawn passed" means combining
the enemy pawn configuration across three files, which the king-relativeHalfKAv2_hminput cannot
express directly. This one is original to this project.
Both fold into the existing threat accumulator, so they add no new SIMD path and cost essentially
nothing at inference. The net format is consequently not SFNNv13; the reader still loads v2-format
nets (zero-filling the passed-pawn segment), so one binary can gate v2 against v3.
New network — nn-rubicon-alea-v3
Own-lineage weights, trained by the project from its own data pipeline — no Stockfish network used as
a seed. Each block is grafted onto the previous net with zero-initialised columns, so the graft is
bit-identical to its parent before training and learning adds signal instead of relearning it.
Measured net-isolated — same binary on both sides, only the network changes:
| Comparison | Elo | LOS | Games | TC |
|---|---|---|---|---|
v2 vs v1 — adds PawnPair, plus own self-play data |
+18.27 ± 9.94 | 99.98% | 1104 | 20+0.2 |
v3 vs v2 — adds PassedPawns |
+6.96 ± 6.56 | 98.1% | 2596 | 15+0.15 |
v3 vs v1 — cumulative |
+15.14 ± 7.69 | 99.99% | 1998 | 20+0.2 |
Network gains shrink at longer time controls — a deeper search recovers part of what the evaluation
already knows — which is why the 15+0.15 row is not additive with the others.
Search and time management
- SPSA mega co-tune of ~50 search parameters, tuned as a block and baked into the compiled
defaults: +15.8 ± 10.9. - TMv2 time management — multiplicative, stateless: stability, eval-trend, node-count and
predicted-move factors, SPSA-tuned. +23.8 ± 18.2. It originally shipped behind a 15 s base-time
threshold after a −22.9 Elo measurement at 10+0.1; a later re-measurement found that cliff no
longer reproduces at any tested time control, and the threshold was removed. TMv2 now runs whenever
the game has an increment. - Two time-management safety stops were re-enabled at zero increment. The increment gate above
also governs the allocation factors, which assume an increment pool — but it had been switching
off two things that allocate nothing: stopping when the root has a single legal move (thinking
longer cannot change the move) and stopping once a mate score has held for several consecutive
iterations. Neither depends on an increment, and both can only stop earlier, never overspend.
They were nonetheless inactive at increment zero — which is how CCRL 40/4 and CEGT are played.
Byte-identical whenever an increment is present, so no measurement above is affected. Verified in
the shipped binary: with one legal move and no increment it now replies in 165 ms instead of
consuming its allocated time. - The unconditional check extension was removed (+8.0 ± 8.1 at 30+0.3): the search used to
extend one ply on every check at any depth, a technique Stockfish dropped years ago. The old
behaviour is still reachable withCheckExtDepth=30. - The quiescence search was rebuilt in two steps. Its move cap had been 1, so outside of check it
examined a single move per node — a chain rather than a tree; raising it to 3 gained
+5.21 ± 6.47. With that cap lifted, removing quiet checks from quiescence then gained
+9.71 ± 5.99 (LOS 99.93%, SPRT bound closed over 3294 games at 20+0.2) — the largest single
search gain in this release, and one that had been hidden: under the old cap, quiet checks competed
with captures for the only slot available, and an earlier measurement had therefore concluded they
were useful. - Continuation-history rework (+13.97 ± 6.43), killer-move staleness fix (+12.15 ± 5.97),
en-passant hash correction, fine-grained SMP tree diversification, and a king-shield-pawn ordering
malus ported from Reckless (+3.53 ± 3.42). - A final pre-release audit compared the search mechanism by mechanism against Stockfish master,
Reckless, Stormphrax and Integral, and fixed seven latent defects — most consequentially a
ProbCut child node that left four per-ply stacks uninitialised, so history bonuses were being
credited to the wrong move class. Gated as a non-regression check: +2.18 ± 6.31.
New UCI options
MultiPV and go searchmoves (analysis), SyzygyProbeDepth, SyzygyProbeLimit,
Syzygy50MoveRule, and UCI_ShowWDL.
Shipped option set: Hash, Threads, MultiPV, UCI_ShowWDL, Clear Hash, Move Overhead,
EvalFile, SyzygyPath, SyzygyProbeDepth, Syzygy50MoveRule, SyzygyProbeLimit,
UCI_EngineAbout. Tuning and diagnostic parameters are hidden in release builds.
Incremental gains over 5.1
Each row is measured against the state immediately before that change — they are not additive,
they overlap. 1 thread, 64 MB, UHO 2024 book, no score-based adjudication.
| Change | TC | Games | Elo | LOS |
|---|---|---|---|---|
| SPSA mega co-tune (~50 params) | 10+0.1 | 1058 | +15.8 ± 10.9 | 99.8% |
| TMv2 time management | 20+0.2 | 380 | +23.8 ± 18.2 | 99.5% |
| v2 network + search re-tune + large-pages NPS | 20+0.2 | 394 | +38.1 ± 17.1 | 100% |
| Unconditional check extension removed | 30+0.3 | 1654 | +8.0 ± 8.1 | 97.3% |
| Fine-grained SMP tree diversification | 16+0.16 | 1700 | +4.91 ± 7.97 | 88.6% |
| Continuation history (CorrHistCont + MathFix) | 16+0.16 | 2862 | +13.97 ± 6.43 | 100% |
| KillerReset (anti-stale killer moves) | 16+0.16 | 3290 | +12.15 ± 5.97 | 100% |
| King-shield-pawn ordering malus | 12+0.12 | 10k+ | +3.53 ± 3.42 | 97.85% |
| Seven latent-defect fixes (final audit) | 8+0.08 | 3190 | +2.18 ± 6.31 | 75.1% |
| QSMoveCap 1 → 3 (quiescence searched one move per node) | 15+0.15 | 2868 | +5.21 ± 6.47 | 94.3% |
| Quiet checks removed from quiescence | 20+0.2 | 3294 | +9.71 ± 5.99 | 99.93% |
The last three rows, measured together: +19.51 ± 10.48, LOS 99.99%, 1016 games at 20+0.2. They
sum to about +25 individually and are worth +20 as a block — a concrete illustration of why this
table must not be added up: all three act on the same quiescence and evaluation circuit and their
gains overlap. The test reproduced the previous state on the same binary through UCI options, so
both sides shared a compiler and build flags.
One change did not survive: a correction-history-plus-ordering bundle measured +10.43 ± 5.57 at
10+0.1 and was baked, but at 20+0.2 the same bundle measured −6.89 ± 9.01. Its weakest member
(CorrMaterial, a material-keyed eval correction) was removed and ships off; the other two
members remain. Short time controls inflate this class of patch, and we would rather record the
retraction than the original number.
Files
| File | |
|---|---|
Triumviratus_6.0_avx512.exe |
Windows x64, AVX-512 + VNNI (Zen 4, Ice Lake and newer) |
Triumviratus_6.0_avx2.exe |
Windows x64, AVX2 + BMI2 — use this if AVX-512 is unavailable |
triumviratus_linux_avx512, triumviratus_linux_avx2 |
Linux x64 |
triumviratus_android, triumviratus_android_dotprod |
Android arm64 |
nn-rubicon-alea-v3.nnue |
the network — provided separately, but not required: see below |
SHA256SUMS.txt |
checksums (LF line endings) |
The network is embedded in every binary — each executable runs on its own, with no .nnue file
present (verified: a binary alone in an empty directory benches 205566). The .nnue is shipped
separately only so you can override it: a file of the same name beside the executable takes
precedence, and EvalFile accepts any path. So a single executable is a complete engine.
AVX-512 is measured +6.78% faster than AVX2 at identical node counts on Zen 4. All Windows
binaries are ThinLTO + profile-guided, trained on real searches over book positions at five different
move times rather than at fixed depth.
One further +2.6% NPS comes from not computing move-ordering masks that are multiplied by a
disabled term — byte-identical, verified node-for-node over 48 million nodes and confirmed in both
measurement orders.
Credits and license
GPLv3 — see COPYING. Only the NNUE inference code derives from Stockfish; the search and the
rest of the engine are the project's own, and the shipped network was trained here. Syzygy probing
uses Fathom (MIT); the move generator descends from BBC by Maksim Korzh. Search and ordering
ideas were studied from Reckless, Caissa, Alexandria, Pawnocchio, Viridithas, Berserk, Obsidian,
Ethereal and Stormphrax. The PawnPair feature design belongs to Stormphrax, Viridithas and
Pawnocchio, not to us — only its implementation here and the trained weights are ours. Because the
engine incorporates Stockfish's GPL code, the whole project is distributed under GPLv3 with
Stockfish's copyright notices preserved.
Testing and search tuning throughout development: Maurizio Platino, who also runs the engine
against curated hard positions at long time controls — the project's only systematic qualitative
strength testing — and contributed hardware for the long tuning runs.
Full credits: see the Credits section in the README.