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.

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

How a move comes about

Schema of the engine. The UCI layer reads the commands and the clock and starts 1 search thread. In it, the root deepens round by round and calls the main search, which hands over to the quiescence search at the horizon; both call the evaluation: the neural network, scaled by material, plus a term for king, bishop and knight against king, and in the search the correction tables and the damping by the fifty-move counter. The search session keeps the transposition table and most learning tables for the whole game; draw detection uses repetitions, a cuckoo table of 3,668 moves, material and the fifty-move rule. Below lies the board: a list of 64 squares and 8 bitboards, attack masks computed at compile time, move generator, legality per node, Zobrist keys, copy-make.
Architecture of Coherent 0.2.24 (schematic)

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.

Flow of one node of the main search in Coherent 0.2.24. Before the moves: draw check for repetition and the fifty-move rule, upcoming repetition with the cuckoo table, mate distance, cut by the transposition table outside the main line, evaluation by the network plus correction, razoring up to depth 3, reverse futility up to depth 8, null move from depth 3, verified with real moves from depth 13, ProbCut from depth 5, one ply shallower without a table move from depth 3 at PV or cut nodes, singular extension from depth 5 with multi-cut. All of these except the evaluation and the shallower search may end the node. Move loop, per move: next move from the staged ordering, pruning of late, futile, poorly rated or losing moves, extensions for singular moves and checks, for later moves a reduced probe whose reduction grows with the logarithm of depth and move number, and a full search for the first move or if the probe beats alpha; the loop ends when a move reaches beta. After the moves: histories, killers and countermove learn, the 6 correction entries learn, and the result is stored in the transposition table.
The steps of one node (schematic)

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

The network

Upper part: schema of the network. Per view 6,144 binary inputs, 8 king buckets of 768 each; a first layer to 768 values per view with 4,718,592 weights; both views joined to 1,536 values with the side to move first; hidden layers of 16 and 32 neurons; 1 output, scaled to centipawns. 4,744,529 parameters in total, 99.5 per cent in the first layer. Lower part: 2 boards with the king buckets, seen from the own side. Version 0.2.23 had 4 buckets: on rank 1, files a and b bucket 0 and c and d bucket 1; on ranks 2 to 8, a and b bucket 2 and c and d bucket 3; files e to h use the same buckets mirrored. Version 0.2.24 has 8: rank 1 as before with buckets 0 and 1, rank 2 with buckets 2 and 3, then 1 bucket for the whole of rank 3 (4), rank 4 (5), ranks 5 and 6 (6) and ranks 7 and 8 (7), mirrored on files e to h.
Network and king buckets (schematic)

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:

3 versions since 0.2.21: each passed both stages against its predecessor 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. 05101520Short stage, 8 s + 0.08 s per move, with 95 % half-widthLong stage, 40 s + 0.4 s per move, with 95 % half-widthElo against the predecessorVersion adopted0.2.220.2.230.2.24Short stage, 8 s + 0.08 s per move, with 95 % half-width, 0.2.22: 4.6 ± 3.28Short stage, 8 s + 0.08 s per move, with 95 % half-width, 0.2.23: 5.64 ± 3.55Short stage, 8 s + 0.08 s per move, with 95 % half-width, 0.2.24: 9.23 ± 5.13Long stage, 40 s + 0.4 s per move, with 95 % half-width, 0.2.22: 4.22 ± 3.19Long stage, 40 s + 0.4 s per move, with 95 % half-width, 0.2.23: 2.65 ± 2.18Long stage, 40 s + 0.4 s per move, with 95 % half-width, 0.2.24: 12.61 ± 6.33

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.

3 versions since 0.2.21: each passed both stages against its predecessor (data of the chess project).

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

FigureVersionValueKind
Arena, published0.2.213701, total band ±51, of it ±5 statisticalmeasurement against 10 foreign engines
AFE0.2.223703 [3693; 3712]estimate
AFE0.2.233703 [3690; 3716]estimate
AFE0.2.243710 [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.