Coherent 0.2.24: the architecture at an interim stage
Listen to this post16 min
Created by AI from the text of this post and read by the synthetic voice “Sulafat”; not a word-for-word version, and it may contain errors.
Loading…
Created by AI from the text of this post and read by the synthetic voice “Sulafat”; not a word-for-word version, and it may contain errors.Position and speed stay in this browser and are sent nowhere.
The recording could not be played. Open the audio file
Coherent is a chess engine that speaks the UCI Universal Chess Interface, the text protocol between a chess engine and the program that runs it. protocol. Version 0.2.24 is the build the oracle adopted on 2026-10-23 in run T-0202. This entry describes how it is put together: how a position becomes a move, which search methods it uses and how its neural network evaluates. At the end come the playing-strength figures known today. It is a snapshot of one version. The figures on its structure were read from the source code of 0.2.24; training and strength figures come from the oracle's register and the website.
At a glance
- About
7,200lines ofC++20, compiled in3translation units, plus a generated file with the network weights. 1search thread. The engine offers3UCI options: hash size (default64MB), a default search depth and the ProbCut margin.- Search: alpha-beta as a principal variation search, with iterative deepening, aspiration windows and a quiescence search.
- Evaluation: only the neural network, scaled by the material on the board, plus a small term for one endgame. Correction tables in the search adjust the network's value.
- Not included: endgame tablebases, an opening book of its own, several threads.
- The search has
114named parameters and the time allocation5more, each with a default and an allowed range.
How a move comes about
The UCI layer reads the commands of the user interface: the position with the moves played so far, then go with the time on the clock. It turns the clock into two time limits and starts the search in a thread of its own. The search session keeps the transposition table and most learning tables for the whole game; they are cleared with ucinewgame. At the root the engine deepens step by step, round after round. Each round goes through the main search, which hands over to the quiescence search at the horizon. Positions are valued by the network. At the end of each round the engine reports the best line so far; when time runs out, it plays the best root move.
Board and move generation
The board is kept twice: as a list of 64 squares and as bitboards, 1 per colour and 1 per piece type. A move fits into 4 bytes. Attack masks for knights, kings and pawns and 8 rays per square are computed while the program is compiled. There are no tables indexed by board occupancy, as many engines use them for sliding pieces. A bishop, rook or queen instead follows each ray up to the first blocker, which a single bit scan finds.
Making a move copies the whole board; taking it back copies the old board back. Pins and checking pieces are computed once per node, after which a mask test per move decides legality; king moves and en passant captures get an extra check. A move from the transposition table is checked under the same conditions as the generator before it is searched.
The search
At the root the engine searches depth 1, 2, 3 and so on, up to the depth asked for or until time runs out. From depth 4 it searches with a narrow aspiration window around the last value; after each miss the window grows, and beyond 1,200 centipawns it is opened completely. The best move of the last round comes first, the others follow by how much work they took, and quiet moves among them by how often they were best.
In each node the main search goes through a fixed order of steps, shown in the picture. First come cheap checks: draw by repetition or the fifty-move rule, a repetition the side to move can force, mate distance, and a cut by the transposition table. Then the network evaluates the position and the correction tables adjust the value. With that value several steps try to end the node early: razoring up to depth 3, reverse futility up to depth 8, the null move from depth 3, verified with real moves from depth 13, and ProbCut from depth 5. From depth 3, a node without a move from the table is searched 1 ply shallower if it lies on the main line or a cut is expected there. From depth 5 the singular extension tests whether the table move alone holds the position; then it is searched deeper, up to 3 plies.
In the move loop the engine prunes moves that promise little once a move has shown that the position is not lost: late quiet moves, moves below a futility margin, quiet moves with a poor history and moves that lose too much material in the static exchange evaluation. Later moves are first searched shallower, by a reduction that grows with the logarithm of depth and of move number; only if that probe beats the lower bound of the window does a full search follow. Checks that do not give away material are searched 1 ply deeper.
At the horizon the quiescence search plays only captures and promotions until the position is quiet. In check it tries evasions; once one avoids mate, only captures and promotions follow. It has no depth limit of its own: captures use up material, and repetitions and the ply limit of the search stack end every series of checks.
What the search learns as it goes
The order in which moves are tried decides how much the search can prune. Coherent roughly tries the move from the transposition table first, then good captures, then 2 killer moves and the countermove, then quiet moves by their history, and bad captures last; the history can shift moves across these stages. The histories are tables the search updates as it goes: for quiet moves by origin and target square and by whether those squares are attacked, for moves near the root, by pawn structure, for captures, and for follow-up moves 1, 2 and 4 plies back.
A second kind of learning corrects the evaluation. For every node not in check the search reads 6 entries: by pawn structure, by the placement of the white pieces, of the black pieces, by the last move, by the minor pieces and by the major pieces, the last two together with both kings. Their weighted sum is added to the network's value. When the search result says more than the evaluation, the entries move a step towards it. Finally the value is pulled towards 0 as the fifty-move counter rises.
Table, draws and clock
- Transposition table:
10bytes per entry,3entries in a block of32bytes. It gets whatever the hash budget leaves after the other search tables. A new position takes the place of the entry with the lowest rank in its block: empty entries first, otherwise depth minus4times age. - Draws: inside the search tree a position repeated once counts as a draw; before the root it takes a third occurrence. Repetitions the side to move can force by a single reversible move are found with a cuckoo table of
3,668reversible moves, without generating moves. - Clock: the engine keeps
5% of its remaining time in reserve, at least30ms and at most half. The rest is shared over the moves still expected, plus59% of the increment; that is the soft limit. The hard limit is3.24times as long, but never more than the time left after the reserve. With8seconds plus0.08per move, as in the oracle's short stage, the first move gets247ms, at most800ms. After each round the engine stops once the soft limit has passed, scaled by how stable the best move is, whether the value is falling and how much of the work went into the best move; the hard limit also ends a round in progress.
The network
The network sees the board twice, once from each side. For each view there are 768 inputs: 2 colours, own or opponent's, times 6 piece types times 64 squares. The square of the own king selects 1 of 8 sets of these inputs, called king buckets; if the king stands on files e to h, the view is mirrored. The first layer turns each view into 768 values. Both views are joined, the side to move first, and pass through layers of 16 and 32 neurons to 1 output in centipawns. The network has 4,744,529 parameters, 99.5 % of them in the first layer, and computes only in integers.
The first layer is not recomputed for each position. A move notes which pieces it moved, and the sums are updated only when a position is evaluated, starting from the nearest position already computed. When the own king changes its bucket or the mirroring of its view, the view is rebuilt from a cache. Vector paths for AVX2 and AVX-512 give the same result as the plain path.
After the network, the value is scaled by the material: with all pieces on the board by about 1.56. For king, bishop and knight against king, a term of 40 centipawns per unit of distance, counted in files plus ranks, leads the bare king into the nearest corner of the bishop's colour. Of the hand-written evaluation of earlier versions, only the piece values are still in use: for the static exchange evaluation and for the material count.
What changed since 0.2.21
3 versions were adopted after 0.2.21, each in a run of the oracle against its predecessor:
0.2.22(2026-10-21): when the evaluation rises, the reverse futility margin is lowered by the actual rise, at most by the former fixed40centipawns.0.2.23(2026-10-22):4speed changes that leave the search results unchanged for the same amount of search work: the transposition table entry is fetched earlier, the network sums run in512-bit registers on processors that support it, a cheap pre-test saves lookups in the cuckoo table, and for the network then in use the outputs of the first layer were reordered so that the next layer can skip more zeros.0.2.24(2026-10-23): a new network with8king buckets instead of4. The new buckets tell apart how far the own king has advanced. Its starting network was trained for16epochs with this layout and then fine-tuned for4epochs on148.8million positions evaluated by Coherent's own search.
3 versions since 0.2.21: each passed both stages against its predecessor. Short stage, 8 s + 0.08 s per move, with 95 % half-width: 0.2.22 4.6, 0.2.23 5.64, 0.2.24 9.23; Long stage, 40 s + 0.4 s per move, with 95 % half-width: 0.2.22 4.22, 0.2.23 2.65, 0.2.24 12.61.
The values are conditional logistic Elo Strength difference to the opponent, estimated from the games, with a 95-percent half-width where the oracle reported one. Never an absolute rating. estimates against the predecessor, in the short stage at 8+0.08 seconds and in the long stage at 40+0.4 seconds; ± gives the approximate 95 per cent interval. Each test stopped as soon as it reached its bound.
Playing strength: what is known
| Figure | Version | Value | Kind |
|---|---|---|---|
| Arena, published | 0.2.21 | 3701, total band ±51, of it ±5 statistical | measurement against 10 foreign engines |
| AFE | 0.2.22 | 3703 [3693; 3712] | estimate |
| AFE | 0.2.23 | 3703 [3690; 3716] | estimate |
| AFE | 0.2.24 | 3710 [3695; 3726] | estimate |
The Arena value is the latest measurement against engines from other authors with a listed rating, anchored to the opponents' CCRL Computer Chess Rating Lists, a public ranking of chess engines from games under standard conditions. Blitz ratings. The website marks it as of limited reliability; the reasons are in the entry “Arena measurement EV-3: 3701 published, 3688 without hobbes”. The AFE Anchor-forwarded Elo: an estimate of a Coherent build’s strength on the scale of the latest anchoring, carried forward by the measured gains of the runs since. An estimate, not a measurement. Explained in full carries that value forward with the gains the oracle measured in the long stage since. It is an estimate, not a measurement; the brackets give its nominal 90 per cent model interval. Before the Arena value of 0.2.21 existed, the AFE of that version was 3735, carried forward from an earlier anchoring. The new anchor set is not bridged to the old one, so the difference is not a measured change. Like the statistical band, the AFE interval does not contain the separate band for the transfer to the rating list. Engine ratings are not FIDE ratings.
How this was checked
Every statement about the structure was read from the source code of version 0.2.24, which is unchanged on the main branch at the time of writing; the figures were bound to the code by a script. The Elo values come from the oracle's register. The AFE values come from the run pages of the website and were recomputed with the published method from the Arena value and the register. An agent of another model family checked the text against the same sources.
Coherent keeps changing: each version the oracle adopts alters part of this picture.