Compare commits

..
Author SHA1 Message Date
Joost VandeVondele 03e27488f3 Stockfish 17.1
Official release version of Stockfish 17.1

Bench: 2030154

---

Stockfish 17.1

Today, we have the pleasure to announce Stockfish 17.1. As always, you can
**freely** download it at [stockfishchess.org/download][1] and use it in the
[GUI of your choice][2].

Join our [Discord server][3] to get in touch with the community of developers
and users of the project!

Quality of chess play

In our testing against its predecessor, Stockfish 17.1 shows a consistent
improvement in performance, with an [Elo gain of up to 20 points][4] and
winning close to 2 times more game pairs than it loses.

Update highlights

New speedtest command

The new `speedtest` command benchmarks your computer's performance (measured in
nodes per second) using a realistic and stable test. To run it, you'll need
[command line access][5]—give it a try and share your results with the
community!

Improved hardware support

Stockfish is [no longer limited to 1024 threads][6] and will allow users to
specify whatever their system is capable of. Additionally, hardware such as
ppc64 and Loongson is now better supported at build time.

Bug fixes for tablebase support

Our previous release introduced improved engine lines (principal variations)
ending in mate as soon as a mate score is announced. A side effect of this
improvement was a [rare corner case][7] involving cursed tablebase wins, only
relevant in correspondence chess when the 50-move rule does not apply,  which
has now been fixed. Relatedly, [time management][8] has also been improved to
avoid potential time losses.

Shoutouts

Download page redesign

We've redesigned the [download page][1] to address unclear wording and simplify
a previously cluttered experience. The page now features a modernized layout,
streamlined navigation, and clearer guidance to help you select the right
binary for your system.

Fishtest framework

Our testing framework has been improved in various ways, both on the worker
side, including the adoption of [Fastchess][9] as a new game manager, and on
the server side, such as streamlined configuration. The reliable availability
of testing resources is key for the progress of the engine.

Thank you

The Stockfish project builds on a thriving community of enthusiasts (thanks
everybody!) who contribute their expertise, time, and resources to build a free
and open-source chess engine that is robust, widely available, and very strong.

We would like to express our gratitude for the [12k stars][10] that light up
our GitHub project! Thank you for your support and encouragement – your
recognition means a lot to us.

We invite our chess fans to [join the Fishtest testing framework][11] to
contribute compute resources needed for development. Programmers can contribute
to the project either directly to [Stockfish][12] (C++), to [Fishtest][13]
(HTML, CSS, JavaScript, and Python), to our trainer [nnue-pytorch][14] (C++ and
Python), or to our [website][15] (HTML, CSS/SCSS, and JavaScript).

The Stockfish team

[1]: https://stockfishchess.org/download
[2]: https://official-stockfish.github.io/docs/stockfish-wiki/Download-and-usage.html#download-a-chess-gui
[3]: https://discord.gg/GWDRS3kU6R
[4]: https://tests.stockfishchess.org/tests/view/67e7d2fd6682f97da2178fbd
[5]: https://official-stockfish.github.io/docs/stockfish-wiki/UCI-&-Commands.html#speedtest
[6]: https://github.com/official-stockfish/Stockfish/commit/652a8874b523360a3b19c5003c8ba9894ac54d0f
[7]: https://github.com/official-stockfish/Stockfish/commit/6c7c5c7e471c16f14518229428e51a3e00c0f1dd
[8]: https://github.com/official-stockfish/Stockfish/commit/0f9ae0d11cd034288a49ef3892c580dfed025091
[9]: https://github.com/Disservin/fastchess
[10]: https://github.com/official-stockfish/Stockfish/stargazers
[11]: https://official-stockfish.github.io/docs/fishtest-wiki/Running-the-Worker.html
[12]: https://github.com/official-stockfish/Stockfish
[13]: https://github.com/official-stockfish/fishtest
[14]: https://github.com/official-stockfish/nnue-pytorch
[15]: https://github.com/official-stockfish/stockfish-web
2025-03-30 13:44:15 +02:00
Disservin aafc732bcb Silence "may be used uninitialized" GCC warning
Helps gcc silence the warning about

```
warning: 'added' may be used uninitialized [-Wmaybe-uninitialized]
const IndexType offsetA0 = TransformedFeatureDimensions * added[0];
```

closes https://github.com/official-stockfish/Stockfish/pull/5950

No functional change
2025-03-29 11:55:55 +01:00
Robert Nurnberg @ elitebookandDisservin 4a869f41c6 Update the WDL model
This PR updates the internal WDL model, using data from 2.6M games
played by the revisions since f3bfce3531.
Note that the normalizing constant increases only moderately from 372 to
377.

```
> ./updateWDL.sh --firstrev f3bfce3531
Running: ./updateWDL.sh --firstrev f3bfce3531 --lasttrev HEAD --materialMin 17 --EloDiffMax 5
started at:  Sat 22 Mar 11:02:14 CET 2025
Look recursively in directory pgns for games with max nElo difference 5 using books matching "UHO_Lichess_4852_v..epd" for SF revisions between f3bfce3531 (from 2025-02-28 09:50:59 +0100) and HEAD (from 2025-03-21 11:22:59 +0100).
Based on 138253430 positions from 2579360 games, NormalizeToPawnValue should change from 372 to 377.
ended at:  Sat 22 Mar 11:04:00 CET 2025
```

```
> cat scoreWDL.log
Converting evals with NormalizeData = {'momType': 'material', 'momMin': 17, 'momMax': 78, 'momTarget': 58, 'as': [-37.45051876, 121.19101539, -132.78783573, 420.70576692]}.
Reading eval stats from updateWDL.json.
Retained (W,D,L) = (33794348, 69943262, 34515820) positions.
Saved distribution plot to updateWDLdistro.png.
Fit WDL model based on material.
Initial objective function:  0.3648260131692729
Final objective function:    0.36482338611818094
Optimization terminated successfully.
const int NormalizeToPawnValue = 377;
Corresponding spread = 71;
Corresponding normalized spread = 0.1879431202530567;
Draw rate at 0.0 eval at material 58 = 0.9902694872976331;
Parameters in internal value units:
p_a = ((-13.500 * x / 58 + 40.928) * x / 58 + -36.828) * x / 58 + 386.830
p_b = ((96.534 * x / 58 + -165.791) * x / 58 + 90.897) * x / 58 + 49.296
    constexpr double as[] = {-13.50030198, 40.92780883, -36.82753545, 386.83004070};
    constexpr double bs[] = {96.53354896, -165.79058388, 90.89679019, 49.29561889};
Preparing plots.
Saved graphics to updateWDL.png.
Total elapsed time = 46.92s.
```

Only affects displayed `cp` and `wdl` values.

closes https://github.com/official-stockfish/Stockfish/pull/5939

No functional change
2025-03-29 11:54:32 +01:00
Michel Van den BerghandDisservin 6028264cb9 Delay check for curl/wget until really needed
closes https://github.com/official-stockfish/Stockfish/pull/5938

No functional change
2025-03-29 11:53:53 +01:00
Joost VandeVondeleandDisservin 12d023ed06 Update CPU contributors
closes https://github.com/official-stockfish/Stockfish/pull/5937

No functional change
2025-03-29 11:52:50 +01:00
mstemberaandDisservin 6ceaca4c7b Change layout of CorrectionHistory<NonPawn>
https://tests.stockfishchess.org/tests/view/67da5b158c7f315cc372a9d2
LLR: 2.95 (-2.94,2.94) <0.00,2.00>
Total: 150368 W: 38874 L: 38401 D: 73093
Ptnml(0-2): 424, 16821, 40262, 17212, 465

Make CorrectionHistory\<NonPawn\> handle both black and white
internally. A follow up to
https://github.com/official-stockfish/Stockfish/pull/5816

closes https://github.com/official-stockfish/Stockfish/pull/5934

No functional change
2025-03-21 11:22:59 +01:00
FauziAkramandDisservin 0dabf4f3fa Removing the conditional bonus calculation
The new value is just a guessed value.

Passed STC:
https://tests.stockfishchess.org/tests/view/67d5ee09517865b4a2dfd2df
LLR: 2.95 (-2.94,2.94) <-1.75,0.25>
Total: 52128 W: 13516 L: 13312 D: 25300
Ptnml(0-2): 157, 6044, 13451, 6262, 150

Passed LTC:
LLR: 2.94 (-2.94,2.94) <-1.75,0.25>
Total: 42384 W: 10855 L: 10657 D: 20872
Ptnml(0-2): 19, 4554, 11852, 4744, 23
https://tests.stockfishchess.org/tests/view/67d5f9d3517865b4a2dfd2ef

closes https://github.com/official-stockfish/Stockfish/pull/5933

Bench: 2030154
2025-03-21 11:22:25 +01:00
Nonlinear2andDisservin 43d8ccf856 change the bonusScale depth component
Passed STC:
https://tests.stockfishchess.org/tests/view/67d35f66517865b4a2dfc801
LLR: 2.94 (-2.94,2.94) <0.00,2.00>
Total: 110816 W: 28875 L: 28449 D: 53492
Ptnml(0-2): 329, 13064, 28231, 13420, 364

Passed LTC:
https://tests.stockfishchess.org/tests/view/67d4bdf0517865b4a2dfd131
LLR: 2.94 (-2.94,2.94) <0.50,2.50>
Total: 121824 W: 31047 L: 30559 D: 60218
Ptnml(0-2): 52, 13056, 34214, 13532, 58

closes https://github.com/official-stockfish/Stockfish/pull/5932

Bench: 2128807
2025-03-21 11:21:10 +01:00
Shawn XuandDisservin 9045f17c3f Simplify captures PCM
Passed Non-regression STC:
LLR: 2.92 (-2.94,2.94) <-1.75,0.25>
Total: 229856 W: 59258 L: 59252 D: 111346
Ptnml(0-2): 746, 27330, 58714, 27448, 690
https://tests.stockfishchess.org/tests/view/67d3fdac517865b4a2dfcef4

Passed Non-regression LTC:
LLR: 2.95 (-2.94,2.94) <-1.75,0.25>
Total: 107652 W: 27470 L: 27338 D: 52844
Ptnml(0-2): 56, 11646, 30280, 11798, 46
https://tests.stockfishchess.org/tests/view/67d5f972517865b4a2dfd2ec

closes https://github.com/official-stockfish/Stockfish/pull/5931

Bench: 1842520
2025-03-21 11:19:45 +01:00
Michael ChalyandDisservin 8fc5e92005 Use slightly different formula for stat score when position is in check
Use formula that is closer to movepicker one.

Passed STC:
https://tests.stockfishchess.org/tests/view/67cffb337be98c1ad9b021ee
LLR: 2.99 (-2.94,2.94) <0.00,2.00>
Total: 250432 W: 64978 L: 64343 D: 121111
Ptnml(0-2): 795, 29390, 64159, 30129, 743

Passed LTC:
https://tests.stockfishchess.org/tests/view/67d3905d517865b4a2dfce8a
LLR: 2.94 (-2.94,2.94) <0.50,2.50>
Total: 140004 W: 35742 L: 35215 D: 69047
Ptnml(0-2): 60, 15111, 39151, 15602, 78

closes https://github.com/official-stockfish/Stockfish/pull/5930

Bench: 2147336
2025-03-21 11:19:09 +01:00
Robert Nurnberg @ elitebookandDisservin 652a8874b5 Allow more than 1024 threads on high-end machines
closes https://github.com/official-stockfish/Stockfish/pull/5929

No functional change
2025-03-21 11:17:59 +01:00
FauziAkramandDisservin 4afd7f1a7b Removing contHist[1] from pruning formula
Passed STC:
LLR: 2.95 (-2.94,2.94) <-1.75,0.25>
Total: 51552 W: 13297 L: 13091 D: 25164
Ptnml(0-2): 166, 6009, 13215, 6225, 161
https://tests.stockfishchess.org/tests/view/67c4de79685e87e15e7c43f5

Passed LTC:
LLR: 2.95 (-2.94,2.94) <-1.75,0.25>
Total: 244554 W: 62135 L: 62142 D: 120277
Ptnml(0-2): 137, 26612, 68794, 26589, 145
https://tests.stockfishchess.org/tests/view/67c50982685e87e15e7c443d

closes https://github.com/official-stockfish/Stockfish/pull/5928

Bench: 1980385
2025-03-21 11:16:27 +01:00
Shawn XuandDisservin fc0e0a44d4 Refactor accumulator storage/updates
Passed Non-regression STC:
LLR: 2.93 (-2.94,2.94) <-1.75,0.25>
Total: 115840 W: 29983 L: 29854 D: 56003
Ptnml(0-2): 338, 12990, 31149, 13091, 352
https://tests.stockfishchess.org/tests/view/67d0a044166a3e8781d84223

closes https://github.com/official-stockfish/Stockfish/pull/5927

No functional change
2025-03-21 11:12:47 +01:00
Shawn XuandDisservin 66aee01bb1 Simplify Return Value Adjustment Condition
Passed Non-regression STC:
LLR: 2.94 (-2.94,2.94) <-1.75,0.25>
Total: 82112 W: 21281 L: 21110 D: 39721
Ptnml(0-2): 258, 9630, 21112, 9795, 261
https://tests.stockfishchess.org/tests/view/67c42528b7226b5d8a2dd3a0

Passed Non-regression LTC:
LLR: 2.94 (-2.94,2.94) <-1.75,0.25>
Total: 182652 W: 46295 L: 46240 D: 90117
Ptnml(0-2): 103, 20025, 51003, 20104, 91
https://tests.stockfishchess.org/tests/view/67c4d56b685e87e15e7c43d8

closes https://github.com/official-stockfish/Stockfish/pull/5925

Bench: 1711791
2025-03-21 11:11:12 +01:00
Daniel MonroeandDisservin f9a6d43286 Simplify condition in futility pruning
Passed STC
LLR: 2.93 (-2.94,2.94) <-1.75,0.25>
Total: 427040 W: 111061 L: 111271 D: 204708
Ptnml(0-2): 1709, 48524, 113171, 48500, 1616
https://tests.stockfishchess.org/tests/view/67af01d01a4c73ae1f930ea4

Passed rebased LTC
LLR: 2.94 (-2.94,2.94) <-1.75,0.25>
Total: 28704 W: 7330 L: 7120 D: 14254
Ptnml(0-2): 8, 3000, 8138, 3186, 20
https://tests.stockfishchess.org/tests/view/67ca629a45214989aa0a123e

closes https://github.com/official-stockfish/Stockfish/pull/5924

Bench: 2050046
2025-03-21 11:09:38 +01:00
Shawn XuandDisservin e3660b47bd Add dbg_clear helper function
closes https://github.com/official-stockfish/Stockfish/pull/5921

No functional change
2025-03-21 11:09:28 +01:00
Carlos EsparzaandDisservin e407a4f269 Simplify risk_tolerance + avoid overflow
passed simplification STC:
LLR: 2.93 (-2.94,2.94) <-1.75,0.25>
Total: 73984 W: 19058 L: 18879 D: 36047
Ptnml(0-2): 232, 8735, 18866, 8940, 219
https://tests.stockfishchess.org/tests/view/67c269a38200cf1034c9baf9

passed simplification LTC:
LLR: 2.94 (-2.94,2.94) <-1.75,0.25>
Total: 39288 W: 10033 L: 9833 D: 19422
Ptnml(0-2): 14, 4168, 11086, 4356, 20
https://tests.stockfishchess.org/tests/view/67c34f8c8200cf1034c9bda1

closes https://github.com/official-stockfish/Stockfish/pull/5919

Bench: 2050046
2025-03-21 11:09:27 +01:00
Shawn XuandDisservin b825ea6e57 Improve Perft Testing
Added #5909 problematic position and chess-library DFRC positions to
perft testing. Additional work done by @Disservin to clean up and
improve error reporting.

closes https://github.com/official-stockfish/Stockfish/pull/5917

No functional change

Co-authored-by: disservin <disservin.social@gmail.com>
2025-03-21 11:03:31 +01:00
99d32e395e Reapply #5909
This version fixes the logic of `gives_check`, which was identified to
be the cause of illegal moves.

closes https://github.com/official-stockfish/Stockfish/pull/5914

No functional change

Co-authored-by: Robert Nürnberg <robert.nurnberg@gmx.de>
Co-authored-by: gab8192 <gabrilomba57@gmail.com>
2025-03-21 11:02:19 +01:00
f3bfce3531 Revert "Replace aligned() function with line_bb() and simplify king piece detection" (#5915)
closes https://github.com/official-stockfish/Stockfish/pull/5915

No functional change

Co-authored-by: Robert Nürnberg <robert.nurnberg@gmx.de>
2025-02-28 09:50:59 +01:00
FauziAkramandDisservin 5c617e579c VVLTC Search Tune
Passed VVLTC with STC bounds:
LLR: 2.94 (-2.94,2.94) <0.00,2.00>
Total: 15788 W: 4106 L: 3868 D: 7814
Ptnml(0-2): 0, 1324, 5009, 1560, 1
https://tests.stockfishchess.org/tests/view/67bf2ddd6e569f6234102ade

Passed VVLTC with LTC bounds:
LLR: 2.95 (-2.94,2.94) <0.50,2.50>
Total: 13622 W: 3620 L: 3368 D: 6634
Ptnml(0-2): 3, 1190, 4170, 1448, 0
https://tests.stockfishchess.org/tests/view/67c04308c8f7c4c0632d8055

closes https://github.com/official-stockfish/Stockfish/pull/5910

Bench: 1823605
2025-02-27 20:40:56 +01:00
Jake SenneandDisservin 6d9c6f99b9 Replace aligned() function with line_bb() and simplify king piece detection
From https://discord.com/channels/435943710472011776/813919248455827515/1342267241168900228

Saves 6 instructions

closes https://github.com/official-stockfish/Stockfish/pull/5909

No functional change
2025-02-27 20:38:03 +01:00
FauziAkramandDisservin a730b4d08b Remove two unnecessary divisions
Passed STC:
LLR: 2.93 (-2.94,2.94) <-1.75,0.25>
Total: 280768 W: 72187 L: 72236 D: 136345
Ptnml(0-2): 815, 33131, 72550, 33064, 824
https://tests.stockfishchess.org/tests/view/67bcf7afe670525923b8a101

Passed LTC:
LLR: 2.94 (-2.94,2.94) <-1.75,0.25>
Total: 108684 W: 27666 L: 27536 D: 53482
Ptnml(0-2): 40, 11768, 30606, 11878, 50
https://tests.stockfishchess.org/tests/view/67be472ed8d5c2c657c52cb8

closes https://github.com/official-stockfish/Stockfish/pull/5908

Bench: 2400689
2025-02-27 20:34:49 +01:00
Shawn XuandDisservin 09faa62621 Simplify NMP Conditions
Passed Non-regression STC:
LLR: 2.94 (-2.94,2.94) <-1.75,0.25>
Total: 142400 W: 36883 L: 36779 D: 68738
Ptnml(0-2): 467, 16804, 36571, 16874, 484
https://tests.stockfishchess.org/tests/view/67bd1898e4a8d7152b974ef1

Passed Non-regression LTC:
LLR: 2.95 (-2.94,2.94) <-1.75,0.25>
Total: 251868 W: 63905 L: 63920 D: 124043
Ptnml(0-2): 133, 27480, 70708, 27495, 118
https://tests.stockfishchess.org/tests/view/67bd1898e4a8d7152b974ef1

closes https://github.com/official-stockfish/Stockfish/pull/5906

Bench: 2188400
2025-02-27 20:31:04 +01:00
mstemberaandDisservin e4d7136042 Combine last 3 add/remove operations
https://tests.stockfishchess.org/tests/view/67ad587052879dfd14d7e8a5
LLR: 2.95 (-2.94,2.94) <0.00,2.00>
Total: 45856 W: 12177 L: 11855 D: 21824
Ptnml(0-2): 176, 4845, 12588, 5119, 200

The two most common cases are when added and removed counts are equal
and when they are off by 1.  When they are off by 1 we currently do a
pass combining 2 and then an extra pass for the last 1.  This patch does
a single combined pass on the final 3 instead. Tested on top of the
simplification in
https://github.com/official-stockfish/Stockfish/pull/5901

closes https://github.com/official-stockfish/Stockfish/pull/5902

No functional change
2025-02-27 20:30:44 +01:00
mstemberaandDisservin d330b48e21 Handle updating the small accumulator the same way as the big one
https://tests.stockfishchess.org/tests/view/67abfe1ca04df5eb8dbebf0b
LLR: 2.97 (-2.94,2.94) <-1.75,0.25>
Total: 153088 W: 40072 L: 39979 D: 73037
Ptnml(0-2): 619, 16728, 41764, 16807, 626

closes https://github.com/official-stockfish/Stockfish/pull/5901

No functional change
2025-02-27 20:30:10 +01:00
FauziAkramandDisservin 93b966829b Simplify bestvalue update formula
Passed STC:
LLR: 2.95 (-2.94,2.94) <-1.75,0.25>
Total: 124960 W: 32598 L: 32472 D: 59890
Ptnml(0-2): 480, 14852, 31694, 14970, 484
https://tests.stockfishchess.org/tests/view/67b348bae00eea114cdba37d

Passed LTC:
LLR: 2.94 (-2.94,2.94) <-1.75,0.25>
Total: 150306 W: 38220 L: 38132 D: 73954
Ptnml(0-2): 98, 16430, 42005, 16526, 94
https://tests.stockfishchess.org/tests/view/67b5e37918a66624a7a3f751

closes https://github.com/official-stockfish/Stockfish/pull/5898

Bench: 2146010
2025-02-24 19:16:26 +01:00
Joost VandeVondeleandDisservin 0f9ae0d11c Check maximum time every iteration
This fixes a TCEC timeloss, where slow DTZ TB7 access, in combination
with syzygy PV extension, led to a timeloss.

While the extension code correctly aborted after spending moveOverhead/2
time, the mainThread did not search sufficient nodes (512 in > 1s) to
trigger the stop in check_time. At the same time, totalTime exceeded
tm.maximum() due to the factors multiplying tm.optimum().

This corner case is fixed by checking also against the tm.maximum() at
each iteration.

Even though this problem can't be triggered on fishtest, the patch was
verified there.

Passed STC:
https://tests.stockfishchess.org/tests/view/67b99e1be99f8640b318810d
LLR: 2.93 (-2.94,2.94) <-1.75,0.25>
Total: 136832 W: 35625 L: 35518 D: 65689
Ptnml(0-2): 499, 14963, 37431, 14978, 545

closes https://github.com/official-stockfish/Stockfish/pull/5896

No functional change
2025-02-24 19:15:32 +01:00
Michael ChalyandDisservin c19a6ea53c Make Pv search shallower in some cases
Conditions are the same as they are for doShallowerSearch, just that
they also apply for cases where LMR wasn't reducing anything - if result
is bad enough reduce search depth of PV search by 1.

Passed STC:
https://tests.stockfishchess.org/tests/view/67b9d2aca49c651c2caac818
LLR: 2.95 (-2.94,2.94) <0.00,2.00>
Total: 29216 W: 7731 L: 7424 D: 14061
Ptnml(0-2): 87, 3345, 7473, 3580, 123

Passed LTC:
https://tests.stockfishchess.org/tests/view/67ba538c01f3463ae1d35e69
LLR: 2.94 (-2.94,2.94) <0.50,2.50>
Total: 33168 W: 8529 L: 8219 D: 16420
Ptnml(0-2): 12, 3505, 9262, 3771, 34

closes https://github.com/official-stockfish/Stockfish/pull/5895

Bench: 2290732
2025-02-24 19:14:04 +01:00
MyselfandDisservin 57f0fe08c0 Add risk tolerance calculation
https://tests.stockfishchess.org/tests/view/67b1db2188b11e2400eb06ae
Passed STC:
LLR: 2.93 (-2.94,2.94) <0.00,2.00>
Total: 123552 W: 32388 L: 31938 D: 59226
Ptnml(0-2): 487, 14520, 31345, 14904, 520

Passed LTC:
https://tests.stockfishchess.org/tests/view/67b3d53f154c4df4fc4b1f43
LLR: 2.95 (-2.94,2.94) <0.50,2.50>
Total: 206928 W: 52916 L: 52246 D: 101766
Ptnml(0-2): 159, 22546, 57394, 23196, 169

closes https://github.com/official-stockfish/Stockfish/pull/5893

Bench: 2705449
2025-02-24 19:12:35 +01:00
Disservin 291a429cdd Remove duplicated info string printing
Currently "info string" is being printed twice for the network arch

```
info string info string NNUE evaluation using nn-1c0000000000.nnue (133MiB, (22528, 3072, 15, 32, 1))
info string info string NNUE evaluation using nn-37f18f62d772.nnue (6MiB, (22528, 128, 15, 32, 1))
```

closes https://github.com/official-stockfish/Stockfish/pull/5889

No functional change
2025-02-24 19:10:38 +01:00
Shawn XuandDisservin 43b2d65d72 Add scaling note to futility pruning
Note that both patches below effectively reduces the frequency of futility pruning.

Passed STC:
LLR: 2.94 (-2.94,2.94) <0.00,2.00>
Total: 51680 W: 13599 L: 13253 D: 24828
Ptnml(0-2): 217, 6056, 12959, 6380, 228
https://tests.stockfishchess.org/tests/view/67ac218fa04df5eb8dbebf26

Passed LTC:
LLR: 2.94 (-2.94,2.94) <0.50,2.50>
Total: 51798 W: 13338 L: 12986 D: 25474
Ptnml(0-2): 42, 5584, 14310, 5906, 57
https://tests.stockfishchess.org/tests/view/67acf04152879dfd14d7e846

Regression at STC SMP:
LLR: 2.94 (-2.94,2.94) <0.00,2.00>
Total: 231552 W: 60226 L: 59642 D: 111684
Ptnml(0-2): 565, 25994, 62031, 26664, 522
https://tests.stockfishchess.org/tests/view/67ae390c1a4c73ae1f930dbf

Passed STC:
LLR: 2.93 (-2.94,2.94) <0.00,2.00>
Total: 22560 W: 6022 L: 5725 D: 10813
Ptnml(0-2): 87, 2524, 5762, 2819, 88
https://tests.stockfishchess.org/tests/view/67ac202aa04df5eb8dbebf22

Passed LTC:
LLR: 2.95 (-2.94,2.94) <0.50,2.50>
Total: 66138 W: 16953 L: 16572 D: 32613
Ptnml(0-2): 62, 7103, 18360, 7480, 64
https://tests.stockfishchess.org/tests/view/67ad47d852879dfd14d7e899

Regression at VVLTC SMP:
LLR: -2.94 (-2.94,2.94) <-1.75,0.25>
Total: 29138 W: 7408 L: 7655 D: 14075
Ptnml(0-2): 0, 2816, 9189, 2559, 5
https://tests.stockfishchess.org/tests/view/67b159ce6c6b9e172ad1598f

closes https://github.com/official-stockfish/Stockfish/pull/5888

No functional change
2025-02-24 19:09:52 +01:00
Nonlinear2andDisservin fc2139fedc se separate parameters for stat values
The code has been refactored to remove the `stat_bonus` and `stat_malus`
functions, as the code for each bonus/malus is now different. This
allows for future tests to modify these formulas individually.

Passed LTC with STC bounds:
https://tests.stockfishchess.org/tests/view/67b115dd6c6b9e172ad1592f
LLR: 2.94 (-2.94,2.94) <0.00,2.00>
Total: 75756 W: 19393 L: 19044 D: 37319
Ptnml(0-2): 60, 8251, 20913, 8588, 66

Passed LTC with LTC bounds:
https://tests.stockfishchess.org/tests/view/67af5f5d6c6b9e172ad15765
LLR: 2.94 (-2.94,2.94) <0.50,2.50>
Total: 108126 W: 27880 L: 27412 D: 52834
Ptnml(0-2): 85, 11786, 29866, 12228, 98

closes https://github.com/official-stockfish/Stockfish/pull/5887

Bench: 2809143
2025-02-24 19:09:28 +01:00
Daniel MonroeandDisservin 45b2b06cea Use same term for small and large net for nnue complexity adjustment
Passed simplification STC
LLR: 2.96 (-2.94,2.94) <-1.75,0.25>
Total: 386496 W: 100682 L: 100850 D: 184964
Ptnml(0-2): 1686, 46399, 97218, 46287, 1658
https://tests.stockfishchess.org/tests/view/67a9cc6d851bb0f25324449e

Passed rebased simplification LTC
LLR: 2.94 (-2.94,2.94) <-1.75,0.25>
Total: 160884 W: 41090 L: 41012 D: 78782
Ptnml(0-2): 133, 17883, 44321, 17983, 122
https://tests.stockfishchess.org/tests/view/67aef2e91a4c73ae1f930e85

closes https://github.com/official-stockfish/Stockfish/pull/5886

Bench: 2962718
2025-02-24 19:07:58 +01:00
FauziAkramandDisservin 095d19afea Use neon_m128_reduce_add_epi32 for NEON vector reduction
Accomplishing the entire horizontal addition in a single NEON instruction

closes https://github.com/official-stockfish/Stockfish/pull/5885

No functional change
2025-02-24 19:07:29 +01:00
FauziAkramandDisservin ee7259e48b Small code cleanup
Use std::is_arithmetic_v as it is the more modern and concise way to
check for arithmetic types. While at it, fixing a static assert in
misc.h, thanks to Shawn and Disservin for helping.

closes https://github.com/official-stockfish/Stockfish/pull/5883

No functional change
2025-02-24 19:04:59 +01:00
Daniel MonroeandDisservin 76c319f438 Simplify ttcut depth condition
Simplify ttcut depth condition in a recent tweak of Nonlinear (PR #5876)

Passed simplification STC
LLR: 2.95 (-2.94,2.94) <-1.75,0.25>
Total: 235328 W: 61646 L: 61644 D: 112038
Ptnml(0-2): 1039, 27947, 59676, 27977, 1025
https://tests.stockfishchess.org/tests/view/67abc7fba04df5eb8dbeb442

Passed simplification LTC
LLR: 2.94 (-2.94,2.94) <-1.75,0.25>
Total: 63744 W: 16306 L: 16128 D: 31310
Ptnml(0-2): 58, 6918, 17748, 7084, 64
https://tests.stockfishchess.org/tests/view/67abd776a04df5eb8dbeb9c1

closes https://github.com/official-stockfish/Stockfish/pull/5877

Bench: 2667779
2025-02-24 19:03:19 +01:00
Carlos EsparzaandDisservin e9997afb1c Replace hint_common_parent_position() by backwards accumulator updates
Only calls to `evaluate()` now trigger NNUE accumulator updates. To make
sure that we are likely to find parent positions from which to update
the accumulators we perform a backwards NNUE update whenever we compute
the accumulator from scratch for some position.

passed STC
LLR: 2.93 (-2.94,2.94) <0.00,2.00>
Total: 39680 W: 10474 L: 10164 D: 19042
Ptnml(0-2): 171, 4068, 11042, 4398, 161
https://tests.stockfishchess.org/tests/view/67a27f26eb183d11c65945be

passed LTC
LLR: 2.94 (-2.94,2.94) <0.50,2.50>
Total: 337308 W: 86408 L: 85550 D: 165350
Ptnml(0-2): 276, 30551, 106126, 31441, 260
https://tests.stockfishchess.org/tests/view/67a287efeb183d11c65945ee

then simplified:
STC
LLR: 2.94 (-2.94,2.94) <-1.75,0.25>
Total: 28608 W: 7641 L: 7413 D: 13554
Ptnml(0-2): 132, 3036, 7744, 3256, 136
https://tests.stockfishchess.org/tests/view/67a4703719f522d3866d3345

LTC
LLR: 2.96 (-2.94,2.94) <-1.75,0.25>
Total: 200226 W: 51026 L: 50990 D: 98210
Ptnml(0-2): 170, 18468, 62799, 18508, 168
https://tests.stockfishchess.org/tests/view/67a4f255229c1a170cc08964

The version in this PR is a bit different from the simplified version,
but it's compile-time changes only.

closes https://github.com/official-stockfish/Stockfish/pull/5870

No functional change
2025-02-24 19:01:23 +01:00
FauziAkramandDisservin fa6c30af81 FutilityValue formula tweak
Passed STC:
LLR: 2.95 (-2.94,2.94) <0.00,2.00>
Total: 29600 W: 7979 L: 7662 D: 13959
Ptnml(0-2): 138, 3446, 7324, 3745, 147
https://tests.stockfishchess.org/tests/view/67ac7dff52879dfd14d7e7da

Passed LTC:
LLR: 2.95 (-2.94,2.94) <0.50,2.50>
Total: 49662 W: 12850 L: 12502 D: 24310
Ptnml(0-2): 41, 5354, 13689, 5710, 37
https://tests.stockfishchess.org/tests/view/67acc1b252879dfd14d7e81d

closes https://github.com/official-stockfish/Stockfish/pull/5879

Bench: 2581469
2025-02-13 20:18:35 +01:00
Daniel MonroeandDisservin d54240c50a Decrease lmr depth if static eval decreases a lot
This tweak originally had some more conditions which have been simplified away.

Passed STC
LLR: 2.93 (-2.94,2.94) <0.00,2.00>
Total: 60064 W: 15797 L: 15439 D: 28828
Ptnml(0-2): 236, 7080, 15106, 7310, 300
https://tests.stockfishchess.org/tests/view/67a2af9cfedef70e42ac3325

Passed LTC
LLR: 2.94 (-2.94,2.94) <0.50,2.50>
Total: 76794 W: 19740 L: 19337 D: 37717
Ptnml(0-2): 61, 8327, 21236, 8694, 79
https://tests.stockfishchess.org/tests/view/67a2c904fedef70e42ac374d

Passed Non-Regression VVLTC scaling check
LLR: 2.94 (-2.94,2.94) <-1.75,0.25>
Total: 29046 W: 7581 L: 7389 D: 14076
Ptnml(0-2): 2, 2557, 9213, 2749, 2
https://tests.stockfishchess.org/tests/view/67a54b591c4a3ea87241cb83

Passed simplification STC
LLR: 2.94 (-2.94,2.94) <-1.75,0.25>
Total: 212448 W: 55244 L: 55217 D: 101987
Ptnml(0-2): 932, 25283, 53707, 25430, 872
https://tests.stockfishchess.org/tests/view/67aaacb02554387b116f698f

Passed simplification LTC
LLR: 2.95 (-2.94,2.94) <-1.75,0.25>
Total: 185736 W: 47270 L: 47217 D: 91249
Ptnml(0-2): 141, 20568, 51394, 20627, 138
https://tests.stockfishchess.org/tests/view/67ab8efa133d55b1d3bc1397

closes https://github.com/official-stockfish/Stockfish/pull/5878

Bench: 2512420
2025-02-13 20:17:26 +01:00
Nonlinear2andDisservin a4edacb87a Tweak the cutnode depth condition for TT cutoffs
Passed STC:
https://tests.stockfishchess.org/tests/view/67ab396ab5c93ee812d851f3
LLR: 2.96 (-2.94,2.94) <0.00,2.00>
Total: 83648 W: 21964 L: 21571 D: 40113
Ptnml(0-2): 339, 9779, 21217, 10128, 361

Passed LTC:
https://tests.stockfishchess.org/tests/view/67ab9647133d55b1d3bc171e
LLR: 2.94 (-2.94,2.94) <0.50,2.50>
Total: 68160 W: 17551 L: 17166 D: 33443
Ptnml(0-2): 62, 7353, 18870, 7728, 67

closes https://github.com/official-stockfish/Stockfish/pull/5876

Bench: 3087275
2025-02-13 19:52:06 +01:00
Michael ChalyandDisservin 9cc15b3049 Do more reductions for cut nodes without a tt move
Logic is somewhat similar to IIR but in LMR.
Usually things like reducing more in IIR scale badly but this patch does
this in LMR where reducing more for cutNodes is in general good, so I
believe there is no non-linear scaling.

Passed STC:
https://tests.stockfishchess.org/tests/view/67abc9aaa04df5eb8dbeb452
LLR: 2.93 (-2.94,2.94) <0.00,2.00>
Total: 42304 W: 11223 L: 10892 D: 20189
Ptnml(0-2): 184, 4904, 10669, 5187, 208

Passed LTC:
https://tests.stockfishchess.org/tests/view/67abcd7ba04df5eb8dbeb96c
LLR: 2.95 (-2.94,2.94) <0.50,2.50>
Total: 32334 W: 8386 L: 8074 D: 15874
Ptnml(0-2): 26, 3446, 8916, 3748, 31

closes https://github.com/official-stockfish/Stockfish/pull/5875

Bench: 2612849
2025-02-13 19:49:54 +01:00
Stefan GeschwentnerandDisservin 7258567804 Refactor reduction rules
Refactor reduction rules so that all ttPv/Pv related stuff is in one
rule and the scaling becomes more clear. No functional change

closes https://github.com/official-stockfish/Stockfish/pull/5871

No functional change
2025-02-13 19:46:53 +01:00
Daniel MonroeandDisservin 3a0418c0d0 Simplify opponent worsening
Passed simplification STC
LLR: 2.94 (-2.94,2.94) <-1.75,0.25>
Total: 57120 W: 14712 L: 14526 D: 27882
Ptnml(0-2): 53, 6241, 15796, 6407, 63
https://tests.stockfishchess.org/tests/view/67a26153eb183d11c659454d

Passed simplification LTC
LLR: 2.94 (-2.94,2.94) <-1.75,0.25>
Total: 313452 W: 79893 L: 79973 D: 153586
Ptnml(0-2): 279, 35053, 86156, 34945, 293
https://tests.stockfishchess.org/tests/view/67a29fe0fedef70e42ac32ae

closes https://github.com/official-stockfish/Stockfish/pull/5867

Bench: 2582245
2025-02-13 19:45:55 +01:00
Carlos EsparzaandDisservin e089f723d8 Remove two xors by setting the hash keys for unreachable squares to zero
performance before:
3.6714 +- 0.20%  Gcycles
3.6620 +- 0.12%  Gcycles
3.6704 +- 0.26%  Gcycles
3.6602 +- 0.27%  Gcycles
3.6799 +- 0.37%  Gcycles

after:
3.6540 +- 0.30%  Gcycles
3.6388 +- 0.25%  Gcycles
3.6557 +- 0.17%  Gcycles
3.6449 +- 0.15%  Gcycles
3.6460 +- 0.26%  Gcycles

(every line is a different `profile-build` and shows the number of
cycles needed for `./stockfish bench`, measured with `perf stat -r 10`)

closes https://github.com/official-stockfish/Stockfish/pull/5754

No functional change
2025-02-13 19:44:53 +01:00
Shawn XuandJoost VandeVondele d66e603070 Increase PCM bonus when cutOffCnt is low
Passed STC:
LLR: 2.95 (-2.94,2.94) <0.00,2.00>
Total: 36832 W: 9763 L: 9438 D: 17631
Ptnml(0-2): 159, 4267, 9254, 4562, 174
https://tests.stockfishchess.org/tests/view/67a29dbafedef70e42ac329a

Passed LTC:
LLR: 2.95 (-2.94,2.94) <0.50,2.50>
Total: 19728 W: 5124 L: 4839 D: 9765
Ptnml(0-2): 18, 2029, 5485, 2314, 18
https://tests.stockfishchess.org/tests/view/67a2a1abfedef70e42ac32b7

closes https://github.com/official-stockfish/Stockfish/pull/5865

Bench: 3197798
2025-02-05 19:00:25 +01:00
Daniel MonroeandJoost VandeVondele 3dfbc5de25 Remove non-pawn material check in qsearch pruning
Passed simplification STC
LLR: 2.96 (-2.94,2.94) <-1.75,0.25>
Total: 47712 W: 12621 L: 12409 D: 22682
Ptnml(0-2): 224, 5349, 12480, 5597, 206
https://tests.stockfishchess.org/tests/view/67a1b4fb612069de394afc37

Passed rebased simplification LTC
LLR: 2.95 (-2.94,2.94) <-1.75,0.25>
Total: 188274 W: 47727 L: 47677 D: 92870
Ptnml(0-2): 171, 20429, 52867, 20519, 151
https://tests.stockfishchess.org/tests/view/67a2a761fedef70e42ac3300

closes https://github.com/official-stockfish/Stockfish/pull/5866

bench 2654242
2025-02-05 18:56:12 +01:00
DisservinandJoost VandeVondele 4c6d2bf921 Show stdout/stderr in CI/CD tests
makes it easier to fix based on warnings shown with e.g. valgrind

closes https://github.com/official-stockfish/Stockfish/pull/5862

No functional change
2025-02-05 18:52:28 +01:00
Disservin 2a5b41fd12 Fixes a wrongly combined merge conflict from the previous merge wave.
Passed STC:
https://tests.stockfishchess.org/tests/view/67a288aaeb183d11c65945f1
LLR: 2.99 (-2.94,2.94) <0.00,2.00>
Total: 51424 W: 13588 L: 13237 D: 24599
Ptnml(0-2): 223, 6039, 12860, 6344, 246

Passed LTC:
https://tests.stockfishchess.org/tests/view/67a28c0aeb183d11c6594609
LLR: 2.94 (-2.94,2.94) <0.50,2.50>
Total: 54144 W: 13900 L: 13543 D: 26701
Ptnml(0-2): 42, 5881, 14870, 6236, 43

closes https://github.com/official-stockfish/Stockfish/pull/5863

Bench: 2345723
2025-02-04 23:08:43 +01:00
Michael ChalyandDisservin e852d9880a Reduce less for positions without tt move
Continuation of work on scaling.
In line with previous scaling patches this one massively reduces
reduction for moves that don't go thru lmr for position without a tt
move.

Passed VVLTC with STC bounds:
https://tests.stockfishchess.org/tests/view/679fd2450774dfd78deb12b2
LLR: 2.94 (-2.94,2.94) <0.00,2.00>
Total: 74718 W: 19354 L: 19042 D: 36322
Ptnml(0-2): 5, 6724, 23595, 7024, 11

Passed VVLTC with LTC bounds:
https://tests.stockfishchess.org/tests/view/67a009930774dfd78deb2346
LLR: 2.94 (-2.94,2.94) <0.50,2.50>
Total: 82638 W: 21587 L: 21212 D: 39839
Ptnml(0-2): 15, 7476, 25953, 7869, 6

closes https://github.com/official-stockfish/Stockfish/pull/5860

Bench: 2887850
2025-02-04 21:37:11 +01:00
FauziAkramandDisservin 67573218e1 VVLTC parameters tweak
Some notes:
- Both tests were conducted on top of #5848.
- Based on tuning suggestions, the extension for capturing the
  previously moved piece was removed/simplified. (Developers can attempt
  to reintroduce it post-merge if needed.)
- Initially, bonusScale = std::max(bonusScale, -2); was included but
  later removed in the second test upon Viz's request, however, it was
  nearly non-functional anyway.

Passed VVLTC under STC bounds:
LLR: 2.95 (-2.94,2.94) <0.00,2.00>
Total: 31508 W: 8153 L: 7895 D: 15460
Ptnml(0-2): 1, 2747, 10005, 2995, 6
https://tests.stockfishchess.org/tests/view/679fdc7a0774dfd78deb1350

Passed VVLTC under LTC bounds:
LLR: 2.94 (-2.94,2.94) <0.50,2.50>
Total: 55026 W: 14370 L: 14046 D: 26610
Ptnml(0-2): 7, 4957, 17262, 5279, 8
https://tests.stockfishchess.org/tests/view/679fec920774dfd78deb19b8

closes https://github.com/official-stockfish/Stockfish/pull/5856

Bench: 2757788
2025-02-04 21:34:08 +01:00
Viren6andDisservin ec7f1d6229 Increment cutoffCnt less often after fail high
Only increment when extension is less than 2 or it's a PvNode.

Tested vs #5851.

Failed STC:
LLR: -2.97 (-2.94,2.94) <0.00,2.00>
Total: 360064 W: 94546 L: 94271 D: 171247
Ptnml(0-2): 1835, 42826, 90314, 43343, 1714
https://tests.stockfishchess.org/tests/view/679f79cc0774dfd78deb1112

Passed LTC:
LLR: 2.94 (-2.94,2.94) <0.00,2.00>
Total: 443076 W: 113942 L: 113081 D: 216053
Ptnml(0-2): 480, 49076, 121579, 49909, 494
https://tests.stockfishchess.org/tests/view/679fa21b0774dfd78deb1178

Passed VLTC:
LLR: 2.94 (-2.94,2.94) <0.50,2.50>
Total: 187184 W: 48098 L: 47495 D: 91591
Ptnml(0-2): 59, 19036, 54792, 19653, 52
https://tests.stockfishchess.org/tests/view/679fb6000774dfd78deb11e8

closes https://github.com/official-stockfish/Stockfish/pull/5855

Bench: 3018089
2025-02-04 21:30:54 +01:00
Michael ChalyandDisservin 3b8bfeb38a Do less aggressive pruning for higher movecounts
Move part of heuristic that makes reduction less before pruning stage.

Passed STC:
https://tests.stockfishchess.org/tests/view/679fdf1b0774dfd78deb13b3
LLR: 2.93 (-2.94,2.94) <0.00,2.00>
Total: 47136 W: 12484 L: 12146 D: 22506
Ptnml(0-2): 211, 5472, 11866, 5806, 213

Passed LTC:
https://tests.stockfishchess.org/tests/view/679fe6790774dfd78deb1753
LLR: 2.94 (-2.94,2.94) <0.50,2.50>
Total: 100536 W: 25837 L: 25383 D: 49316
Ptnml(0-2): 103, 10990, 27622, 11456, 97

closes https://github.com/official-stockfish/Stockfish/pull/5853

Bench: 3265587
2025-02-04 21:28:49 +01:00
Kenneth LeeandDisservin 09623abbe8 Simplify cutoffCnt further
Based off [Simplify cutoffCnt](https://github.com/official-stockfish/Stockfish/commit/69be04d38e10003853e78e4aa2b32aa252a82850) commit

Original
[commit](https://github.com/kennethlee33/Stockfish/commit/a77a895c3b7460f86b11a3ddfe3528f5be1276b9)
adding extension condition seems to not be improving strength anymore

Passed STC:
LLR: 2.93 (-2.94,2.94) <-1.75,0.25>
Total: 54176 W: 14331 L: 14125 D: 25720
Ptnml(0-2): 261, 6340, 13676, 6554, 257
https://tests.stockfishchess.org/tests/view/679edb7c0774dfd78deb0eed

Passed LTC:
LLR: 2.95 (-2.94,2.94) <-1.75,0.25>
Total: 267198 W: 68148 L: 68179 D: 130871
Ptnml(0-2): 232, 30051, 73055, 30038, 223
https://tests.stockfishchess.org/tests/view/679ef2c70774dfd78deb0f43

closes https://github.com/official-stockfish/Stockfish/pull/5851

Bench: 3119355
2025-02-04 21:26:04 +01:00
Nonlinear2andDisservin 9ed1725e78 Simplify bonusScale formula
Passed STC:
https://tests.stockfishchess.org/tests/view/679ea7bc0774dfd78deb0d68
LLR: 2.93 (-2.94,2.94) <-1.75,0.25>
Total: 47680 W: 12575 L: 12364 D: 22741
Ptnml(0-2): 179, 5589, 12139, 5708, 225

Passed LTC:
https://tests.stockfishchess.org/tests/view/679eb7760774dfd78deb0dbb
LLR: 2.96 (-2.94,2.94) <-1.75,0.25>
Total: 314220 W: 80110 L: 80189 D: 153921
Ptnml(0-2): 265, 35121, 86420, 35036, 268

closes https://github.com/official-stockfish/Stockfish/pull/5849

Bench: 3161782
2025-02-04 21:24:06 +01:00
Nonlinear2andDisservin fccc6f624e Reduce full depth search twice
Passed STC:
https://tests.stockfishchess.org/tests/view/679f429e0774dfd78deb10a5
LLR: 2.95 (-2.94,2.94) <0.00,2.00>
Total: 71584 W: 18905 L: 18529 D: 34150
Ptnml(0-2): 302, 8372, 18081, 8722, 315

Passed LTC:
https://tests.stockfishchess.org/tests/view/679f72a00774dfd78deb1102
LLR: 2.94 (-2.94,2.94) <0.50,2.50>
Total: 353952 W: 91007 L: 90024 D: 172921
Ptnml(0-2): 375, 39163, 96921, 40138, 379

closes https://github.com/official-stockfish/Stockfish/pull/5848

Bench: 3642363
2025-02-04 21:22:08 +01:00
Disservin c12dbdedd9 Disallow same option being added twice
Now exits during startup.

```
./stockfish
Stockfish dev-20250202-243c7c6a by the Stockfish developers (see AUTHORS file)
x1,5,0,10,0.5,0.0020
Option: "x1" was already added!
```

i.e. prevents and helps debug this case

```cpp
int x1 = 5;

TUNE(x1);
TUNE(x1);
```

closes https://github.com/official-stockfish/Stockfish/pull/5847

No functional change
2025-02-04 21:18:01 +01:00
Shawn XuandDisservin 8c73472ac8 Simplify depth increase condition further
Passed Non-regression STC:
LLR: 2.95 (-2.94,2.94) <-1.75,0.25>
Total: 51232 W: 13560 L: 13351 D: 24321
Ptnml(0-2): 183, 6075, 12920, 6226, 212
https://tests.stockfishchess.org/tests/view/679d7b2b0774dfd78deb043f

Passed Non-regression LTC (v. #5827):
LLR: 2.94 (-2.94,2.94) <-1.75,0.25>
Total: 172398 W: 44108 L: 44042 D: 84248
Ptnml(0-2): 122, 19207, 47489, 19245, 136
https://tests.stockfishchess.org/tests/view/679d7fb10774dfd78deb05d2

Passed Non-regression VLTC (v. #5827):
LLR: 2.94 (-2.94,2.94) <-1.75,0.25>
Total: 388540 W: 99314 L: 99464 D: 189762
Ptnml(0-2): 89, 40454, 113350, 40272, 105
https://tests.stockfishchess.org/tests/view/679da3be0774dfd78deb0ad4

closes https://github.com/official-stockfish/Stockfish/pull/5846

Bench: 2688175
2025-02-04 21:11:37 +01:00
Guenther DemetzandDisservin 2a1ab11ab0 Micro-optimization for SEE: remove a superfluous condition
This condition can never be true, it's superfluous.

It never triggers even with a bench 16 1 20 run.
To met the condition it would imply that the previous recapture was done
by a higher rated piece than a Queen.
This is only the case when the King recaptures and that's already
handled in line 1161: (return (attackers & ~pieces(stm)) ? res ^ 1).

closes https://github.com/official-stockfish/Stockfish/pull/5839

No functional change
2025-02-04 21:11:05 +01:00
Robert Nurnberg @ elitebookandDisservin d46c0b6f49 Add cursed win checks to CI matetrack tests
This PR adds a run for the `matecheck.py` script from the matetrack repo
with the option `--syzygy50MoveRule false`.

The new tests guard against a re-introduction of the bugs recently fixed
by https://github.com/official-stockfish/Stockfish/pull/5814.

closes https://github.com/official-stockfish/Stockfish/pull/5829

No functional change
2025-02-02 13:54:04 +01:00
Kenneth LeeandDisservin 9f0844c101 Simplify extensions depth increase condition
Passed STC:
LLR: 2.95 (-2.94,2.94) <-1.75,0.25>
Total: 42784 W: 11198 L: 10979 D: 20607
Ptnml(0-2): 166, 5024, 10822, 5185, 195
https://tests.stockfishchess.org/tests/view/6795b6f8f6281b7d7b1869d6

Failed LTC:
LLR: -2.95 (-2.94,2.94) <-1.75,0.25>
Total: 283614 W: 72046 L: 72587 D: 138981
Ptnml(0-2): 241, 32097, 77647, 31606, 216
https://tests.stockfishchess.org/tests/view/6795cbb6f6281b7d7b186a07

Passed VLTC:
LLR: 2.94 (-2.94,2.94) <-1.75,0.25>
Total: 59678 W: 15387 L: 15211 D: 29080
Ptnml(0-2): 23, 6169, 17273, 6357, 17
https://tests.stockfishchess.org/tests/view/6795c6dbf6281b7d7b1869f9

closes https://github.com/official-stockfish/Stockfish/pull/5827

Bench: 3088494
2025-02-02 13:52:16 +01:00
Disservin 65a9a391e9 Silence clang-format issue
No functional change
2025-02-02 13:49:54 +01:00
Michael ChalyandDisservin dabffbceff Make pruning at ttpv nodes more aggressive
Continuation of work done by @FauziAkram and @Viren6 They had a series
of patches that decrease pruning for ttPv nodes - and it passed as a
gainer at lower time controls while revert passed as a gainer at higher
time controls.
So it's a logical continuation of this work that increases pruning for
ttPv nodes in hopes of scaling to longer TCs.

Fixed games STC:
https://tests.stockfishchess.org/tests/view/679ee3910774dfd78deb0efd
Elo: -4.98 ± 2.1 (95%) LOS: 0.0%
Total: 28584 W: 7229 L: 7639 D: 13716
Ptnml(0-2): 143, 3579, 7219, 3247, 104
nElo: -9.54 ± 4.0 (95%) PairsRatio: 0.90

Passed VVLTC with STC bounds:
https://tests.stockfishchess.org/tests/view/679d21f70774dfd78deaf553
LLR: 2.94 (-2.94,2.94) <0.00,2.00>
Total: 323282 W: 83729 L: 83105 D: 156448
Ptnml(0-2): 37, 29842, 101269, 30446, 47

Passed VVLTC with LTC bounds:
https://tests.stockfishchess.org/tests/view/679e7a970774dfd78deb0cd3
LLR: 2.95 (-2.94,2.94) <0.50,2.50>
Total: 113712 W: 29485 L: 29051 D: 55176
Ptnml(0-2): 13, 10376, 35640, 10818, 9

closes https://github.com/official-stockfish/Stockfish/pull/5844

Bench: 2964045
2025-02-02 13:47:52 +01:00
Shawn XuandDisservin 344e89275a Simplify Away Quadruple Extensions
Passed Non-regression LTC:
LLR: 2.96 (-2.94,2.94) <-1.75,0.25>
Total: 95856 W: 24551 L: 24404 D: 46901
Ptnml(0-2): 85, 10621, 26364, 10778, 80
https://tests.stockfishchess.org/tests/view/679a9aedae346be6da0eebd6

Passed Non-regression VLTC:
LLR: 2.95 (-2.94,2.94) <-1.75,0.25>
Total: 157536 W: 40000 L: 39921 D: 77615
Ptnml(0-2): 43, 16416, 45775, 16487, 47
https://tests.stockfishchess.org/tests/view/679aed8f51037ccaf3e30fbf

Passed Non-regression VVLTC:
LLR: 2.94 (-2.94,2.94) <-1.75,0.25>
Total: 51598 W: 13345 L: 13172 D: 25081
Ptnml(0-2): 0, 4735, 16162, 4896, 6
https://tests.stockfishchess.org/tests/view/679d368b0774dfd78deb0163

closes https://github.com/official-stockfish/Stockfish/pull/5843

Bench: 2399312
2025-02-02 13:44:22 +01:00
Stefan GeschwentnerandDisservin c83ddd9e4b Tweak correction history factors
The values are taken from this tuning
https://tests.stockfishchess.org/tests/view/679c4e150774dfd78deaf376
which added also a new material correction history. The full tune
doesn't work but ignoring the new history results in this changes.

Passed STC:
LLR: 2.94 (-2.94,2.94) <0.00,2.00>
Total: 102368 W: 27057 L: 26638 D: 48673
Ptnml(0-2): 394, 12031, 25949, 12382, 428
https://tests.stockfishchess.org/tess/view/679d2ca70774dfd78deaf796

Passed LTC:
LLR: 2.96 (-2.94,2.94) <0.50,2.50>
Total: 55044 W: 14215 L: 13855 D: 26974
Ptnml(0-2): 43, 5956, 15172, 6300, 51
https://tests.stockfishchess.org/tests/view/679d30be0774dfd78deafda2

closes https://github.com/official-stockfish/Stockfish/pull/5841

Bench: 3068583
2025-02-02 13:43:32 +01:00
Daniel MonroeandDisservin 7690fac5cf Simp probcut disable condition
Disable probcut check when we the ttValue is not at least probCutBeta,
regardless of tt depth.

Passed simplification STC
LLR: 2.92 (-2.94,2.94) <-1.75,0.25>
Total: 60896 W: 16030 L: 15835 D: 29031
Ptnml(0-2): 220, 7164, 15507, 7315, 242
https://tests.stockfishchess.org/tests/view/679c0a3251037ccaf3e3141e

Passed simplification LTC
LLR: 2.94 (-2.94,2.94) <-1.75,0.25>
Total: 76644 W: 19557 L: 19392 D: 37695
Ptnml(0-2): 50, 8486, 21104, 8613, 69
https://tests.stockfishchess.org/tests/view/679c380b0774dfd78deaf35c

closes https://github.com/official-stockfish/Stockfish/pull/5840

Bench: 3543770
2025-02-02 13:39:47 +01:00
Michael ChalyandDisservin 40e0486d02 Make IIR for PvNodes less aggressive
In line with previous experiments on improving scaling of IIR.
Now it disables IIR for pv nodes with depth <= 2, so disallowing for it
to perform a qsearch dive.

Fixed games STC:
https://tests.stockfishchess.org/tests/view/679ae6a951037ccaf3e30fb3
Elo: -10.36 ± 2.5 (95%) LOS: 0.0%
Total: 20020 W: 4902 L: 5499 D: 9619
Ptnml(0-2): 128, 2653, 4976, 2194, 59

Passed VVLTC with STC bounds:
https://tests.stockfishchess.org/tests/view/67954f2e406a4efe9eb7d266
LLR: 2.94 (-2.94,2.94) <0.00,2.00>
Total: 196758 W: 50725 L: 50258 D: 95775
Ptnml(0-2): 21, 18153, 61564, 18620, 21

Passed VVLTC with LTC bounds:
https://tests.stockfishchess.org/tests/view/6795a26bf6281b7d7b18698b
LLR: 2.94 (-2.94,2.94) <0.50,2.50>
Total: 323092 W: 83679 L: 82857 D: 156556
Ptnml(0-2): 48, 29475, 101659, 30335, 29

closes https://github.com/official-stockfish/Stockfish/pull/5834

Bench: 3464332
2025-02-02 13:37:47 +01:00
Daniel MonroeandDisservin 5ef1f2b132 Refactor prior reduction
Make index of reduction consistent with rest of Stack

closes https://github.com/official-stockfish/Stockfish/pull/5832

No functional change
2025-02-02 13:36:58 +01:00
Carlos EsparzaandDisservin 7684b6e4d8 Don't increase rule50 when doing null moves
also prefetch a bit earlier while we're at it

passed STC: https://tests.stockfishchess.org/tests/view/678c0860f4dc0a8b4ae8cf58
LLR: 2.95 (-2.94,2.94) <-1.75,0.25>
Total: 67328 W: 17608 L: 17418 D: 32302
Ptnml(0-2): 256, 7905, 17156, 8087, 260

passed LTC: https://tests.stockfishchess.org/tests/view/678c1a56f4dc0a8b4ae8cfb1
LLR: 2.94 (-2.94,2.94) <-1.75,0.25>
Total: 340896 W: 86577 L: 86685 D: 167634
Ptnml(0-2): 291, 38325, 93332, 38201, 299

closes https://github.com/official-stockfish/Stockfish/pull/5831

Bench: 1910281
2025-02-02 13:35:48 +01:00
Shawn XuandDisservin 4a77fb213f Clean up corrhist
Passed Non-regression STC:
LLR: 2.94 (-2.94,2.94) <-1.75,0.25>
Total: 89056 W: 23225 L: 23067 D: 42764
Ptnml(0-2): 292, 9688, 24470, 9726, 352
https://tests.stockfishchess.org/tests/view/679816b2ae346be6da0ee8e7

closes https://github.com/official-stockfish/Stockfish/pull/5830

Bench: 1767398
2025-02-02 13:33:35 +01:00
FauziAkramandDisservin f50d52aa7f No Ply Restriction in the condition that limits the depth extension to a certain point
No Ply Restriction in the condition that limits the depth extension to a
certain point.

Passed again LTC rebased:
LLR: 2.95 (-2.94,2.94) <-1.75,0.25>
Total: 195108 W: 49916 L: 49872 D: 95320
Ptnml(0-2): 170, 21846, 53464, 21918, 156
https://tests.stockfishchess.org/tests/view/6795542a406a4efe9eb7d361

closes https://github.com/official-stockfish/Stockfish/pull/5824

Bench: 1767398
2025-01-26 22:53:34 +01:00
Robert Nurnberg @ elitebookandDisservin c180163540 Update fastchess CI Version
This PR updates the fastchess version used as part of the CI to the one
used on fishtest, see
https://github.com/official-stockfish/fishtest/pull/2180.

Also change the name/repo from fast-chess to fastchess.

closes https://github.com/official-stockfish/Stockfish/pull/5826

No functional change
2025-01-26 22:45:33 +01:00
Daniel MonroeandDisservin ebdc7ba2da Refactor prior countermove bonus
Passed simplification STC
LLR: 2.97 (-2.94,2.94) <-1.75,0.25>
Total: 155424 W: 40252 L: 40159 D: 75013
Ptnml(0-2): 511, 18655, 39328, 18666, 552
https://tests.stockfishchess.org/tests/view/6794084fe96bfb672ad18d90

Passed rebased simplification LTC
LLR: 2.97 (-2.94,2.94) <-1.75,0.25>
Total: 103944 W: 26567 L: 26427 D: 50950
Ptnml(0-2): 69, 11640, 28418, 11772, 73
https://tests.stockfishchess.org/tests/view/67955c9a406a4efe9eb7d7e4

closes https://github.com/official-stockfish/Stockfish/pull/5825

Bench: 1839554
2025-01-26 22:43:02 +01:00
Nonlinear2andDisservin a016abd698 Decrease all stats malus according to move count
Passed STC:
https://tests.stockfishchess.org/tests/view/6794c4634f7de645171fb341
LLR: 2.95 (-2.94,2.94) <0.00,2.00>
Total: 28096 W: 7412 L: 7106 D: 13578
Ptnml(0-2): 97, 3194, 7148, 3524, 85

Passed LTC:
https://tests.stockfishchess.org/tests/view/6794ea13406a4efe9eb7d06b
LLR: 2.95 (-2.94,2.94) <0.50,2.50>
Total: 58086 W: 15049 L: 14684 D: 28353
Ptnml(0-2): 27, 6344, 15957, 6667, 48

closes https://github.com/official-stockfish/Stockfish/pull/5823

Bench: 1711170
2025-01-26 22:42:41 +01:00
Martin NovákandDisservin 831cb01cea Remove major corrhist
Remove major correction history and slightly increase all other
correction weights.

Passed STC:
LLR: 2.95 (-2.94,2.94) <-1.75,0.25>
Total: 50080 W: 13171 L: 12959 D: 23950
Ptnml(0-2): 196, 5998, 12462, 6166, 218
https://tests.stockfishchess.org/tests/live_elo/67954526406a4efe9eb7d176

Passed LTC:
LLR: 2.95 (-2.94,2.94) <-1.75,0.25>
Total: 51504 W: 13188 L: 12995 D: 25321
Ptnml(0-2): 54, 5658, 14128, 5865, 47
https://tests.stockfishchess.org/tests/live_elo/67954961406a4efe9eb7d251

closes https://github.com/official-stockfish/Stockfish/pull/5822

Bench: 2081366
2025-01-26 22:41:00 +01:00
FauziAkramandDisservin 69be04d38e Simplify cutoffCnt
Passed STC:
LLR: 2.94 (-2.94,2.94) <-1.75,0.25>
Total: 235872 W: 61156 L: 61155 D: 113561
Ptnml(0-2): 843, 28269, 59658, 28376, 790
https://tests.stockfishchess.org/tests/view/6794dd3e4f7de645171fb380

Passed LTC:
LLR: 2.94 (-2.94,2.94) <-1.75,0.25>
Total: 61494 W: 15644 L: 15462 D: 30388
Ptnml(0-2): 61, 6822, 16788, 7026, 50
https://tests.stockfishchess.org/tests/view/6794f86a406a4efe9eb7d093

closes https://github.com/official-stockfish/Stockfish/pull/5821

Bench: 2168937
2025-01-26 22:39:32 +01:00
Daniel MonroeandJoost VandeVondele 27e747d1d7 Simplify futility margin in lmr for quiets.
Replace the "low bestValue condition" with whether there is a best move.

Passed Simplification STC
LLR: 2.95 (-2.94,2.94) <-1.75,0.25>
Total: 102560 W: 26517 L: 26367 D: 49676
Ptnml(0-2): 328, 12223, 26036, 12357, 336
https://tests.stockfishchess.org/tests/view/679310e4ca18a2c66da02af8

Passed Simplification LTC
LLR: 2.95 (-2.94,2.94) <-1.75,0.25>
Total: 66942 W: 17130 L: 16953 D: 32859
Ptnml(0-2): 52, 7459, 18290, 7600, 70
https://tests.stockfishchess.org/tests/view/679459a3e96bfb672ad18ddf

closes https://github.com/official-stockfish/Stockfish/pull/5820

Bench: 1438043
2025-01-25 20:59:33 +01:00
Stefan GeschwentnerandJoost VandeVondele 1b31e266b0 Consider more nodes as ttPv nodes.
Remove depth condition in propagation rule for ttPv state from a node to
it childs.

Because this change marks more nodes as ttPv, we have a time sensitive
ttPv reduction rule and the STC snd LTC seems to show bad scaling. So i
have also submitted a VLTC non-regression to check the scaling at higher
time control.

The results gives a little indication that we have perhaps good scaling
with more ttPv nodes so that could be further explored.

Passed non-regression STC:
LLR: 2.95 (-2.94,2.94) <-1.75,0.25>
Total: 82528 W: 21627 L: 21453 D: 39448
Ptnml(0-2): 317, 9809, 20891, 9877, 370
https://tests.stockfishchess.org/tests/view/678e608cd63764e34db49ad7

Passed non-regression LTC:
LLR: 2.94 (-2.94,2.94) <-1.75,0.25>
Total: 310440 W: 78879 L: 78956 D: 152605
Ptnml(0-2): 255, 34915, 84938, 34876, 236
https://tests.stockfishchess.org/tests/view/678fab89ac8f8f5496155f3c

Passed non-regression VLTC for scaling verification:
LLR: 2.95 (-2.94,2.94) <-1.75,0.25>
Total: 59496 W: 15158 L: 14983 D: 29355
Ptnml(0-2): 15, 6039, 17470, 6204, 20
https://tests.stockfishchess.org/tests/view/6794bd1f4f7de645171fb33b

closes https://github.com/official-stockfish/Stockfish/pull/5819

Bench: 1829507
2025-01-25 20:56:14 +01:00
889fed448c Better nonpawn indexing
Improves indexing scheme, by noting that both sides are likely to access the same non_pawn_index nearby.

LLR: 2.93 (-2.94,2.94) <0.00,2.00>
Total: 75936 W: 19905 L: 19554 D: 36477
Ptnml(0-2): 190, 7863, 21554, 8128, 233
https://tests.stockfishchess.org/tests/view/67904d0cfc8c306ba6cea332

closes https://github.com/official-stockfish/Stockfish/pull/5816

No functional change

Co-authored-by: Andrew Grant <andrew.github@grantnet.us>
2025-01-25 20:53:53 +01:00
Viren6andJoost VandeVondele 435ba3dbb5 Revert "Moving up the if position is or has been on the PV reduction"
Passed VVLTC 1:
LLR: 2.94 (-2.94,2.94) <0.00,2.00>
Total: 68362 W: 17830 L: 17523 D: 33009
Ptnml(0-2): 9, 6253, 21347, 6566, 6
https://tests.stockfishchess.org/tests/view/6790271cfc8c306ba6cea2c1

Passed VVLTC 2:
LLR: 2.95 (-2.94,2.94) <0.50,2.50>
Total: 113256 W: 29158 L: 28721 D: 55377
Ptnml(0-2): 13, 10521, 35122, 10960, 12
https://tests.stockfishchess.org/tests/view/678d3e47d63764e34db491a3

closes https://github.com/official-stockfish/Stockfish/pull/5815

bench 1943998
2025-01-25 20:51:31 +01:00
Robert Nurnberg @ elitebookandJoost VandeVondele 6c7c5c7e47 Do not change TB cursed wins to draws if requested
If Syzygy50MoveRule is false, do not calls to is_draw() need to be guarded.
Also fixes a TB rootmove ranking issue in this case.

closes https://github.com/official-stockfish/Stockfish/pull/5814

No functional change
2025-01-25 20:42:50 +01:00
pkrisz99andJoost VandeVondele 75b75bc16a Add improving to a condition of NMP
This patch makes one of the conditions for null-move pruning depend on whether we're improving. Keep in mind that it relies on the "classical" definiton, rather than the refined one.

Passed STC: https://tests.stockfishchess.org/tests/view/678d5267d63764e34db49720
LLR: 2.94 (-2.94,2.94) <0.00,2.00>
Total: 38976 W: 10296 L: 9974 D: 18706
Ptnml(0-2): 135, 4504, 9902, 4798, 149

Passed LTC: https://tests.stockfishchess.org/tests/view/678d5891d63764e34db49731
LLR: 2.95 (-2.94,2.94) <0.50,2.50>
Total: 275772 W: 70655 L: 69836 D: 135281
Ptnml(0-2): 217, 30615, 75394, 31452, 208

closes https://github.com/official-stockfish/Stockfish/pull/5813

Bench: 2475787
2025-01-25 20:41:37 +01:00
Shawn XuandJoost VandeVondele d606311e55 Fix undefined behavior
From cppreference: "It is undefined behavior to read from the member of the
union that wasn't most recently written. Many compilers implement, as a
non-standard language extension, the ability to read inactive members of a
union."

closes https://github.com/official-stockfish/Stockfish/pull/5811

no functional change
2025-01-25 20:33:43 +01:00
FauziAkramandJoost VandeVondele aa894c0f93 Comments Tweak
* Remove from comments, hardcoded exact values for parameters that are subject to tuning.
* Remove the Elo worth, as they are now completely outdated, making them irrelevant and potentially misleading.
* Consolidated scaling-related comments into a single section for clarity. Used asterisks (*) to highlight parameters significantly affected by scaling, given their separation in the code.

closes https://github.com/official-stockfish/Stockfish/pull/5810

No functional change
2025-01-25 20:29:40 +01:00
Nonlinear2andJoost VandeVondele 4975b2bc6f Increase prior countermove bonus if TT move
Passed STC:
https://tests.stockfishchess.org/tests/view/678c4c8bf4dc0a8b4ae8db5c
LLR: 2.97 (-2.94,2.94) <0.00,2.00>
Total: 273408 W: 71089 L: 70415 D: 131904
Ptnml(0-2): 937, 32466, 69229, 33130, 942

Passed LTC:
https://tests.stockfishchess.org/tests/view/678ccabdf4dc0a8b4ae8dd7a
LLR: 2.95 (-2.94,2.94) <0.50,2.50>
Total: 148614 W: 38138 L: 37584 D: 72892
Ptnml(0-2): 97, 16450, 40689, 16944, 127

closes https://github.com/official-stockfish/Stockfish/pull/5809

Bench: 1582867
2025-01-25 20:27:11 +01:00
Stefan GeschwentnerandJoost VandeVondele 59c578ad28 Add move count based reduction.
Do less reduction which is linear increasing with move count (factor = 64).

Passed STC:
LLR: 2.94 (-2.94,2.94) <0.00,2.00>
Total: 191488 W: 49982 L: 49432 D: 92074
Ptnml(0-2): 731, 22523, 48614, 23217, 659
https://tests.stockfishchess.org/tests/view/678d0b29d63764e34db4904b

Passed LTC:
LLR: 2.94 (-2.94,2.94) <0.50,2.50>
Total: 90582 W: 23150 L: 22717 D: 44715
Ptnml(0-2): 73, 9936, 24822, 10405, 55
https://tests.stockfishchess.org/tests/view/678d347cd63764e34db4916f

closes https://github.com/official-stockfish/Stockfish/pull/5807

Bench: 1803474
2025-01-25 20:23:33 +01:00
Shawn XuandJoost VandeVondele e7367cef0f Clean up pack reordering
closes https://github.com/official-stockfish/Stockfish/pull/5802

no functional change
2025-01-25 20:17:39 +01:00
mstemberaandJoost VandeVondele 18b3465a86 Generate lookup indices at compile time.
Credit to @Disservin: the constexpr lsb is just the De Bruijn bitscan with the xor from the cpw https://www.chessprogramming.org/BitScan

closes https://github.com/official-stockfish/Stockfish/pull/5801

No functional change
2025-01-25 20:12:38 +01:00
Shawn XuandJoost VandeVondele 62ecdfe82c simplify accumulator updates
After #5759 accumulator updates are strictly on a per-move basis. Therefore, the generic code for updating multiple moves at once is no longer needed.

Passed Non-regression STC:
LLR: 3.00 (-2.94,2.94) <-1.75,0.25>
Total: 81696 W: 21204 L: 21039 D: 39453
Ptnml(0-2): 210, 8431, 23416, 8566, 225
https://tests.stockfishchess.org/tests/view/67823a24a31c4c13e83518a8

closes https://github.com/official-stockfish/Stockfish/pull/5760

no functional change
2025-01-25 20:09:09 +01:00
Joost VandeVondele 8e3e22b3d4 Replace depth increase condition with !opponentWorsening
Passed simplification STC
LLR: 2.94 (-2.94,2.94) <-1.75,0.25>
Total: 220544 W: 57417 L: 57399 D: 105728
Ptnml(0-2): 816, 26554, 55540, 26520, 842
https://tests.stockfishchess.org/tests/view/678970e38082388fa0cbfe02

Passed simplification LTC
LLR: 2.94 (-2.94,2.94) <-1.75,0.25>
Total: 132600 W: 33868 L: 33760 D: 64972
Ptnml(0-2): 126, 14770, 36390, 14898, 116
https://tests.stockfishchess.org/tests/view/678accabc00c743bc9e9fc7f

closes https://github.com/official-stockfish/Stockfish/pull/5798

bench 1632964
2025-01-18 21:33:17 +01:00
Daniel MonroeandJoost VandeVondele f00d91f8ac Refine probcut
Allow probcut for depth 3 and disable deeper verification search when it would simply repeat the qsearch.

Passed STC
LLR: 2.93 (-2.94,2.94) <0.00,2.00>
Total: 283232 W: 74450 L: 73760 D: 135022
Ptnml(0-2): 1052, 33780, 71349, 34296, 1139
https://tests.stockfishchess.org/tests/view/67843b58460e2910c51ddcc6

Passed LTC
LLR: 2.94 (-2.94,2.94) <0.50,2.50>
Total: 339654 W: 86845 L: 85893 D: 166916
Ptnml(0-2): 298, 37734, 92802, 38704, 289
https://tests.stockfishchess.org/tests/view/678aa722c00c743bc9e9face

closes https://github.com/official-stockfish/Stockfish/pull/5797

bench 1288648
2025-01-18 21:27:42 +01:00
Shawn XuandJoost VandeVondele 738ac2a100 tuned TM values
Tuned 70k games at 240+2.4 th 2: https://tests.stockfishchess.org/tests/view/6783b1b16ddf09c0b4b703f5

Failed STC:
LLR: -2.93 (-2.94,2.94) <0.00,2.00>
Total: 491872 W: 128260 L: 127804 D: 235808
Ptnml(0-2): 1579, 55449, 131572, 55609, 1727
https://tests.stockfishchess.org/tests/view/6785a045460e2910c51de4b8

Passed LTC:
LLR: 2.94 (-2.94,2.94) <0.00,2.00>
Total: 154824 W: 39315 L: 38874 D: 76635
Ptnml(0-2): 110, 15809, 45147, 16222, 124
https://tests.stockfishchess.org/tests/view/678ac722c00c743bc9e9fc35

Passed VLTC:
LLR: 2.95 (-2.94,2.94) <0.50,2.50>
Total: 77404 W: 19825 L: 19452 D: 38127
Ptnml(0-2): 18, 7262, 23765, 7643, 14
https://tests.stockfishchess.org/tests/view/678b2a98c00c743bc9ea048c

closes https://github.com/official-stockfish/Stockfish/pull/5796

No functional change
2025-01-18 21:24:01 +01:00
FauziAkramandJoost VandeVondele c94bcf62e4 Moving up the if position is or has been on the PV reduction
Passed STC:
LLR: 2.93 (-2.94,2.94) <0.00,2.00>
Total: 29664 W: 7880 L: 7570 D: 14214
Ptnml(0-2): 93, 3487, 7390, 3741, 121
https://tests.stockfishchess.org/tests/view/678ac957c00c743bc9e9fc3f

Passed LTC:
LLR: 2.94 (-2.94,2.94) <0.50,2.50>
Total: 81354 W: 20903 L: 20487 D: 39964
Ptnml(0-2): 66, 9003, 22123, 9419, 66
https://tests.stockfishchess.org/tests/view/678ad359c00c743bc9e9fcfa

closes https://github.com/official-stockfish/Stockfish/pull/5794

Bench: 1414638
2025-01-18 21:18:48 +01:00
mstemberaandJoost VandeVondele 329c267e25 Optimize find_nnz() by reducing the size of lookup_indices
https://tests.stockfishchess.org/tests/view/67896b688082388fa0cbfdee
LLR: 2.93 (-2.94,2.94) <0.00,2.00>
Total: 452800 W: 118213 L: 117300 D: 217287
Ptnml(0-2): 1638, 50255, 121864, 50842, 1801

It's faster to shrink lookup_indices[] to 8 bit and zero extend to 16 bit using _mm_cvtepu8_epi16() than to read the larger 16 bit version. I suspect that having the constants available at compile time isn't too valuable and can be simplified back to generating at initialization time since this version also almost passed. https://tests.stockfishchess.org/tests/view/67863057460e2910c51de7e0 I will try that as a follow up.

closes https://github.com/official-stockfish/Stockfish/pull/5793

No functional change
2025-01-18 21:13:12 +01:00
Michael ChalyandJoost VandeVondele 7701d0b3c4 Introduce one more continuation history
This one is counter counter counter history - with really low update value and divided by 3 in movepicker unlike the other ones.

Passed STC:
https://tests.stockfishchess.org/tests/view/67861495460e2910c51de720
LLR: 2.93 (-2.94,2.94) <0.00,2.00>
Total: 44352 W: 11699 L: 11370 D: 21283
Ptnml(0-2): 156, 5098, 11361, 5383, 178

Passed LTC:
https://tests.stockfishchess.org/tests/view/6786e89e3b8f206a2696b646
LLR: 2.94 (-2.94,2.94) <0.50,2.50>
Total: 432660 W: 110355 L: 109207 D: 213098
Ptnml(0-2): 381, 48214, 118039, 49268, 428

closes https://github.com/official-stockfish/Stockfish/pull/5792

Bench: 1491837
2025-01-18 21:04:55 +01:00
Nonlinear2andJoost VandeVondele b392ac76db Increase history bonus of TT moves
Passed STC:
https://tests.stockfishchess.org/tests/view/678807653b8f206a2696b78b
LLR: 2.96 (-2.94,2.94) <0.00,2.00>
Total: 42208 W: 11113 L: 10783 D: 20312
Ptnml(0-2): 148, 4919, 10651, 5227, 159

Passed LTC:
https://tests.stockfishchess.org/tests/view/6788a8463b8f206a2696b956
LLR: 2.94 (-2.94,2.94) <0.50,2.50>
Total: 122886 W: 31454 L: 30952 D: 60480
Ptnml(0-2): 105, 13567, 33619, 14025, 127

closes https://github.com/official-stockfish/Stockfish/pull/5791

Bench: 1760081
2025-01-18 21:02:04 +01:00
FauziAkramandJoost VandeVondele 165ace194f Remove the cap from maxscale for x moves in y seconds TC
Passed STC 40/10:
LLR: 2.93 (-2.94,2.94) <-1.75,0.25>
Total: 48800 W: 13044 L: 12835 D: 22921
Ptnml(0-2): 229, 5457, 12863, 5578, 273
https://tests.stockfishchess.org/tests/view/67862dae460e2910c51de7c9

Passed LTC 40/40:
LLR: 2.94 (-2.94,2.94) <-1.75,0.25>
Total: 141296 W: 36110 L: 36014 D: 69172
Ptnml(0-2): 222, 14350, 41440, 14382, 254
https://tests.stockfishchess.org/tests/view/678799903b8f206a2696b6f8

Passed STC 80/8:
LLR: 2.99 (-2.94,2.94) <-1.75,0.25>
Total: 155120 W: 41442 L: 41346 D: 72332
Ptnml(0-2): 953, 17232, 41102, 17312, 961
https://tests.stockfishchess.org/tests/view/678aca4dc00c743bc9e9fc47

Passed LTC 80/60:
LLR: 2.94 (-2.94,2.94) <-1.75,0.25>
Total: 93950 W: 24042 L: 23904 D: 46004
Ptnml(0-2): 80, 9020, 28627, 9178, 70
https://tests.stockfishchess.org/tests/view/678af705c00c743bc9e9fe94

closes https://github.com/official-stockfish/Stockfish/pull/5790

No functional change
2025-01-18 20:58:41 +01:00
ppigazziniandJoost VandeVondele 4423c8eefa Return stockfish-macos-m1-apple-silicon.tar
https://github.com/[ppigazzini/stockfish-downloader now uses the official SF script for POSIX systems.

closes https://github.com/official-stockfish/Stockfish/pull/5789

No functional change
2025-01-18 20:56:23 +01:00
Shawn XuandJoost VandeVondele ccbd060b01 simplify razoring
Passed Non-regression STC:
LLR: 2.94 (-2.94,2.94) <-1.75,0.25>
Total: 93056 W: 24215 L: 24054 D: 44787
Ptnml(0-2): 364, 11085, 23470, 11244, 365
https://tests.stockfishchess.org/tests/view/67883a5d3b8f206a2696b804

Passed Non-regression LTC:
LLR: 2.94 (-2.94,2.94) <-1.75,0.25>
Total: 66564 W: 16971 L: 16794 D: 32799
Ptnml(0-2): 56, 7403, 18192, 7570, 61
https://tests.stockfishchess.org/tests/view/6789ffa78082388fa0cbfe95

closes https://github.com/official-stockfish/Stockfish/pull/5788

bench 1500649
2025-01-18 20:54:55 +01:00
DisservinandJoost VandeVondele 132b90df04 Update CI to Ubuntu 22.04 from 20.04
fixes #5756
closes https://github.com/official-stockfish/Stockfish/pull/5786

No functional change
2025-01-18 20:52:07 +01:00
Daniel MonroeandJoost VandeVondele a944f08225 retroactive reduction decrease if eval improves
If the previous reduction was large but the static eval improves then increase the search depth. This patch looks at the next node when calculating the reduction, something I don't think has been done before and which can probably used for further elo gaining patches.

Passed STC
LLR: 2.93 (-2.94,2.94) <0.00,2.00>
Total: 55936 W: 14813 L: 14462 D: 26661
Ptnml(0-2): 220, 6565, 14094, 6822, 267
https://tests.stockfishchess.org/tests/view/67845b70460e2910c51ddcff

Passed LTC
LLR: 2.94 (-2.94,2.94) <0.50,2.50>
Total: 189468 W: 48411 L: 47773 D: 93284
Ptnml(0-2): 180, 20801, 52131, 21445, 177
https://tests.stockfishchess.org/tests/view/6784e2cb460e2910c51ddf86

closes https://github.com/official-stockfish/Stockfish/pull/5785

bench: 1512884
2025-01-18 20:50:04 +01:00
FauziAkramandJoost VandeVondele 69ec5dcbfc Remove the type of moved piece from the evasion capture movepick formula
In the move generation the moves are generated in the order pawns, knight, bishops, rooks, queens and king.
This follows increasing type_of(pos.moved_piece(m)) term, so in master a capturing was sorted after a capturing rook if the same piece was captured in evasion.
Because we use a stable sorting method (stable means the order of elements with the same value are not changed) and generate the moves in the above order we do'nt need the removed term.

Passed STC:
LLR: 2.98 (-2.94,2.94) <-1.75,0.25>
Total: 170560 W: 44222 L: 44148 D: 82190
Ptnml(0-2): 569, 18792, 46488, 18858, 573
https://tests.stockfishchess.org/tests/view/678530ee460e2910c51de21d

closes https://github.com/official-stockfish/Stockfish/pull/5784

No functional change
2025-01-18 20:44:04 +01:00
pb00067andJoost VandeVondele 56000827af Simplify common hint for parent position
Removes function hint_common_access_for_perspective together with it's comments,
which weren't accurate anymore since merge of #5576

https://tests.stockfishchess.org/tests/view/6784c9cd460e2910c51dde39
LLR: 2.93 (-2.94,2.94) <-1.75,0.25>
Total: 295104 W: 76702 L: 76765 D: 141637
Ptnml(0-2): 1031, 32135, 81249, 32140, 997

closes https://github.com/official-stockfish/Stockfish/pull/5780

No functional change
2025-01-18 20:35:46 +01:00
DisservinandJoost VandeVondele 4c2241089d Remove addition of 1ms to all timestamps
The +1 was a quick fix to avoid the division by zero, a more correct approach is to use 1ms as the minimum reported timestamp to avoid a division by zero.
Later timestamps no longer include an additional 1ms.

closes https://github.com/official-stockfish/Stockfish/pull/5778

No functional change
2025-01-18 20:32:00 +01:00
DisservinandJoost VandeVondele 675319b45d Fix Path to AUTHORS in CONTRIBUTING
closes https://github.com/official-stockfish/Stockfish/pull/5777

No functional change
2025-01-18 20:30:44 +01:00
Daniel MonroeandJoost VandeVondele 5868b4cb58 remove eval== staticeval check in fut pruning
Simplify corrplexity in futility margin
Don't check that staticEval == eval when applying the corrplexity-based adjustment in futility pruning.

Passed Simplification STC
LLR: 2.96 (-2.94,2.94) <-1.75,0.25>
Total: 121760 W: 31640 L: 31512 D: 58608
Ptnml(0-2): 349, 14400, 31289, 14458, 384
https://tests.stockfishchess.org/tests/view/6780c4109168c8bf30927777

Passed Simplification LTC
LLR: 2.94 (-2.94,2.94) <-1.75,0.25>
Total: 134772 W: 34245 L: 34140 D: 66387
Ptnml(0-2): 94, 14869, 37350, 14984, 89
https://tests.stockfishchess.org/tests/view/6782d6ea6ddf09c0b4b6dd36

closes https://github.com/official-stockfish/Stockfish/pull/5776

Bench: 1487627
2025-01-18 20:25:59 +01:00
mstemberaandJoost VandeVondele 3104cd72d5 Fix initialization of TTData.
https://tests.stockfishchess.org/tests/view/6757757686d5ee47d9541de9
LLR: 2.93 (-2.94,2.94) <-1.75,0.25>
Total: 151200 W: 39396 L: 39306 D: 72498
Ptnml(0-2): 445, 16404, 41781, 16556, 414

Discussed in more detail here #5766

closes https://github.com/official-stockfish/Stockfish/pull/5773

No functional change
2025-01-18 20:23:10 +01:00
Carlos EsparzaandJoost VandeVondele aaafaaecf2 prefetch in do_move()
this allows removing Position::key_after()

STC
LLR: 2.93 (-2.94,2.94) <-1.75,0.25>
Total: 24960 W: 6556 L: 6336 D: 12068
Ptnml(0-2): 59, 2554, 7056, 2730, 81

LTC
LLR: 2.94 (-2.94,2.94) <-1.75,0.25>
Total: 115080 W: 29319 L: 29204 D: 56557
Ptnml(0-2): 51, 10736, 35864, 10825, 64

STC with 2MB hash
LLR: 3.04 (-2.94,2.94) <-1.75,0.25>
Total: 182176 W: 46998 L: 46932 D: 88246
Ptnml(0-2): 526, 19711, 50544, 19785, 522

LTC with 8MB hash
LLR: 2.94 (-2.94,2.94) <-1.75,0.25>
Total: 441180 W: 111557 L: 111746 D: 217877
Ptnml(0-2): 229, 39698, 140929, 39501, 233

closes https://github.com/official-stockfish/Stockfish/pull/5770

bench: 1379150
2025-01-18 20:19:53 +01:00
FauziAkramandDisservin c085670b84 Increase the depth margin
Tested at VVLTC against the passed patches.

Test 1 against PR5764
LLR: 2.94 (-2.94,2.94) <0.50,2.50>
Total: 167260 W: 43053 L: 42521 D: 81686
Ptnml(0-2): 7, 15272, 52542, 15800, 9
https://tests.stockfishchess.org/tests/view/6782ef196ddf09c0b4b6e780

Test 2 against PR5765
LLR: 2.94 (-2.94,2.94) <0.00,2.00>
Total: 300012 W: 77364 L: 76771 D: 145877
Ptnml(0-2): 22, 27555, 94256, 28154, 19
https://tests.stockfishchess.org/tests/view/678366446ddf09c0b4b7028c

closes https://github.com/official-stockfish/Stockfish/pull/5768

Bench: 1379150
2025-01-12 21:36:39 +01:00
Viren6andDisservin e2612f9a29 Introduce Correction History Quad Extensions
Also modifies the double and triple extension margins with the correction history adjustment.

STC Elo Estimate:
Elo: -4.40 ± 1.4 (95%) LOS: 0.0%
Total: 60000 W: 15230 L: 15990 D: 28780
Ptnml(0-2): 264, 7495, 15168, 6883, 190
nElo: -8.48 ± 2.8 (95%) PairsRatio: 0.91
https://tests.stockfishchess.org/tests/view/6783a3786ddf09c0b4b703a1

Passed 1st VVLTC:
LLR: 2.95 (-2.94,2.94) <0.00,2.00>
Total: 35736 W: 9354 L: 9088 D: 17294
Ptnml(0-2): 4, 3191, 11212, 3457, 4
https://tests.stockfishchess.org/tests/view/6783a3336ddf09c0b4b7039b

Passed 2nd VVLTC:
LLR: 2.95 (-2.94,2.94) <0.50,2.50>
Total: 36394 W: 9515 L: 9225 D: 17654
Ptnml(0-2): 1, 3271, 11364, 3559, 2
https://tests.stockfishchess.org/tests/view/678395e26ddf09c0b4b70345

closes https://github.com/official-stockfish/Stockfish/pull/5767

Bench: 1567166
2025-01-12 21:36:39 +01:00
Muzhen GamingandDisservin 93edf7a74c VVLTC Search Tune
Values were tuned with 118k VVLTC games.

Tested against #5764.

Passed VVLTC 1st sprt:
https://tests.stockfishchess.org/tests/view/678331226ddf09c0b4b6fd78
LLR: 2.94 (-2.94,2.94) <0.00,2.00>
Total: 43556 W: 11219 L: 10942 D: 21395
Ptnml(0-2): 2, 3975, 13549, 4248, 4

Passed VVLTC 2nd sprt:
https://tests.stockfishchess.org/tests/view/67834aa06ddf09c0b4b6fe34
LLR: 2.95 (-2.94,2.94) <0.50,2.50>
Total: 37150 W: 9577 L: 9285 D: 18288
Ptnml(0-2): 2, 3344, 11593, 3632, 4

closes https://github.com/official-stockfish/Stockfish/pull/5765

Bench: 1258128
2025-01-12 21:36:31 +01:00
Michael ChalyandDisservin 8b32e4825f Make IIR less aggressive
This patch is an elo gaining simplification which gains elo at longer time controls.
Patch disallows IIR for cutNodes with existing tt moves as well as makes
IIR for pv nodes less aggressive, basiclally confirming suspected
scaling patterns for this heuristic.

Result of 50k games STC run:
https://tests.stockfishchess.org/tests/view/678304676ddf09c0b4b6f9f9
Elo: -2.93 ± 1.6 (95%) LOS: 0.0%
Total: 50000 W: 12718 L: 13140 D: 24142
Ptnml(0-2): 189, 6087, 12835, 5735, 154
nElo: -5.71 ± 3.0 (95%) PairsRatio: 0.94

Passed VVLTC SPRT with STC bounds:
https://tests.stockfishchess.org/tests/view/6782eb1a6ddf09c0b4b6e6b0
LLR: 2.95 (-2.94,2.94) <0.00,2.00>
Total: 150292 W: 38868 L: 38458 D: 72966
Ptnml(0-2): 19, 13890, 46907, 14322, 8

Passed VVLTC SPRT with LTC bounds:
https://tests.stockfishchess.org/tests/view/6782d8d96ddf09c0b4b6df18
LLR: 2.95 (-2.94,2.94) <0.50,2.50>
Total: 153388 W: 39791 L: 39285 D: 74312
Ptnml(0-2): 13, 13924, 48311, 14436, 10

closes https://github.com/official-stockfish/Stockfish/pull/5763

Bench: 1507606
2025-01-12 21:25:36 +01:00
mstemberaandDisservin b84c8807a3 Optimize attackers_to()
https://tests.stockfishchess.org/tests/view/6782decb6ddf09c0b4b6e1b0
LLR: 2.93 (-2.94,2.94) <0.00,2.00>
Total: 105920 W: 27571 L: 27181 D: 51168
Ptnml(0-2): 284, 10808, 30403, 11164, 301

- If we only need to know if attackers exist we can skip some
  calculations.
- Also calculating slider/magic attackers first is better because the
  double lookup is slow due to memory latency.
- I also included a couple of very minor cleanups in search that
  probably don't warrant their own PR but I can open separately if
  that's better.

closes https://github.com/official-stockfish/Stockfish/pull/5762

No functional change
2025-01-12 21:24:44 +01:00
Shawn XuandDisservin 921361829a Simplify away capthist bonus in Probcut
The explicit bonus has been obsoleted with the introduction of #5695

Passed Non-regression STC:
LLR: 2.95 (-2.94,2.94) <-1.75,0.25>
Total: 132832 W: 34519 L: 34403 D: 63910
Ptnml(0-2): 430, 15754, 33931, 15872, 429
https://tests.stockfishchess.org/tests/view/678158c49168c8bf30927834

Passed Non-regression LTC:
LLR: 2.95 (-2.94,2.94) <-1.75,0.25>
Total: 123492 W: 31426 L: 31309 D: 60757
Ptnml(0-2): 79, 13705, 34051, 13842, 69
https://tests.stockfishchess.org/tests/view/6782b07e6ddf09c0b4b6dbb7

closes https://github.com/official-stockfish/Stockfish/pull/5761

Bench: 1180439
2025-01-12 21:23:29 +01:00
Shawn XuandDisservin 8d517bddff Simplify accumulator updates
AMD Ryzen 5 7600X
```
sf_base =  1902646 +/-   2114 (95%)
sf_test =  1920873 +/-   2515 (95%)
diff    =    18227 +/-   3067 (95%)
speedup = 0.95800% +/- 0.161% (95%)
```

Ryzen 9 5950X
```
sf_base =  1413387 +/-   3592 (95%)
sf_test =  1437893 +/-   3355 (95%)
diff    =    24505 +/-   4669 (95%)
speedup = 1.73380% +/- 0.330% (95%)
```

Intel Core i7-6700K
```
sf_base =   912476 +/-   1863 (95%)
sf_test =   921864 +/-   2042 (95%)
diff    =     9388 +/-   3333 (95%)
speedup = 1.02893% +/- 0.365% (95%)
```

Raspberry Pi 5
```
sf_base =   260993 +/-   1508 (95%)
sf_test =   262912 +/-   1746 (95%)
diff    =     1918 +/-   1221 (95%)
speedup = 0.73504% +/- 0.468% (95%)
```

Passed Non-regression STC:
LLR: 2.95 (-2.94,2.94) <-1.75,0.25>
Total: 23072 W: 6041 L: 5813 D: 11218
Ptnml(0-2): 61, 2435, 6319, 2657, 64
https://tests.stockfishchess.org/tests/view/6780a0ca9168c8bf30927757

closes https://github.com/official-stockfish/Stockfish/pull/5759

No functional change
2025-01-12 21:21:53 +01:00
Shawn XuandDisservin 28c07fb456 Simplify Probcut Condition
Rebased and properly guarded #5720

Passed Non-regression STC:
LLR: 2.94 (-2.94,2.94) <-1.75,0.25>
Total: 179616 W: 45764 L: 45706 D: 88146
Ptnml(0-2): 125, 19665, 50162, 19739, 117
https://tests.stockfishchess.org/tests/view/677590531a2f267f20548b82

Passed Non-regression LTC:
LLR: 2.94 (-2.94,2.94) <-1.75,0.25>
Total: 445728 W: 113467 L: 113682 D: 218579
Ptnml(0-2): 331, 49226, 123900, 49141, 266
https://tests.stockfishchess.org/tests/view/67734f351a2f267f205489d9

closes https://github.com/official-stockfish/Stockfish/pull/5758

Bench: 1180421
2025-01-12 21:18:39 +01:00
Disservin ea71a08843 Improve Instrumented Python Testing Script
For betting debugging and earlier stop in case of termination, like in
https://github.com/official-stockfish/Stockfish/pull/5754#issuecomment-2576120357

closes https://github.com/official-stockfish/Stockfish/pull/5755

No functional change
2025-01-12 21:18:08 +01:00
Maxim MasiutinandDisservin d49fd9090b Add .gitattributes for script LE
closes https://github.com/official-stockfish/Stockfish/pull/5753

No functional change
2025-01-12 21:16:32 +01:00
pb00067andDisservin c88a5b3950 Simplify away hint for common parent position at probcut
Since it's introduction at probcut step the nnue network has changed
substantially and now it no longer seems useful.

Passed non-regression test at STC
https://tests.stockfishchess.org/tests/view/675fe27986d5ee47d9542d86
LLR: 2.93 (-2.94,2.94) <-1.75,0.25>
Total: 118656 W: 30732 L: 30609 D: 57315
Ptnml(0-2): 319, 12767, 33049, 12858, 335

N.B.: It may be useful to reintroduce it here at probcut if we know that
a node that was cut away previously now has to be explored. Exploring
new ground will deliver no tt-hits so in this case the hint for common
parent position might be useful.

No functional change
2025-01-12 21:15:35 +01:00
Shawn XuandDisservin 403a5e100b Simplify Fail-Low Bonus
Passed Non-regression STC:
LLR: 2.92 (-2.94,2.94) <-1.75,0.25>
Total: 66592 W: 17426 L: 17239 D: 31927
Ptnml(0-2): 208, 7812, 17109, 7919, 248
https://tests.stockfishchess.org/tests/view/6774e1711a2f267f20548b22

Passed Non-regression LTC:
LLR: 2.94 (-2.94,2.94) <-1.75,0.25>
Total: 179616 W: 45764 L: 45706 D: 88146
Ptnml(0-2): 125, 19665, 50162, 19739, 117
https://tests.stockfishchess.org/tests/view/677590531a2f267f20548b82

closes https://github.com/official-stockfish/Stockfish/pull/5751

Bench: 1310158
2025-01-12 21:14:11 +01:00
Shawn XuandDisservin 5370c3035e Refactor Stats Array
* Limit use of `StatsEntry` wrapper to arithmetic types
* Generalize `Stats` to `MultiArray` by discarding the template parameter `D`
* Allow `MultiArray::fill` to take any type assignable to element type
* Remove now-unused operator overloads on `StatsEntry`

closes https://github.com/official-stockfish/Stockfish/pull/5750

No functional change
2025-01-12 21:13:14 +01:00
Shawn XuandDisservin c47e6fcf84 Small cleanup of nnue_feature_transformer.h
Passed Non-regression STC:
LLR: 2.94 (-2.94,2.94) <-1.75,0.25>
Total: 285760 W: 73716 L: 73768 D: 138276
Ptnml(0-2): 777, 30775, 79851, 30677, 800
https://tests.stockfishchess.org/tests/view/676f78681a2f267f205485aa

closes https://github.com/official-stockfish/Stockfish/pull/5745

No functional change
2025-01-12 21:11:59 +01:00
Shawn XuandDisservin d1a1ff4f17 Simplify Razoring
Passed Non-regression STC:
LLR: 2.95 (-2.94,2.94) <-1.75,0.25>
Total: 95584 W: 24906 L: 24750 D: 45928
Ptnml(0-2): 285, 11227, 24632, 11343, 305
https://tests.stockfishchess.org/tests/view/675e0ed286d5ee47d95429ee

Passed Non-regression LTC:
LLR: 2.96 (-2.94,2.94) <-1.75,0.25>
Total: 191292 W: 48637 L: 48589 D: 94066
Ptnml(0-2): 97, 21061, 53276, 21121, 91
https://tests.stockfishchess.org/tests/view/675f08c686d5ee47d9542be3

closes https://github.com/official-stockfish/Stockfish/pull/5724

Bench: 1286274
2025-01-12 21:11:27 +01:00
sscg13andDisservin 7858f9dfdc Use same pawn value in both nets when doing material scaling of eval
Passed Non-regression STC:
LLR: 2.94 (-2.94,2.94) <-1.75,0.25>
Total: 221312 W: 57291 L: 57274 D: 106747
Ptnml(0-2): 760, 26152, 56841, 26117, 786
https://tests.stockfishchess.org/tests/view/676e2a101a2f267f20548453

Passed Non-regression LTC:
LLR: 2.94 (-2.94,2.94) <-1.75,0.25>
Total: 176808 W: 45084 L: 45023 D: 86701
Ptnml(0-2): 112, 19418, 49286, 19473, 115
https://tests.stockfishchess.org/tests/view/676f424d1a2f267f2054857f

closes https://github.com/official-stockfish/Stockfish/pull/5741

Bench: 1121800
2025-01-12 21:09:58 +01:00
Daniel MonroeandDisservin c76c179361 Remove non-functional std::min()
closes https://github.com/official-stockfish/Stockfish/pull/5749

No functional change
2025-01-06 00:48:05 +01:00
Daniel MonroeandDisservin 1611b9c940 Corrplexity for futility pruning
Add corrhist-based term to futility margin

Inspired by a recent patch of Shawn Xu, this tweak increases the margin
over beta needed to futility prune based on the correction history, with
an offset.

Passed STC
LLR: 2.97 (-2.94,2.94) <0.00,2.00>
Total: 545504 W: 141957 L: 140885 D: 262662
Ptnml(0-2): 1829, 64226, 139551, 65336, 1810
https://tests.stockfishchess.org/tests/view/67634a8386d5ee47d95439db

Passed LTC
LLR: 2.94 (-2.94,2.94) <0.50,2.50>
Total: 125994 W: 32199 L: 31695 D: 62100
Ptnml(0-2): 97, 13742, 34798, 14280, 80
https://tests.stockfishchess.org/tests/view/6765cf9986d5ee47d9544217

closes https://github.com/official-stockfish/Stockfish/pull/5748

Bench: 999324
2025-01-06 00:46:30 +01:00
Shawn XuandDisservin 5488dd2f91 Update Copyright Year
closes https://github.com/official-stockfish/Stockfish/pull/5747

No functional change
2025-01-06 00:45:28 +01:00
Shawn XuandDisservin 00da3ff463 Cleanup stats entry
Prevents potential issue caused by publicly inheriting from STL container types

closes https://github.com/official-stockfish/Stockfish/pull/5746

No functional change
2025-01-06 00:44:25 +01:00
Shawn XuandDisservin 5cf6f99177 Remove some incorrectly marked const qualifiers
closes https://github.com/official-stockfish/Stockfish/pull/5744

No functional change
2025-01-06 00:43:49 +01:00
Shawn XuandDisservin 78b5733939 Simplify post-lmr conthist bonus
Passed Non-regression STC:
LLR: 2.95 (-2.94,2.94) <-1.75,0.25>
Total: 49184 W: 12735 L: 12528 D: 23921
Ptnml(0-2): 134, 5746, 12647, 5909, 156
https://tests.stockfishchess.org/tests/view/6765cd2e86d5ee47d954420e

Passed Non-regression LTC:
LLR: 2.94 (-2.94,2.94) <-1.75,0.25>
Total: 177270 W: 45227 L: 45166 D: 86877
Ptnml(0-2): 132, 19498, 49302, 19583, 120
https://tests.stockfishchess.org/tests/view/676721fd86d5ee47d9544489

closes https://github.com/official-stockfish/Stockfish/pull/5734

Bench: 1042099
2025-01-06 00:43:37 +01:00
Michael ChalyandDisservin 03e4cde729 Allow Pv nodes at certain conditions to spawn zero window searches deeper than default
In current case it's allowed if there is no best move.

Passed STC:
https://tests.stockfishchess.org/tests/view/67640fd586d5ee47d9543d5a
LLR: 2.96 (-2.94,2.94) <0.00,2.00>
Total: 392480 W: 102038 L: 101192 D: 189250
Ptnml(0-2): 1303, 46287, 100253, 47055, 1342

Passed LTC:
https://tests.stockfishchess.org/tests/view/67671a4686d5ee47d9544476
LLR: 2.94 (-2.94,2.94) <0.50,2.50>
Total: 128616 W: 32941 L: 32433 D: 63242
Ptnml(0-2): 84, 13997, 35634, 14513, 80

closes https://github.com/official-stockfish/Stockfish/pull/5733

Bench: 1095871
2025-01-06 00:40:05 +01:00
mstemberaandDisservin f656fdfa9a Simplify Zobrist keys for captures
The Zobrist keys for NO_PIECE are 0 so no need to special case captures.
Also the TranspositionTable reference passed to do_null_move() can be
const.

STC Simplification:
https://tests.stockfishchess.org/tests/view/6764a79a86d5ee47d9544005
LLR: 2.96 (-2.94,2.94) <-1.75,0.25>
Total: 114240 W: 29654 L: 29523 D: 55063
Ptnml(0-2): 329, 12360, 31620, 12473, 338

closes https://github.com/official-stockfish/Stockfish/pull/5731

No functional change
2024-12-22 15:29:42 +01:00
Michael ChalyandDisservin 79261bec59 Simplify away reductions adjustment for multithreaded search
Seem to no longer bring measurable benefit.

Passed STC SMP simplification:
https://tests.stockfishchess.org/tests/view/6753561a86d5ee47d954151f
LLR: 2.94 (-2.94,2.94) <-1.75,0.25>
Total: 38000 W: 9864 L: 9656 D: 18480
Ptnml(0-2): 53, 4177, 10320, 4409, 41

Passed LTC SMP simplification:
https://tests.stockfishchess.org/tests/view/6753d75f86d5ee47d9541669
LLR: 2.95 (-2.94,2.94) <-1.75,0.25>
Total: 258674 W: 66314 L: 66335 D: 126025
Ptnml(0-2): 77, 26957, 75303, 26910, 90

Passed 16 threads LTC simplification:
https://tests.stockfishchess.org/tests/view/675a066286d5ee47d9542296
LLR: 2.94 (-2.94,2.94) <-1.75,0.25>
Total: 221804 W: 56950 L: 56936 D: 107918
Ptnml(0-2): 34, 21491, 67839, 21503, 35

closes https://github.com/official-stockfish/Stockfish/pull/5729

Bench: 1294909
2024-12-22 15:28:15 +01:00
Disservin 4bc2a24245 Workaround for clang-format bug
closes https://github.com/official-stockfish/Stockfish/pull/5728

No functional change
2024-12-22 15:27:40 +01:00
Shawn XuandDisservin e7e78aa09e Adjust LMR with correction history
A positive constant increase in base reduction is applied to counter the
decrease in average reduction from this tweak.

Passed STC:
LLR: 2.98 (-2.94,2.94) <0.00,2.00>
Total: 109216 W: 28415 L: 27989 D: 52812
Ptnml(0-2): 310, 12848, 27911, 13184, 355
https://tests.stockfishchess.org/tests/view/6760bb0e86d5ee47d9542f26

Passed LTC:
LLR: 2.95 (-2.94,2.94) <0.50,2.50>
Total: 66918 W: 17073 L: 16694 D: 33151
Ptnml(0-2): 33, 7175, 18666, 7550, 35
https://tests.stockfishchess.org/tests/view/6761e10f86d5ee47d95431fa

closes https://github.com/official-stockfish/Stockfish/pull/5727

Bench: 1294909
2024-12-22 15:26:39 +01:00
FauziAkramandDisservin a04b07265f Make reductionScale smoother
Making the second part of the formula smoother, changing it to a linear
function, increasing steadily as reductionScale increases and at the
same time, it should be a little bit simpler, therefore the
simplification bounds.

Passed STC:
LLR: 2.94 (-2.94,2.94) <-1.75,0.25>
Total: 83040 W: 21493 L: 21322 D: 40225
Ptnml(0-2): 252, 9848, 21209, 9899, 312
https://tests.stockfishchess.org/tests/view/6762145486d5ee47d9543242

Passed LTC:
LLR: 2.94 (-2.94,2.94) <-1.75,0.25>
Total: 230124 W: 58485 L: 58478 D: 113161
Ptnml(0-2): 175, 25620, 63484, 25589, 194
https://tests.stockfishchess.org/tests/view/6762d4ef86d5ee47d9543367

closes https://github.com/official-stockfish/Stockfish/pull/5725

Bench: 1204658
2024-12-22 15:24:09 +01:00
Shawn XuandDisservin 6075e787d0 Add CI test with glibcxx assertions enabled
Re: https://github.com/official-stockfish/Stockfish/pull/5721#pullrequestreview-2504542601

closes https://github.com/official-stockfish/Stockfish/pull/5723

No functional change
2024-12-22 15:20:25 +01:00
Disservin 2dc47e4345 Cleanup Evaluate Calls
Makes code a bit easier to read as well.

closes https://github.com/official-stockfish/Stockfish/pull/5722

No functional change
2024-12-22 15:19:53 +01:00
Shawn XuandDisservin 77ec878ffa Prevent out of bounds access of dbg info arrays
closes https://github.com/official-stockfish/Stockfish/pull/5721

No functional change
2024-12-22 15:19:13 +01:00
Daniel MonroeandDisservin ba145332c9 Remove time reduction for recaptures
Passed simplification STC
LLR: 2.96 (-2.94,2.94) <-1.75,0.25>
Total: 54016 W: 14098 L: 13902 D: 26016
Ptnml(0-2): 165, 5797, 14919, 5931, 196
https://tests.stockfishchess.org/tests/view/6758a90486d5ee47d954201e

Passed simplification LTC
LLR: 2.94 (-2.94,2.94) <-1.75,0.25>
Total: 296940 W: 75631 L: 75689 D: 145620
Ptnml(0-2): 145, 28928, 90384, 28866, 147
https://tests.stockfishchess.org/tests/view/6758df7a86d5ee47d9542091

closes https://github.com/official-stockfish/Stockfish/pull/5719

Bench: 1148169
2024-12-22 15:17:55 +01:00
Shawn XuandDisservin e770b55f7f Remove Extraneous Parenthesis
No longer needed after
https://github.com/official-stockfish/Stockfish/pull/5667.

closes https://github.com/official-stockfish/Stockfish/pull/5717

No functional change
2024-12-22 15:17:33 +01:00
Disservin 1776448917 Move Embedded Net Data out of Anon Namespace
fixes https://github.com/official-stockfish/Stockfish/issues/5714

closes https://github.com/official-stockfish/Stockfish/pull/5715

No functional change
2024-12-22 15:16:07 +01:00
Disservin f414d490bc Update Incbin Library
No functional change
2024-12-22 15:16:01 +01:00
Shawn XuandDisservin b822fdf2f2 Tune histories
Passed STC:
LLR: 2.93 (-2.94,2.94) <0.00,2.00>
Total: 268736 W: 70080 L: 69421 D: 129235
Ptnml(0-2): 831, 31795, 68460, 32448, 834
https://tests.stockfishchess.org/tests/view/6750778886d5ee47d9540e7c

Passed LTC:
LLR: 2.95 (-2.94,2.94) <0.50,2.50>
Total: 505356 W: 129145 L: 127868 D: 248343
Ptnml(0-2): 307, 54901, 140959, 56230, 281
https://tests.stockfishchess.org/tests/view/675367de86d5ee47d9541536

closes https://github.com/official-stockfish/Stockfish/pull/5712

Bench: 1148169
2024-12-22 15:14:22 +01:00
Nonlinear2andGitHub cf10644d6e Fix duplicate code (#5711)
closes https://github.com/official-stockfish/Stockfish/pull/5711

No functional change
2024-12-08 22:24:29 +01:00
mstemberaandDisservin a8b6bf1b1a Small Major/Minor piece key simplification/optimization.
closes https://github.com/official-stockfish/Stockfish/pull/5710

No functional change
2024-12-08 19:58:34 +01:00
Michael ChalyandDisservin afaf3a0f2a Refine statscore for captures
Continuation of previous attempts there.
Now instead of using capture history with a static offset also add the
value of the captured piece in the same way at it is used in movepicker.

Passed STC:
https://tests.stockfishchess.org/tests/view/674aa3d386d5ee47d95404aa
LLR: 2.93 (-2.94,2.94) <0.00,2.00>
Total: 116480 W: 30433 L: 29999 D: 56048
Ptnml(0-2): 361, 13720, 29662, 14118, 379

Passed LTC:
https://tests.stockfishchess.org/tests/view/674c4b2d86d5ee47d954073f
LLR: 2.94 (-2.94,2.94) <0.50,2.50>
Total: 133542 W: 34365 L: 33847 D: 65330
Ptnml(0-2): 78, 14585, 36934, 15089, 85

closes https://github.com/official-stockfish/Stockfish/pull/5706

Bench: 934447
2024-12-08 19:57:59 +01:00
xu-shawnandDisservin e8d2ba194a Add Leela Data Attribution
closes https://github.com/official-stockfish/Stockfish/pull/5705

No functional change
2024-12-08 19:56:01 +01:00
Shawn XuandDisservin 6a8478c6ad Simplify Prior Capture Countermove Bonus
Passed Non-regression STC:
LLR: 2.94 (-2.94,2.94) <-1.75,0.25>
Total: 184032 W: 47626 L: 47568 D: 88838
Ptnml(0-2): 590, 21808, 47238, 21714, 666
https://tests.stockfishchess.org/tests/view/67412c7686d5ee47d953f743

Passed Non-regression LTC:
LLR: 2.96 (-2.94,2.94) <-1.75,0.25>
Total: 169218 W: 43395 L: 43323 D: 82500
Ptnml(0-2): 302, 18567, 46791, 18655, 294
https://tests.stockfishchess.org/tests/view/6743b7e086d5ee47d953f9a6

closes https://github.com/official-stockfish/Stockfish/pull/5701

Bench: 1130692
2024-12-08 19:55:10 +01:00
Carlos EsparzaandDisservin 1f9404434d Simplify picking of evasion moves
Sort evasions before we start returning them in next_move() (just like
every other kind of move) instead of looking for the biggest element on
every call to next_move(). The bench number changes because the old
method is not equivalent to a stable sort.

Passed STC:
LLR: 2.93 (-2.94,2.94) <-1.75,0.25>
Total: 132064 W: 34318 L: 34204 D: 63542
Ptnml(0-2): 392, 15522, 34106, 15604, 408
https://tests.stockfishchess.org/tests/view/6743fee086d5ee47d953f9ca

Passed LTC:
LLR: 2.94 (-2.94,2.94) <-1.75,0.25>
Total: 97542 W: 24899 L: 24757 D: 47886
Ptnml(0-2): 63, 10646, 27193, 10824, 45
https://tests.stockfishchess.org/tests/view/674509cd86d5ee47d953fb96

closes https://github.com/official-stockfish/Stockfish/pull/5700

Bench: 1094825
2024-12-08 19:54:18 +01:00
pb00067andDisservin 713000c517 Same weight for black and white nonPawnCorrection history
Since we don't have color dependent parameters in NNUE eval, it also has
no sense IMO to have color dependent parameters in correction histories.

Ideally a fixed depth search on a single thread should be determistic,
so delivering the same result (move) if we just flip colors on the
board.

Patch replaces 2 parameters (122 and 185) with just one value 154 (= the avg of the two).

Passed STC-non regression
https://tests.stockfishchess.org/tests/view/6740a63286d5ee47d953f656
LLR: 2.95 (-2.94,2.94) <-1.75,0.25>
Total: 122336 W: 31499 L: 31372 D: 59465
Ptnml(0-2): 336, 14535, 31301, 14658, 338

Passed LTC-non regression
https://tests.stockfishchess.org/tests/view/67419bae86d5ee47d953f7b6
LLR: 2.94 (-2.94,2.94) <-1.75,0.25>
Total: 101400 W: 25870 L: 25731 D: 49799
Ptnml(0-2): 78, 11109, 28166, 11290, 57

closes https://github.com/official-stockfish/Stockfish/pull/5698

Bench: 1215483
2024-12-08 19:52:16 +01:00
FauziAkramandDisservin d5a36a3c92 Simplify probCutBeta formula
After recent changes to the improving definition, seems like there is no
need anymore to keep opponentWorsening in the probCutBeta formula.

Passed STC:
LLR: 2.94 (-2.94,2.94) <-1.75,0.25>
Total: 214272 W: 55566 L: 55541 D: 103165
Ptnml(0-2): 620, 25540, 54817, 25513, 646
https://tests.stockfishchess.org/tests/view/6735243d86d5ee47d953eaea

Passed LTC:
LLR: 2.94 (-2.94,2.94) <-1.75,0.25>
Total: 126708 W: 32329 L: 32216 D: 62163
Ptnml(0-2): 68, 13986, 35123, 14119, 58
https://tests.stockfishchess.org/tests/view/67393cf686d5ee47d953ef99

closes https://github.com/official-stockfish/Stockfish/pull/5697

Bench: 983067
2024-12-08 19:49:01 +01:00
Nonlinear2andDisservin da82942b54 Add functions to check for decisive scores
Thanks to peregrineshahin and robbyrobbyrob for their suggestions.

closes https://github.com/official-stockfish/Stockfish/pull/5696

No functional change
2024-12-08 19:48:49 +01:00
Nonlinear2andDisservin 57e06be71f Add functions to check for decisive scores
Thanks to peregrineshahin and robbyrobbyrob for their suggestions.

closes https://github.com/official-stockfish/Stockfish/pull/5696

No functional change
2024-12-08 19:47:02 +01:00
Daniel MonroeandDisservin 70bb317afe Bonus for a prior capture that causes a fail low.
This tweak adds a bonus equal to twice the stat_bonus for the current depth for a prior capture that caused a fail high, similar to the prior countermove bonus we currently have.

Passed STC
https://tests.stockfishchess.org/tests/view/673bc14b86d5ee47d953f1f2
LLR: 2.95 (-2.94,2.94) <0.00,2.00>
Total: 105824 W: 27538 L: 27118 D: 51168
Ptnml(0-2): 358, 12370, 27024, 12814, 346

Passed LTC
https://tests.stockfishchess.org/tests/view/673ccbff86d5ee47d953f2d9
LLR: 2.94 (-2.94,2.94) <0.50,2.50>
Total: 134502 W: 34340 L: 33820 D: 66342
Ptnml(0-2): 102, 14634, 37229, 15214, 72

closes https://github.com/official-stockfish/Stockfish/pull/5695

Bench: 1107054
2024-12-08 19:46:07 +01:00
Daniel MonroeandDisservin 55905e562a Simplify movepick coefficients
This commit sets movepick weights for all continuation histories to 1
and doubles the weight for the main history, inspired by a recent tune.

Passed STC
https://tests.stockfishchess.org/tests/view/6735151a86d5ee47d953eaa2
LLR: 2.92 (-2.94,2.94) <-1.75,0.25>
Total: 29984 W: 7840 L: 7612 D: 14532
Ptnml(0-2): 85, 3511, 7571, 3741, 84

Passed LTC
https://tests.stockfishchess.org/tests/view/673667a986d5ee47d953ec78
LLR: 2.94 (-2.94,2.94) <-1.75,0.25>
Total: 26268 W: 6726 L: 6510 D: 13032
Ptnml(0-2): 16, 2797, 7288, 3021, 12

closes https://github.com/official-stockfish/Stockfish/pull/5680

Bench: 1130293
2024-12-08 19:45:48 +01:00
Shawn XuandDisservin b7f17346e5 Fix Sanitizer Tests
closes https://github.com/official-stockfish/Stockfish/pull/5692

No functional change
2024-11-22 23:41:34 +01:00
Daniel MonroeandDisservin fb6be17ad4 Simplify statscore at captures
Simplify statscores for captures, setting them to 0

A recent tweak of Vizvezdenec finds substantial elo gain from giving
captures a separate statscore, which is used mainly for reductions. The
idea is that the old combination of quiet histories was inappropriate
and that a value based on the capture history is more suitable. This
simplification sets the statscore for captures to 0, suggesting that the
elo gain came from rectifying the quiet history/capture mismatch.

Passed STC (against a slightly older version of Viz's patch)
https://tests.stockfishchess.org/tests/view/673ac6e286d5ee47d953f0ec
LR: 2.96 (-2.94,2.94) <-1.75,0.25>
Total: 57312 W: 14872 L: 14672 D: 27768
Ptnml(0-2): 152, 6761, 14649, 6923, 171

Passed LTC (against Viz's newest patch)
https://tests.stockfishchess.org/tests/view/673cd00686d5ee47d953f2db
LLR: 2.95 (-2.94,2.94) <-1.75,0.25>
Total: 88236 W: 22510 L: 22358 D: 43368
Ptnml(0-2): 70, 9530, 24745, 9724, 49

closes https://github.com/official-stockfish/Stockfish/pull/5691

Bench: 959947
2024-11-22 23:34:15 +01:00
Shawn XuandDisservin 4fcd78ceb4 Simplify Probcut Bonus
Passed STC:
LLR: 2.99 (-2.94,2.94) <-1.75,0.25>
Total: 172288 W: 44656 L: 44580 D: 83052
Ptnml(0-2): 507, 20650, 43782, 20670, 535
https://tests.stockfishchess.org/tests/view/673b74f986d5ee47d953f1a3

Passed LTC:
LLR: 2.94 (-2.94,2.94) <-1.75,0.25>
Total: 94596 W: 24098 L: 23953 D: 46545
Ptnml(0-2): 57, 10322, 26393, 10471, 55
https://tests.stockfishchess.org/tests/view/673d191886d5ee47d953f337

closes https://github.com/official-stockfish/Stockfish/pull/5688

Bench: 1031022
2024-11-22 23:31:34 +01:00
Michael ChalyandDisservin cd3c13a883 Further tweak statscore for captures
Even lower offset.

Passed STC:
https://tests.stockfishchess.org/tests/view/673a66d786d5ee47d953f070
LLR: 2.94 (-2.94,2.94) <0.00,2.00>
Total: 63776 W: 16570 L: 16216 D: 30990
Ptnml(0-2): 178, 7371, 16478, 7641, 220

Passed LTC:
https://tests.stockfishchess.org/tests/view/673b2e2a86d5ee47d953f14b
LLR: 2.95 (-2.94,2.94) <0.50,2.50>
Total: 156960 W: 39999 L: 39435 D: 77526
Ptnml(0-2): 96, 16965, 43803, 17511, 105

closes https://github.com/official-stockfish/Stockfish/pull/5686

Bench: 867931
2024-11-22 23:29:37 +01:00
Guenther DemetzandDisservin d29c8bd5d4 Rewrite of 'Adjust correction history' condition
Current condition is convoluted and hard to understand because of
several negations. Also added 2 comments to make the concept behind the
condition better understandable.

closes https://github.com/official-stockfish/Stockfish/pull/5685

No functional change
2024-11-22 23:24:15 +01:00
FauziAkramandDisservin 0282edc0b0 Simplify bonus formula
Give full bonus instead of half.

Passed STC:
LLR: 2.95 (-2.94,2.94) <-1.75,0.25>
Total: 23872 W: 6254 L: 6018 D: 11600
Ptnml(0-2): 80, 2691, 6152, 2939, 74
https://tests.stockfishchess.org/tests/view/673b709686d5ee47d953f19d

Passed LTC:
LLR: 2.95 (-2.94,2.94) <-1.75,0.25>
Total: 42894 W: 10924 L: 10725 D: 21245
Ptnml(0-2): 30, 4592, 12011, 4777, 37
https://tests.stockfishchess.org/tests/view/673bb50386d5ee47d953f1eb

closes https://github.com/official-stockfish/Stockfish/pull/5683

Bench: 836558
2024-11-22 23:23:42 +01:00
Michael ChalyandDisservin f129bf0de9 Tweak statscore for captures
Followup of a recent patch that separated statscore for captures and non-captures.
Lower value that we subtract from statscore if a move is a capture.

Passed STC:
https://tests.stockfishchess.org/tests/view/67385b6786d5ee47d953eeba
LLR: 2.93 (-2.94,2.94) <0.00,2.00>
Total: 50592 W: 13223 L: 12888 D: 24481
Ptnml(0-2): 154, 5853, 12931, 6220, 138

Passed LTC:
https://tests.stockfishchess.org/tests/view/6739056e86d5ee47d953ef3f
LLR: 2.95 (-2.94,2.94) <0.50,2.50>
Total: 23598 W: 6155 L: 5862 D: 11581
Ptnml(0-2): 16, 2466, 6543, 2757, 17

closes https://github.com/official-stockfish/Stockfish/pull/5682

Bench: 771180
2024-11-22 23:12:43 +01:00
Michael ChalyandDisservin 82b092ca48 Adjust statscore for captures
Instead of using quiet histories use capture history with a different
offset.

Passed STC:
https://tests.stockfishchess.org/tests/view/6731d5cc86d5ee47d953e719
LLR: 2.96 (-2.94,2.94) <0.00,2.00>
Total: 428896 W: 111160 L: 110269 D: 207467
Ptnml(0-2): 1220, 50296, 110534, 51169, 1229

Passed LTC:
https://tests.stockfishchess.org/tests/view/6733d9fd86d5ee47d953e962
LLR: 2.95 (-2.94,2.94) <0.50,2.50>
Total: 105882 W: 26918 L: 26458 D: 52506
Ptnml(0-2): 66, 11430, 29482, 11904, 59

closes https://github.com/official-stockfish/Stockfish/pull/5679

Bench: 840721
2024-11-13 20:35:02 +01:00
Disservin 49138b8c33 Fix CI Docker Buildx
closes https://github.com/official-stockfish/Stockfish/pull/5678

No functional change
2024-11-13 20:35:02 +01:00
FauziAkramandDisservin ce2d9e27ea Simplify big-net reevaluation
Passed STC:
LLR: 2.95 (-2.94,2.94) <-1.75,0.25>
Total: 37408 W: 9699 L: 9477 D: 18232
Ptnml(0-2): 130, 4326, 9577, 4534, 137
https://tests.stockfishchess.org/tests/view/672ffd8086d5ee47d953e633

Passed LTC:
LLR: 2.95 (-2.94,2.94) <-1.75,0.25>
Total: 151062 W: 38087 L: 37999 D: 74976
Ptnml(0-2): 63, 16686, 41958, 16748, 76
https://tests.stockfishchess.org/tests/view/673087aa86d5ee47d953e66b

closes https://github.com/official-stockfish/Stockfish/pull/5674

Bench: 848812
2024-11-13 20:35:02 +01:00
Linmiao XuandDisservin 070db8b3a1 Update default main net to nn-1c0000000000.nnue
Found by updating 489 L2 weights with values found from around
31k / 60k spsa games.

Spsa was configured to use 60k games, down from 120k games in:
https://github.com/official-stockfish/Stockfish/pull/5459

623 spsa params:
L2 weights from `nn-1cedc0ffeeee.nnue` where 24 <= |value| <= 30
A: 3000, alpha: 0.602, gamma: 0.101
weights: [-127, 127], c_end = 6

Passed STC:
https://tests.stockfishchess.org/tests/view/6728d61e86d5ee47d953dcaf
LLR: 2.93 (-2.94,2.94) <0.00,2.00>
Total: 187168 W: 48642 L: 48107 D: 90419
Ptnml(0-2): 558, 21888, 48213, 22311, 614

Passed LTC:
https://tests.stockfishchess.org/tests/view/672b018f86d5ee47d953de98
LLR: 2.94 (-2.94,2.94) <0.50,2.50>
Total: 235074 W: 59924 L: 59202 D: 115948
Ptnml(0-2): 131, 25467, 65610, 26207, 122

closes https://github.com/official-stockfish/Stockfish/pull/5673

Bench: 898850
2024-11-13 20:35:02 +01:00
Nonlinear2andDisservin 43e100ae06 Use cutnode as TT Cutoff Condition
At low enough depths, fail high with TT only when expected cutnode.

Passed STC:
https://tests.stockfishchess.org/tests/view/6726357b86d5ee47d953da8c
LLR: 2.93 (-2.94,2.94) <0.00,2.00>
Total: 41184 W: 10873 L: 10551 D: 19760
Ptnml(0-2): 131, 4728, 10554, 5046, 133

Passed LTC:
https://tests.stockfishchess.org/tests/view/6727326a86d5ee47d953db30
LLR: 2.94 (-2.94,2.94) <0.50,2.50>
Total: 270888 W: 69040 L: 68243 D: 133605
Ptnml(0-2): 180, 29385, 75485, 30246, 148

closes https://github.com/official-stockfish/Stockfish/pull/5670

Bench: 805776
2024-11-13 20:35:02 +01:00
Muzhen GamingandDisservin 3d084e9164 VVLTC Search Tune
A single tuning run of 190k games was conducted:
https://tests.stockfishchess.org/tests/view/670f3e3786d5ee47d953c554.

Passed VVLTC 1st sprt:
https://tests.stockfishchess.org/tests/view/672344dc86d5ee47d953d8c3
LLR: 2.94 (-2.94,2.94) <0.00,2.00>
Total: 56768 W: 14615 L: 14323 D: 27830
Ptnml(0-2): 3, 5152, 17789, 5430, 10

Passed VVLTC 2nd sprt (rebased):
https://tests.stockfishchess.org/tests/view/6726d83786d5ee47d953db03
LLR: 2.94 (-2.94,2.94) <0.50,2.50>
Total: 57884 W: 14885 L: 14554 D: 28445
Ptnml(0-2): 5, 5300, 17999, 5635, 3

closes https://github.com/official-stockfish/Stockfish/pull/5669

Bench: 920336
2024-11-13 20:34:53 +01:00
Shawn XuandDisservin cc5c67c564 Introduce Fractional LMR
Tuning Run (90k Games):
https://tests.stockfishchess.org/tests/view/67202b1c86d5ee47d953d442

Passed STC:
LLR: 2.94 (-2.94,2.94) <0.00,2.00>
Total: 241024 W: 62616 L: 62001 D: 116407
Ptnml(0-2): 716, 28231, 62015, 28822, 728
https://tests.stockfishchess.org/tests/view/6725196786d5ee47d953d9f2

Passed LTC:
LLR: 2.95 (-2.94,2.94) <0.50,2.50>
Total: 92532 W: 23678 L: 23246 D: 45608
Ptnml(0-2): 45, 9981, 25797, 10383, 60
https://tests.stockfishchess.org/tests/view/6727d3cb86d5ee47d953db9d

closes https://github.com/official-stockfish/Stockfish/pull/5667

Bench: 1066071
2024-11-13 20:12:47 +01:00
mstemberaandDisservin f77bac3dca Remove stale Cache::clear() method
closes https://github.com/official-stockfish/Stockfish/pull/5666

No functional change
2024-11-13 20:11:03 +01:00
FauziAkramandDisservin 54cf226604 Revert VLTC regression from #5634
https://tests.stockfishchess.org/tests/view/671bf61b86d5ee47d953cf23

And thanks to @xu-shawn for suggesting running a VLTC regress test since
depth modifications affect scaling. Also, the LTC was showing a slight
regress after 680+k games  ~= -0.34 , for reference:
https://tests.stockfishchess.org/tests/view/67042b1f86d5ee47d953be7c

closes https://github.com/official-stockfish/Stockfish/pull/5663

Bench: 1307308
2024-11-13 20:09:13 +01:00
Michael ChalyandDisservin ecf5646f6e Refine definition of improving
This patch also allows improving flag to be true if static evaluation of
the position is good enough.

Passed STC:
https://tests.stockfishchess.org/tests/view/6720906086d5ee47d953d4d0
LLR: 2.94 (-2.94,2.94) <0.00,2.00>
Total: 34816 W: 9172 L: 8858 D: 16786
Ptnml(0-2): 113, 3988, 8887, 4312, 108

Passed LTC:
https://tests.stockfishchess.org/tests/view/6721162686d5ee47d953d597
LLR: 2.96 (-2.94,2.94) <0.50,2.50>
Total: 145374 W: 37118 L: 36574 D: 71682
Ptnml(0-2): 91, 15875, 40212, 16417, 92

closes https://github.com/official-stockfish/Stockfish/pull/5662

Bench: 1518856
2024-11-13 20:08:14 +01:00
Shawn XuandDisservin c2611efe5c Move history code to a separate header
Since no correction histories are ever used inside Movepick, and many
existing histories are closely integrated into search, it might be more
logical to separate them into their own header. PR based on #5650

closes https://github.com/official-stockfish/Stockfish/pull/5652

No functional change
2024-11-13 20:07:15 +01:00
mstemberaandDisservin 16fee2a7da Cleanup TT::hashfull()
closes https://github.com/official-stockfish/Stockfish/pull/5651

No functional change
2024-11-13 20:06:49 +01:00
MinetaSandDisservin 24c57793e1 Remove moveCountPruning in search.cpp
The definition of moveCountPruning may cause confusion by implying that
the variable is unconstrained. However, once it is set to true, it
should not be reset to false, otherwise it would break the internal
logic of MovePicker.

Several patches have overlooked this constraint. For example:
https://tests.stockfishchess.org/tests/view/671e7c0486d5ee47d953d226
https://tests.stockfishchess.org/tests/view/66a1de7b4ff211be9d4eccea

The implementation approach was suggested by Disservin.

Passed non-regression STC:
LLR: 3.02 (-2.94,2.94) <-1.75,0.25>
Total: 180672 W: 47072 L: 47006 D: 86594
Ptnml(0-2): 536, 19482, 50247, 19522, 549
https://tests.stockfishchess.org/tests/view/6720df6f86d5ee47d953d542

closes https://github.com/official-stockfish/Stockfish/pull/5661

No functional change
2024-10-31 10:08:34 +01:00
FauziAkramandDisservin 8681d3c2b3 Simplify Time Management Formula
Decreasing the number of operations
Passed STC:
LLR: 2.97 (-2.94,2.94) <-1.75,0.25>
Total: 38880 W: 10038 L: 9823 D: 19019
Ptnml(0-2): 92, 4334, 10395, 4505, 114
https://tests.stockfishchess.org/tests/view/67112bf586d5ee47d953c6be

Passed LTC:
LLR: 2.94 (-2.94,2.94) <-1.75,0.25>
Total: 242844 W: 61425 L: 61431 D: 119988
Ptnml(0-2): 145, 25175, 70797, 25151, 154
https://tests.stockfishchess.org/tests/view/6712387486d5ee47d953c737

closes https://github.com/official-stockfish/Stockfish/pull/5655

Bench: 1281912
2024-10-31 10:07:24 +01:00
Shawn XuandDisservin 4a9c980f3b Template Corrhist
Avoids duplication of `using ... = Stats<int16_t,
CORRECTION_HISTORY_LIMIT, COLOR_NB, CORRECTION_HISTORY_SIZE>;`

closes https://github.com/official-stockfish/Stockfish/pull/5650

No functional change

Co-authored-by: Disservin <disservin.social@gmail.com>
2024-10-31 09:27:12 +01:00
Michael ChalyandDisservin 8ef403c786 Small cleanup for stats adjustments
After some simplifications bonuses and maluses are the same for quiet
and non-quiet moves so it makes no sense to use quietMoveBonus/Malus,
instead use just bonus/malus.

closes https://github.com/official-stockfish/Stockfish/pull/5649

No functional change
2024-10-31 09:26:00 +01:00
Disservin c15113554f Speedup Makefile on Windows
The Makefile is notoriously slow on windows, because of new processes
being spawned I believe. This pr improves it a little bit for the help
and config-sanity targets, with the latter also improving `make -j
build` because it depends on that. On the same machine ubuntu (wsl) is
more than 3 times faster, if there are other improvements we can make
I'd be happy to hear about them. Ultimately
https://github.com/official-stockfish/Stockfish/pull/5543 also aims to
improve this I believe, but it will take some additional time before
that lands.

```
make config-sanity:

    patch: 6.199s
    master: 12.738s

make help:

    patch: 3.1s
    master: 11.49s

make -j build:

    patch: 36s
    master: 43.25s

make -j build:

    master ubuntu: 10s
```

closes https://github.com/official-stockfish/Stockfish/pull/5642

No functional change
2024-10-31 09:25:59 +01:00
FauziAkramandDisservin 2ce47573b4 Remove -stat_malus(newDepth)
Passed STC:
LLR: 2.97 (-2.94,2.94) <-1.75,0.25>
Total: 92544 W: 23940 L: 23778 D: 44826
Ptnml(0-2): 286, 10936, 23638, 11154, 258
https://tests.stockfishchess.org/tests/view/670c3d6986d5ee47d953c30b

Passed LTC:
LLR: 2.95 (-2.94,2.94) <-1.75,0.25>
Total: 43164 W: 10986 L: 10786 D: 21392
Ptnml(0-2): 27, 4713, 11905, 4907, 30
https://tests.stockfishchess.org/tests/view/670eda3d86d5ee47d953c51d

closes https://github.com/official-stockfish/Stockfish/pull/5639

Bench: 1281912
2024-10-31 09:25:59 +01:00
FauziAkramandDisservin b325b2c348 Simplify bestValue formula
Passed STC:
LLR: 2.94 (-2.94,2.94) <-1.75,0.25>
Total: 45888 W: 12051 L: 11841 D: 21996
Ptnml(0-2): 123, 5356, 11807, 5504, 154
https://tests.stockfishchess.org/tests/view/670bb89086d5ee47d953c2d8

Passed LTC:
LLR: 2.94 (-2.94,2.94) <-1.75,0.25>
Total: 51336 W: 13021 L: 12830 D: 25485
Ptnml(0-2): 34, 5594, 14227, 5773, 40
https://tests.stockfishchess.org/tests/view/670c587f86d5ee47d953c31b

closes https://github.com/official-stockfish/Stockfish/pull/5637

Bench: 1192999
2024-10-31 09:25:59 +01:00
FauziAkramandDisservin 7f386d109e Remove material corrHist
Passed STC:
LLR: 2.96 (-2.94,2.94) <-1.75,0.25>
Total: 80832 W: 21150 L: 20975 D: 38707
Ptnml(0-2): 283, 9531, 20598, 9736, 268
https://tests.stockfishchess.org/tests/view/670302fe86d5ee47d953bd68

Passed LTC:
LLR: 2.95 (-2.94,2.94) <-1.75,0.25>
Total: 46008 W: 11621 L: 11423 D: 22964
Ptnml(0-2): 30, 5072, 12606, 5262, 34
https://tests.stockfishchess.org/tests/view/6704074686d5ee47d953be53

Passed LTC Rebased:
LLR: 2.95 (-2.94,2.94) <-1.75,0.25>
Total: 95814 W: 24340 L: 24195 D: 47279
Ptnml(0-2): 71, 10497, 26602, 10690, 47
https://tests.stockfishchess.org/tests/view/670ae1ac86d5ee47d953c262

closes https://github.com/official-stockfish/Stockfish/pull/5636

Bench: 1119774
2024-10-31 09:25:56 +01:00
Taras VukandDisservin bf2a0d5392 Simplify internal iterative reductions
Passed STC:
LLR: 2.92 (-2.94,2.94) <-1.75,0.25>
Total: 138656 W: 36182 L: 36074 D: 66400
Ptnml(0-2): 523, 16422, 35310, 16570, 503
https://tests.stockfishchess.org/tests/view/6702beb386d5ee47d953bd41

Passed LTC:
LLR: 2.94 (-2.94,2.94) <-1.75,0.25>
Total: 680844 W: 172021 L: 172480 D: 336343
Ptnml(0-2): 492, 76259, 187419, 75720, 532
https://tests.stockfishchess.org/tests/view/67042b1f86d5ee47d953be7c

closes https://github.com/official-stockfish/Stockfish/pull/5634

Bench: 1169252
2024-10-31 09:13:35 +01:00
FauziAkramandDisservin 2f3e6198e8 Simplify optimism divisor.
Passed STC:
LLR: 2.97 (-2.94,2.94) <-1.75,0.25>
Total: 139360 W: 36143 L: 36033 D: 67184
Ptnml(0-2): 436, 16456, 35778, 16582, 428
https://tests.stockfishchess.org/tests/view/66fc49c786d5ee47d953b94e

Passed LTC:
LLR: 2.95 (-2.94,2.94) <-1.75,0.25>
Total: 257748 W: 65163 L: 65184 D: 127401
Ptnml(0-2): 173, 28471, 71611, 28442, 177
https://tests.stockfishchess.org/tests/view/66ff01ae86d5ee47d953bb54

Passed LTC against rebased version:
LLR: 2.94 (-2.94,2.94) <-1.75,0.25>
Total: 53610 W: 13691 L: 13501 D: 26418
Ptnml(0-2): 52, 5942, 14605, 6176, 30
https://tests.stockfishchess.org/tests/view/670a9c5c86d5ee47d953c231

closes https://github.com/official-stockfish/Stockfish/pull/5633

Bench: 1282078
2024-10-31 09:12:34 +01:00
Linmiao XuandDisservin 656b2cb645 Update default main net to nn-1cedc0ffeeee.nnue
Created by setting output weights (256) and biases (8) of the previous main net
nn-1111cefa1111.nnue to values found with spsa after 38k / 120k games at 120+1.2
using the same method as:
https://github.com/official-stockfish/Stockfish/pull/5459

nn-1111cefa1111.nnue -> nn-1cedc0ffeeee.nnue
  # weights changed: 185
  mean: 0.0703 +/- 2.53
  min: -6
  max:  6

Passed STC:
https://tests.stockfishchess.org/tests/view/6703589b86d5ee47d953bda1
LLR: 2.93 (-2.94,2.94) <0.00,2.00>
Total: 101984 W: 26690 L: 26275 D: 49019
Ptnml(0-2): 375, 11944, 25926, 12385, 362

Passed LTC:
https://tests.stockfishchess.org/tests/view/670542d286d5ee47d953befa
LLR: 2.94 (-2.94,2.94) <0.50,2.50>
Total: 106224 W: 27079 L: 26618 D: 52527
Ptnml(0-2): 71, 11508, 29487, 11981, 65

closes https://github.com/official-stockfish/Stockfish/pull/5632

Bench: 1351413
2024-10-31 09:12:20 +01:00
Michael ChalyandDisservin 9766db8139 Make low ply history size fixed
Size of low ply history should always be the same, so ensure it.

closes https://github.com/official-stockfish/Stockfish/pull/5630

No functional change
2024-10-12 16:40:55 +02:00
Shawn XuandDisservin b261df970d Fix majorPieceKey Updates
Passed STC:
LLR: 2.98 (-2.94,2.94) <0.00,2.00>
Total: 476160 W: 124285 L: 123311 D: 228564
Ptnml(0-2): 1662, 56266, 121219, 57302, 1631
https://tests.stockfishchess.org/tests/view/66ea3dc186d5ee47d953ae07

Failed Yellow LTC:
LLR: -2.94 (-2.94,2.94) <0.50,2.50>
Total: 230634 W: 58525 L: 58295 D: 113814
Ptnml(0-2): 113, 25301, 64299, 25451, 153
https://tests.stockfishchess.org/tests/view/66f1825e86d5ee47d953b2ec

Passed Non-regression LTC:
LLR: 2.94 (-2.94,2.94) <-1.75,0.25>
Total: 112344 W: 28590 L: 28462 D: 55292
Ptnml(0-2): 71, 12439, 31039, 12537, 86
https://tests.stockfishchess.org/tests/view/6707474486d5ee47d953bfe3

closes https://github.com/official-stockfish/Stockfish/pull/5629

Bench: 1283457
2024-10-12 16:40:49 +02:00
Nonlinear2andDisservin aaadbe0572 Introduce mean squared score for delta adjustments
This patch introduces the value `meanSquaredScore`, which makes the
initial delta sensitive to unstable iterative deepening scores.

Passed STC:
https://tests.stockfishchess.org/tests/view/66fed74286d5ee47d953bb42
LLR: 2.98 (-2.94,2.94) <0.00,2.00>
Total: 71104 W: 18635 L: 18262 D: 34207
Ptnml(0-2): 234, 8365, 17993, 8714, 246

Passed LTC:
https://tests.stockfishchess.org/tests/view/6700088e86d5ee47d953bbe9
LLR: 2.95 (-2.94,2.94) <0.50,2.50>
Total: 212544 W: 54238 L: 53560 D: 104746
Ptnml(0-2): 120, 23093, 59172, 23763, 124

closes https://github.com/official-stockfish/Stockfish/pull/5627

Bench: 1395505
2024-10-12 16:40:37 +02:00
Mathias ParnaudeauandDisservin d4358ddba7 Add autodetection of ppc64 architectures
That allows 'make -j profile-build' work on ppc64 architectures, setting the use of
the appropriate SIMD extension, Altivec or VSX.
For VSX, gcc allows to map SSE2 intrinsics and get benefit of the existing SIMD code.

On PowerMac G5, using altivec provides a performance improvement of 30%.
On Talos 2, using vsx provides a performance improvement of 120%.

closes https://github.com/official-stockfish/Stockfish/pull/5624

No functional change
2024-10-12 16:30:44 +02:00
mstemberaandDisservin 76923bb6fe Optimize magics
Reduce the size of the Magics table by half on modern cpu's and lay it
out to match our access pattern. Namely we typically access the magics
for the same square for both bishop and rook back to back so we want
those to be in the same cache line.

https://tests.stockfishchess.org/tests/view/6701c9b386d5ee47d953bcf4
LLR: 2.94 (-2.94,2.94) <0.00,2.00>
Total: 121664 W: 31931 L: 31497 D: 58236
Ptnml(0-2): 395, 13658, 32322, 14032, 425

A similar patch minus the size reduction finished yellow
https://tests.stockfishchess.org/tests/view/6695f03f4ff211be9d4ec16c
LLR: -2.94 (-2.94,2.94) <0.00,2.00>
Total: 310688 W: 80940 L: 80746 D: 149002
Ptnml(0-2): 1119, 35032, 82846, 35230, 1117

closes https://github.com/official-stockfish/Stockfish/pull/5623

No functional change
2024-10-12 16:30:44 +02:00
FauziAkramandDisservin 9a21e3e996 Simplify bestvalue formula
Passed STC:
LLR: 2.97 (-2.94,2.94) <-1.75,0.25>
Total: 163680 W: 42689 L: 42605 D: 78386
Ptnml(0-2): 619, 19555, 41386, 19683, 597
https://tests.stockfishchess.org/tests/view/66f9451386d5ee47d953b7d9

Passed LTC:
LLR: 2.94 (-2.94,2.94) <-1.75,0.25>
Total: 96498 W: 24582 L: 24438 D: 47478
Ptnml(0-2): 62, 10642, 26718, 10744, 83
https://tests.stockfishchess.org/tests/view/66fd765786d5ee47d953ba1c

closes https://github.com/official-stockfish/Stockfish/pull/5622

Bench: 1309815
2024-10-12 16:30:44 +02:00
mstemberaandDisservin 3348603770 Simplify previous #5608
https://github.com/official-stockfish/Stockfish/pull/5608

STC: https://tests.stockfishchess.org/tests/view/66fb1bab86d5ee47d953b8cc
LLR: 2.94 (-2.94,2.94) <-1.75,0.25>
Total: 25536 W: 6797 L: 6560 D: 12179
Ptnml(0-2): 93, 2953, 6460, 3148, 114

LTC https://tests.stockfishchess.org/tests/view/66fb690e86d5ee47d953b8eb
LLR: 2.94 (-2.94,2.94) <-1.75,0.25>
Total: 225114 W: 57200 L: 57188 D: 110726
Ptnml(0-2): 197, 25076, 61995, 25096, 193

closes https://github.com/official-stockfish/Stockfish/pull/5621

Bench: 1570076
2024-10-12 16:30:44 +02:00
Disservin dce72913fe Temporarily fix clang-format mismatch
closes https://github.com/official-stockfish/Stockfish/pull/5620

No functional change
2024-10-12 16:30:44 +02:00
Linmiao XuandDisservin e046c4ef0d Simplify evaluation scaling
Set digits in adjusted eval params all to 7.

Passed non-regression STC:
https://tests.stockfishchess.org/tests/view/66fc493d86d5ee47d953b94c
LLR: 2.94 (-2.94,2.94) <-1.75,0.25>
Total: 57696 W: 15098 L: 14898 D: 27700
Ptnml(0-2): 205, 6784, 14678, 6968, 213

Passed non-regression LTC:
https://tests.stockfishchess.org/tests/view/66fd4b9386d5ee47d953b9d5
LLR: 2.94 (-2.94,2.94) <-1.75,0.25>
Total: 93786 W: 23868 L: 23721 D: 46197
Ptnml(0-2): 55, 10322, 25993, 10467, 56

closes https://github.com/official-stockfish/Stockfish/pull/5618

Bench: 1277182
2024-10-12 16:30:44 +02:00
Ömer Faruk TutkunandDisservin 6592b13d56 Introduce Continuation Correction History
Continuation correction history uses last 2 move to correct static eval.

ContCorrHist first introduced by @martinnovaak in
Motor(https://github.com/martinnovaak/motor/pull/162). Earlier ideas
using last move to correct eval is introduced by @MinusKelvin in
Ice4(https://github.com/MinusKelvin/ice4/commit/45daf7d9ea64ea4efaf0d2b4e99f53e12e08c838)

Passed STC:

LLR: 2.96 (-2.94,2.94) <0.00,2.00>
Total: 310144 W: 81267 L: 80538 D: 148339
Ptnml(0-2): 1160, 36607, 78834, 37286, 1185
https://tests.stockfishchess.org/tests/view/66f96cbc86d5ee47d953b7f7

Passed LTC:

LLR: 2.94 (-2.94,2.94) <0.50,2.50>
Total: 97470 W: 24892 L: 24447 D: 48131
Ptnml(0-2): 63, 10631, 26915, 11050, 76
https://tests.stockfishchess.org/tests/view/66fd59bc86d5ee47d953b9ea

closes https://github.com/official-stockfish/Stockfish/pull/5617

Bench: 1143382
2024-10-12 16:30:44 +02:00
Taras VukandJoost VandeVondele 81c1d31084 Decrease probCutBeta based on opponentWorsening
Passed STC:
LLR: 2.97 (-2.94,2.94) <0.00,2.00>
Total: 62112 W: 16305 L: 15947 D: 29860
Ptnml(0-2): 203, 7226, 15856, 7552, 219
https://tests.stockfishchess.org/tests/view/66f85fc986d5ee47d953b71e

Passed LTC:
LLR: 2.94 (-2.94,2.94) <0.50,2.50>
Total: 129552 W: 33223 L: 32710 D: 63619
Ptnml(0-2): 94, 14250, 35573, 14767, 92
https://tests.stockfishchess.org/tests/view/66f93fef86d5ee47d953b7d2

closes https://github.com/official-stockfish/Stockfish/pull/5615

bench: 1511354
2024-10-04 08:35:08 +02:00
Michael ChalyandJoost VandeVondele 7ac745a736 Refactor root history into low ply history
This patch changes root history to low ply history - butterfly history for plies < 4.
Doubles weight of this history for root, latter plies have lesser effect.

Passed STC:
https://tests.stockfishchess.org/tests/view/66f77d2386d5ee47d953b65d
LLR: 2.94 (-2.94,2.94) <0.00,2.00>
Total: 180992 W: 47362 L: 46830 D: 86800
Ptnml(0-2): 554, 21499, 45928, 21891, 624

Passed LTC:
https://tests.stockfishchess.org/tests/view/66fb557986d5ee47d953b8e5
LLR: 2.95 (-2.94,2.94) <0.50,2.50>
Total: 42462 W: 11013 L: 10682 D: 20767
Ptnml(0-2): 33, 4518, 11795, 4855, 30

closes https://github.com/official-stockfish/Stockfish/pull/5614

Bench 1264335
2024-10-04 08:32:21 +02:00
Linmiao XuandJoost VandeVondele 0186904f53 Remove evaluation grain
Passed non-regression STC:
https://tests.stockfishchess.org/tests/view/66fa345a86d5ee47d953b86e
LLR: 2.96 (-2.94,2.94) <-1.75,0.25>
Total: 39776 W: 10528 L: 10306 D: 18942
Ptnml(0-2): 134, 4674, 10063, 4870, 147

Passed non-regression LTC:
https://tests.stockfishchess.org/tests/view/66facfb886d5ee47d953b8a8
LLR: 2.94 (-2.94,2.94) <-1.75,0.25>
Total: 64230 W: 16484 L: 16305 D: 31441
Ptnml(0-2): 38, 7195, 17483, 7348, 51

closes https://github.com/official-stockfish/Stockfish/pull/5613

bench 1013135
2024-10-04 08:29:09 +02:00
Linmiao XuandJoost VandeVondele 2b9154882a Tweak 7 eval params
Values found from 120k / 120k spsa games at 30+0.3

Passed STC:
https://tests.stockfishchess.org/tests/view/66ecd7ce86d5ee47d953b003
LLR: 2.93 (-2.94,2.94) <0.00,2.00>
Total: 241312 W: 62994 L: 62373 D: 115945
Ptnml(0-2): 754, 28684, 61280, 29063, 875

Passed LTC:
https://tests.stockfishchess.org/tests/view/66f1f3a286d5ee47d953b331
LLR: 2.94 (-2.94,2.94) <0.50,2.50>
Total: 304896 W: 77580 L: 76709 D: 150607
Ptnml(0-2): 198, 33413, 84360, 34274, 203

closes https://github.com/official-stockfish/Stockfish/pull/5611

bench 1173651
2024-10-01 21:02:44 +02:00
Taras VukandJoost VandeVondele c85f802185 Tweak ttCapture reduction
More reduction at shallow depth for quiet moves when ttMove is a capture.

Passed STC:
LLR: 2.93 (-2.94,2.94) <0.00,2.00>
Total: 365728 W: 95896 L: 95090 D: 174742
Ptnml(0-2): 1283, 43133, 93262, 43867, 1319
https://tests.stockfishchess.org/tests/view/66edd35986d5ee47d953b0d5

Passed LTC:
LLR: 2.96 (-2.94,2.94) <0.50,2.50>
Total: 200526 W: 51197 L: 50540 D: 98789
Ptnml(0-2): 119, 21952, 55462, 22613, 117
https://tests.stockfishchess.org/tests/view/66f405dc86d5ee47d953b460

closes https://github.com/official-stockfish/Stockfish/pull/5610

bench: 1269487
2024-10-01 20:59:17 +02:00
Shawn XuandJoost VandeVondele d6043970bd Make Correction History Size Uniform
Passed Non-regression STC:
LLR: 2.93 (-2.94,2.94) <-1.75,0.25>
Total: 207232 W: 53834 L: 53802 D: 99596
Ptnml(0-2): 695, 24486, 53200, 24562, 673
https://tests.stockfishchess.org/tests/view/66e9f5a886d5ee47d953ada1

Passed Non-regression LTC:
LLR: 2.94 (-2.94,2.94) <-1.75,0.25>
Total: 99120 W: 25264 L: 25123 D: 48733
Ptnml(0-2): 66, 10803, 27675, 10956, 60
https://tests.stockfishchess.org/tests/view/66ed7ebc86d5ee47d953b056

Passed Non-regression LTC vs #5606:
LLR: 2.96 (-2.94,2.94) <-1.75,0.25>
Total: 208950 W: 53049 L: 53019 D: 102882
Ptnml(0-2): 111, 23232, 57760, 23260, 112
https://tests.stockfishchess.org/tests/view/66f1843886d5ee47d953b2f2

closes https://github.com/official-stockfish/Stockfish/pull/5609

bench 1575189
2024-09-28 18:01:31 +02:00
peregrineshahinandJoost VandeVondele 56444ce1f7 Push expected cutting late moves up in the move ordering.
since the passing of the LMR verification is coming from a relatively late move
this means we have wasted some time trying/picking other moves, and it would
make sense to push it up in the move ordering for future positions not to be as
late.

Passed STC:
https://tests.stockfishchess.org/tests/view/66f0f69186d5ee47d953b2aa
LLR: 2.93 (-2.94,2.94) <0.00,2.00>
Total: 34144 W: 9024 L: 8709 D: 16411
Ptnml(0-2): 137, 3875, 8732, 4192, 136

Passed LTC:
https://tests.stockfishchess.org/tests/view/66f1d84a86d5ee47d953b325
LLR: 2.94 (-2.94,2.94) <0.50,2.50>
Total: 62808 W: 16054 L: 15684 D: 31070
Ptnml(0-2): 24, 6725, 17555, 7057, 43

closes https://github.com/official-stockfish/Stockfish/pull/5608

bench: 1452807
2024-09-28 18:01:31 +02:00
Tomasz SobczykandJoost VandeVondele 3ac75cd27d Add a standardized benchmark command speedtest.
`speedtest [threads] [hash_MiB] [time_s]`. `threads` default to system concurrency. `hash_MiB` defaults to `threads*128`. `time_s` defaults to 150.

Intended to be used with default parameters, as a stable hardware benchmark.

Example:
```
C:\dev\stockfish-master\src>stockfish.exe speedtest
Stockfish dev-20240928-nogit by the Stockfish developers (see AUTHORS file)
info string Using 16 threads
Warmup position 3/3
Position 258/258
===========================
Version                    : Stockfish dev-20240928-nogit
Compiled by                : g++ (GNUC) 13.2.0 on MinGW64
Compilation architecture   : x86-64-vnni256
Compilation settings       : 64bit VNNI BMI2 AVX2 SSE41 SSSE3 SSE2 POPCNT
Compiler __VERSION__ macro : 13.2.0
Large pages                : yes
User invocation            : speedtest
Filled invocation          : speedtest 16 2048 150
Available processors       : 0-15
Thread count               : 16
Thread binding             : none
TT size [MiB]              : 2048
Hash max, avg [per mille]  :
    single search          : 40, 21
    single game            : 631, 428
Total nodes searched       : 2099917842
Total search time [s]      : 153.937
Nodes/second               : 13641410
```

-------------------------------

Small unrelated tweaks:
 - Network verification output is now handled as a callback.
 - TT hashfull queries allow specifying maximum entry age.

closes https://github.com/official-stockfish/Stockfish/pull/5354

No functional change
2024-09-28 18:01:26 +02:00
Nonlinear2andJoost VandeVondele aff1f67997 simplify see pruning in qsearch
passed non-regression STC:
LLR: 2.96 (-2.94,2.94) <-1.75,0.25>
Total: 34880 W: 9193 L: 8968 D: 16719
Ptnml(0-2): 103, 4047, 8935, 4232, 123
https://tests.stockfishchess.org/tests/view/66ee83bd86d5ee47d953b15b

passed non-regression LTC:
LLR: 2.95 (-2.94,2.94) <-1.75,0.25>
Total: 69126 W: 17529 L: 17357 D: 34240
Ptnml(0-2): 41, 7507, 19285, 7699, 31
https://tests.stockfishchess.org/tests/view/66ef3e0386d5ee47d953b1d3

closes https://github.com/official-stockfish/Stockfish/pull/5607

Bench: 1339840
2024-09-28 17:22:33 +02:00
Joost VandeVondele ae420e735f Tweak Correction histories
tune parameters some more, adjust scores updated for each history

passed STC:
https://tests.stockfishchess.org/tests/view/66ea569186d5ee47d953ae48
LLR: 2.92 (-2.94,2.94) <0.00,2.00>
Total: 36288 W: 9660 L: 9344 D: 17284
Ptnml(0-2): 110, 4207, 9220, 4471, 136

passed LTC:
https://tests.stockfishchess.org/tests/view/66ea9b4e86d5ee47d953ae6f
LLR: 2.94 (-2.94,2.94) <0.50,2.50>
Total: 241446 W: 61748 L: 61010 D: 118688
Ptnml(0-2): 173, 26211, 67202, 26979, 158

closes https://github.com/official-stockfish/Stockfish/pull/5606

Bench: 1677953
2024-09-28 17:17:44 +02:00
FauziAkramandJoost VandeVondele 5d0bb5976e Removed ROOK threatenedByPawn
Passed STC:
LLR: 2.93 (-2.94,2.94) <-1.75,0.25>
Total: 56608 W: 14788 L: 14588 D: 27232
Ptnml(0-2): 162, 6763, 14313, 6845, 221
https://tests.stockfishchess.org/tests/view/66e83f9c86d5ee47d953ab1d

Passed LTC:
LLR: 2.94 (-2.94,2.94) <-1.75,0.25>
Total: 175758 W: 44501 L: 44438 D: 86819
Ptnml(0-2): 125, 19489, 48601, 19526, 138
https://tests.stockfishchess.org/tests/view/66e882d486d5ee47d953ab8a

closes https://github.com/official-stockfish/Stockfish/pull/5601

bench: 1241271
2024-09-28 17:17:14 +02:00
Wencey WangandJoost VandeVondele 93869d5d0a Fix native arch builds on loongarch64
Adds support for LSX and LASX

closes https://github.com/official-stockfish/Stockfish/pull/5600

No functional change
2024-09-28 17:12:12 +02:00
Shawn XuandDisservin 60351b9df9 Introduce Various Correction histories
This patch introduces three additional correction histories, namely,
Major Piece Correction History, Minor Piece Correction History, and
Non-Pawn Correction History.

Introduced by @mcthouacbb in Sirius
(https://github.com/mcthouacbb/Sirius) chess engine. The Major Piece
Correction History is indexed by side-to-move and the Zobrist key
representing the position of the King, Rook, and Queen of both sides.
Likewise, the Minor Piece Correction History is indexed by side-to-move
and the Zobrist key representing the position of the King, Knight, and
Bishop of both sides.

Also See:
https://github.com/mcthouacbb/Sirius/commit/97b85bbaac88ff5a0f63e28776027dd3de77164e
https://github.com/mcthouacbb/Sirius/commit/3099cdef2f13e29805654b5f8153e6ecd5853195

Introduced by @zzzzz151 in Starzix (https://github.com/zzzzz151/Starzix)
chess engine. Non-Pawn correction history consists of side-to-move, side
of Zobrist key, and a Zobrist key representing of the position of all
non-pawn pieces of **one side**. The non-pawn correction values for both
key sides are then summed.

Also See:
https://github.com/zzzzz151/Starzix/commit/34911772f178c27b3a239dda0acb79c397c3a2f0
https://github.com/zzzzz151/Starzix/commit/33e0df8dd2db1d4775974ab12e3390154697f47a

The weights on the final correction value of the above correction
histories, as well as existing correction histories, are then tuned in
two separate SPSA sessions, totaling 75k games.

SPSA1:
https://tests.stockfishchess.org/tests/view/66e5243886d5ee47d953a86b
(Stopped early due to some weights reaching the maximum value)

SPSA2:
https://tests.stockfishchess.org/tests/view/66e6a26f86d5ee47d953a965

Also thanks to @martinnovaak, (Motor
https://github.com/martinnovaak/motor author) for insights and
suggestions.

Passed STC:
LLR: 2.94 (-2.94,2.94) <0.00,2.00>
Total: 23328 W: 6197 L: 5901 D: 11230
Ptnml(0-2): 82, 2582, 6041, 2876, 83
https://tests.stockfishchess.org/tests/view/66e8787b86d5ee47d953ab6f

Passed LTC:
LLR: 2.94 (-2.94,2.94) <0.50,2.50>
Total: 10626 W: 2826 L: 2560 D: 5240
Ptnml(0-2): 4, 1054, 2941, 1300, 14
https://tests.stockfishchess.org/tests/view/66e8ab2386d5ee47d953aba8

closes https://github.com/official-stockfish/Stockfish/pull/5598

Bench: 1011161
2024-09-17 21:01:43 +02:00
Michael ChalyandDisservin 240a5b1c72 Introduce separate butterfly history table for sorting root moves
Idea of this patch comes from the fact that current history heuristics
are mostly populated by low depth entries since our stat bonus reaches
maximum value at depth 5-6 and number of low depth nodes is much bigger
than number of high depth nodes. But it doesn't make a whole lost of
sense to use this low-depth centered histories to sort moves at root.
Current patch introduces special history table that is used exclusively
at root, it remembers which quiet moves were good and which quiet moves
were not good there and uses this information for move ordering.

Passed STC:
https://tests.stockfishchess.org/tests/view/66dda74adc53972b68218cc9
LLR: 2.93 (-2.94,2.94) <0.00,2.00>
Total: 127680 W: 33579 L: 33126 D: 60975
Ptnml(0-2): 422, 15098, 32391, 15463, 466

Passed LTC:
https://tests.stockfishchess.org/tests/view/66dead2adc53972b68218d34
LLR: 2.95 (-2.94,2.94) <0.50,2.50>
Total: 381978 W: 96958 L: 95923 D: 189097
Ptnml(0-2): 277, 42165, 105089, 43162, 296

closes https://github.com/official-stockfish/Stockfish/pull/5595

Bench: 1611283
2024-09-17 20:54:02 +02:00
Shawn XuandDisservin 5ce7f866a5 Simplify Fail Low Bonus
Passed Non-regression STC:
LLR: 2.93 (-2.94,2.94) <-1.75,0.25>
Total: 302528 W: 78190 L: 78264 D: 146074
Ptnml(0-2): 1029, 35797, 77551, 35993, 894
https://tests.stockfishchess.org/tests/view/66dcebdedc53972b68218c7e

Passed Non-regression LTC:
LLR: 2.95 (-2.94,2.94) <-1.75,0.25>
Total: 122754 W: 31025 L: 30907 D: 60822
Ptnml(0-2): 74, 13597, 33908, 13733, 65
https://tests.stockfishchess.org/tests/view/66e0c38686d5ee47d953a481

closes https://github.com/official-stockfish/Stockfish/pull/5594

Bench: 1646373
2024-09-17 20:50:30 +02:00
Muzhen GamingandDisservin 224c147bd6 VVLTC Search Tune
Tuned with 115k games at VVLTC:
https://tests.stockfishchess.org/tests/view/66c80e09bf8c9d8780fda62a

Passed VVLTC 1st sprt:
https://tests.stockfishchess.org/tests/view/66d69ade9de3e7f9b33d14f9
LLR: 2.94 (-2.94,2.94) <0.00,2.00>
Total: 54270 W: 13935 L: 13647 D: 26688
Ptnml(0-2): 2, 4907, 17032, 5189, 5

Passed VVLTC 2nd sprt:
https://tests.stockfishchess.org/tests/view/66dcf9c1dc53972b68218c84
LLR: 2.94 (-2.94,2.94) <0.50,2.50>
Total: 136696 W: 34941 L: 34462 D: 67293
Ptnml(0-2): 8, 12659, 42535, 13138, 8

closes https://github.com/official-stockfish/Stockfish/pull/5592

Bench: 1644273
2024-09-17 20:47:24 +02:00
Disservin a06e7004c1 Port instrumented testing to python
Since an unknown amount of time the instrumented CI has been a bit
flawed, explained here
https://github.com/official-stockfish/Stockfish/issues/5185. It also
experiences random timeout issues where restarting the workflow fixes it
or very long run times (more than other workflows) and is not very
portable.

The intention of this commit is to port the instrumented.sh to python
which also works on other operating systems. It should also be
relatively easy for beginners to add new tests to assert stockfish's
output and to run it.
From the source directory the following command can be run.

`python3 ../tests/instrumented.py --none ./stockfish`

A test runner will go over the test suites and run the test cases.

All instrumented tests should have been ported over.
The required python version for this is should be 3.7 (untested) + the
requests package, testing.py includes some infrastructure code which
setups the testing.

fixes https://github.com/official-stockfish/Stockfish/issues/5185
closes https://github.com/official-stockfish/Stockfish/pull/5583

No functional change
2024-09-17 20:24:17 +02:00
MinetaSandDisservin f677aee28b Fix net downloading script
The recent commit introduced a bug in the net downloading script that
the file is not downloaded correctly and the content is redirected to
stdout.

closes https://github.com/official-stockfish/Stockfish/pull/5585

No functional change
2024-09-10 23:00:41 +02:00
Nonlinear2andDisservin d8e49cdbdd Remove the moveCount increase in the LMR condition.
Passed non-regression STC:
LLR: 2.93 (-2.94,2.94) <-1.75,0.25>
Total: 87104 W: 22630 L: 22464 D: 42010
Ptnml(0-2): 316, 10295, 22132, 10525, 284
https://tests.stockfishchess.org/tests/view/66dccd00dc53972b68218c60

Passed non-regression LTC:
LLR: 2.94 (-2.94,2.94) <-1.75,0.25>
Total: 94050 W: 23869 L: 23722 D: 46459
Ptnml(0-2): 49, 10400, 25985, 10537, 54
https://tests.stockfishchess.org/tests/view/66dd69c7dc53972b68218ca5

closes https://github.com/official-stockfish/Stockfish/pull/5582

Bench: 1281840
2024-09-10 22:59:27 +02:00
MinetaSandDisservin 6de2587236 Remove statScore condition in NMP
Eliminate the condition that is nearly 100% likelihood of being true.

Passed non-regression STC:
LLR: 2.94 (-2.94,2.94) <-1.75,0.25>
Total: 208832 W: 54053 L: 54022 D: 100757
Ptnml(0-2): 753, 24987, 52901, 25026, 749
https://tests.stockfishchess.org/tests/view/66cddb50bf8c9d8780fdabaf

Passed non-regression LTC:
LLR: 2.94 (-2.94,2.94) <-1.75,0.25>
Total: 154344 W: 39132 L: 39047 D: 76165
Ptnml(0-2): 115, 17231, 42403, 17300, 123
https://tests.stockfishchess.org/tests/view/66cfafe39de3e7f9b33d1050

closes https://github.com/official-stockfish/Stockfish/pull/5558

Bench: 1393697
2024-09-10 22:58:47 +02:00
MinetaSandDisservin 2680c9c799 Small speedup in incremental accumulator updates
Instead of updating at most two accumulators, update all accumluators
during incremental updates. Tests have shown that this change yields a
small speedup of at least 0.5%, and up to 1% with shorter TC.

Passed STC:
LLR: 2.93 (-2.94,2.94) <0.00,2.00>
Total: 54368 W: 14179 L: 13842 D: 26347
Ptnml(0-2): 173, 6122, 14262, 6449, 178
https://tests.stockfishchess.org/tests/view/66db038a9de3e7f9b33d1ad9

Passed 5+0.05:
LLR: 2.98 (-2.94,2.94) <0.00,2.00>
Total: 55040 W: 14682 L: 14322 D: 26036
Ptnml(0-2): 303, 6364, 13856, 6664, 333
https://tests.stockfishchess.org/tests/view/66dbc325dc53972b68218ba7

Passed non-regression LTC:
LLR: 2.95 (-2.94,2.94) <-1.75,0.25>
Total: 57390 W: 14555 L: 14376 D: 28459
Ptnml(0-2): 37, 5876, 16683, 6069, 30
https://tests.stockfishchess.org/tests/view/66dbc30adc53972b68218ba5

closes https://github.com/official-stockfish/Stockfish/pull/5576

No functional change
2024-09-09 18:02:32 +02:00
Disservin effa246071 Use optional for the engine path
- A small quality of file change is to change the type of engine path
  from a string to an optional string, skips the binary directory
  lookup, which is commonly disabled by people who create wasm builds or
  include stockfish as a library.

closes https://github.com/official-stockfish/Stockfish/pull/5575

No functional change
2024-09-09 18:02:32 +02:00
Michael ChalyandDisservin a8cb002038 Simplify ttmove reduction
Remove condition that clamps reductions for tt move.

Passed STC:
https://tests.stockfishchess.org/tests/view/66d5f1239de3e7f9b33d14b0
LLR: 2.94 (-2.94,2.94) <-1.75,0.25>
Total: 91136 W: 23805 L: 23646 D: 43685
Ptnml(0-2): 334, 10328, 24066, 10525, 315

Passed LTC:
https://tests.stockfishchess.org/tests/view/66d7c5889de3e7f9b33d1721
LLR: 2.95 (-2.94,2.94) <-1.75,0.25>
Total: 139242 W: 35130 L: 35030 D: 69082
Ptnml(0-2): 78, 15200, 38986, 15258, 99

closes https://github.com/official-stockfish/Stockfish/pull/5574

Bench: 1268715
2024-09-09 18:02:32 +02:00
xu-shawnandDisservin d7e3a708d4 Remove ARCH=... from README.md
closes https://github.com/official-stockfish/Stockfish/pull/5570

No functional change
2024-09-09 18:02:32 +02:00
MinetaSandDisservin 1b310cc87e Export and clean up net downloading script
Fixes https://github.com/official-stockfish/Stockfish/issues/5564

This patch extracts the net downloading script in Makefile into an
external script file. Also the script is moderately rewritten for
improved readability and speed.

* Use wget preferentially over curl, as curl is known to have slight
  overhead.
* Use command instead of hash to check if command exists. Reportedly,
  hash always returns zero in some POSIX shells even when the command
  fails.
* Command existence checks (wget/curl, sha256sum) are performed only
  once at the beginning.
* Each of common patterns is encapsulated in a function
  (get_nnue_filename, validate_network).
* Print out error/warning messages to stderr.

closes https://github.com/official-stockfish/Stockfish/pull/5563

No functional change

Co-authored-by: Disservin <disservin.social@gmail.com>
2024-09-09 18:02:27 +02:00
xu-shawnandDisservin 66a7965b0f Copy scripts directory in distributed packages
closes https://github.com/official-stockfish/Stockfish/pull/5571

No functional change
2024-09-09 17:54:27 +02:00
Daniel MonroeandDisservin e74452ae44 Reduce on ttcaptures if not capture
Tweak ttcapture reduction.
Reduce on ttcaptures only if the current move is a capture

Passed STC:
LLR: 2.93 (-2.94,2.94) <0.00,2.00>
Total: 94912 W: 24896 L: 24492 D: 45524
Ptnml(0-2): 301, 11197, 24087, 11539, 332
https://tests.stockfishchess.org/tests/view/66cd2264bf8c9d8780fdab34

Passed LTC:
LLR: 2.94 (-2.94,2.94) <0.50,2.50>
Total: 60738 W: 15465 L: 15096 D: 30177
Ptnml(0-2): 42, 6573, 16775, 6932, 47
https://tests.stockfishchess.org/tests/view/66cf356d9de3e7f9b33d0fde

closes https://github.com/official-stockfish/Stockfish/pull/5562

Bench: 1268700
2024-09-09 17:48:26 +02:00
Shawn XuandDisservin ddc9f48bc3 Introduce Material Correction History
Idea from Caissa (https://github.com/Witek902/Caissa) chess engine.

Add a secondary correction history indexed by the material key of a position.
The material key is the zobrist hash representing the number of pieces left in a
position.

Passed STC:
LLR: 2.94 (-2.94,2.94) <0.00,2.00>
Total: 189472 W: 49360 L: 48813 D: 91299
Ptnml(0-2): 666, 22453, 47953, 22996, 668
https://tests.stockfishchess.org/tests/view/66cbddafbf8c9d8780fda9f1

Passed LTC:
LLR: 2.94 (-2.94,2.94) <0.50,2.50>
Total: 224190 W: 57022 L: 56312 D: 110856
Ptnml(0-2): 197, 24723, 61540, 25443, 192
https://tests.stockfishchess.org/tests/view/66cd529bbf8c9d8780fdab4c

closes https://github.com/official-stockfish/Stockfish/pull/5556

Bench: 1462697
2024-09-09 17:43:05 +02:00
FauziAkramandDisservin 4fb04eb3df Simplify history bonus
After we recently added the disallowance for negative bonuses, it is no
longer necessary to keep the max comparison in the previous step.

Passed STC:
LLR: 2.93 (-2.94,2.94) <-1.75,0.25>
Total: 72000 W: 18820 L: 18637 D: 34543
Ptnml(0-2): 267, 8489, 18276, 8730, 238
https://tests.stockfishchess.org/tests/view/66ce132cbf8c9d8780fdabe7

Passed LTC:
LLR: 2.94 (-2.94,2.94) <-1.75,0.25>
Total: 67452 W: 17136 L: 16961 D: 33355
Ptnml(0-2): 35, 7489, 18519, 7632, 51
https://tests.stockfishchess.org/tests/view/66cf6ad49de3e7f9b33d1010

closes https://github.com/official-stockfish/Stockfish/pull/5554

Bench: 1147012
2024-09-09 17:34:31 +02:00
Disservin f4ba7ce67a Restore development
closes https://github.com/official-stockfish/Stockfish/pull/5580

No functional change
2024-09-09 17:21:14 +02:00
80 changed files with 4516 additions and 2270 deletions
+4 -4
View File
@@ -1,8 +1,8 @@
{
"config": [
{
"name": "Ubuntu 20.04 GCC",
"os": "ubuntu-20.04",
"name": "Ubuntu 22.04 GCC",
"os": "ubuntu-22.04",
"simple_name": "ubuntu",
"compiler": "g++",
"comp": "gcc",
@@ -111,7 +111,7 @@
{
"binaries": "x86-64-avxvnni",
"config": {
"ubuntu-20.04": null
"ubuntu-22.04": null
}
},
{
@@ -153,7 +153,7 @@
{
"binaries": "apple-silicon",
"config": {
"os": "ubuntu-20.04"
"os": "ubuntu-22.04"
}
}
]
+1 -1
View File
@@ -18,7 +18,7 @@ permissions:
jobs:
Clang-Format:
name: Clang-Format
runs-on: ubuntu-20.04
runs-on: ubuntu-22.04
steps:
- uses: actions/checkout@v4
with:
+8 -8
View File
@@ -19,22 +19,22 @@ jobs:
working-directory: Stockfish/src
run: make -j build debug=yes
- name: Checkout fast-chess repo
- name: Checkout fastchess repo
uses: actions/checkout@v4
with:
repository: Disservin/fast-chess
path: fast-chess
ref: d54af1910d5479c669dc731f1f54f9108a251951
repository: Disservin/fastchess
path: fastchess
ref: 894616028492ae6114835195f14a899f6fa237d3
persist-credentials: false
- name: fast-chess build
working-directory: fast-chess
- name: fastchess build
working-directory: fastchess
run: make -j
- name: Run games
working-directory: fast-chess
working-directory: fastchess
run: |
./fast-chess -rounds 4 -games 2 -repeat -concurrency 4 -openings file=app/tests/data/openings.epd format=epd order=random -srand $RANDOM\
./fastchess -rounds 4 -games 2 -repeat -concurrency 4 -openings file=app/tests/data/openings.epd format=epd order=random -srand $RANDOM\
-engine name=sf1 cmd=/home/runner/work/Stockfish/Stockfish/Stockfish/src/stockfish\
-engine name=sf2 cmd=/home/runner/work/Stockfish/Stockfish/Stockfish/src/stockfish\
-ratinginterval 1 -report penta=true -each proto=uci tc=4+0.04 -log file=fast.log | tee fast.out
+19 -2
View File
@@ -24,7 +24,7 @@ jobs:
with:
repository: vondele/matetrack
path: matetrack
ref: 814160f82e6428ed2f6522dc06c2a6fa539cd413
ref: 4f8a80860ed8f3607f05a9195df8b40203bdc360
persist-credentials: false
- name: matetrack install deps
@@ -50,5 +50,22 @@ jobs:
- name: Run matetrack
working-directory: matetrack
run: |
python matecheck.py --syzygyPath 3-4-5-wdl/:3-4-5-dtz/ --engine /home/runner/work/Stockfish/Stockfish/Stockfish/src/stockfish --epdFile mates2000.epd --nodes 100000 | tee matecheckout.out
python matecheck.py --syzygyPath 3-4-5-wdl/:3-4-5-dtz/ --engine /home/runner/work/Stockfish/Stockfish/Stockfish/src/stockfish --epdFile mates2000.epd --nodes 100000 | tee matecheckout.out
! grep "issues were detected" matecheckout.out > /dev/null
- name: Run matetrack with --syzygy50MoveRule false
working-directory: matetrack
run: |
grep 5men cursed.epd > cursed5.epd
python matecheck.py --syzygyPath 3-4-5-wdl/:3-4-5-dtz/ --engine /home/runner/work/Stockfish/Stockfish/Stockfish/src/stockfish --epdFile cursed5.epd --nodes 100000 --syzygy50MoveRule false | tee matecheckcursed.out
! grep "issues were detected" matecheckcursed.out > /dev/null
- name: Verify mate and TB win count for matecheckcursed.out
working-directory: matetrack
run: |
mates=$(grep "Found mates:" matecheckcursed.out | awk '{print $3}')
tbwins=$(grep "Found TB wins:" matecheckcursed.out | awk '{print $4}')
if [ $(($mates + $tbwins)) -ne 32 ]; then
echo "Sum of mates and TB wins is not 32 in matecheckcursed.out" >&2
exit 1
fi
+11 -2
View File
@@ -21,19 +21,28 @@ jobs:
sanitizers:
- name: Run with thread sanitizer
make_option: sanitize=thread
cxx_extra_flags: ""
instrumented_option: sanitizer-thread
- name: Run with UB sanitizer
make_option: sanitize=undefined
cxx_extra_flags: ""
instrumented_option: sanitizer-undefined
- name: Run under valgrind
make_option: ""
cxx_extra_flags: ""
instrumented_option: valgrind
- name: Run under valgrind-thread
make_option: ""
cxx_extra_flags: ""
instrumented_option: valgrind-thread
- name: Run non-instrumented
make_option: ""
cxx_extra_flags: ""
instrumented_option: none
- name: Run with glibcxx assertions
make_option: ""
cxx_extra_flags: -D_GLIBCXX_ASSERTIONS
instrumented_option: non
defaults:
run:
working-directory: src
@@ -72,7 +81,7 @@ jobs:
- name: ${{ matrix.sanitizers.name }}
run: |
export CXXFLAGS="-O1 -fno-inline"
export CXXFLAGS="-O1 -fno-inline ${{ matrix.sanitizers.cxx_extra_flags }}"
make clean
make -j4 ARCH=x86-64-sse41-popcnt ${{ matrix.sanitizers.make_option }} debug=yes optimize=no build > /dev/null
../tests/instrumented.sh --${{ matrix.sanitizers.instrumented_option }}
python3 ../tests/instrumented.py --${{ matrix.sanitizers.instrumented_option }} ./stockfish
+11 -11
View File
@@ -13,15 +13,15 @@ jobs:
fail-fast: false
matrix:
config:
- name: Ubuntu 20.04 GCC
os: ubuntu-20.04
- name: Ubuntu 22.04 GCC
os: ubuntu-22.04
compiler: g++
comp: gcc
run_32bit_tests: true
run_64bit_tests: true
shell: bash
- name: Ubuntu 20.04 Clang
os: ubuntu-20.04
- name: Ubuntu 22.04 Clang
os: ubuntu-22.04
compiler: clang++
comp: clang
run_32bit_tests: true
@@ -139,11 +139,11 @@ jobs:
- name: Build Docker container
if: matrix.config.base_image
run: |
docker buildx build --load -t sf_builder - << EOF
docker buildx build --platform ${{ matrix.config.platform }} --load -t sf_builder - << EOF
FROM ${{ matrix.config.base_image }}
WORKDIR /app
RUN apk update && apk add make g++
CMD ["sh", "script.sh"]
CMD ["sh", "src/script.sh"]
EOF
- name: Download required macOS packages
@@ -176,7 +176,7 @@ jobs:
$COMPCXX -v
else
echo "$COMPCXX -v" > script.sh
docker run --rm --platform ${{ matrix.config.platform }} -v ${{ github.workspace }}/src:/app sf_builder
docker run --rm --platform ${{ matrix.config.platform }} -v ${{ github.workspace }}:/app sf_builder
fi
- name: Test help target
@@ -342,8 +342,8 @@ jobs:
- name: Test riscv64 build
if: matrix.config.run_riscv64_tests
run: |
echo "export LDFLAGS='-static' && make clean && make -j4 ARCH=riscv64 build" > script.sh
docker run --rm --platform ${{ matrix.config.platform }} -v ${{ github.workspace }}/src:/app sf_builder
echo "cd src && export LDFLAGS='-static' && make clean && make -j4 ARCH=riscv64 build" > script.sh
docker run --rm --platform ${{ matrix.config.platform }} -v ${{ github.workspace }}:/app sf_builder
../tests/signature.sh $benchref
# ppc64 tests
@@ -351,8 +351,8 @@ jobs:
- name: Test ppc64 build
if: matrix.config.run_ppc64_tests
run: |
echo "export LDFLAGS='-static' && make clean && make -j4 ARCH=ppc-64 build" > script.sh
docker run --rm --platform ${{ matrix.config.platform }} -v ${{ github.workspace }}/src:/app sf_builder
echo "cd src && export LDFLAGS='-static' && make clean && make -j4 ARCH=ppc-64 build" > script.sh
docker run --rm --platform ${{ matrix.config.platform }} -v ${{ github.workspace }}:/app sf_builder
../tests/signature.sh $benchref
# Other tests
+1
View File
@@ -59,6 +59,7 @@ jobs:
mv "${{ matrix.config.simple_name }} ${{ matrix.binaries }}" stockfish-workflow
cd stockfish-workflow
cp -r src ../stockfish/
cp -r scripts ../stockfish/
cp stockfish-$NAME-$BINARY$EXT ../stockfish/
cp "Top CPU Contributors.txt" ../stockfish/
cp Copying.txt ../stockfish/
+5
View File
@@ -10,3 +10,8 @@ src/-lstdc++.res
# Neural network for the NNUE evaluation
**/*.nnue
# Files generated by the instrumented tests
tsan.supp
__pycache__/
tests/syzygy
tests/bench_tmp.epd
+7
View File
@@ -45,7 +45,9 @@ Bruno de Melo Costa (BM123499)
Bruno Pellanda (pellanda)
Bryan Cross (crossbr)
candirufish
Carlos Esparza Sánchez (ces42)
Chess13234
Chris Bao (sscg13)
Chris Cain (ceebo)
Ciekce
clefrks
@@ -123,10 +125,12 @@ jundery
Justin Blanchard (UncombedCoconut)
Kelly Wilson
Ken Takusagawa
Kenneth Lee (kennethlee33)
Kian E (KJE-98)
kinderchocolate
Kiran Panditrao (Krgp)
Kojirion
Krisztián Peőcz
Krystian Kuzniarek (kuzkry)
Leonardo Ljubičić (ICCF World Champion)
Leonid Pechenik (lp--)
@@ -143,6 +147,7 @@ Maciej Żenczykowski (zenczykowski)
Malcolm Campbell (xoto10)
Mark Tenzer (31m059)
marotear
Mathias Parnaudeau (mparnaudeau)
Matt Ginsberg (mattginsberg)
Matthew Lai (matthewlai)
Matthew Sullivan (Matt14916)
@@ -176,6 +181,7 @@ Ofek Shochat (OfekShochat, ghostway)
Ondrej Mosnáček (WOnder93)
Ondřej Mišina (AndrovT)
Oskar Werkelin Ahlin
Ömer Faruk Tutkun (OmerFarukTutkun)
Pablo Vazquez
Panthee
Pascal Romaret
@@ -237,6 +243,7 @@ Unai Corzo (unaiic)
Uri Blass (uriblass)
Vince Negri (cuddlestmonkey)
Viren
Wencey Wang
windfishballad
xefoci7612
Xiang Wang (KatyushaScarlet)
+1 -2
View File
@@ -49,7 +49,7 @@ further discussion._
- Provide a clear and concise description of the changes in the pull request
description.
_First time contributors should add their name to [AUTHORS](../AUTHORS)._
_First time contributors should add their name to [AUTHORS](./AUTHORS)._
_Stockfish's development is not focused on adding new features. Thus any pull
request introducing new features will potentially be closed without further
@@ -86,7 +86,6 @@ more details.
Thank you for contributing to Stockfish and helping us make it even better!
[copying-link]: https://github.com/official-stockfish/Stockfish/blob/master/Copying.txt
[discord-link]: https://discord.gg/GWDRS3kU6R
[discussions-link]: https://github.com/official-stockfish/Stockfish/discussions/new
+8 -1
View File
@@ -97,7 +97,7 @@ descriptions. An example suitable for most Intel and AMD chips:
```
cd src
make -j profile-build ARCH=x86-64-avx2
make -j profile-build
```
Detailed compilation instructions for all platforms can be found in our
@@ -120,6 +120,11 @@ where the source code can be found) to generate the exact binary you are
distributing. If you make any changes to the source code, these changes must
also be made available under GPL v3.
## Acknowledgements
Stockfish uses neural networks trained on [data provided by the Leela Chess Zero
project][lc0-data-link], which is made available under the [Open Database License][odbl-link] (ODbL).
[authors-link]: https://github.com/official-stockfish/Stockfish/blob/master/AUTHORS
[build-link]: https://github.com/official-stockfish/Stockfish/actions/workflows/stockfish.yml
@@ -144,6 +149,8 @@ also be made available under GPL v3.
[wiki-uci-link]: https://github.com/official-stockfish/Stockfish/wiki/UCI-&-Commands
[wiki-usage-link]: https://github.com/official-stockfish/Stockfish/wiki/Download-and-usage
[worker-link]: https://github.com/official-stockfish/fishtest/wiki/Running-the-worker
[lc0-data-link]: https://storage.lczero.org/files/training_data
[odbl-link]: https://opendatacommons.org/licenses/odbl/odbl-10.txt
[build-badge]: https://img.shields.io/github/actions/workflow/status/official-stockfish/Stockfish/stockfish.yml?branch=master&style=for-the-badge&label=stockfish&logo=github
[commits-badge]: https://img.shields.io/github/commits-since/official-stockfish/Stockfish/latest?style=for-the-badge
+119 -98
View File
@@ -1,118 +1,126 @@
Contributors to Fishtest with >10,000 CPU hours, as of 2024-08-31.
Contributors to Fishtest with >10,000 CPU hours, as of 2025-03-22.
Thank you!
Username CPU Hours Games played
------------------------------------------------------------------
noobpwnftw 40428649 3164740143
technologov 23581394 1076895482
vdv 19425375 718302718
linrock 10034115 643194527
noobpwnftw 41712226 3294628533
vdv 28993864 954145232
technologov 24984442 1115931964
linrock 11463033 741692823
mlang 3026000 200065824
okrout 2572676 237511408
pemo 1836785 62226157
okrout 2726068 248285678
olafm 2420096 161297116
pemo 1838361 62294199
TueRens 1804847 80170868
dew 1689162 100033738
TueRens 1648780 77891164
sebastronomy 1468328 60859092
grandphish2 1466110 91776075
sebastronomy 1655637 67294942
grandphish2 1474752 92156319
JojoM 1130625 73666098
olafm 1067009 74807270
rpngn 973590 59996557
oz 921203 60370346
tvijlbrief 796125 51897690
oz 781847 53910686
rpngn 768460 49812975
gvreuls 751085 52177668
gvreuls 792215 55184194
mibere 703840 46867607
leszek 566598 42024615
cw 519601 34988161
leszek 599745 44681421
cw 519602 34988289
fastgm 503862 30260818
CSU_Dynasty 468784 31385034
maximmasiutin 439192 27893522
ctoks 435148 28541909
CSU_Dynasty 474794 31654170
maximmasiutin 441753 28129452
robal 437950 28869118
ctoks 435150 28542141
crunchy 427414 27371625
bcross 415724 29061187
robal 371112 24642270
mgrabiak 367963 26464704
mgrabiak 380202 27586936
velislav 342588 22140902
ncfish1 329039 20624527
Fisherman 327231 21829379
Sylvain27 317021 11494912
marrco 310446 19587107
Dantist 296386 18031762
tolkki963 262050 22049676
Sylvain27 255595 8864404
Fifis 289595 14969251
tolkki963 286043 23596996
Calis007 272677 17281620
cody 258835 13301710
nordlandia 249322 16420192
Fifis 237657 13065577
marrco 234581 17714473
Calis007 217537 14450582
javran 212141 16507618
glinscott 208125 13277240
drabel 204167 13930674
mhoram 202894 12601997
bking_US 198894 11876016
Wencey 198537 9606420
Thanar 179852 12365359
javran 169679 13481966
armo9494 162863 10937118
sschnee 170521 10891112
armo9494 168141 11177514
DesolatedDodo 160605 10392474
spams 157128 10319326
DesolatedDodo 156683 10211206
Wencey 152308 8375444
maposora 155839 13963260
sqrt2 147963 9724586
vdbergh 140311 9225125
vdbergh 140514 9242985
jcAEie 140086 10603658
CoffeeOne 137100 5024116
malala 136182 8002293
Goatminola 134893 11640524
xoto 133759 9159372
Dubslow 129614 8519312
markkulix 132104 11000548
naclosagc 131472 4660806
Dubslow 129685 8527664
davar 129023 8376525
DMBK 122960 8980062
dsmith 122059 7570238
CypressChess 120784 8672620
sschnee 120526 7547722
maposora 119734 10749710
Wolfgang 120919 8619168
CypressChess 120902 8683904
amicic 119661 7938029
Wolfgang 115713 8159062
cuistot 116864 7828864
sterni1971 113754 6054022
Data 113305 8220352
BrunoBanani 112960 7436849
markkulix 112897 9133168
cuistot 109802 7121030
megaman7de 109139 7360928
skiminki 107583 7218170
sterni1971 104431 5938282
zeryl 104523 6618969
MaZePallas 102823 6633619
sunu 100167 7040199
zeryl 99331 6221261
thirdlife 99156 2245320
thirdlife 99178 2246544
ElbertoOne 99028 7023771
megaman7de 98456 6675076
Goatminola 96765 8257832
TataneSan 97257 4239502
romangol 95662 7784954
bigpen0r 94825 6529241
brabos 92118 6186135
Maxim 90818 3283364
psk 89957 5984901
szupaw 89775 7800606
jromang 87260 5988073
racerschmacer 85805 6122790
Vizvezdenec 83761 5344740
0x3C33 82614 5271253
szupaw 82495 7151686
Spprtr 82103 5663635
BRAVONE 81239 5054681
MarcusTullius 78930 5189659
Mineta 78731 4947996
Torom 77978 2651656
nssy 76497 5259388
cody 76126 4492126
jromang 76106 5236025
MarcusTullius 76103 5061991
woutboat 76072 6022922
Spprtr 75977 5252287
woutboat 76379 6031688
teddybaer 75125 5407666
Pking_cda 73776 5293873
Viren6 73664 1356502
yurikvelo 73611 5046822
Mineta 71130 4711422
Bobo1239 70579 4794999
solarlight 70517 5028306
dv8silencer 70287 3883992
manap 66273 4121774
tinker 64333 4268790
qurashee 61208 3429862
AGI 58195 4329580
DanielMiao1 60181 1317252
AGI 58316 4336328
jojo2357 57435 4944212
robnjr 57262 4053117
Freja 56938 3733019
MaxKlaxxMiner 56879 3423958
ttruscott 56010 3680085
rkl 55132 4164467
jmdana 54697 4012593
jmdana 54988 4041917
notchris 53936 4184018
renouve 53811 3501516
CounterFlow 52536 3203740
finfish 51360 3370515
eva42 51272 3599691
eastorwest 51117 3454811
@@ -122,33 +130,36 @@ GPUex 48686 3684998
OuaisBla 48626 3445134
ronaldjerum 47654 3240695
biffhero 46564 3111352
oryx 45639 3546530
oryx 46141 3583236
jibarbosa 45890 4541218
DeepnessFulled 45734 3944282
abdicj 45577 2631772
VoyagerOne 45476 3452465
mecevdimitar 44240 2584396
speedycpu 43842 3003273
jbwiebe 43305 2805433
gopeto 43046 2821514
YvesKn 42628 2177630
Antihistamine 41788 2761312
mhunt 41735 2691355
jibarbosa 41640 4145702
somethingintheshadows 41502 3330418
homyur 39893 2850481
gri 39871 2515779
DeepnessFulled 39020 3323102
vidar808 39774 1656372
Garf 37741 2999686
SC 37299 2731694
Gaster319 37118 3279678
naclosagc 36562 1279618
Gaster319 37229 3289674
csnodgrass 36207 2688994
ZacHFX 35528 2486328
icewulf 34782 2415146
strelock 34716 2074055
gopeto 33717 2245606
EthanOConnor 33370 2090311
slakovv 32915 2021889
jojo2357 32890 2826662
shawnxu 32019 2802552
shawnxu 32144 2814668
Gelma 31771 1551204
vidar808 31560 1351810
srowen 31181 1732120
kdave 31157 2198362
manapbk 30987 1810399
ZacHFX 30966 2272416
TataneSan 30713 1513402
votoanthuan 30691 2460856
Prcuvu 30377 2170122
anst 30301 2190091
@@ -157,145 +168,155 @@ spcc 29925 1901692
hyperbolic.tom 29840 2017394
chuckstablers 29659 2093438
Pyafue 29650 1902349
WoodMan777 29300 2579864
belzedar94 28846 1811530
mecevdimitar 27610 1721382
chriswk 26902 1868317
xwziegtm 26897 2124586
Jopo12321 26818 1816482
achambord 26582 1767323
somethingintheshadows 26496 2186404
Patrick_G 26276 1801617
yorkman 26193 1992080
srowen 25743 1490684
Ulysses 25413 1702830
Jopo12321 25227 1652482
Ulysses 25517 1711634
SFTUser 25182 1675689
nabildanial 25068 1531665
Sharaf_DG 24765 1786697
rodneyc 24376 1416402
jsys14 24297 1721230
AndreasKrug 24235 1934711
agg177 23890 1395014
AndreasKrug 23754 1890115
Ente 23752 1678188
JanErik 23408 1703875
Isidor 23388 1680691
Norabor 23371 1603244
WoodMan777 23253 2023048
Nullvalue 23155 2022752
fishtester 23115 1581502
wizardassassin 23073 1789536
Skiff84 22984 1053680
cisco2015 22920 1763301
ols 22914 1322047
Hjax 22561 1566151
Zirie 22542 1472937
team-oh 22272 1636708
mkstockfishtester 22253 2029566
Roady 22220 1465606
MazeOfGalious 21978 1629593
sg4032 21950 1643373
tsim67 21747 1330880
tsim67 21939 1343944
ianh2105 21725 1632562
Skiff84 21711 1014212
Serpensin 21704 1809188
xor12 21628 1680365
dex 21612 1467203
nesoneg 21494 1463031
IslandLambda 21468 1239756
user213718 21454 1404128
Serpensin 21452 1790510
sphinx 21211 1384728
qoo_charly_cai 21136 1514927
IslandLambda 21062 1220838
jjoshua2 21001 1423089
Zake9298 20938 1565848
horst.prack 20878 1465656
fishtester 20729 1348888
0xB00B1ES 20590 1208666
ols 20477 1195945
Dinde 20459 1292774
t3hf1sht3ster 20456 670646
j3corre 20405 941444
0x539 20332 1039516
Adrian.Schmidt123 20316 1281436
malfoy 20313 1350694
purpletree 20019 1461026
wei 19973 1745989
teenychess 19819 1762006
rstoesser 19569 1293588
eudhan 19274 1283717
nalanzeyu 19211 396674
vulcan 18871 1729392
wizardassassin 18795 1376884
Karpovbot 18766 1053178
jundery 18445 1115855
mkstockfishtester 18350 1690676
Farseer 18281 1074642
sebv15 18267 1262588
whelanh 17887 347974
ville 17883 1384026
chris 17698 1487385
purplefishies 17595 1092533
dju 17414 981289
iisiraider 17275 1049015
Karby 17177 1030688
DragonLord 17014 1162790
Karby 17008 1013160
pirt 16965 1271519
pirt 16991 1274215
redstone59 16842 1461780
Alb11747 16787 1213990
Naven94 16414 951718
scuzzi 16115 994341
scuzzi 16155 995347
IgorLeMasson 16064 1147232
ako027ako 15671 1173203
xuhdev 15516 1528278
infinigon 15285 965966
Nikolay.IT 15154 1068349
Andrew Grant 15114 895539
OssumOpossum 14857 1007129
LunaticBFF57 14525 1190310
enedene 14476 905279
Hjax 14394 1005013
YELNAMRON 14475 1141330
RickGroszkiewicz 14272 1385984
joendter 14269 982014
bpfliegel 14233 882523
YELNAMRON 14230 1128094
mpx86 14019 759568
jpulman 13982 870599
getraideBFF 13871 1172846
crocogoat 13817 1119086
Nesa92 13806 1116101
crocogoat 13803 1117422
joster 13710 946160
mbeier 13650 1044928
Pablohn26 13552 1088532
wxt9861 13550 1312306
Dark_wizzie 13422 1007152
Rudolphous 13244 883140
Jackfish 13177 894206
MooTheCow 13091 892304
Machariel 13010 863104
nalanzeyu 12996 232590
mabichito 12903 749391
Jackfish 12895 868928
thijsk 12886 722107
AdrianSA 12860 804972
Flopzee 12698 894821
whelanh 12682 266404
szczur90 12684 977536
Kyrega 12661 456438
mschmidt 12644 863193
korposzczur 12606 838168
fatmurphy 12547 853210
Oakwen 12532 855759
icewulf 12447 854878
SapphireBrand 12416 969604
deflectooor 12386 579392
modolief 12386 896470
Farseer 12249 694108
ckaz 12273 754644
Hongildong 12201 648712
pgontarz 12151 848794
dbernier 12103 860824
szczur90 12035 942376
FormazChar 12019 910409
FormazChar 12051 913497
shreven 12044 884734
rensonthemove 11999 971993
stocky 11954 699440
MooTheCow 11923 779432
3cho 11842 1036786
ckaz 11792 732276
ImperiumAeternum 11482 979142
infinity 11470 727027
aga 11412 695127
Def9Infinity 11408 700682
torbjo 11395 729145
Thomas A. Anderson 11372 732094
savage84 11358 670860
Def9Infinity 11345 696552
d64 11263 789184
ali-al-zhrani 11245 779246
ImperiumAeternum 11155 952000
vaskoul 11144 953906
snicolet 11106 869170
dapper 11032 771402
Ethnikoi 10993 945906
Snuuka 10938 435504
Karmatron 10871 678306
gerbil 10871 1005842
OliverClarke 10696 942654
basepi 10637 744851
michaelrpg 10624 748179
Cubox 10621 826448
gerbil 10519 971688
michaelrpg 10509 739239
dragon123118 10421 936506
OIVAS7572 10420 995586
GBx3TV 10388 339952
Garruk 10365 706465
dzjp 10343 732529
RickGroszkiewicz 10263 990798
borinot 10026 902130
+1
View File
@@ -0,0 +1 @@
*.sh text eol=lf
+34 -1
View File
@@ -26,6 +26,17 @@ check_znver_1_2() {
[ "$vendor_id" = "AuthenticAMD" ] && [ "$cpu_family" = "23" ] && znver_1_2=true
}
# Set the file CPU loongarch64 architecture
set_arch_loongarch64() {
if check_flags 'lasx'; then
true_arch='loongarch64-lasx'
elif check_flags 'lsx'; then
true_arch='lonngarch64-lsx'
else
true_arch='loongarch64'
fi
}
# Set the file CPU x86_64 architecture
set_arch_x86_64() {
if check_flags 'avx512vnni' 'avx512dq' 'avx512f' 'avx512bw' 'avx512vl'; then
@@ -43,6 +54,20 @@ set_arch_x86_64() {
fi
}
set_arch_ppc_64() {
if $(grep -q -w "altivec" /proc/cpuinfo); then
power=$(grep -oP -m 1 'cpu\t+: POWER\K\d+' /proc/cpuinfo)
if [ "0$power" -gt 7 ]; then
# VSX started with POWER8
true_arch='ppc-64-vsx'
else
true_arch='ppc-64-altivec'
fi
else
true_arch='ppc-64'
fi
}
# Check the system type
uname_s=$(uname -s)
uname_m=$(uname -m)
@@ -51,7 +76,7 @@ case $uname_s in
case $uname_m in
'arm64')
true_arch='apple-silicon'
file_arch='x86-64-sse41-popcnt' # Supported by Rosetta 2
file_arch='m1-apple-silicon'
;;
'x86_64')
flags=$(sysctl -n machdep.cpu.features machdep.cpu.leaf7_features | tr '\n' ' ' | tr '[:upper:]' '[:lower:]' | tr -d '_.')
@@ -76,6 +101,10 @@ case $uname_s in
file_os='ubuntu'
true_arch='x86-32'
;;
'ppc64'*)
file_os='ubuntu'
set_arch_ppc_64
;;
'aarch64')
file_os='android'
true_arch='armv8'
@@ -90,6 +119,10 @@ case $uname_s in
true_arch="$true_arch-neon"
fi
;;
'loongarch64'*)
file_os='linux'
set_arch_loongarch64
;;
*) # Unsupported machine type, exit with error
printf 'Unsupported machine type: %s\n' "$uname_m"
exit 1
Executable
+76
View File
@@ -0,0 +1,76 @@
#!/bin/sh
wget_or_curl=$( (command -v wget > /dev/null 2>&1 && echo "wget -qO-") || \
(command -v curl > /dev/null 2>&1 && echo "curl -skL"))
sha256sum=$( (command -v shasum > /dev/null 2>&1 && echo "shasum -a 256") || \
(command -v sha256sum > /dev/null 2>&1 && echo "sha256sum"))
if [ -z "$sha256sum" ]; then
>&2 echo "sha256sum not found, NNUE files will be assumed valid."
fi
get_nnue_filename() {
grep "$1" evaluate.h | grep "#define" | sed "s/.*\(nn-[a-z0-9]\{12\}.nnue\).*/\1/"
}
validate_network() {
# If no sha256sum command is available, assume the file is always valid.
if [ -n "$sha256sum" ] && [ -f "$1" ]; then
if [ "$1" != "nn-$($sha256sum "$1" | cut -c 1-12).nnue" ]; then
rm -f "$1"
return 1
fi
fi
}
fetch_network() {
_filename="$(get_nnue_filename "$1")"
if [ -z "$_filename" ]; then
>&2 echo "NNUE file name not found for: $1"
return 1
fi
if [ -f "$_filename" ]; then
if validate_network "$_filename"; then
echo "Existing $_filename validated, skipping download"
return
else
echo "Removing invalid NNUE file: $_filename"
fi
fi
if [ -z "$wget_or_curl" ]; then
>&2 printf "%s\n" "Neither wget or curl is installed." \
"Install one of these tools to download NNUE files automatically."
exit 1
fi
for url in \
"https://tests.stockfishchess.org/api/nn/$_filename" \
"https://github.com/official-stockfish/networks/raw/master/$_filename"; do
echo "Downloading from $url ..."
if $wget_or_curl "$url" > "$_filename"; then
if validate_network "$_filename"; then
echo "Successfully validated $_filename"
else
echo "Downloaded $_filename is invalid"
continue
fi
else
echo "Failed to download from $url"
fi
if [ -f "$_filename" ]; then
return
fi
done
# Download was not successful in the loop, return false.
>&2 echo "Failed to download $_filename"
return 1
}
fetch_network EvalFileDefaultNameBig && \
fetch_network EvalFileDefaultNameSmall
+204 -179
View File
@@ -1,5 +1,5 @@
# Stockfish, a UCI chess playing engine derived from Glaurung 2.1
# Copyright (C) 2004-2024 The Stockfish developers (see AUTHORS file)
# Copyright (C) 2004-2025 The Stockfish developers (see AUTHORS file)
#
# Stockfish is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
@@ -55,9 +55,10 @@ PGOBENCH = $(WINE_PATH) ./$(EXE) bench
SRCS = benchmark.cpp bitboard.cpp evaluate.cpp main.cpp \
misc.cpp movegen.cpp movepick.cpp position.cpp \
search.cpp thread.cpp timeman.cpp tt.cpp uci.cpp ucioption.cpp tune.cpp syzygy/tbprobe.cpp \
nnue/nnue_misc.cpp nnue/features/half_ka_v2_hm.cpp nnue/network.cpp engine.cpp score.cpp memory.cpp
nnue/nnue_accumulator.cpp nnue/nnue_misc.cpp nnue/features/half_ka_v2_hm.cpp nnue/network.cpp \
engine.cpp score.cpp memory.cpp
HEADERS = benchmark.h bitboard.h evaluate.h misc.h movegen.h movepick.h \
HEADERS = benchmark.h bitboard.h evaluate.h misc.h movegen.h movepick.h history.h \
nnue/nnue_misc.h nnue/features/half_ka_v2_hm.h nnue/layers/affine_transform.h \
nnue/layers/affine_transform_sparse_input.h nnue/layers/clipped_relu.h nnue/layers/simd.h \
nnue/layers/sqr_clipped_relu.h nnue/nnue_accumulator.h nnue/nnue_architecture.h \
@@ -98,8 +99,12 @@ VPATH = syzygy:nnue:nnue/features
# avx512 = yes/no --- -mavx512bw --- Use Intel Advanced Vector Extensions 512
# vnni256 = yes/no --- -mavx256vnni --- Use Intel Vector Neural Network Instructions 512 with 256bit operands
# vnni512 = yes/no --- -mavx512vnni --- Use Intel Vector Neural Network Instructions 512
# altivec = yes/no --- -maltivec --- Use PowerPC Altivec SIMD extension
# vsx = yes/no --- -mvsx --- Use POWER VSX SIMD extension
# neon = yes/no --- -DUSE_NEON --- Use ARM SIMD architecture
# dotprod = yes/no --- -DUSE_NEON_DOTPROD --- Use ARM advanced SIMD Int8 dot product instructions
# lsx = yes/no --- -mlsx --- Use Loongson SIMD eXtension
# lasx = yes/no --- -mlasx --- use Loongson Advanced SIMD eXtension
#
# Note that Makefile is space sensitive, so when adding new architectures
# or modifying existing flags, you have to make sure there are no extra spaces
@@ -124,8 +129,9 @@ endif
ifeq ($(ARCH), $(filter $(ARCH), \
x86-64-vnni512 x86-64-vnni256 x86-64-avx512 x86-64-avxvnni x86-64-bmi2 \
x86-64-avx2 x86-64-sse41-popcnt x86-64-modern x86-64-ssse3 x86-64-sse3-popcnt \
x86-64 x86-32-sse41-popcnt x86-32-sse2 x86-32 ppc-64 ppc-32 e2k \
armv7 armv7-neon armv8 armv8-dotprod apple-silicon general-64 general-32 riscv64 loongarch64))
x86-64 x86-32-sse41-popcnt x86-32-sse2 x86-32 ppc-64 ppc-64-altivec ppc-64-vsx ppc-32 e2k \
armv7 armv7-neon armv8 armv8-dotprod apple-silicon general-64 general-32 riscv64 \
loongarch64 loongarch64-lsx loongarch64-lasx))
SUPPORTED_ARCH=true
else
SUPPORTED_ARCH=false
@@ -148,9 +154,13 @@ avxvnni = no
avx512 = no
vnni256 = no
vnni512 = no
altivec = no
vsx = no
neon = no
dotprod = no
arm_version = 0
lsx = no
lasx = no
STRIP = strip
ifneq ($(shell which clang-format-18 2> /dev/null),)
@@ -355,6 +365,20 @@ ifeq ($(ARCH),ppc-64)
prefetch = yes
endif
ifeq ($(ARCH),ppc-64-altivec)
arch = ppc64
popcnt = yes
prefetch = yes
altivec = yes
endif
ifeq ($(ARCH),ppc-64-vsx)
arch = ppc64
popcnt = yes
prefetch = yes
vsx = yes
endif
ifeq ($(findstring e2k,$(ARCH)),e2k)
arch = e2k
mmx = yes
@@ -370,8 +394,19 @@ ifeq ($(ARCH),riscv64)
arch = riscv64
endif
ifeq ($(ARCH),loongarch64)
ifeq ($(findstring loongarch64,$(ARCH)),loongarch64)
arch = loongarch64
prefetch = yes
ifeq ($(findstring -lasx,$(ARCH)),-lasx)
lsx = yes
lasx = yes
endif
ifeq ($(findstring -lsx,$(ARCH)),-lsx)
lsx = yes
endif
endif
endif
@@ -408,7 +443,7 @@ ifeq ($(COMP),gcc)
ifeq ($(ARCH),riscv64)
CXXFLAGS += -latomic
endif
else ifeq ($(ARCH),loongarch64)
else ifeq ($(arch),loongarch64)
CXXFLAGS += -latomic
else
CXXFLAGS += -m$(bits)
@@ -480,7 +515,7 @@ ifeq ($(COMP),clang)
ifeq ($(ARCH),riscv64)
CXXFLAGS += -latomic
endif
else ifeq ($(ARCH),loongarch64)
else ifeq ($(arch),loongarch64)
CXXFLAGS += -latomic
else
CXXFLAGS += -m$(bits)
@@ -634,7 +669,7 @@ else
endif
ifeq ($(popcnt),yes)
ifeq ($(arch),$(filter $(arch),ppc64 armv7 armv8 arm64))
ifeq ($(arch),$(filter $(arch),ppc64 ppc64-altivec ppc64-vsx armv7 armv8 arm64))
CXXFLAGS += -DUSE_POPCNT
else
CXXFLAGS += -msse3 -mpopcnt -DUSE_POPCNT
@@ -704,6 +739,20 @@ ifeq ($(mmx),yes)
endif
endif
ifeq ($(altivec),yes)
CXXFLAGS += -maltivec
ifeq ($(COMP),gcc)
CXXFLAGS += -mabi=altivec
endif
endif
ifeq ($(vsx),yes)
CXXFLAGS += -mvsx
ifeq ($(COMP),gcc)
CXXFLAGS += -DNO_WARN_X86_INTRINSICS -DUSE_SSE2
endif
endif
ifeq ($(neon),yes)
CXXFLAGS += -DUSE_NEON=$(arm_version)
ifeq ($(KERNEL),Linux)
@@ -719,6 +768,18 @@ ifeq ($(dotprod),yes)
CXXFLAGS += -march=armv8.2-a+dotprod -DUSE_NEON_DOTPROD
endif
ifeq ($(lasx),yes)
ifeq ($(comp),$(filter $(comp),gcc clang mingw icx))
CXXFLAGS += -mlasx
endif
endif
ifeq ($(lsx),yes)
ifeq ($(comp),$(filter $(comp),gcc clang mingw icx))
CXXFLAGS += -mlsx
endif
endif
### 3.7 pext
ifeq ($(pext),yes)
CXXFLAGS += -DUSE_PEXT
@@ -791,71 +852,75 @@ endif
### ==========================================================================
help:
@echo ""
@echo "To compile stockfish, type: "
@echo ""
@echo "make -j target [ARCH=arch] [COMP=compiler] [COMPCXX=cxx]"
@echo ""
@echo "Supported targets:"
@echo ""
@echo "help > Display architecture details"
@echo "profile-build > standard build with profile-guided optimization"
@echo "build > skip profile-guided optimization"
@echo "net > Download the default nnue nets"
@echo "strip > Strip executable"
@echo "install > Install executable"
@echo "clean > Clean up"
@echo ""
@echo "Supported archs:"
@echo ""
@echo "native > select the best architecture for the host processor (default)"
@echo "x86-64-vnni512 > x86 64-bit with vnni 512bit support"
@echo "x86-64-vnni256 > x86 64-bit with vnni 512bit support, limit operands to 256bit wide"
@echo "x86-64-avx512 > x86 64-bit with avx512 support"
@echo "x86-64-avxvnni > x86 64-bit with vnni 256bit support"
@echo "x86-64-bmi2 > x86 64-bit with bmi2 support"
@echo "x86-64-avx2 > x86 64-bit with avx2 support"
@echo "x86-64-sse41-popcnt > x86 64-bit with sse41 and popcnt support"
@echo "x86-64-modern > deprecated, currently x86-64-sse41-popcnt"
@echo "x86-64-ssse3 > x86 64-bit with ssse3 support"
@echo "x86-64-sse3-popcnt > x86 64-bit with sse3 compile and popcnt support"
@echo "x86-64 > x86 64-bit generic (with sse2 support)"
@echo "x86-32-sse41-popcnt > x86 32-bit with sse41 and popcnt support"
@echo "x86-32-sse2 > x86 32-bit with sse2 support"
@echo "x86-32 > x86 32-bit generic (with mmx compile support)"
@echo "ppc-64 > PPC 64-bit"
@echo "ppc-32 > PPC 32-bit"
@echo "armv7 > ARMv7 32-bit"
@echo "armv7-neon > ARMv7 32-bit with popcnt and neon"
@echo "armv8 > ARMv8 64-bit with popcnt and neon"
@echo "armv8-dotprod > ARMv8 64-bit with popcnt, neon and dot product support"
@echo "e2k > Elbrus 2000"
@echo "apple-silicon > Apple silicon ARM64"
@echo "general-64 > unspecified 64-bit"
@echo "general-32 > unspecified 32-bit"
@echo "riscv64 > RISC-V 64-bit"
@echo "loongarch64 > LoongArch 64-bit"
@echo ""
@echo "Supported compilers:"
@echo ""
@echo "gcc > GNU compiler (default)"
@echo "mingw > GNU compiler with MinGW under Windows"
@echo "clang > LLVM Clang compiler"
@echo "icx > Intel oneAPI DPC++/C++ Compiler"
@echo "ndk > Google NDK to cross-compile for Android"
@echo ""
@echo "Simple examples. If you don't know what to do, you likely want to run one of: "
@echo ""
@echo "make -j profile-build ARCH=x86-64-avx2 # typically a fast compile for common systems "
@echo "make -j profile-build ARCH=x86-64-sse41-popcnt # A more portable compile for 64-bit systems "
@echo "make -j profile-build ARCH=x86-64 # A portable compile for 64-bit systems "
@echo ""
@echo "Advanced examples, for experienced users: "
@echo ""
@echo "make -j profile-build ARCH=x86-64-avxvnni"
@echo "make -j profile-build ARCH=x86-64-avxvnni COMP=gcc COMPCXX=g++-12.0"
@echo "make -j build ARCH=x86-64-ssse3 COMP=clang"
@echo ""
@echo "" && \
echo "To compile stockfish, type: " && \
echo "" && \
echo "make -j target [ARCH=arch] [COMP=compiler] [COMPCXX=cxx]" && \
echo "" && \
echo "Supported targets:" && \
echo "" && \
echo "help > Display architecture details" && \
echo "profile-build > standard build with profile-guided optimization" && \
echo "build > skip profile-guided optimization" && \
echo "net > Download the default nnue nets" && \
echo "strip > Strip executable" && \
echo "install > Install executable" && \
echo "clean > Clean up" && \
echo "" && \
echo "Supported archs:" && \
echo "" && \
echo "native > select the best architecture for the host processor (default)" && \
echo "x86-64-vnni512 > x86 64-bit with vnni 512bit support" && \
echo "x86-64-vnni256 > x86 64-bit with vnni 512bit support, limit operands to 256bit wide" && \
echo "x86-64-avx512 > x86 64-bit with avx512 support" && \
echo "x86-64-avxvnni > x86 64-bit with vnni 256bit support" && \
echo "x86-64-bmi2 > x86 64-bit with bmi2 support" && \
echo "x86-64-avx2 > x86 64-bit with avx2 support" && \
echo "x86-64-sse41-popcnt > x86 64-bit with sse41 and popcnt support" && \
echo "x86-64-modern > deprecated, currently x86-64-sse41-popcnt" && \
echo "x86-64-ssse3 > x86 64-bit with ssse3 support" && \
echo "x86-64-sse3-popcnt > x86 64-bit with sse3 compile and popcnt support" && \
echo "x86-64 > x86 64-bit generic (with sse2 support)" && \
echo "x86-32-sse41-popcnt > x86 32-bit with sse41 and popcnt support" && \
echo "x86-32-sse2 > x86 32-bit with sse2 support" && \
echo "x86-32 > x86 32-bit generic (with mmx compile support)" && \
echo "ppc-64 > PPC 64-bit" && \
echo "ppc-64-altivec > PPC 64-bit with altivec support" && \
echo "ppc-64-vsx > PPC 64-bit with vsx support" && \
echo "ppc-32 > PPC 32-bit" && \
echo "armv7 > ARMv7 32-bit" && \
echo "armv7-neon > ARMv7 32-bit with popcnt and neon" && \
echo "armv8 > ARMv8 64-bit with popcnt and neon" && \
echo "armv8-dotprod > ARMv8 64-bit with popcnt, neon and dot product support" && \
echo "e2k > Elbrus 2000" && \
echo "apple-silicon > Apple silicon ARM64" && \
echo "general-64 > unspecified 64-bit" && \
echo "general-32 > unspecified 32-bit" && \
echo "riscv64 > RISC-V 64-bit" && \
echo "loongarch64 > LoongArch 64-bit" && \
echo "loongarch64-lsx > LoongArch 64-bit with SIMD eXtension" && \
echo "loongarch64-lasx > LoongArch 64-bit with Advanced SIMD eXtension" && \
echo "" && \
echo "Supported compilers:" && \
echo "" && \
echo "gcc > GNU compiler (default)" && \
echo "mingw > GNU compiler with MinGW under Windows" && \
echo "clang > LLVM Clang compiler" && \
echo "icx > Intel oneAPI DPC++/C++ Compiler" && \
echo "ndk > Google NDK to cross-compile for Android" && \
echo "" && \
echo "Simple examples. If you don't know what to do, you likely want to run one of: " && \
echo "" && \
echo "make -j profile-build ARCH=x86-64-avx2 # typically a fast compile for common systems " && \
echo "make -j profile-build ARCH=x86-64-sse41-popcnt # A more portable compile for 64-bit systems " && \
echo "make -j profile-build ARCH=x86-64 # A portable compile for 64-bit systems " && \
echo "" && \
echo "Advanced examples, for experienced users: " && \
echo "" && \
echo "make -j profile-build ARCH=x86-64-avxvnni" && \
echo "make -j profile-build ARCH=x86-64-avxvnni COMP=gcc COMPCXX=g++-12.0" && \
echo "make -j build ARCH=x86-64-ssse3 COMP=clang" && \
echo ""
ifneq ($(SUPPORTED_ARCH), true)
@echo "Specify a supported architecture with the ARCH option for more details"
@echo ""
@@ -917,59 +982,9 @@ profileclean:
@rm -f stockfish.res
@rm -f ./-lstdc++.res
define fetch_network
@echo "Default net: $(nnuenet)"
@if [ "x$(curl_or_wget)" = "x" ]; then \
echo "Neither curl nor wget is installed. Install one of these tools unless the net has been downloaded manually"; \
fi
@if [ "x$(shasum_command)" = "x" ]; then \
echo "shasum / sha256sum not found, skipping net validation"; \
elif test -f "$(nnuenet)"; then \
if [ "$(nnuenet)" != "nn-"`$(shasum_command) $(nnuenet) | cut -c1-12`".nnue" ]; then \
echo "Removing invalid network"; rm -f $(nnuenet); \
fi; \
fi;
@for nnuedownloadurl in "$(nnuedownloadurl1)" "$(nnuedownloadurl2)"; do \
if test -f "$(nnuenet)"; then \
echo "$(nnuenet) available : OK"; break; \
else \
if [ "x$(curl_or_wget)" != "x" ]; then \
echo "Downloading $${nnuedownloadurl}"; $(curl_or_wget) $${nnuedownloadurl} > $(nnuenet);\
else \
echo "No net found and download not possible"; exit 1;\
fi; \
fi; \
if [ "x$(shasum_command)" != "x" ]; then \
if [ "$(nnuenet)" != "nn-"`$(shasum_command) $(nnuenet) | cut -c1-12`".nnue" ]; then \
echo "Removing failed download"; rm -f $(nnuenet); \
fi; \
fi; \
done
@if ! test -f "$(nnuenet)"; then \
echo "Failed to download $(nnuenet)."; \
fi;
@if [ "x$(shasum_command)" != "x" ]; then \
if [ "$(nnuenet)" = "nn-"`$(shasum_command) $(nnuenet) | cut -c1-12`".nnue" ]; then \
echo "Network validated"; break; \
fi; \
fi;
endef
# set up shell variables for the net stuff
define netvariables
$(eval nnuenet := $(shell grep $(1) evaluate.h | grep define | sed 's/.*\(nn-[a-z0-9]\{12\}.nnue\).*/\1/'))
$(eval nnuedownloadurl1 := https://tests.stockfishchess.org/api/nn/$(nnuenet))
$(eval nnuedownloadurl2 := https://github.com/official-stockfish/networks/raw/master/$(nnuenet))
$(eval curl_or_wget := $(shell if hash curl 2>/dev/null; then echo "curl -skL"; elif hash wget 2>/dev/null; then echo "wget -qO-"; fi))
$(eval shasum_command := $(shell if hash shasum 2>/dev/null; then echo "shasum -a 256 "; elif hash sha256sum 2>/dev/null; then echo "sha256sum "; fi))
endef
# evaluation network (nnue)
net:
$(call netvariables, EvalFileDefaultNameBig)
$(call fetch_network)
$(call netvariables, EvalFileDefaultNameSmall)
$(call fetch_network)
@$(SHELL) ../scripts/net.sh
format:
$(CLANG-FORMAT) -i $(SRCS) $(HEADERS) -style=file
@@ -986,61 +1001,71 @@ all: $(EXE) .depend
config-sanity: net
@echo ""
@echo "Config:"
@echo "debug: '$(debug)'"
@echo "sanitize: '$(sanitize)'"
@echo "optimize: '$(optimize)'"
@echo "arch: '$(arch)'"
@echo "bits: '$(bits)'"
@echo "kernel: '$(KERNEL)'"
@echo "os: '$(OS)'"
@echo "prefetch: '$(prefetch)'"
@echo "popcnt: '$(popcnt)'"
@echo "pext: '$(pext)'"
@echo "sse: '$(sse)'"
@echo "mmx: '$(mmx)'"
@echo "sse2: '$(sse2)'"
@echo "ssse3: '$(ssse3)'"
@echo "sse41: '$(sse41)'"
@echo "avx2: '$(avx2)'"
@echo "avxvnni: '$(avxvnni)'"
@echo "avx512: '$(avx512)'"
@echo "vnni256: '$(vnni256)'"
@echo "vnni512: '$(vnni512)'"
@echo "neon: '$(neon)'"
@echo "dotprod: '$(dotprod)'"
@echo "arm_version: '$(arm_version)'"
@echo "target_windows: '$(target_windows)'"
@echo ""
@echo "Flags:"
@echo "CXX: $(CXX)"
@echo "CXXFLAGS: $(CXXFLAGS)"
@echo "LDFLAGS: $(LDFLAGS)"
@echo ""
@echo "Testing config sanity. If this fails, try 'make help' ..."
@echo ""
@test "$(debug)" = "yes" || test "$(debug)" = "no"
@test "$(optimize)" = "yes" || test "$(optimize)" = "no"
@test "$(SUPPORTED_ARCH)" = "true"
@test "$(arch)" = "any" || test "$(arch)" = "x86_64" || test "$(arch)" = "i386" || \
@echo "Config:" && \
echo "debug: '$(debug)'" && \
echo "sanitize: '$(sanitize)'" && \
echo "optimize: '$(optimize)'" && \
echo "arch: '$(arch)'" && \
echo "bits: '$(bits)'" && \
echo "kernel: '$(KERNEL)'" && \
echo "os: '$(OS)'" && \
echo "prefetch: '$(prefetch)'" && \
echo "popcnt: '$(popcnt)'" && \
echo "pext: '$(pext)'" && \
echo "sse: '$(sse)'" && \
echo "mmx: '$(mmx)'" && \
echo "sse2: '$(sse2)'" && \
echo "ssse3: '$(ssse3)'" && \
echo "sse41: '$(sse41)'" && \
echo "avx2: '$(avx2)'" && \
echo "avxvnni: '$(avxvnni)'" && \
echo "avx512: '$(avx512)'" && \
echo "vnni256: '$(vnni256)'" && \
echo "vnni512: '$(vnni512)'" && \
echo "altivec: '$(altivec)'" && \
echo "vsx: '$(vsx)'" && \
echo "neon: '$(neon)'" && \
echo "dotprod: '$(dotprod)'" && \
echo "arm_version: '$(arm_version)'" && \
echo "lsx: '$(lsx)'" && \
echo "lasx: '$(lasx)'" && \
echo "target_windows: '$(target_windows)'" && \
echo "" && \
echo "Flags:" && \
echo "CXX: $(CXX)" && \
echo "CXXFLAGS: $(CXXFLAGS)" && \
echo "LDFLAGS: $(LDFLAGS)" && \
echo "" && \
echo "Testing config sanity. If this fails, try 'make help' ..." && \
echo "" && \
(test "$(debug)" = "yes" || test "$(debug)" = "no") && \
(test "$(optimize)" = "yes" || test "$(optimize)" = "no") && \
(test "$(SUPPORTED_ARCH)" = "true") && \
(test "$(arch)" = "any" || test "$(arch)" = "x86_64" || test "$(arch)" = "i386" || \
test "$(arch)" = "ppc64" || test "$(arch)" = "ppc" || test "$(arch)" = "e2k" || \
test "$(arch)" = "armv7" || test "$(arch)" = "armv8" || test "$(arch)" = "arm64" || test "$(arch)" = "riscv64" || test "$(arch)" = "loongarch64"
@test "$(bits)" = "32" || test "$(bits)" = "64"
@test "$(prefetch)" = "yes" || test "$(prefetch)" = "no"
@test "$(popcnt)" = "yes" || test "$(popcnt)" = "no"
@test "$(pext)" = "yes" || test "$(pext)" = "no"
@test "$(sse)" = "yes" || test "$(sse)" = "no"
@test "$(mmx)" = "yes" || test "$(mmx)" = "no"
@test "$(sse2)" = "yes" || test "$(sse2)" = "no"
@test "$(ssse3)" = "yes" || test "$(ssse3)" = "no"
@test "$(sse41)" = "yes" || test "$(sse41)" = "no"
@test "$(avx2)" = "yes" || test "$(avx2)" = "no"
@test "$(avx512)" = "yes" || test "$(avx512)" = "no"
@test "$(vnni256)" = "yes" || test "$(vnni256)" = "no"
@test "$(vnni512)" = "yes" || test "$(vnni512)" = "no"
@test "$(neon)" = "yes" || test "$(neon)" = "no"
@test "$(comp)" = "gcc" || test "$(comp)" = "icx" || test "$(comp)" = "mingw" || test "$(comp)" = "clang" \
|| test "$(comp)" = "armv7a-linux-androideabi16-clang" || test "$(comp)" = "aarch64-linux-android21-clang"
test "$(arch)" = "armv7" || test "$(arch)" = "armv8" || test "$(arch)" = "arm64" || \
test "$(arch)" = "riscv64" || test "$(arch)" = "loongarch64") && \
(test "$(bits)" = "32" || test "$(bits)" = "64") && \
(test "$(prefetch)" = "yes" || test "$(prefetch)" = "no") && \
(test "$(popcnt)" = "yes" || test "$(popcnt)" = "no") && \
(test "$(pext)" = "yes" || test "$(pext)" = "no") && \
(test "$(sse)" = "yes" || test "$(sse)" = "no") && \
(test "$(mmx)" = "yes" || test "$(mmx)" = "no") && \
(test "$(sse2)" = "yes" || test "$(sse2)" = "no") && \
(test "$(ssse3)" = "yes" || test "$(ssse3)" = "no") && \
(test "$(sse41)" = "yes" || test "$(sse41)" = "no") && \
(test "$(avx2)" = "yes" || test "$(avx2)" = "no") && \
(test "$(avx512)" = "yes" || test "$(avx512)" = "no") && \
(test "$(vnni256)" = "yes" || test "$(vnni256)" = "no") && \
(test "$(vnni512)" = "yes" || test "$(vnni512)" = "no") && \
(test "$(altivec)" = "yes" || test "$(altivec)" = "no") && \
(test "$(vsx)" = "yes" || test "$(vsx)" = "no") && \
(test "$(neon)" = "yes" || test "$(neon)" = "no") && \
(test "$(lsx)" = "yes" || test "$(lsx)" = "no") && \
(test "$(lasx)" = "yes" || test "$(lasx)" = "no") && \
(test "$(comp)" = "gcc" || test "$(comp)" = "icx" || test "$(comp)" = "mingw" || \
test "$(comp)" = "clang" || test "$(comp)" = "armv7a-linux-androideabi16-clang" || \
test "$(comp)" = "aarch64-linux-android21-clang")
$(EXE): $(OBJS)
+$(CXX) -o $@ $(OBJS) $(LDFLAGS)
+350 -1
View File
@@ -1,6 +1,6 @@
/*
Stockfish, a UCI chess playing engine derived from Glaurung 2.1
Copyright (C) 2004-2024 The Stockfish developers (see AUTHORS file)
Copyright (C) 2004-2025 The Stockfish developers (see AUTHORS file)
Stockfish is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -17,6 +17,7 @@
*/
#include "benchmark.h"
#include "numa.h"
#include <cstdlib>
#include <fstream>
@@ -91,6 +92,282 @@ const std::vector<std::string> Defaults = {
};
// clang-format on
// clang-format off
// human-randomly picked 5 games with <60 moves from
// https://tests.stockfishchess.org/tests/view/665c71f9fd45fb0f907c21e0
// only moves for one side
const std::vector<std::vector<std::string>> BenchmarkPositions = {
{
"rnbq1k1r/ppp1bppp/4pn2/8/2B5/2NP1N2/PPP2PPP/R1BQR1K1 b - - 2 8",
"rnbq1k1r/pp2bppp/4pn2/2p5/2B2B2/2NP1N2/PPP2PPP/R2QR1K1 b - - 1 9",
"r1bq1k1r/pp2bppp/2n1pn2/2p5/2B1NB2/3P1N2/PPP2PPP/R2QR1K1 b - - 3 10",
"r1bq1k1r/pp2bppp/2n1p3/2p5/2B1PB2/5N2/PPP2PPP/R2QR1K1 b - - 0 11",
"r1b2k1r/pp2bppp/2n1p3/2p5/2B1PB2/5N2/PPP2PPP/3RR1K1 b - - 0 12",
"r1b1k2r/pp2bppp/2n1p3/2p5/2B1PB2/2P2N2/PP3PPP/3RR1K1 b - - 0 13",
"r1b1k2r/1p2bppp/p1n1p3/2p5/4PB2/2P2N2/PP2BPPP/3RR1K1 b - - 1 14",
"r1b1k2r/4bppp/p1n1p3/1pp5/P3PB2/2P2N2/1P2BPPP/3RR1K1 b - - 0 15",
"r1b1k2r/4bppp/p1n1p3/1P6/2p1PB2/2P2N2/1P2BPPP/3RR1K1 b - - 0 16",
"r1b1k2r/4bppp/2n1p3/1p6/2p1PB2/1PP2N2/4BPPP/3RR1K1 b - - 0 17",
"r3k2r/3bbppp/2n1p3/1p6/2P1PB2/2P2N2/4BPPP/3RR1K1 b - - 0 18",
"r3k2r/3bbppp/2n1p3/8/1pP1P3/2P2N2/3BBPPP/3RR1K1 b - - 1 19",
"1r2k2r/3bbppp/2n1p3/8/1pPNP3/2P5/3BBPPP/3RR1K1 b - - 3 20",
"1r2k2r/3bbppp/2n1p3/8/2PNP3/2B5/4BPPP/3RR1K1 b - - 0 21",
"1r2k2r/3bb1pp/2n1pp2/1N6/2P1P3/2B5/4BPPP/3RR1K1 b - - 1 22",
"1r2k2r/3b2pp/2n1pp2/1N6/1BP1P3/8/4BPPP/3RR1K1 b - - 0 23",
"1r2k2r/3b2pp/4pp2/1N6/1nP1P3/8/3RBPPP/4R1K1 b - - 1 24",
"1r5r/3bk1pp/4pp2/1N6/1nP1PP2/8/3RB1PP/4R1K1 b - - 0 25",
"1r5r/3bk1pp/2n1pp2/1N6/2P1PP2/8/3RBKPP/4R3 b - - 2 26",
"1r5r/3bk1pp/2n2p2/1N2p3/2P1PP2/6P1/3RBK1P/4R3 b - - 0 27",
"1r1r4/3bk1pp/2n2p2/1N2p3/2P1PP2/6P1/3RBK1P/R7 b - - 2 28",
"1r1r4/N3k1pp/2n1bp2/4p3/2P1PP2/6P1/3RBK1P/R7 b - - 4 29",
"1r1r4/3bk1pp/2N2p2/4p3/2P1PP2/6P1/3RBK1P/R7 b - - 0 30",
"1r1R4/4k1pp/2b2p2/4p3/2P1PP2/6P1/4BK1P/R7 b - - 0 31",
"3r4/4k1pp/2b2p2/4P3/2P1P3/6P1/4BK1P/R7 b - - 0 32",
"3r4/R3k1pp/2b5/4p3/2P1P3/6P1/4BK1P/8 b - - 1 33",
"8/3rk1pp/2b5/R3p3/2P1P3/6P1/4BK1P/8 b - - 3 34",
"8/3r2pp/2bk4/R1P1p3/4P3/6P1/4BK1P/8 b - - 0 35",
"8/2kr2pp/2b5/R1P1p3/4P3/4K1P1/4B2P/8 b - - 2 36",
"1k6/3r2pp/2b5/RBP1p3/4P3/4K1P1/7P/8 b - - 4 37",
"8/1k1r2pp/2b5/R1P1p3/4P3/3BK1P1/7P/8 b - - 6 38",
"1k6/3r2pp/2b5/2P1p3/4P3/3BK1P1/7P/R7 b - - 8 39",
"1k6/r5pp/2b5/2P1p3/4P3/3BK1P1/7P/5R2 b - - 10 40",
"1k3R2/6pp/2b5/2P1p3/4P3/r2BK1P1/7P/8 b - - 12 41",
"5R2/2k3pp/2b5/2P1p3/4P3/r2B2P1/3K3P/8 b - - 14 42",
"5R2/2k3pp/2b5/2P1p3/4P3/3BK1P1/r6P/8 b - - 16 43",
"5R2/2k3pp/2b5/2P1p3/4P3/r2B2P1/4K2P/8 b - - 18 44",
"5R2/2k3pp/2b5/2P1p3/4P3/3B1KP1/r6P/8 b - - 20 45",
"8/2k2Rpp/2b5/2P1p3/4P3/r2B1KP1/7P/8 b - - 22 46",
"3k4/5Rpp/2b5/2P1p3/4P3/r2B2P1/4K2P/8 b - - 24 47",
"3k4/5Rpp/2b5/2P1p3/4P3/3B1KP1/r6P/8 b - - 26 48",
"3k4/5Rpp/2b5/2P1p3/4P3/r2B2P1/4K2P/8 b - - 28 49",
"3k4/5Rpp/2b5/2P1p3/4P3/3BK1P1/r6P/8 b - - 30 50",
"3k4/5Rpp/2b5/2P1p3/4P3/r2B2P1/3K3P/8 b - - 32 51",
"3k4/5Rpp/2b5/2P1p3/4P3/2KB2P1/r6P/8 b - - 34 52",
"3k4/5Rpp/2b5/2P1p3/4P3/r2B2P1/2K4P/8 b - - 36 53",
"3k4/5Rpp/2b5/2P1p3/4P3/1K1B2P1/r6P/8 b - - 38 54",
"3k4/6Rp/2b5/2P1p3/4P3/1K1B2P1/7r/8 b - - 0 55",
"3k4/8/2b3Rp/2P1p3/4P3/1K1B2P1/7r/8 b - - 1 56",
"8/2k3R1/2b4p/2P1p3/4P3/1K1B2P1/7r/8 b - - 3 57",
"3k4/8/2b3Rp/2P1p3/4P3/1K1B2P1/7r/8 b - - 5 58",
"8/2k5/2b3Rp/2P1p3/1K2P3/3B2P1/7r/8 b - - 7 59",
"8/2k5/2b3Rp/2P1p3/4P3/2KB2P1/3r4/8 b - - 9 60",
"8/2k5/2b3Rp/2P1p3/1K2P3/3B2P1/6r1/8 b - - 11 61",
"8/2k5/2b3Rp/2P1p3/4P3/2KB2P1/3r4/8 b - - 13 62",
"8/2k5/2b3Rp/2P1p3/2K1P3/3B2P1/6r1/8 b - - 15 63",
"4b3/2k3R1/7p/2P1p3/2K1P3/3B2P1/6r1/8 b - - 17 64",
},
{
"r1bqkbnr/npp1pppp/p7/3P4/4pB2/2N5/PPP2PPP/R2QKBNR w KQkq - 1 6",
"r1bqkb1r/npp1pppp/p4n2/3P4/4pB2/2N5/PPP1QPPP/R3KBNR w KQkq - 3 7",
"r2qkb1r/npp1pppp/p4n2/3P1b2/4pB2/2N5/PPP1QPPP/2KR1BNR w kq - 5 8",
"r2qkb1r/1pp1pppp/p4n2/1n1P1b2/4pB2/2N4P/PPP1QPP1/2KR1BNR w kq - 1 9",
"r2qkb1r/1pp1pppp/5n2/1p1P1b2/4pB2/7P/PPP1QPP1/2KR1BNR w kq - 0 10",
"r2qkb1r/1ppbpppp/5n2/1Q1P4/4pB2/7P/PPP2PP1/2KR1BNR w kq - 1 11",
"3qkb1r/1Qpbpppp/5n2/3P4/4pB2/7P/rPP2PP1/2KR1BNR w k - 0 12",
"q3kb1r/1Qpbpppp/5n2/3P4/4pB2/7P/rPP2PP1/1K1R1BNR w k - 2 13",
"r3kb1r/2pbpppp/5n2/3P4/4pB2/7P/1PP2PP1/1K1R1BNR w k - 0 14",
"r3kb1r/2Bb1ppp/4pn2/3P4/4p3/7P/1PP2PP1/1K1R1BNR w k - 0 15",
"r3kb1r/2Bb2pp/4pn2/8/4p3/7P/1PP2PP1/1K1R1BNR w k - 0 16",
"r3k2r/2Bb2pp/4pn2/2b5/4p3/7P/1PP1NPP1/1K1R1B1R w k - 2 17",
"r6r/2Bbk1pp/4pn2/2b5/3Np3/7P/1PP2PP1/1K1R1B1R w - - 4 18",
"r6r/b2bk1pp/4pn2/4B3/3Np3/7P/1PP2PP1/1K1R1B1R w - - 6 19",
"r1r5/b2bk1pp/4pn2/4B3/2BNp3/7P/1PP2PP1/1K1R3R w - - 8 20",
"r7/b2bk1pp/4pn2/2r1B3/2BNp3/1P5P/2P2PP1/1K1R3R w - - 1 21",
"rb6/3bk1pp/4pn2/2r1B3/2BNpP2/1P5P/2P3P1/1K1R3R w - - 1 22",
"1r6/3bk1pp/4pn2/2r5/2BNpP2/1P5P/2P3P1/1K1R3R w - - 0 23",
"1r6/3bk1p1/4pn1p/2r5/2BNpP2/1P5P/2P3P1/2KR3R w - - 0 24",
"8/3bk1p1/1r2pn1p/2r5/2BNpP1P/1P6/2P3P1/2KR3R w - - 1 25",
"8/3bk3/1r2pnpp/2r5/2BNpP1P/1P6/2P3P1/2K1R2R w - - 0 26",
"2b5/4k3/1r2pnpp/2r5/2BNpP1P/1P4P1/2P5/2K1R2R w - - 1 27",
"8/1b2k3/1r2pnpp/2r5/2BNpP1P/1P4P1/2P5/2K1R1R1 w - - 3 28",
"8/1b1nk3/1r2p1pp/2r5/2BNpPPP/1P6/2P5/2K1R1R1 w - - 1 29",
"8/1b2k3/1r2p1pp/2r1nP2/2BNp1PP/1P6/2P5/2K1R1R1 w - - 1 30",
"8/1b2k3/1r2p1p1/2r1nPp1/2BNp2P/1P6/2P5/2K1R1R1 w - - 0 31",
"8/1b2k3/1r2p1n1/2r3p1/2BNp2P/1P6/2P5/2K1R1R1 w - - 0 32",
"8/1b2k3/1r2p1n1/6r1/2BNp2P/1P6/2P5/2K1R3 w - - 0 33",
"8/1b2k3/1r2p3/4n1P1/2BNp3/1P6/2P5/2K1R3 w - - 1 34",
"8/1b2k3/1r2p3/4n1P1/2BN4/1P2p3/2P5/2K4R w - - 0 35",
"8/1b2k3/1r2p2R/6P1/2nN4/1P2p3/2P5/2K5 w - - 0 36",
"8/1b2k3/3rp2R/6P1/2PN4/4p3/2P5/2K5 w - - 1 37",
"8/4k3/3rp2R/6P1/2PN4/2P1p3/6b1/2K5 w - - 1 38",
"8/4k3/r3p2R/2P3P1/3N4/2P1p3/6b1/2K5 w - - 1 39",
"8/3k4/r3p2R/2P2NP1/8/2P1p3/6b1/2K5 w - - 3 40",
"8/3k4/4p2R/2P3P1/8/2P1N3/6b1/r1K5 w - - 1 41",
"8/3k4/4p2R/2P3P1/8/2P1N3/3K2b1/6r1 w - - 3 42",
"8/3k4/4p2R/2P3P1/8/2PKNb2/8/6r1 w - - 5 43",
"8/4k3/4p1R1/2P3P1/8/2PKNb2/8/6r1 w - - 7 44",
"8/4k3/4p1R1/2P3P1/3K4/2P1N3/8/6rb w - - 9 45",
"8/3k4/4p1R1/2P1K1P1/8/2P1N3/8/6rb w - - 11 46",
"8/3k4/4p1R1/2P3P1/5K2/2P1N3/8/4r2b w - - 13 47",
"8/3k4/2b1p2R/2P3P1/5K2/2P1N3/8/4r3 w - - 15 48",
"8/3k4/2b1p3/2P3P1/5K2/2P1N2R/8/6r1 w - - 17 49",
"2k5/7R/2b1p3/2P3P1/5K2/2P1N3/8/6r1 w - - 19 50",
"2k5/7R/4p3/2P3P1/b1P2K2/4N3/8/6r1 w - - 1 51",
"2k5/3bR3/4p3/2P3P1/2P2K2/4N3/8/6r1 w - - 3 52",
"3k4/3b2R1/4p3/2P3P1/2P2K2/4N3/8/6r1 w - - 5 53",
"3kb3/6R1/4p1P1/2P5/2P2K2/4N3/8/6r1 w - - 1 54",
"3kb3/6R1/4p1P1/2P5/2P2KN1/8/8/2r5 w - - 3 55",
"3kb3/6R1/4p1P1/2P1N3/2P2K2/8/8/5r2 w - - 5 56",
"3kb3/6R1/4p1P1/2P1N3/2P5/4K3/8/4r3 w - - 7 57",
},
{
"rnbq1rk1/ppp1npb1/4p1p1/3P3p/3PP3/2N2N2/PP2BPPP/R1BQ1RK1 b - - 0 8",
"rnbq1rk1/ppp1npb1/6p1/3pP2p/3P4/2N2N2/PP2BPPP/R1BQ1RK1 b - - 0 9",
"rn1q1rk1/ppp1npb1/6p1/3pP2p/3P2b1/2N2N2/PP2BPPP/R1BQR1K1 b - - 2 10",
"r2q1rk1/ppp1npb1/2n3p1/3pP2p/3P2bN/2N5/PP2BPPP/R1BQR1K1 b - - 4 11",
"r4rk1/pppqnpb1/2n3p1/3pP2p/3P2bN/2N4P/PP2BPP1/R1BQR1K1 b - - 0 12",
"r4rk1/pppqnpb1/2n3p1/3pP2p/3P3N/7P/PP2NPP1/R1BQR1K1 b - - 0 13",
"r4rk1/pppq1pb1/2n3p1/3pPN1p/3P4/7P/PP2NPP1/R1BQR1K1 b - - 0 14",
"r4rk1/ppp2pb1/2n3p1/3pPq1p/3P1N2/7P/PP3PP1/R1BQR1K1 b - - 1 15",
"r4rk1/pppq1pb1/2n3p1/3pP2p/P2P1N2/7P/1P3PP1/R1BQR1K1 b - - 0 16",
"r2n1rk1/pppq1pb1/6p1/3pP2p/P2P1N2/R6P/1P3PP1/2BQR1K1 b - - 2 17",
"r4rk1/pppq1pb1/4N1p1/3pP2p/P2P4/R6P/1P3PP1/2BQR1K1 b - - 0 18",
"r4rk1/ppp2pb1/4q1p1/3pP1Bp/P2P4/R6P/1P3PP1/3QR1K1 b - - 1 19",
"r3r1k1/ppp2pb1/4q1p1/3pP1Bp/P2P1P2/R6P/1P4P1/3QR1K1 b - - 0 20",
"r3r1k1/ppp3b1/4qpp1/3pP2p/P2P1P1B/R6P/1P4P1/3QR1K1 b - - 1 21",
"r3r1k1/ppp3b1/4q1p1/3pP2p/P4P1B/R6P/1P4P1/3QR1K1 b - - 0 22",
"r4rk1/ppp3b1/4q1p1/3pP1Bp/P4P2/R6P/1P4P1/3QR1K1 b - - 2 23",
"r4rk1/pp4b1/4q1p1/2ppP1Bp/P4P2/3R3P/1P4P1/3QR1K1 b - - 1 24",
"r4rk1/pp4b1/4q1p1/2p1P1Bp/P2p1PP1/3R3P/1P6/3QR1K1 b - - 0 25",
"r4rk1/pp4b1/4q1p1/2p1P1B1/P2p1PP1/3R4/1P6/3QR1K1 b - - 0 26",
"r5k1/pp3rb1/4q1p1/2p1P1B1/P2p1PP1/6R1/1P6/3QR1K1 b - - 2 27",
"5rk1/pp3rb1/4q1p1/2p1P1B1/P2pRPP1/6R1/1P6/3Q2K1 b - - 4 28",
"5rk1/1p3rb1/p3q1p1/P1p1P1B1/3pRPP1/6R1/1P6/3Q2K1 b - - 0 29",
"4r1k1/1p3rb1/p3q1p1/P1p1P1B1/3pRPP1/1P4R1/8/3Q2K1 b - - 0 30",
"4r1k1/5rb1/pP2q1p1/2p1P1B1/3pRPP1/1P4R1/8/3Q2K1 b - - 0 31",
"4r1k1/5rb1/pq4p1/2p1P1B1/3pRPP1/1P4R1/4Q3/6K1 b - - 1 32",
"4r1k1/1r4b1/pq4p1/2p1P1B1/3pRPP1/1P4R1/2Q5/6K1 b - - 3 33",
"4r1k1/1r4b1/1q4p1/p1p1P1B1/3p1PP1/1P4R1/2Q5/4R1K1 b - - 1 34",
"4r1k1/3r2b1/1q4p1/p1p1P1B1/2Qp1PP1/1P4R1/8/4R1K1 b - - 3 35",
"4r1k1/3r2b1/4q1p1/p1p1P1B1/2Qp1PP1/1P4R1/5K2/4R3 b - - 5 36",
"4r1k1/3r2b1/6p1/p1p1P1B1/2Pp1PP1/6R1/5K2/4R3 b - - 0 37",
"4r1k1/3r2b1/6p1/p1p1P1B1/2P2PP1/3p2R1/5K2/3R4 b - - 1 38",
"5rk1/3r2b1/6p1/p1p1P1B1/2P2PP1/3p2R1/8/3RK3 b - - 3 39",
"5rk1/6b1/6p1/p1p1P1B1/2Pr1PP1/3R4/8/3RK3 b - - 0 40",
"5rk1/3R2b1/6p1/p1p1P1B1/2r2PP1/8/8/3RK3 b - - 1 41",
"5rk1/3R2b1/6p1/p1p1P1B1/4rPP1/8/3K4/3R4 b - - 3 42",
"1r4k1/3R2b1/6p1/p1p1P1B1/4rPP1/2K5/8/3R4 b - - 5 43",
"1r4k1/3R2b1/6p1/p1p1P1B1/2K2PP1/4r3/8/3R4 b - - 7 44",
"1r3bk1/8/3R2p1/p1p1P1B1/2K2PP1/4r3/8/3R4 b - - 9 45",
"1r3bk1/8/6R1/2p1P1B1/p1K2PP1/4r3/8/3R4 b - - 0 46",
"1r3b2/5k2/R7/2p1P1B1/p1K2PP1/4r3/8/3R4 b - - 2 47",
"5b2/1r3k2/R7/2p1P1B1/p1K2PP1/4r3/8/7R b - - 4 48",
"5b2/5k2/R7/2pKP1B1/pr3PP1/4r3/8/7R b - - 6 49",
"5b2/5k2/R1K5/2p1P1B1/p2r1PP1/4r3/8/7R b - - 8 50",
"8/R4kb1/2K5/2p1P1B1/p2r1PP1/4r3/8/7R b - - 10 51",
"8/R5b1/2K3k1/2p1PPB1/p2r2P1/4r3/8/7R b - - 0 52",
"8/6R1/2K5/2p1PPk1/p2r2P1/4r3/8/7R b - - 0 53",
"8/6R1/2K5/2p1PP2/p2r1kP1/4r3/8/5R2 b - - 2 54",
"8/6R1/2K2P2/2p1P3/p2r2P1/4r1k1/8/5R2 b - - 0 55",
"8/5PR1/2K5/2p1P3/p2r2P1/4r3/6k1/5R2 b - - 0 56",
},
{
"rn1qkb1r/p1pbpppp/5n2/8/2pP4/2N5/1PQ1PPPP/R1B1KBNR w KQkq - 0 7",
"r2qkb1r/p1pbpppp/2n2n2/8/2pP4/2N2N2/1PQ1PPPP/R1B1KB1R w KQkq - 2 8",
"r2qkb1r/p1pbpppp/5n2/8/1npPP3/2N2N2/1PQ2PPP/R1B1KB1R w KQkq - 1 9",
"r2qkb1r/p1pb1ppp/4pn2/8/1npPP3/2N2N2/1P3PPP/R1BQKB1R w KQkq - 0 10",
"r2qk2r/p1pbbppp/4pn2/8/1nBPP3/2N2N2/1P3PPP/R1BQK2R w KQkq - 1 11",
"r2q1rk1/p1pbbppp/4pn2/8/1nBPP3/2N2N2/1P3PPP/R1BQ1RK1 w - - 3 12",
"r2q1rk1/2pbbppp/p3pn2/8/1nBPPB2/2N2N2/1P3PPP/R2Q1RK1 w - - 0 13",
"r2q1rk1/2p1bppp/p3pn2/1b6/1nBPPB2/2N2N2/1P3PPP/R2QR1K1 w - - 2 14",
"r2q1rk1/4bppp/p1p1pn2/1b6/1nBPPB2/1PN2N2/5PPP/R2QR1K1 w - - 0 15",
"r4rk1/3qbppp/p1p1pn2/1b6/1nBPPB2/1PN2N2/3Q1PPP/R3R1K1 w - - 2 16",
"r4rk1/1q2bppp/p1p1pn2/1b6/1nBPPB2/1PN2N1P/3Q1PP1/R3R1K1 w - - 1 17",
"r3r1k1/1q2bppp/p1p1pn2/1b6/1nBPPB2/1PN2N1P/4QPP1/R3R1K1 w - - 3 18",
"r3r1k1/1q1nbppp/p1p1p3/1b6/1nBPPB2/1PN2N1P/4QPP1/3RR1K1 w - - 5 19",
"r3rbk1/1q1n1ppp/p1p1p3/1b6/1nBPPB2/1PN2N1P/3RQPP1/4R1K1 w - - 7 20",
"r3rbk1/1q3ppp/pnp1p3/1b6/1nBPPB2/1PN2N1P/3RQPP1/4R2K w - - 9 21",
"2r1rbk1/1q3ppp/pnp1p3/1b6/1nBPPB2/1PN2N1P/3RQPP1/1R5K w - - 11 22",
"2r1rbk1/1q4pp/pnp1pp2/1b6/1nBPPB2/1PN2N1P/4QPP1/1R1R3K w - - 0 23",
"2r1rbk1/5qpp/pnp1pp2/1b6/1nBPP3/1PN1BN1P/4QPP1/1R1R3K w - - 2 24",
"2r1rbk1/5qp1/pnp1pp1p/1b6/1nBPP3/1PN1BN1P/4QPP1/1R1R2K1 w - - 0 25",
"2r1rbk1/5qp1/pnp1pp1p/1b6/2BPP3/1P2BN1P/n3QPP1/1R1R2K1 w - - 0 26",
"r3rbk1/5qp1/pnp1pp1p/1b6/2BPP3/1P2BN1P/Q4PP1/1R1R2K1 w - - 1 27",
"rr3bk1/5qp1/pnp1pp1p/1b6/2BPP3/1P2BN1P/Q4PP1/R2R2K1 w - - 3 28",
"rr2qbk1/6p1/pnp1pp1p/1b6/2BPP3/1P2BN1P/4QPP1/R2R2K1 w - - 5 29",
"rr2qbk1/6p1/1np1pp1p/pb6/2BPP3/1P1QBN1P/5PP1/R2R2K1 w - - 0 30",
"rr2qbk1/6p1/1n2pp1p/pp6/3PP3/1P1QBN1P/5PP1/R2R2K1 w - - 0 31",
"rr2qbk1/6p1/1n2pp1p/1p1P4/p3P3/1P1QBN1P/5PP1/R2R2K1 w - - 0 32",
"rr2qbk1/3n2p1/3Ppp1p/1p6/p3P3/1P1QBN1P/5PP1/R2R2K1 w - - 1 33",
"rr3bk1/3n2p1/3Ppp1p/1p5q/pP2P3/3QBN1P/5PP1/R2R2K1 w - - 1 34",
"rr3bk1/3n2p1/3Ppp1p/1p5q/1P2P3/p2QBN1P/5PP1/2RR2K1 w - - 0 35",
"1r3bk1/3n2p1/r2Ppp1p/1p5q/1P2P3/pQ2BN1P/5PP1/2RR2K1 w - - 2 36",
"1r2qbk1/2Rn2p1/r2Ppp1p/1p6/1P2P3/pQ2BN1P/5PP1/3R2K1 w - - 4 37",
"1r2qbk1/2Rn2p1/r2Ppp1p/1pB5/1P2P3/1Q3N1P/p4PP1/3R2K1 w - - 0 38",
"1r2q1k1/2Rn2p1/r2bpp1p/1pB5/1P2P3/1Q3N1P/p4PP1/R5K1 w - - 0 39",
"1r2q1k1/2Rn2p1/3rpp1p/1p6/1P2P3/1Q3N1P/p4PP1/R5K1 w - - 0 40",
"2r1q1k1/2Rn2p1/3rpp1p/1p6/1P2P3/5N1P/Q4PP1/R5K1 w - - 1 41",
"1r2q1k1/1R1n2p1/3rpp1p/1p6/1P2P3/5N1P/Q4PP1/R5K1 w - - 3 42",
"2r1q1k1/2Rn2p1/3rpp1p/1p6/1P2P3/5N1P/Q4PP1/R5K1 w - - 5 43",
"1r2q1k1/1R1n2p1/3rpp1p/1p6/1P2P3/5N1P/Q4PP1/R5K1 w - - 7 44",
"1rq3k1/R2n2p1/3rpp1p/1p6/1P2P3/5N1P/Q4PP1/R5K1 w - - 9 45",
"2q3k1/Rr1n2p1/3rpp1p/1p6/1P2P3/5N1P/4QPP1/R5K1 w - - 11 46",
"Rrq3k1/3n2p1/3rpp1p/1p6/1P2P3/5N1P/4QPP1/R5K1 w - - 13 47",
},
{
"rn1qkb1r/1pp2ppp/p4p2/3p1b2/5P2/1P2PN2/P1PP2PP/RN1QKB1R b KQkq - 1 6",
"r2qkb1r/1pp2ppp/p1n2p2/3p1b2/3P1P2/1P2PN2/P1P3PP/RN1QKB1R b KQkq - 0 7",
"r2qkb1r/1pp2ppp/p4p2/3p1b2/1n1P1P2/1P1BPN2/P1P3PP/RN1QK2R b KQkq - 2 8",
"r2qkb1r/1pp2ppp/p4p2/3p1b2/3P1P2/1P1PPN2/P5PP/RN1QK2R b KQkq - 0 9",
"r2qk2r/1pp2ppp/p2b1p2/3p1b2/3P1P2/1PNPPN2/P5PP/R2QK2R b KQkq - 2 10",
"r2qk2r/1p3ppp/p1pb1p2/3p1b2/3P1P2/1PNPPN2/P5PP/R2Q1RK1 b kq - 1 11",
"r2q1rk1/1p3ppp/p1pb1p2/3p1b2/3P1P2/1PNPPN2/P2Q2PP/R4RK1 b - - 3 12",
"r2qr1k1/1p3ppp/p1pb1p2/3p1b2/3P1P2/1P1PPN2/P2QN1PP/R4RK1 b - - 5 13",
"r3r1k1/1p3ppp/pqpb1p2/3p1b2/3P1P2/1P1PPNN1/P2Q2PP/R4RK1 b - - 7 14",
"r3r1k1/1p3ppp/pqp2p2/3p1b2/1b1P1P2/1P1PPNN1/P1Q3PP/R4RK1 b - - 9 15",
"r3r1k1/1p1b1ppp/pqp2p2/3p4/1b1P1P2/1P1PPNN1/P4QPP/R4RK1 b - - 11 16",
"2r1r1k1/1p1b1ppp/pqp2p2/3p4/1b1PPP2/1P1P1NN1/P4QPP/R4RK1 b - - 0 17",
"2r1r1k1/1p1b1ppp/pq3p2/2pp4/1b1PPP2/PP1P1NN1/5QPP/R4RK1 b - - 0 18",
"2r1r1k1/1p1b1ppp/pq3p2/2Pp4/4PP2/PPbP1NN1/5QPP/R4RK1 b - - 0 19",
"2r1r1k1/1p1b1ppp/p4p2/2Pp4/4PP2/PqbP1NN1/5QPP/RR4K1 b - - 1 20",
"2r1r1k1/1p1b1ppp/p4p2/2Pp4/q3PP2/P1bP1NN1/R4QPP/1R4K1 b - - 3 21",
"2r1r1k1/1p3ppp/p4p2/1bPP4/q4P2/P1bP1NN1/R4QPP/1R4K1 b - - 0 22",
"2r1r1k1/1p3ppp/p4p2/2PP4/q4P2/P1bb1NN1/R4QPP/2R3K1 b - - 1 23",
"2r1r1k1/1p3ppp/p2P1p2/2P5/2q2P2/P1bb1NN1/R4QPP/2R3K1 b - - 0 24",
"2rr2k1/1p3ppp/p2P1p2/2P5/2q2P2/P1bb1NN1/R4QPP/2R4K b - - 2 25",
"2rr2k1/1p3ppp/p2P1p2/2Q5/5P2/P1bb1NN1/R5PP/2R4K b - - 0 26",
"3r2k1/1p3ppp/p2P1p2/2r5/5P2/P1bb1N2/R3N1PP/2R4K b - - 1 27",
"3r2k1/1p3ppp/p2P1p2/2r5/5P2/P1b2N2/4R1PP/2R4K b - - 0 28",
"3r2k1/1p3ppp/p2P1p2/2r5/1b3P2/P4N2/4R1PP/3R3K b - - 2 29",
"3r2k1/1p2Rppp/p2P1p2/b1r5/5P2/P4N2/6PP/3R3K b - - 4 30",
"3r2k1/1R3ppp/p1rP1p2/b7/5P2/P4N2/6PP/3R3K b - - 0 31",
"3r2k1/1R3ppp/p2R1p2/b7/5P2/P4N2/6PP/7K b - - 0 32",
"6k1/1R3ppp/p2r1p2/b7/5P2/P4NP1/7P/7K b - - 0 33",
"6k1/1R3p1p/p2r1pp1/b7/5P1P/P4NP1/8/7K b - - 0 34",
"6k1/3R1p1p/pr3pp1/b7/5P1P/P4NP1/8/7K b - - 2 35",
"6k1/5p2/pr3pp1/b2R3p/5P1P/P4NP1/8/7K b - - 1 36",
"6k1/5p2/pr3pp1/7p/5P1P/P1bR1NP1/8/7K b - - 3 37",
"6k1/5p2/p1r2pp1/7p/5P1P/P1bR1NP1/6K1/8 b - - 5 38",
"6k1/5p2/p1r2pp1/b2R3p/5P1P/P4NP1/6K1/8 b - - 7 39",
"6k1/5p2/p4pp1/b2R3p/5P1P/P4NPK/2r5/8 b - - 9 40",
"6k1/2b2p2/p4pp1/7p/5P1P/P2R1NPK/2r5/8 b - - 11 41",
"6k1/2b2p2/5pp1/p6p/3N1P1P/P2R2PK/2r5/8 b - - 1 42",
"6k1/2b2p2/5pp1/p6p/3N1P1P/P1R3PK/r7/8 b - - 3 43",
"6k1/5p2/1b3pp1/p6p/5P1P/P1R3PK/r1N5/8 b - - 5 44",
"8/5pk1/1bR2pp1/p6p/5P1P/P5PK/r1N5/8 b - - 7 45",
"3b4/5pk1/2R2pp1/p4P1p/7P/P5PK/r1N5/8 b - - 0 46",
"8/4bpk1/2R2pp1/p4P1p/6PP/P6K/r1N5/8 b - - 0 47",
"8/5pk1/2R2pP1/p6p/6PP/b6K/r1N5/8 b - - 0 48",
"8/6k1/2R2pp1/p6P/7P/b6K/r1N5/8 b - - 0 49",
"8/6k1/2R2p2/p6p/7P/b5K1/r1N5/8 b - - 1 50",
"8/8/2R2pk1/p6p/7P/b4K2/r1N5/8 b - - 3 51",
"8/8/2R2pk1/p6p/7P/4NK2/rb6/8 b - - 5 52",
"2R5/8/5pk1/7p/p6P/4NK2/rb6/8 b - - 1 53",
"6R1/8/5pk1/7p/p6P/4NK2/1b6/r7 b - - 3 54",
"R7/5k2/5p2/7p/p6P/4NK2/1b6/r7 b - - 5 55",
"R7/5k2/5p2/7p/7P/p3N3/1b2K3/r7 b - - 1 56",
"8/R4k2/5p2/7p/7P/p3N3/1b2K3/7r b - - 3 57",
"8/8/5pk1/7p/R6P/p3N3/1b2K3/7r b - - 5 58",
"8/8/5pk1/7p/R6P/p7/4K3/2bN3r b - - 7 59",
"8/8/5pk1/7p/R6P/p7/4KN1r/2b5 b - - 9 60",
"8/8/5pk1/7p/R6P/p3K3/1b3N1r/8 b - - 11 61",
"8/8/R4pk1/7p/7P/p1b1K3/5N1r/8 b - - 13 62",
"8/8/5pk1/7p/7P/2b1K3/R4N1r/8 b - - 0 63",
"8/8/5pk1/7p/3K3P/8/R4N1r/4b3 b - - 2 64",
}
};
// clang-format on
} // namespace
namespace Stockfish::Benchmark {
@@ -160,4 +437,76 @@ std::vector<std::string> setup_bench(const std::string& currentFen, std::istream
return list;
}
BenchmarkSetup setup_benchmark(std::istream& is) {
// TT_SIZE_PER_THREAD is chosen such that roughly half of the hash is used all positions
// for the current sequence have been searched.
static constexpr int TT_SIZE_PER_THREAD = 128;
static constexpr int DEFAULT_DURATION_S = 150;
BenchmarkSetup setup{};
// Assign default values to missing arguments
int desiredTimeS;
if (!(is >> setup.threads))
setup.threads = get_hardware_concurrency();
else
setup.originalInvocation += std::to_string(setup.threads);
if (!(is >> setup.ttSize))
setup.ttSize = TT_SIZE_PER_THREAD * setup.threads;
else
setup.originalInvocation += " " + std::to_string(setup.ttSize);
if (!(is >> desiredTimeS))
desiredTimeS = DEFAULT_DURATION_S;
else
setup.originalInvocation += " " + std::to_string(desiredTimeS);
setup.filledInvocation += std::to_string(setup.threads) + " " + std::to_string(setup.ttSize)
+ " " + std::to_string(desiredTimeS);
auto getCorrectedTime = [&](int ply) {
// time per move is fit roughly based on LTC games
// seconds = 50/{ply+15}
// ms = 50000/{ply+15}
// with this fit 10th move gets 2000ms
// adjust for desired 10th move time
return 50000.0 / (static_cast<double>(ply) + 15.0);
};
float totalTime = 0;
for (const auto& game : BenchmarkPositions)
{
setup.commands.emplace_back("ucinewgame");
int ply = 1;
for (int i = 0; i < static_cast<int>(game.size()); ++i)
{
const float correctedTime = getCorrectedTime(ply);
totalTime += correctedTime;
ply += 1;
}
}
float timeScaleFactor = static_cast<float>(desiredTimeS * 1000) / totalTime;
for (const auto& game : BenchmarkPositions)
{
setup.commands.emplace_back("ucinewgame");
int ply = 1;
for (const std::string& fen : game)
{
setup.commands.emplace_back("position fen " + fen);
const int correctedTime = static_cast<int>(getCorrectedTime(ply) * timeScaleFactor);
setup.commands.emplace_back("go movetime " + std::to_string(correctedTime));
ply += 1;
}
}
return setup;
}
} // namespace Stockfish
+11 -1
View File
@@ -1,6 +1,6 @@
/*
Stockfish, a UCI chess playing engine derived from Glaurung 2.1
Copyright (C) 2004-2024 The Stockfish developers (see AUTHORS file)
Copyright (C) 2004-2025 The Stockfish developers (see AUTHORS file)
Stockfish is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -27,6 +27,16 @@ namespace Stockfish::Benchmark {
std::vector<std::string> setup_bench(const std::string&, std::istream&);
struct BenchmarkSetup {
int ttSize;
int threads;
std::vector<std::string> commands;
std::string originalInvocation;
std::string filledInvocation;
};
BenchmarkSetup setup_benchmark(std::istream&);
} // namespace Stockfish
#endif // #ifndef BENCHMARK_H_INCLUDED
+26 -20
View File
@@ -1,6 +1,6 @@
/*
Stockfish, a UCI chess playing engine derived from Glaurung 2.1
Copyright (C) 2004-2024 The Stockfish developers (see AUTHORS file)
Copyright (C) 2004-2025 The Stockfish developers (see AUTHORS file)
Stockfish is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -34,15 +34,14 @@ Bitboard BetweenBB[SQUARE_NB][SQUARE_NB];
Bitboard PseudoAttacks[PIECE_TYPE_NB][SQUARE_NB];
Bitboard PawnAttacks[COLOR_NB][SQUARE_NB];
Magic RookMagics[SQUARE_NB];
Magic BishopMagics[SQUARE_NB];
alignas(64) Magic Magics[SQUARE_NB][2];
namespace {
Bitboard RookTable[0x19000]; // To store rook attacks
Bitboard BishopTable[0x1480]; // To store bishop attacks
void init_magics(PieceType pt, Bitboard table[], Magic magics[]);
void init_magics(PieceType pt, Bitboard table[], Magic magics[][2]);
// Returns the bitboard of target square for the given step
// from the given square. If the step is off the board, returns empty bitboard.
@@ -82,8 +81,8 @@ void Bitboards::init() {
for (Square s2 = SQ_A1; s2 <= SQ_H8; ++s2)
SquareDistance[s1][s2] = std::max(distance<File>(s1, s2), distance<Rank>(s1, s2));
init_magics(ROOK, RookTable, RookMagics);
init_magics(BISHOP, BishopTable, BishopMagics);
init_magics(ROOK, RookTable, Magics);
init_magics(BISHOP, BishopTable, Magics);
for (Square s1 = SQ_A1; s1 <= SQ_H8; ++s1)
{
@@ -140,41 +139,49 @@ Bitboard sliding_attack(PieceType pt, Square sq, Bitboard occupied) {
// Computes all rook and bishop attacks at startup. Magic
// bitboards are used to look up attacks of sliding pieces. As a reference see
// www.chessprogramming.org/Magic_Bitboards. In particular, here we use the so
// called "fancy" approach.
void init_magics(PieceType pt, Bitboard table[], Magic magics[]) {
// https://www.chessprogramming.org/Magic_Bitboards. In particular, here we use
// the so called "fancy" approach.
void init_magics(PieceType pt, Bitboard table[], Magic magics[][2]) {
#ifndef USE_PEXT
// Optimal PRNG seeds to pick the correct magics in the shortest time
int seeds[][RANK_NB] = {{8977, 44560, 54343, 38998, 5731, 95205, 104912, 17020},
{728, 10316, 55013, 32803, 12281, 15100, 16645, 255}};
Bitboard occupancy[4096], reference[4096], edges, b;
int epoch[4096] = {}, cnt = 0, size = 0;
Bitboard occupancy[4096];
int epoch[4096] = {}, cnt = 0;
#endif
Bitboard reference[4096];
int size = 0;
for (Square s = SQ_A1; s <= SQ_H8; ++s)
{
// Board edges are not considered in the relevant occupancies
edges = ((Rank1BB | Rank8BB) & ~rank_bb(s)) | ((FileABB | FileHBB) & ~file_bb(s));
Bitboard edges = ((Rank1BB | Rank8BB) & ~rank_bb(s)) | ((FileABB | FileHBB) & ~file_bb(s));
// Given a square 's', the mask is the bitboard of sliding attacks from
// 's' computed on an empty board. The index must be big enough to contain
// all the attacks for each possible subset of the mask and so is 2 power
// the number of 1s of the mask. Hence we deduce the size of the shift to
// apply to the 64 or 32 bits word to get the index.
Magic& m = magics[s];
Magic& m = magics[s][pt - BISHOP];
m.mask = sliding_attack(pt, s, 0) & ~edges;
m.shift = (Is64Bit ? 64 : 32) - popcount(m.mask);
#ifndef USE_PEXT
m.shift = (Is64Bit ? 64 : 32) - popcount(m.mask);
#endif
// Set the offset for the attacks table of the square. We have individual
// table sizes for each square with "Fancy Magic Bitboards".
m.attacks = s == SQ_A1 ? table : magics[s - 1].attacks + size;
m.attacks = s == SQ_A1 ? table : magics[s - 1][pt - BISHOP].attacks + size;
size = 0;
// Use Carry-Rippler trick to enumerate all subsets of masks[s] and
// store the corresponding sliding attack bitboard in reference[].
b = size = 0;
Bitboard b = 0;
do
{
#ifndef USE_PEXT
occupancy[size] = b;
#endif
reference[size] = sliding_attack(pt, s, b);
if (HasPext)
@@ -184,9 +191,7 @@ void init_magics(PieceType pt, Bitboard table[], Magic magics[]) {
b = (b - m.mask) & m.mask;
} while (b);
if (HasPext)
continue;
#ifndef USE_PEXT
PRNG rng(seeds[Is64Bit][rank_of(s)]);
// Find a magic for square 's' picking up an (almost) random number
@@ -215,6 +220,7 @@ void init_magics(PieceType pt, Bitboard table[], Magic magics[]) {
break;
}
}
#endif
}
}
}
+18 -15
View File
@@ -1,6 +1,6 @@
/*
Stockfish, a UCI chess playing engine derived from Glaurung 2.1
Copyright (C) 2004-2024 The Stockfish developers (see AUTHORS file)
Copyright (C) 2004-2025 The Stockfish developers (see AUTHORS file)
Stockfish is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -22,6 +22,7 @@
#include <algorithm>
#include <cassert>
#include <cmath>
#include <cstring>
#include <cstdint>
#include <cstdlib>
#include <string>
@@ -67,27 +68,31 @@ extern Bitboard PawnAttacks[COLOR_NB][SQUARE_NB];
// Magic holds all magic bitboards relevant data for a single square
struct Magic {
Bitboard mask;
Bitboard magic;
Bitboard* attacks;
unsigned shift;
#ifndef USE_PEXT
Bitboard magic;
unsigned shift;
#endif
// Compute the attack's index using the 'magic bitboards' approach
unsigned index(Bitboard occupied) const {
if (HasPext)
return unsigned(pext(occupied, mask));
#ifdef USE_PEXT
return unsigned(pext(occupied, mask));
#else
if (Is64Bit)
return unsigned(((occupied & mask) * magic) >> shift);
unsigned lo = unsigned(occupied) & unsigned(mask);
unsigned hi = unsigned(occupied >> 32) & unsigned(mask >> 32);
return (lo * unsigned(magic) ^ hi * unsigned(magic >> 32)) >> shift;
#endif
}
Bitboard attacks_bb(Bitboard occupied) const { return attacks[index(occupied)]; }
};
extern Magic RookMagics[SQUARE_NB];
extern Magic BishopMagics[SQUARE_NB];
extern Magic Magics[SQUARE_NB][2];
constexpr Bitboard square_bb(Square s) {
assert(is_ok(s));
@@ -229,9 +234,8 @@ inline Bitboard attacks_bb(Square s, Bitboard occupied) {
switch (Pt)
{
case BISHOP :
return BishopMagics[s].attacks[BishopMagics[s].index(occupied)];
case ROOK :
return RookMagics[s].attacks[RookMagics[s].index(occupied)];
return Magics[s][Pt - BISHOP].attacks_bb(occupied);
case QUEEN :
return attacks_bb<BISHOP>(s, occupied) | attacks_bb<ROOK>(s, occupied);
default :
@@ -265,11 +269,10 @@ inline int popcount(Bitboard b) {
#ifndef USE_POPCNT
union {
Bitboard bb;
uint16_t u[4];
} v = {b};
return PopCnt16[v.u[0]] + PopCnt16[v.u[1]] + PopCnt16[v.u[2]] + PopCnt16[v.u[3]];
std::uint16_t indices[4];
std::memcpy(indices, &b, sizeof(b));
return PopCnt16[indices[0]] + PopCnt16[indices[1]] + PopCnt16[indices[2]]
+ PopCnt16[indices[3]];
#elif defined(_MSC_VER)
+104 -67
View File
@@ -1,6 +1,6 @@
/*
Stockfish, a UCI chess playing engine derived from Glaurung 2.1
Copyright (C) 2004-2024 The Stockfish developers (see AUTHORS file)
Copyright (C) 2004-2025 The Stockfish developers (see AUTHORS file)
Stockfish is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -18,6 +18,7 @@
#include "engine.h"
#include <algorithm>
#include <cassert>
#include <deque>
#include <iosfwd>
@@ -32,6 +33,7 @@
#include "misc.h"
#include "nnue/network.h"
#include "nnue/nnue_common.h"
#include "numa.h"
#include "perft.h"
#include "position.h"
#include "search.h"
@@ -44,11 +46,12 @@ namespace Stockfish {
namespace NN = Eval::NNUE;
constexpr auto StartFEN = "rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq - 0 1";
constexpr int MaxHashMB = Is64Bit ? 33554432 : 2048;
constexpr auto StartFEN = "rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq - 0 1";
constexpr int MaxHashMB = Is64Bit ? 33554432 : 2048;
int MaxThreads = std::max(1024, 4 * int(get_hardware_concurrency()));
Engine::Engine(std::string path) :
binaryDirectory(CommandLine::get_binary_directory(path)),
Engine::Engine(std::optional<std::string> path) :
binaryDirectory(path ? CommandLine::get_binary_directory(*path) : ""),
numaContext(NumaConfig::from_system()),
states(new std::deque<StateInfo>(1)),
threads(),
@@ -58,58 +61,84 @@ Engine::Engine(std::string path) :
NN::NetworkBig({EvalFileDefaultNameBig, "None", ""}, NN::EmbeddedNNUEType::BIG),
NN::NetworkSmall({EvalFileDefaultNameSmall, "None", ""}, NN::EmbeddedNNUEType::SMALL))) {
pos.set(StartFEN, false, &states->back());
capSq = SQ_NONE;
options["Debug Log File"] << Option("", [](const Option& o) {
start_logger(o);
return std::nullopt;
});
options["NumaPolicy"] << Option("auto", [this](const Option& o) {
set_numa_config_from_option(o);
return numa_config_information_as_string() + "\n" + thread_binding_information_as_string();
});
options.add( //
"Debug Log File", Option("", [](const Option& o) {
start_logger(o);
return std::nullopt;
}));
options["Threads"] << Option(1, 1, 1024, [this](const Option&) {
resize_threads();
return thread_binding_information_as_string();
});
options.add( //
"NumaPolicy", Option("auto", [this](const Option& o) {
set_numa_config_from_option(o);
return numa_config_information_as_string() + "\n"
+ thread_allocation_information_as_string();
}));
options["Hash"] << Option(16, 1, MaxHashMB, [this](const Option& o) {
set_tt_size(o);
return std::nullopt;
});
options.add( //
"Threads", Option(1, 1, MaxThreads, [this](const Option&) {
resize_threads();
return thread_allocation_information_as_string();
}));
options["Clear Hash"] << Option([this](const Option&) {
search_clear();
return std::nullopt;
});
options["Ponder"] << Option(false);
options["MultiPV"] << Option(1, 1, MAX_MOVES);
options["Skill Level"] << Option(20, 0, 20);
options["Move Overhead"] << Option(10, 0, 5000);
options["nodestime"] << Option(0, 0, 10000);
options["UCI_Chess960"] << Option(false);
options["UCI_LimitStrength"] << Option(false);
options["UCI_Elo"] << Option(Stockfish::Search::Skill::LowestElo,
Stockfish::Search::Skill::LowestElo,
Stockfish::Search::Skill::HighestElo);
options["UCI_ShowWDL"] << Option(false);
options["SyzygyPath"] << Option("", [](const Option& o) {
Tablebases::init(o);
return std::nullopt;
});
options["SyzygyProbeDepth"] << Option(1, 1, 100);
options["Syzygy50MoveRule"] << Option(true);
options["SyzygyProbeLimit"] << Option(7, 0, 7);
options["EvalFile"] << Option(EvalFileDefaultNameBig, [this](const Option& o) {
load_big_network(o);
return std::nullopt;
});
options["EvalFileSmall"] << Option(EvalFileDefaultNameSmall, [this](const Option& o) {
load_small_network(o);
return std::nullopt;
});
options.add( //
"Hash", Option(16, 1, MaxHashMB, [this](const Option& o) {
set_tt_size(o);
return std::nullopt;
}));
options.add( //
"Clear Hash", Option([this](const Option&) {
search_clear();
return std::nullopt;
}));
options.add( //
"Ponder", Option(false));
options.add( //
"MultiPV", Option(1, 1, MAX_MOVES));
options.add("Skill Level", Option(20, 0, 20));
options.add("Move Overhead", Option(10, 0, 5000));
options.add("nodestime", Option(0, 0, 10000));
options.add("UCI_Chess960", Option(false));
options.add("UCI_LimitStrength", Option(false));
options.add("UCI_Elo",
Option(Stockfish::Search::Skill::LowestElo, Stockfish::Search::Skill::LowestElo,
Stockfish::Search::Skill::HighestElo));
options.add("UCI_ShowWDL", Option(false));
options.add( //
"SyzygyPath", Option("", [](const Option& o) {
Tablebases::init(o);
return std::nullopt;
}));
options.add("SyzygyProbeDepth", Option(1, 1, 100));
options.add("Syzygy50MoveRule", Option(true));
options.add("SyzygyProbeLimit", Option(7, 0, 7));
options.add( //
"EvalFile", Option(EvalFileDefaultNameBig, [this](const Option& o) {
load_big_network(o);
return std::nullopt;
}));
options.add( //
"EvalFileSmall", Option(EvalFileDefaultNameSmall, [this](const Option& o) {
load_small_network(o);
return std::nullopt;
}));
load_networks();
resize_threads();
@@ -124,7 +153,6 @@ std::uint64_t Engine::perft(const std::string& fen, Depth depth, bool isChess960
void Engine::go(Search::LimitsType& limits) {
assert(limits.perft == 0);
verify_networks();
limits.capSq = capSq;
threads.start_thinking(options, pos, states, limits);
}
@@ -156,6 +184,10 @@ void Engine::set_on_bestmove(std::function<void(std::string_view, std::string_vi
updateContext.onBestmove = std::move(f);
}
void Engine::set_on_verify_networks(std::function<void(std::string_view)>&& f) {
onVerifyNetworks = std::move(f);
}
void Engine::wait_for_search_finished() { threads.main_thread()->wait_for_search_finished(); }
void Engine::set_position(const std::string& fen, const std::vector<std::string>& moves) {
@@ -163,7 +195,6 @@ void Engine::set_position(const std::string& fen, const std::vector<std::string>
states = StateListPtr(new std::deque<StateInfo>(1));
pos.set(fen, options["UCI_Chess960"], &states->back());
capSq = SQ_NONE;
for (const auto& move : moves)
{
auto m = UCIEngine::to_move(pos, move);
@@ -173,11 +204,6 @@ void Engine::set_position(const std::string& fen, const std::vector<std::string>
states->emplace_back();
pos.do_move(m, states->back());
capSq = SQ_NONE;
DirtyPiece& dp = states->back().dirtyPiece;
if (dp.dirty_num > 1 && dp.to[1] == SQ_NONE)
capSq = m.to_sq();
}
}
@@ -226,8 +252,8 @@ void Engine::set_ponderhit(bool b) { threads.main_manager()->ponder = b; }
// network related
void Engine::verify_networks() const {
networks->big.verify(options["EvalFile"]);
networks->small.verify(options["EvalFileSmall"]);
networks->big.verify(options["EvalFile"], onVerifyNetworks);
networks->small.verify(options["EvalFileSmall"], onVerifyNetworks);
}
void Engine::load_networks() {
@@ -285,6 +311,8 @@ std::string Engine::visualize() const {
return ss.str();
}
int Engine::get_hashfull(int maxAge) const { return tt.hashfull(maxAge); }
std::vector<std::pair<size_t, size_t>> Engine::get_bound_thread_count_by_numa_node() const {
auto counts = threads.get_bound_thread_count_by_numa_node();
const NumaConfig& cfg = numaContext.get_numa_config();
@@ -310,15 +338,9 @@ std::string Engine::numa_config_information_as_string() const {
std::string Engine::thread_binding_information_as_string() const {
auto boundThreadsByNode = get_bound_thread_count_by_numa_node();
std::stringstream ss;
size_t threadsSize = threads.size();
ss << "Using " << threadsSize << (threadsSize > 1 ? " threads" : " thread");
if (boundThreadsByNode.empty())
return ss.str();
ss << " with NUMA node thread binding: ";
bool isFirst = true;
for (auto&& [current, total] : boundThreadsByNode)
@@ -332,4 +354,19 @@ std::string Engine::thread_binding_information_as_string() const {
return ss.str();
}
std::string Engine::thread_allocation_information_as_string() const {
std::stringstream ss;
size_t threadsSize = threads.size();
ss << "Using " << threadsSize << (threadsSize > 1 ? " threads" : " thread");
auto boundThreadsByNodeStr = thread_binding_information_as_string();
if (boundThreadsByNodeStr.empty())
return ss.str();
ss << " with NUMA node thread binding: ";
ss << boundThreadsByNodeStr;
return ss.str();
}
}
+8 -6
View File
@@ -1,6 +1,6 @@
/*
Stockfish, a UCI chess playing engine derived from Glaurung 2.1
Copyright (C) 2004-2024 The Stockfish developers (see AUTHORS file)
Copyright (C) 2004-2025 The Stockfish developers (see AUTHORS file)
Stockfish is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -39,15 +39,13 @@
namespace Stockfish {
enum Square : int;
class Engine {
public:
using InfoShort = Search::InfoShort;
using InfoFull = Search::InfoFull;
using InfoIter = Search::InfoIteration;
Engine(std::string path = "");
Engine(std::optional<std::string> path = std::nullopt);
// Cannot be movable due to components holding backreferences to fields
Engine(const Engine&) = delete;
@@ -81,6 +79,7 @@ class Engine {
void set_on_update_full(std::function<void(const InfoFull&)>&&);
void set_on_iter(std::function<void(const InfoIter&)>&&);
void set_on_bestmove(std::function<void(std::string_view, std::string_view)>&&);
void set_on_verify_networks(std::function<void(std::string_view)>&&);
// network related
@@ -97,12 +96,15 @@ class Engine {
const OptionsMap& get_options() const;
OptionsMap& get_options();
int get_hashfull(int maxAge = 0) const;
std::string fen() const;
void flip();
std::string visualize() const;
std::vector<std::pair<size_t, size_t>> get_bound_thread_count_by_numa_node() const;
std::string get_numa_config_as_string() const;
std::string numa_config_information_as_string() const;
std::string thread_allocation_information_as_string() const;
std::string thread_binding_information_as_string() const;
private:
@@ -112,14 +114,14 @@ class Engine {
Position pos;
StateListPtr states;
Square capSq;
OptionsMap options;
ThreadPool threads;
TranspositionTable tt;
LazyNumaReplicated<Eval::NNUE::Networks> networks;
Search::SearchManager::UpdateContext updateContext;
Search::SearchManager::UpdateContext updateContext;
std::function<void(std::string_view)> onVerifyNetworks;
};
} // namespace Stockfish
+17 -18
View File
@@ -1,6 +1,6 @@
/*
Stockfish, a UCI chess playing engine derived from Glaurung 2.1
Copyright (C) 2004-2024 The Stockfish developers (see AUTHORS file)
Copyright (C) 2004-2025 The Stockfish developers (see AUTHORS file)
Stockfish is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -54,37 +54,33 @@ bool Eval::use_smallnet(const Position& pos) {
// of the position from the point of view of the side to move.
Value Eval::evaluate(const Eval::NNUE::Networks& networks,
const Position& pos,
Eval::NNUE::AccumulatorStack& accumulators,
Eval::NNUE::AccumulatorCaches& caches,
int optimism) {
assert(!pos.checkers());
bool smallNet = use_smallnet(pos);
int v;
auto [psqt, positional] = smallNet ? networks.small.evaluate(pos, &caches.small)
: networks.big.evaluate(pos, &caches.big);
bool smallNet = use_smallnet(pos);
auto [psqt, positional] = smallNet ? networks.small.evaluate(pos, accumulators, &caches.small)
: networks.big.evaluate(pos, accumulators, &caches.big);
Value nnue = (125 * psqt + 131 * positional) / 128;
// Re-evaluate the position when higher eval accuracy is worth the time spent
if (smallNet && (nnue * psqt < 0 || std::abs(nnue) < 227))
if (smallNet && (std::abs(nnue) < 236))
{
std::tie(psqt, positional) = networks.big.evaluate(pos, &caches.big);
std::tie(psqt, positional) = networks.big.evaluate(pos, accumulators, &caches.big);
nnue = (125 * psqt + 131 * positional) / 128;
smallNet = false;
}
// Blend optimism and eval with nnue complexity
int nnueComplexity = std::abs(psqt - positional);
optimism += optimism * nnueComplexity / (smallNet ? 433 : 453);
nnue -= nnue * nnueComplexity / (smallNet ? 18815 : 17864);
optimism += optimism * nnueComplexity / 468;
nnue -= nnue * nnueComplexity / 18000;
int material = (smallNet ? 553 : 532) * pos.count<PAWN>() + pos.non_pawn_material();
v = (nnue * (73921 + material) + optimism * (8112 + material)) / (smallNet ? 68104 : 74715);
// Evaluation grain (to get more alpha-beta cuts) with randomization (for robustness)
v = (v / 16) * 16 - 1 + (pos.key() & 0x2);
int material = 535 * pos.count<PAWN>() + pos.non_pawn_material();
int v = (nnue * (77777 + material) + optimism * (7777 + material)) / 77777;
// Damp down the evaluation linearly when shuffling
v -= v * pos.rule50_count() / 212;
@@ -104,7 +100,10 @@ std::string Eval::trace(Position& pos, const Eval::NNUE::Networks& networks) {
if (pos.checkers())
return "Final evaluation: none (in check)";
auto caches = std::make_unique<Eval::NNUE::AccumulatorCaches>(networks);
Eval::NNUE::AccumulatorStack accumulators;
auto caches = std::make_unique<Eval::NNUE::AccumulatorCaches>(networks);
accumulators.reset(pos, networks, *caches);
std::stringstream ss;
ss << std::showpoint << std::noshowpos << std::fixed << std::setprecision(2);
@@ -112,12 +111,12 @@ std::string Eval::trace(Position& pos, const Eval::NNUE::Networks& networks) {
ss << std::showpoint << std::showpos << std::fixed << std::setprecision(2) << std::setw(15);
auto [psqt, positional] = networks.big.evaluate(pos, &caches->big);
auto [psqt, positional] = networks.big.evaluate(pos, accumulators, &caches->big);
Value v = psqt + positional;
v = pos.side_to_move() == WHITE ? v : -v;
ss << "NNUE evaluation " << 0.01 * UCIEngine::to_cp(v, pos) << " (white side)\n";
v = evaluate(networks, pos, *caches, VALUE_ZERO);
v = evaluate(networks, pos, accumulators, *caches, VALUE_ZERO);
v = pos.side_to_move() == WHITE ? v : -v;
ss << "Final evaluation " << 0.01 * UCIEngine::to_cp(v, pos) << " (white side)";
ss << " [with scaled NNUE, ...]";
+4 -2
View File
@@ -1,6 +1,6 @@
/*
Stockfish, a UCI chess playing engine derived from Glaurung 2.1
Copyright (C) 2004-2024 The Stockfish developers (see AUTHORS file)
Copyright (C) 2004-2025 The Stockfish developers (see AUTHORS file)
Stockfish is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -33,12 +33,13 @@ namespace Eval {
// for the build process (profile-build and fishtest) to work. Do not change the
// name of the macro or the location where this macro is defined, as it is used
// in the Makefile/Fishtest.
#define EvalFileDefaultNameBig "nn-1111cefa1111.nnue"
#define EvalFileDefaultNameBig "nn-1c0000000000.nnue"
#define EvalFileDefaultNameSmall "nn-37f18f62d772.nnue"
namespace NNUE {
struct Networks;
struct AccumulatorCaches;
class AccumulatorStack;
}
std::string trace(Position& pos, const Eval::NNUE::Networks& networks);
@@ -47,6 +48,7 @@ int simple_eval(const Position& pos, Color c);
bool use_smallnet(const Position& pos);
Value evaluate(const NNUE::Networks& networks,
const Position& pos,
Eval::NNUE::AccumulatorStack& accumulators,
Eval::NNUE::AccumulatorCaches& caches,
int optimism);
} // namespace Eval
+171
View File
@@ -0,0 +1,171 @@
/*
Stockfish, a UCI chess playing engine derived from Glaurung 2.1
Copyright (C) 2004-2025 The Stockfish developers (see AUTHORS file)
Stockfish is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
Stockfish is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef HISTORY_H_INCLUDED
#define HISTORY_H_INCLUDED
#include <algorithm>
#include <array>
#include <cassert>
#include <cmath>
#include <cstdint>
#include <cstdlib>
#include <limits>
#include <type_traits> // IWYU pragma: keep
#include "misc.h"
#include "position.h"
namespace Stockfish {
constexpr int PAWN_HISTORY_SIZE = 512; // has to be a power of 2
constexpr int CORRECTION_HISTORY_SIZE = 32768; // has to be a power of 2
constexpr int CORRECTION_HISTORY_LIMIT = 1024;
constexpr int LOW_PLY_HISTORY_SIZE = 4;
static_assert((PAWN_HISTORY_SIZE & (PAWN_HISTORY_SIZE - 1)) == 0,
"PAWN_HISTORY_SIZE has to be a power of 2");
static_assert((CORRECTION_HISTORY_SIZE & (CORRECTION_HISTORY_SIZE - 1)) == 0,
"CORRECTION_HISTORY_SIZE has to be a power of 2");
enum PawnHistoryType {
Normal,
Correction
};
template<PawnHistoryType T = Normal>
inline int pawn_structure_index(const Position& pos) {
return pos.pawn_key() & ((T == Normal ? PAWN_HISTORY_SIZE : CORRECTION_HISTORY_SIZE) - 1);
}
inline int minor_piece_index(const Position& pos) {
return pos.minor_piece_key() & (CORRECTION_HISTORY_SIZE - 1);
}
template<Color c>
inline int non_pawn_index(const Position& pos) {
return pos.non_pawn_key(c) & (CORRECTION_HISTORY_SIZE - 1);
}
// StatsEntry is the container of various numerical statistics. We use a class
// instead of a naked value to directly call history update operator<<() on
// the entry. The first template parameter T is the base type of the array,
// and the second template parameter D limits the range of updates in [-D, D]
// when we update values with the << operator
template<typename T, int D>
class StatsEntry {
static_assert(std::is_arithmetic_v<T>, "Not an arithmetic type");
static_assert(D <= std::numeric_limits<T>::max(), "D overflows T");
T entry;
public:
StatsEntry& operator=(const T& v) {
entry = v;
return *this;
}
operator const T&() const { return entry; }
void operator<<(int bonus) {
// Make sure that bonus is in range [-D, D]
int clampedBonus = std::clamp(bonus, -D, D);
entry += clampedBonus - entry * std::abs(clampedBonus) / D;
assert(std::abs(entry) <= D);
}
};
enum StatsType {
NoCaptures,
Captures
};
template<typename T, int D, std::size_t... Sizes>
using Stats = MultiArray<StatsEntry<T, D>, Sizes...>;
// ButterflyHistory records how often quiet moves have been successful or unsuccessful
// during the current search, and is used for reduction and move ordering decisions.
// It uses 2 tables (one for each color) indexed by the move's from and to squares,
// see https://www.chessprogramming.org/Butterfly_Boards (~11 elo)
using ButterflyHistory = Stats<std::int16_t, 7183, COLOR_NB, int(SQUARE_NB) * int(SQUARE_NB)>;
// LowPlyHistory is adressed by play and move's from and to squares, used
// to improve move ordering near the root
using LowPlyHistory =
Stats<std::int16_t, 7183, LOW_PLY_HISTORY_SIZE, int(SQUARE_NB) * int(SQUARE_NB)>;
// CapturePieceToHistory is addressed by a move's [piece][to][captured piece type]
using CapturePieceToHistory = Stats<std::int16_t, 10692, PIECE_NB, SQUARE_NB, PIECE_TYPE_NB>;
// PieceToHistory is like ButterflyHistory but is addressed by a move's [piece][to]
using PieceToHistory = Stats<std::int16_t, 30000, PIECE_NB, SQUARE_NB>;
// ContinuationHistory is the combined history of a given pair of moves, usually
// the current one given a previous one. The nested history table is based on
// PieceToHistory instead of ButterflyBoards.
// (~63 elo)
using ContinuationHistory = MultiArray<PieceToHistory, PIECE_NB, SQUARE_NB>;
// PawnHistory is addressed by the pawn structure and a move's [piece][to]
using PawnHistory = Stats<std::int16_t, 8192, PAWN_HISTORY_SIZE, PIECE_NB, SQUARE_NB>;
// Correction histories record differences between the static evaluation of
// positions and their search score. It is used to improve the static evaluation
// used by some search heuristics.
// see https://www.chessprogramming.org/Static_Evaluation_Correction_History
enum CorrHistType {
Pawn, // By color and pawn structure
Minor, // By color and positions of minor pieces (Knight, Bishop)
NonPawn, // By non-pawn material positions and color
PieceTo, // By [piece][to] move
Continuation, // Combined history of move pairs
};
namespace Detail {
template<CorrHistType>
struct CorrHistTypedef {
using type = Stats<std::int16_t, CORRECTION_HISTORY_LIMIT, CORRECTION_HISTORY_SIZE, COLOR_NB>;
};
template<>
struct CorrHistTypedef<PieceTo> {
using type = Stats<std::int16_t, CORRECTION_HISTORY_LIMIT, PIECE_NB, SQUARE_NB>;
};
template<>
struct CorrHistTypedef<Continuation> {
using type = MultiArray<CorrHistTypedef<PieceTo>::type, PIECE_NB, SQUARE_NB>;
};
template<>
struct CorrHistTypedef<NonPawn> {
using type =
Stats<std::int16_t, CORRECTION_HISTORY_LIMIT, CORRECTION_HISTORY_SIZE, COLOR_NB, COLOR_NB>;
};
}
template<CorrHistType T>
using CorrectionHistory = typename Detail::CorrHistTypedef<T>::type;
} // namespace Stockfish
#endif // #ifndef HISTORY_H_INCLUDED
+167 -59
View File
@@ -3,8 +3,8 @@
* @author Dale Weiler
* @brief Utility for including binary files
*
* Facilities for including binary files into the current translation unit
* and making use of them externally in other translation units.
* Facilities for including binary files into the current translation unit and
* making use from them externally in other translation units.
*/
#ifndef INCBIN_HDR
#define INCBIN_HDR
@@ -26,7 +26,9 @@
defined(__SSSE3__) || \
defined(__SSE4_1__) || \
defined(__SSE4_2__) || \
defined(__neon__)
defined(__neon__) || \
defined(__ARM_NEON) || \
defined(__ALTIVEC__)
# define INCBIN_ALIGNMENT_INDEX 4
#elif ULONG_MAX != 0xffffffffu
# define INCBIN_ALIGNMENT_INDEX 3
@@ -64,6 +66,9 @@
X
#define INCBIN_INVOKE(N, ...) \
INCBIN_EVAL(N(__VA_ARGS__))
/* Variable argument count for overloading by arity */
#define INCBIN_VA_ARG_COUNTER(_1, _2, _3, N, ...) N
#define INCBIN_VA_ARGC(...) INCBIN_VA_ARG_COUNTER(__VA_ARGS__, 3, 2, 1, 0)
/* Green Hills uses a different directive for including binary data */
#if defined(__ghs__)
@@ -117,29 +122,50 @@
#endif
/**
* @brief Optionally override the linker section into which data is emitted.
*
* @warning If you use this facility, you'll have to deal with platform-specific linker output
* section naming on your own
*
* Overriding the default linker output section, e.g for esp8266/Arduino:
* @code
* #define INCBIN_OUTPUT_SECTION ".irom.text"
* #include "incbin.h"
* INCBIN(Foo, "foo.txt");
* // Data is emitted into program memory that never gets copied to RAM
* @endcode
* @brief Optionally override the linker section into which size and data is
* emitted.
*
* @warning If you use this facility, you might have to deal with
* platform-specific linker output section naming on your own.
*/
#if !defined(INCBIN_OUTPUT_SECTION)
# if defined(__APPLE__)
# define INCBIN_OUTPUT_SECTION ".const_data"
# define INCBIN_OUTPUT_SECTION ".const_data"
# else
# define INCBIN_OUTPUT_SECTION ".rodata"
# define INCBIN_OUTPUT_SECTION ".rodata"
# endif
#endif
/**
* @brief Optionally override the linker section into which data is emitted.
*
* @warning If you use this facility, you might have to deal with
* platform-specific linker output section naming on your own.
*/
#if !defined(INCBIN_OUTPUT_DATA_SECTION)
# define INCBIN_OUTPUT_DATA_SECTION INCBIN_OUTPUT_SECTION
#endif
/**
* @brief Optionally override the linker section into which size is emitted.
*
* @warning If you use this facility, you might have to deal with
* platform-specific linker output section naming on your own.
*
* @note This is useful for Harvard architectures where program memory cannot
* be directly read from the program without special instructions. With this you
* can chose to put the size variable in RAM rather than ROM.
*/
#if !defined(INCBIN_OUTPUT_SIZE_SECTION)
# define INCBIN_OUTPUT_SIZE_SECTION INCBIN_OUTPUT_SECTION
#endif
#if defined(__APPLE__)
/* The directives are different for Apple-branded compilers */
# include "TargetConditionals.h"
# if defined(TARGET_OS_IPHONE) && !defined(INCBIN_SILENCE_BITCODE_WARNING)
# warning "incbin is incompatible with bitcode. Using the library will break upload to App Store if you have bitcode enabled. Add `#define INCBIN_SILENCE_BITCODE_WARNING` before including this header to silence this warning."
# endif
/* The directives are different for Apple branded compilers */
# define INCBIN_SECTION INCBIN_OUTPUT_SECTION "\n"
# define INCBIN_GLOBAL(NAME) ".globl " INCBIN_MANGLE INCBIN_STRINGIZE(INCBIN_PREFIX) #NAME "\n"
# define INCBIN_INT ".long "
@@ -179,27 +205,17 @@
/**
* @brief Specify the prefix to use for symbol names.
*
* By default this is `g', producing symbols of the form:
* @code
* #include "incbin.h"
* INCBIN(Foo, "foo.txt");
* @note By default this is "g".
*
* // Now you have the following symbols:
* // const unsigned char gFooData[];
* // const unsigned char *const gFooEnd;
* // const unsigned int gFooSize;
* @endcode
*
* If however you specify a prefix before including: e.g:
* @code
* #define INCBIN_PREFIX incbin
* #include "incbin.h"
* INCBIN(Foo, "foo.txt");
*
* // Now you have the following symbols instead:
* // const unsigned char incbinFooData[];
* // const unsigned char *const incbinFooEnd;
* // const unsigned int incbinFooSize;
* // const unsigned char incbinFoo<data>[];
* // const unsigned char *const incbinFoo<end>;
* // const unsigned int incbinFoo<size>;
* @endcode
*/
#if !defined(INCBIN_PREFIX)
@@ -213,18 +229,8 @@
* - INCBIN_STYLE_CAMEL "CamelCase"
* - INCBIN_STYLE_SNAKE "snake_case"
*
* Default option is *INCBIN_STYLE_CAMEL* producing symbols of the form:
* @code
* #include "incbin.h"
* INCBIN(Foo, "foo.txt");
* @note By default this is INCBIN_STYLE_CAMEL
*
* // Now you have the following symbols:
* // const unsigned char <prefix>FooData[];
* // const unsigned char *const <prefix>FooEnd;
* // const unsigned int <prefix>FooSize;
* @endcode
*
* If however you specify a style before including: e.g:
* @code
* #define INCBIN_STYLE INCBIN_STYLE_SNAKE
* #include "incbin.h"
@@ -261,8 +267,8 @@
INCBIN_STRINGIZE( \
INCBIN_STYLE_IDENT(TYPE)) \
/* Generate the global labels by indirectly invoking the macro
* with our style type and concatenate the name against them. */
/* Generate the global labels by indirectly invoking the macro with our style
* type and concatenating the name against them. */
#define INCBIN_GLOBAL_LABELS(NAME, TYPE) \
INCBIN_INVOKE( \
INCBIN_GLOBAL, \
@@ -288,23 +294,38 @@
* The symbol names are a concatenation of `INCBIN_PREFIX' before *NAME*; with
* "Data", as well as "End" and "Size" after. An example is provided below.
*
* @param TYPE Optional array type. Omitting this picks a default of `unsigned char`.
* @param NAME The name given for the binary data
*
* @code
* INCBIN_EXTERN(Foo);
*
* // Now you have the following symbols:
* // extern const unsigned char <prefix>FooData[];
* // extern const unsigned char *const <prefix>FooEnd;
* // extern const unsigned int <prefix>FooSize;
* // extern const unsigned char <prefix>Foo<data>[];
* // extern const unsigned char *const <prefix>Foo<end>;
* // extern const unsigned int <prefix>Foo<size>;
* @endcode
*
* You may specify a custom optional data type as well as the first argument.
* @code
* INCBIN_EXTERN(custom_type, Foo);
*
* // Now you have the following symbols:
* // extern const custom_type <prefix>Foo<data>[];
* // extern const custom_type *const <prefix>Foo<end>;
* // extern const unsigned int <prefix>Foo<size>;
* @endcode
*/
#define INCBIN_EXTERN(NAME) \
INCBIN_EXTERNAL const INCBIN_ALIGN unsigned char \
#define INCBIN_EXTERN(...) \
INCBIN_CONCATENATE(INCBIN_EXTERN_, INCBIN_VA_ARGC(__VA_ARGS__))(__VA_ARGS__)
#define INCBIN_EXTERN_1(NAME, ...) \
INCBIN_EXTERN_2(unsigned char, NAME)
#define INCBIN_EXTERN_2(TYPE, NAME) \
INCBIN_EXTERNAL const INCBIN_ALIGN TYPE \
INCBIN_CONCATENATE( \
INCBIN_CONCATENATE(INCBIN_PREFIX, NAME), \
INCBIN_STYLE_IDENT(DATA))[]; \
INCBIN_EXTERNAL const INCBIN_ALIGN unsigned char *const \
INCBIN_EXTERNAL const INCBIN_ALIGN TYPE *const \
INCBIN_CONCATENATE( \
INCBIN_CONCATENATE(INCBIN_PREFIX, NAME), \
INCBIN_STYLE_IDENT(END)); \
@@ -313,6 +334,29 @@
INCBIN_CONCATENATE(INCBIN_PREFIX, NAME), \
INCBIN_STYLE_IDENT(SIZE))
/**
* @brief Externally reference textual data included in another translation unit.
*
* Produces three external symbols that reference the textual data included in
* another translation unit.
*
* The symbol names are a concatenation of `INCBIN_PREFIX' before *NAME*; with
* "Data", as well as "End" and "Size" after. An example is provided below.
*
* @param NAME The name given for the textual data
*
* @code
* INCBIN_EXTERN(Foo);
*
* // Now you have the following symbols:
* // extern const char <prefix>Foo<data>[];
* // extern const char *const <prefix>Foo<end>;
* // extern const unsigned int <prefix>Foo<size>;
* @endcode
*/
#define INCTXT_EXTERN(NAME) \
INCBIN_EXTERN_2(char, NAME)
/**
* @brief Include a binary file into the current translation unit.
*
@@ -322,6 +366,7 @@
* The symbol names are a concatenation of `INCBIN_PREFIX' before *NAME*; with
* "Data", as well as "End" and "Size" after. An example is provided below.
*
* @param TYPE Optional array type. Omitting this picks a default of `unsigned char`.
* @param NAME The name to associate with this binary data (as an identifier.)
* @param FILENAME The file to include (as a string literal.)
*
@@ -329,9 +374,20 @@
* INCBIN(Icon, "icon.png");
*
* // Now you have the following symbols:
* // const unsigned char <prefix>IconData[];
* // const unsigned char *const <prefix>IconEnd;
* // const unsigned int <prefix>IconSize;
* // const unsigned char <prefix>Icon<data>[];
* // const unsigned char *const <prefix>Icon<end>;
* // const unsigned int <prefix>Icon<size>;
* @endcode
*
* You may specify a custom optional data type as well as the first argument.
* These macros are specialized by arity.
* @code
* INCBIN(custom_type, Icon, "icon.png");
*
* // Now you have the following symbols:
* // const custom_type <prefix>Icon<data>[];
* // const custom_type *const <prefix>Icon<end>;
* // const unsigned int <prefix>Icon<size>;
* @endcode
*
* @warning This must be used in global scope
@@ -341,15 +397,28 @@
* please @see INCBIN_EXTERN.
*/
#ifdef _MSC_VER
#define INCBIN(NAME, FILENAME) \
INCBIN_EXTERN(NAME)
# define INCBIN(NAME, FILENAME) \
INCBIN_EXTERN(NAME)
#else
#define INCBIN(NAME, FILENAME) \
# define INCBIN(...) \
INCBIN_CONCATENATE(INCBIN_, INCBIN_VA_ARGC(__VA_ARGS__))(__VA_ARGS__)
# if defined(__GNUC__)
# define INCBIN_1(...) _Pragma("GCC error \"Single argument INCBIN not allowed\"")
# elif defined(__clang__)
# define INCBIN_1(...) _Pragma("clang error \"Single argument INCBIN not allowed\"")
# else
# define INCBIN_1(...) /* Cannot do anything here */
# endif
# define INCBIN_2(NAME, FILENAME) \
INCBIN_3(unsigned char, NAME, FILENAME)
# define INCBIN_3(TYPE, NAME, FILENAME) INCBIN_COMMON(TYPE, NAME, FILENAME, /* No terminator for binary data */)
# define INCBIN_COMMON(TYPE, NAME, FILENAME, TERMINATOR) \
__asm__(INCBIN_SECTION \
INCBIN_GLOBAL_LABELS(NAME, DATA) \
INCBIN_ALIGN_HOST \
INCBIN_MANGLE INCBIN_STRINGIZE(INCBIN_PREFIX) #NAME INCBIN_STYLE_STRING(DATA) ":\n" \
INCBIN_MACRO " \"" FILENAME "\"\n" \
TERMINATOR \
INCBIN_GLOBAL_LABELS(NAME, END) \
INCBIN_ALIGN_BYTE \
INCBIN_MANGLE INCBIN_STRINGIZE(INCBIN_PREFIX) #NAME INCBIN_STYLE_STRING(END) ":\n" \
@@ -362,7 +431,46 @@
INCBIN_ALIGN_HOST \
".text\n" \
); \
INCBIN_EXTERN(NAME)
INCBIN_EXTERN(TYPE, NAME)
#endif
/**
* @brief Include a textual file into the current translation unit.
*
* This behaves the same as INCBIN except it produces char compatible arrays
* and implicitly adds a null-terminator byte, thus the size of data included
* by this is one byte larger than that of INCBIN.
*
* Includes a textual file into the current translation unit, producing three
* symbols for objects that encode the data and size respectively.
*
* The symbol names are a concatenation of `INCBIN_PREFIX' before *NAME*; with
* "Data", as well as "End" and "Size" after. An example is provided below.
*
* @param NAME The name to associate with this binary data (as an identifier.)
* @param FILENAME The file to include (as a string literal.)
*
* @code
* INCTXT(Readme, "readme.txt");
*
* // Now you have the following symbols:
* // const char <prefix>Readme<data>[];
* // const char *const <prefix>Readme<end>;
* // const unsigned int <prefix>Readme<size>;
* @endcode
*
* @warning This must be used in global scope
* @warning The identifiers may be different if INCBIN_STYLE is not default
*
* To externally reference the data included by this in another translation unit
* please @see INCBIN_EXTERN.
*/
#if defined(_MSC_VER)
# define INCTXT(NAME, FILENAME) \
INCBIN_EXTERN(NAME)
#else
# define INCTXT(NAME, FILENAME) \
INCBIN_COMMON(char, NAME, FILENAME, INCBIN_BYTE "0\n")
#endif
#endif
#endif
+1 -1
View File
@@ -1,6 +1,6 @@
/*
Stockfish, a UCI chess playing engine derived from Glaurung 2.1
Copyright (C) 2004-2024 The Stockfish developers (see AUTHORS file)
Copyright (C) 2004-2025 The Stockfish developers (see AUTHORS file)
Stockfish is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
+32 -1
View File
@@ -1,6 +1,6 @@
/*
Stockfish, a UCI chess playing engine derived from Glaurung 2.1
Copyright (C) 2004-2024 The Stockfish developers (see AUTHORS file)
Copyright (C) 2004-2025 The Stockfish developers (see AUTHORS file)
Stockfish is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -212,6 +212,37 @@ void* aligned_large_pages_alloc(size_t allocSize) {
#endif
bool has_large_pages() {
#if defined(_WIN32)
constexpr size_t page_size = 2 * 1024 * 1024; // 2MB page size assumed
void* mem = aligned_large_pages_alloc_windows(page_size);
if (mem == nullptr)
{
return false;
}
else
{
aligned_large_pages_free(mem);
return true;
}
#elif defined(__linux__)
#if defined(MADV_HUGEPAGE)
return true;
#else
return false;
#endif
#else
return false;
#endif
}
// aligned_large_pages_free() will free the previously memory allocated
// by aligned_large_pages_alloc(). The effect is a nop if mem == nullptr.
+3 -1
View File
@@ -1,6 +1,6 @@
/*
Stockfish, a UCI chess playing engine derived from Glaurung 2.1
Copyright (C) 2004-2024 The Stockfish developers (see AUTHORS file)
Copyright (C) 2004-2025 The Stockfish developers (see AUTHORS file)
Stockfish is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -38,6 +38,8 @@ void std_aligned_free(void* ptr);
void* aligned_large_pages_alloc(size_t size);
void aligned_large_pages_free(void* mem);
bool has_large_pages();
// Frees memory which was placed there with placement new.
// Works for both single objects and arrays of unknown bound.
template<typename T, typename FREE_FUNC>
+52 -31
View File
@@ -1,6 +1,6 @@
/*
Stockfish, a UCI chess playing engine derived from Glaurung 2.1
Copyright (C) 2004-2024 The Stockfish developers (see AUTHORS file)
Copyright (C) 2004-2025 The Stockfish developers (see AUTHORS file)
Stockfish is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -18,7 +18,9 @@
#include "misc.h"
#include <array>
#include <atomic>
#include <cassert>
#include <cctype>
#include <cmath>
#include <cstdlib>
@@ -38,7 +40,7 @@ namespace Stockfish {
namespace {
// Version number or dev.
constexpr std::string_view version = "17";
constexpr std::string_view version = "17.1";
// Our fancy logging facility. The trick here is to replace cin.rdbuf() and
// cout.rdbuf() with two Tie objects that tie cin and cout to a file stream. We
@@ -122,7 +124,7 @@ class Logger {
//
// For releases (non-dev builds) we only include the version number:
// Stockfish version
std::string engine_info(bool to_uci) {
std::string engine_version_info() {
std::stringstream ss;
ss << "Stockfish " << version << std::setfill('0');
@@ -151,11 +153,14 @@ std::string engine_info(bool to_uci) {
#endif
}
ss << (to_uci ? "\nid author " : " by ") << "the Stockfish developers (see AUTHORS file)";
return ss.str();
}
std::string engine_info(bool to_uci) {
return engine_version_info() + (to_uci ? "\nid author " : " by ")
+ "the Stockfish developers (see AUTHORS file)";
}
// Returns a string trying to describe the compiler we use
std::string compiler_info() {
@@ -282,9 +287,18 @@ namespace {
template<size_t N>
struct DebugInfo {
std::atomic<int64_t> data[N] = {0};
std::array<std::atomic<int64_t>, N> data = {0};
constexpr std::atomic<int64_t>& operator[](int index) { return data[index]; }
[[nodiscard]] constexpr std::atomic<int64_t>& operator[](size_t index) {
assert(index < N);
return data[index];
}
constexpr DebugInfo& operator=(const DebugInfo& other) {
for (size_t i = 0; i < N; i++)
data[i].store(other.data[i].load());
return *this;
}
};
struct DebugExtremes: public DebugInfo<3> {
@@ -294,54 +308,54 @@ struct DebugExtremes: public DebugInfo<3> {
}
};
DebugInfo<2> hit[MaxDebugSlots];
DebugInfo<2> mean[MaxDebugSlots];
DebugInfo<3> stdev[MaxDebugSlots];
DebugInfo<6> correl[MaxDebugSlots];
DebugExtremes extremes[MaxDebugSlots];
std::array<DebugInfo<2>, MaxDebugSlots> hit;
std::array<DebugInfo<2>, MaxDebugSlots> mean;
std::array<DebugInfo<3>, MaxDebugSlots> stdev;
std::array<DebugInfo<6>, MaxDebugSlots> correl;
std::array<DebugExtremes, MaxDebugSlots> extremes;
} // namespace
void dbg_hit_on(bool cond, int slot) {
++hit[slot][0];
++hit.at(slot)[0];
if (cond)
++hit[slot][1];
++hit.at(slot)[1];
}
void dbg_mean_of(int64_t value, int slot) {
++mean[slot][0];
mean[slot][1] += value;
++mean.at(slot)[0];
mean.at(slot)[1] += value;
}
void dbg_stdev_of(int64_t value, int slot) {
++stdev[slot][0];
stdev[slot][1] += value;
stdev[slot][2] += value * value;
++stdev.at(slot)[0];
stdev.at(slot)[1] += value;
stdev.at(slot)[2] += value * value;
}
void dbg_extremes_of(int64_t value, int slot) {
++extremes[slot][0];
++extremes.at(slot)[0];
int64_t current_max = extremes[slot][1].load();
while (current_max < value && !extremes[slot][1].compare_exchange_weak(current_max, value))
int64_t current_max = extremes.at(slot)[1].load();
while (current_max < value && !extremes.at(slot)[1].compare_exchange_weak(current_max, value))
{}
int64_t current_min = extremes[slot][2].load();
while (current_min > value && !extremes[slot][2].compare_exchange_weak(current_min, value))
int64_t current_min = extremes.at(slot)[2].load();
while (current_min > value && !extremes.at(slot)[2].compare_exchange_weak(current_min, value))
{}
}
void dbg_correl_of(int64_t value1, int64_t value2, int slot) {
++correl[slot][0];
correl[slot][1] += value1;
correl[slot][2] += value1 * value1;
correl[slot][3] += value2;
correl[slot][4] += value2 * value2;
correl[slot][5] += value1 * value2;
++correl.at(slot)[0];
correl.at(slot)[1] += value1;
correl.at(slot)[2] += value1 * value1;
correl.at(slot)[3] += value2;
correl.at(slot)[4] += value2 * value2;
correl.at(slot)[5] += value1 * value2;
}
void dbg_print() {
@@ -385,6 +399,13 @@ void dbg_print() {
}
}
void dbg_clear() {
hit.fill({});
mean.fill({});
stdev.fill({});
correl.fill({});
extremes.fill({});
}
// Used to serialize access to std::cout
// to avoid multiple threads writing at the same time.
@@ -451,7 +472,7 @@ void remove_whitespace(std::string& s) {
s.erase(std::remove_if(s.begin(), s.end(), [](char c) { return std::isspace(c); }), s.end());
}
bool is_whitespace(const std::string& s) {
bool is_whitespace(std::string_view s) {
return std::all_of(s.begin(), s.end(), [](char c) { return std::isspace(c); });
}
+101 -9
View File
@@ -1,6 +1,6 @@
/*
Stockfish, a UCI chess playing engine derived from Glaurung 2.1
Copyright (C) 2004-2024 The Stockfish developers (see AUTHORS file)
Copyright (C) 2004-2025 The Stockfish developers (see AUTHORS file)
Stockfish is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -20,6 +20,7 @@
#define MISC_H_INCLUDED
#include <algorithm>
#include <array>
#include <cassert>
#include <chrono>
#include <cstddef>
@@ -28,6 +29,7 @@
#include <iosfwd>
#include <optional>
#include <string>
#include <string_view>
#include <vector>
#define stringify2(x) #x
@@ -35,6 +37,7 @@
namespace Stockfish {
std::string engine_version_info();
std::string engine_info(bool to_uci = false);
std::string compiler_info();
@@ -70,6 +73,7 @@ void dbg_stdev_of(int64_t value, int slot = 0);
void dbg_extremes_of(int64_t value, int slot = 0);
void dbg_correl_of(int64_t value1, int64_t value2, int slot = 0);
void dbg_print();
void dbg_clear();
using TimePoint = std::chrono::milliseconds::rep; // A value in milliseconds
static_assert(sizeof(TimePoint) == sizeof(int64_t), "TimePoint should be 64 bits");
@@ -79,8 +83,8 @@ inline TimePoint now() {
.count();
}
inline std::vector<std::string> split(const std::string& s, const std::string& delimiter) {
std::vector<std::string> res;
inline std::vector<std::string_view> split(std::string_view s, std::string_view delimiter) {
std::vector<std::string_view> res;
if (s.empty())
return res;
@@ -102,7 +106,7 @@ inline std::vector<std::string> split(const std::string& s, const std::string& d
}
void remove_whitespace(std::string& s);
bool is_whitespace(const std::string& s);
bool is_whitespace(std::string_view s);
enum SyncCout {
IO_LOCK,
@@ -117,11 +121,8 @@ void sync_cout_start();
void sync_cout_end();
// True if and only if the binary is compiled on a little-endian machine
static inline const union {
uint32_t i;
char c[4];
} Le = {0x01020304};
static inline const bool IsLittleEndian = (Le.c[0] == 4);
static inline const std::uint16_t Le = 1;
static inline const bool IsLittleEndian = *reinterpret_cast<const char*>(&Le) == 1;
template<typename T, std::size_t MaxSize>
@@ -140,6 +141,97 @@ class ValueList {
};
template<typename T, std::size_t Size, std::size_t... Sizes>
class MultiArray;
namespace Detail {
template<typename T, std::size_t Size, std::size_t... Sizes>
struct MultiArrayHelper {
using ChildType = MultiArray<T, Sizes...>;
};
template<typename T, std::size_t Size>
struct MultiArrayHelper<T, Size> {
using ChildType = T;
};
template<typename To, typename From>
constexpr bool is_strictly_assignable_v =
std::is_assignable_v<To&, From> && (std::is_same_v<To, From> || !std::is_convertible_v<From, To>);
}
// MultiArray is a generic N-dimensional array.
// The template parameters (Size and Sizes) encode the dimensions of the array.
template<typename T, std::size_t Size, std::size_t... Sizes>
class MultiArray {
using ChildType = typename Detail::MultiArrayHelper<T, Size, Sizes...>::ChildType;
using ArrayType = std::array<ChildType, Size>;
ArrayType data_;
public:
using value_type = typename ArrayType::value_type;
using size_type = typename ArrayType::size_type;
using difference_type = typename ArrayType::difference_type;
using reference = typename ArrayType::reference;
using const_reference = typename ArrayType::const_reference;
using pointer = typename ArrayType::pointer;
using const_pointer = typename ArrayType::const_pointer;
using iterator = typename ArrayType::iterator;
using const_iterator = typename ArrayType::const_iterator;
using reverse_iterator = typename ArrayType::reverse_iterator;
using const_reverse_iterator = typename ArrayType::const_reverse_iterator;
constexpr auto& at(size_type index) noexcept { return data_.at(index); }
constexpr const auto& at(size_type index) const noexcept { return data_.at(index); }
constexpr auto& operator[](size_type index) noexcept { return data_[index]; }
constexpr const auto& operator[](size_type index) const noexcept { return data_[index]; }
constexpr auto& front() noexcept { return data_.front(); }
constexpr const auto& front() const noexcept { return data_.front(); }
constexpr auto& back() noexcept { return data_.back(); }
constexpr const auto& back() const noexcept { return data_.back(); }
auto* data() { return data_.data(); }
const auto* data() const { return data_.data(); }
constexpr auto begin() noexcept { return data_.begin(); }
constexpr auto end() noexcept { return data_.end(); }
constexpr auto begin() const noexcept { return data_.begin(); }
constexpr auto end() const noexcept { return data_.end(); }
constexpr auto cbegin() const noexcept { return data_.cbegin(); }
constexpr auto cend() const noexcept { return data_.cend(); }
constexpr auto rbegin() noexcept { return data_.rbegin(); }
constexpr auto rend() noexcept { return data_.rend(); }
constexpr auto rbegin() const noexcept { return data_.rbegin(); }
constexpr auto rend() const noexcept { return data_.rend(); }
constexpr auto crbegin() const noexcept { return data_.crbegin(); }
constexpr auto crend() const noexcept { return data_.crend(); }
constexpr bool empty() const noexcept { return data_.empty(); }
constexpr size_type size() const noexcept { return data_.size(); }
constexpr size_type max_size() const noexcept { return data_.max_size(); }
template<typename U>
void fill(const U& v) {
static_assert(Detail::is_strictly_assignable_v<T, U>,
"Cannot assign fill value to entry type");
for (auto& ele : data_)
{
if constexpr (sizeof...(Sizes) == 0)
ele = v;
else
ele.fill(v);
}
}
constexpr void swap(MultiArray<T, Size, Sizes...>& other) noexcept { data_.swap(other.data_); }
};
// xorshift64star Pseudo-Random Number Generator
// This class is based on original code written and dedicated
// to the public domain by Sebastiano Vigna (2014).
+1 -1
View File
@@ -1,6 +1,6 @@
/*
Stockfish, a UCI chess playing engine derived from Glaurung 2.1
Copyright (C) 2004-2024 The Stockfish developers (see AUTHORS file)
Copyright (C) 2004-2025 The Stockfish developers (see AUTHORS file)
Stockfish is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
+1 -1
View File
@@ -1,6 +1,6 @@
/*
Stockfish, a UCI chess playing engine derived from Glaurung 2.1
Copyright (C) 2004-2024 The Stockfish developers (see AUTHORS file)
Copyright (C) 2004-2025 The Stockfish developers (see AUTHORS file)
Stockfish is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
+33 -31
View File
@@ -1,6 +1,6 @@
/*
Stockfish, a UCI chess playing engine derived from Glaurung 2.1
Copyright (C) 2004-2024 The Stockfish developers (see AUTHORS file)
Copyright (C) 2004-2025 The Stockfish developers (see AUTHORS file)
Stockfish is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -18,11 +18,11 @@
#include "movepick.h"
#include <algorithm>
#include <cassert>
#include <utility>
#include <limits>
#include "bitboard.h"
#include "misc.h"
#include "position.h"
namespace Stockfish {
@@ -82,16 +82,20 @@ MovePicker::MovePicker(const Position& p,
Move ttm,
Depth d,
const ButterflyHistory* mh,
const LowPlyHistory* lph,
const CapturePieceToHistory* cph,
const PieceToHistory** ch,
const PawnHistory* ph) :
const PawnHistory* ph,
int pl) :
pos(p),
mainHistory(mh),
lowPlyHistory(lph),
captureHistory(cph),
continuationHistory(ch),
pawnHistory(ph),
ttMove(ttm),
depth(d) {
depth(d),
ply(pl) {
if (pos.checkers())
stage = EVASION_TT + !(ttm && pos.pseudo_legal(ttm));
@@ -152,12 +156,13 @@ void MovePicker::score() {
Square to = m.to_sq();
// histories
m.value = (*mainHistory)[pos.side_to_move()][m.from_to()];
m.value = 2 * (*mainHistory)[pos.side_to_move()][m.from_to()];
m.value += 2 * (*pawnHistory)[pawn_structure_index(pos)][pc][to];
m.value += 2 * (*continuationHistory[0])[pc][to];
m.value += (*continuationHistory[0])[pc][to];
m.value += (*continuationHistory[1])[pc][to];
m.value += (*continuationHistory[2])[pc][to] / 3;
m.value += (*continuationHistory[2])[pc][to];
m.value += (*continuationHistory[3])[pc][to];
m.value += (*continuationHistory[4])[pc][to] / 3;
m.value += (*continuationHistory[5])[pc][to];
// bonus for checks
@@ -171,16 +176,18 @@ void MovePicker::score() {
: 0;
// malus for putting piece en prise
m.value -= (pt == QUEEN ? bool(to & threatenedByRook) * 49000
: pt == ROOK ? bool(to & threatenedByMinor) * 24335
: bool(to & threatenedByPawn) * 14900);
m.value -= (pt == QUEEN ? bool(to & threatenedByRook) * 49000
: pt == ROOK && bool(to & threatenedByMinor) ? 24335
: 0);
if (ply < LOW_PLY_HISTORY_SIZE)
m.value += 8 * (*lowPlyHistory)[ply][m.from_to()] / (1 + 2 * ply);
}
else // Type == EVASIONS
{
if (pos.capture_stage(m))
m.value =
PieceValue[pos.piece_on(m.to_sq())] - type_of(pos.moved_piece(m)) + (1 << 28);
m.value = PieceValue[pos.piece_on(m.to_sq())] + (1 << 28);
else
m.value = (*mainHistory)[pos.side_to_move()][m.from_to()]
+ (*continuationHistory[0])[pos.moved_piece(m)][m.to_sq()]
@@ -190,26 +197,20 @@ void MovePicker::score() {
// Returns the next move satisfying a predicate function.
// This never returns the TT move, as it was emitted before.
template<MovePicker::PickType T, typename Pred>
template<typename Pred>
Move MovePicker::select(Pred filter) {
while (cur < endMoves)
{
if constexpr (T == Best)
std::swap(*cur, *std::max_element(cur, endMoves));
for (; cur < endMoves; ++cur)
if (*cur != ttMove && filter())
return *cur++;
cur++;
}
return Move::none();
}
// This is the most important method of the MovePicker class. We emit one
// new pseudo-legal move on every call until there are no more moves left,
// picking the move with the highest score from a list of generated moves.
Move MovePicker::next_move(bool skipQuiets) {
Move MovePicker::next_move() {
auto quiet_threshold = [](Depth d) { return -3560 * d; };
@@ -236,7 +237,7 @@ top:
goto top;
case GOOD_CAPTURE :
if (select<Next>([&]() {
if (select([&]() {
// Move losing capture to endBadCaptures to be tried later
return pos.see_ge(*cur, -cur->value / 18) ? true
: (*endBadCaptures++ = *cur, false);
@@ -260,7 +261,7 @@ top:
[[fallthrough]];
case GOOD_QUIET :
if (!skipQuiets && select<Next>([]() { return true; }))
if (!skipQuiets && select([]() { return true; }))
{
if ((cur - 1)->value > -7998 || (cur - 1)->value <= quiet_threshold(depth))
return *(cur - 1);
@@ -277,7 +278,7 @@ top:
[[fallthrough]];
case BAD_CAPTURE :
if (select<Next>([]() { return true; }))
if (select([]() { return true; }))
return *(cur - 1);
// Prepare the pointers to loop over the bad quiets
@@ -289,7 +290,7 @@ top:
case BAD_QUIET :
if (!skipQuiets)
return select<Next>([]() { return true; });
return select([]() { return true; });
return Move::none();
@@ -298,21 +299,22 @@ top:
endMoves = generate<EVASIONS>(pos, cur);
score<EVASIONS>();
partial_insertion_sort(cur, endMoves, std::numeric_limits<int>::min());
++stage;
[[fallthrough]];
case EVASION :
return select<Best>([]() { return true; });
case QCAPTURE :
return select([]() { return true; });
case PROBCUT :
return select<Next>([&]() { return pos.see_ge(*cur, threshold); });
case QCAPTURE :
return select<Next>([]() { return true; });
return select([&]() { return pos.see_ge(*cur, threshold); });
}
assert(false);
return Move::none(); // Silence warning
}
void MovePicker::skip_quiet_moves() { skipQuiets = true; }
} // namespace Stockfish
+12 -121
View File
@@ -1,6 +1,6 @@
/*
Stockfish, a UCI chess playing engine derived from Glaurung 2.1
Copyright (C) 2004-2024 The Stockfish developers (see AUTHORS file)
Copyright (C) 2004-2025 The Stockfish developers (see AUTHORS file)
Stockfish is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -19,123 +19,13 @@
#ifndef MOVEPICK_H_INCLUDED
#define MOVEPICK_H_INCLUDED
#include <algorithm>
#include <array>
#include <cassert>
#include <cmath>
#include <cstdint>
#include <cstdlib>
#include <limits>
#include <type_traits> // IWYU pragma: keep
#include "history.h"
#include "movegen.h"
#include "position.h"
#include "types.h"
namespace Stockfish {
constexpr int PAWN_HISTORY_SIZE = 512; // has to be a power of 2
constexpr int CORRECTION_HISTORY_SIZE = 16384; // has to be a power of 2
constexpr int CORRECTION_HISTORY_LIMIT = 1024;
static_assert((PAWN_HISTORY_SIZE & (PAWN_HISTORY_SIZE - 1)) == 0,
"PAWN_HISTORY_SIZE has to be a power of 2");
static_assert((CORRECTION_HISTORY_SIZE & (CORRECTION_HISTORY_SIZE - 1)) == 0,
"CORRECTION_HISTORY_SIZE has to be a power of 2");
enum PawnHistoryType {
Normal,
Correction
};
template<PawnHistoryType T = Normal>
inline int pawn_structure_index(const Position& pos) {
return pos.pawn_key() & ((T == Normal ? PAWN_HISTORY_SIZE : CORRECTION_HISTORY_SIZE) - 1);
}
// StatsEntry stores the stat table value. It is usually a number but could
// be a move or even a nested history. We use a class instead of a naked value
// to directly call history update operator<<() on the entry so to use stats
// tables at caller sites as simple multi-dim arrays.
template<typename T, int D>
class StatsEntry {
T entry;
public:
void operator=(const T& v) { entry = v; }
T* operator&() { return &entry; }
T* operator->() { return &entry; }
operator const T&() const { return entry; }
void operator<<(int bonus) {
static_assert(D <= std::numeric_limits<T>::max(), "D overflows T");
// Make sure that bonus is in range [-D, D]
int clampedBonus = std::clamp(bonus, -D, D);
entry += clampedBonus - entry * std::abs(clampedBonus) / D;
assert(std::abs(entry) <= D);
}
};
// Stats is a generic N-dimensional array used to store various statistics.
// The first template parameter T is the base type of the array, and the second
// template parameter D limits the range of updates in [-D, D] when we update
// values with the << operator, while the last parameters (Size and Sizes)
// encode the dimensions of the array.
template<typename T, int D, int Size, int... Sizes>
struct Stats: public std::array<Stats<T, D, Sizes...>, Size> {
using stats = Stats<T, D, Size, Sizes...>;
void fill(const T& v) {
// For standard-layout 'this' points to the first struct member
assert(std::is_standard_layout_v<stats>);
using entry = StatsEntry<T, D>;
entry* p = reinterpret_cast<entry*>(this);
std::fill(p, p + sizeof(*this) / sizeof(entry), v);
}
};
template<typename T, int D, int Size>
struct Stats<T, D, Size>: public std::array<StatsEntry<T, D>, Size> {};
// In stats table, D=0 means that the template parameter is not used
enum StatsParams {
NOT_USED = 0
};
enum StatsType {
NoCaptures,
Captures
};
// ButterflyHistory records how often quiet moves have been successful or unsuccessful
// during the current search, and is used for reduction and move ordering decisions.
// It uses 2 tables (one for each color) indexed by the move's from and to squares,
// see www.chessprogramming.org/Butterfly_Boards (~11 elo)
using ButterflyHistory = Stats<int16_t, 7183, COLOR_NB, int(SQUARE_NB) * int(SQUARE_NB)>;
// CapturePieceToHistory is addressed by a move's [piece][to][captured piece type]
using CapturePieceToHistory = Stats<int16_t, 10692, PIECE_NB, SQUARE_NB, PIECE_TYPE_NB>;
// PieceToHistory is like ButterflyHistory but is addressed by a move's [piece][to]
using PieceToHistory = Stats<int16_t, 29952, PIECE_NB, SQUARE_NB>;
// ContinuationHistory is the combined history of a given pair of moves, usually
// the current one given a previous one. The nested history table is based on
// PieceToHistory instead of ButterflyBoards.
// (~63 elo)
using ContinuationHistory = Stats<PieceToHistory, NOT_USED, PIECE_NB, SQUARE_NB>;
// PawnHistory is addressed by the pawn structure and a move's [piece][to]
using PawnHistory = Stats<int16_t, 8192, PAWN_HISTORY_SIZE, PIECE_NB, SQUARE_NB>;
// CorrectionHistory is addressed by color and pawn structure
using CorrectionHistory =
Stats<int16_t, CORRECTION_HISTORY_LIMIT, COLOR_NB, CORRECTION_HISTORY_SIZE>;
class Position;
// The MovePicker class is used to pick one pseudo-legal move at a time from the
// current position. The most important method is next_move(), which emits one
@@ -145,11 +35,6 @@ using CorrectionHistory =
// a cut-off first.
class MovePicker {
enum PickType {
Next,
Best
};
public:
MovePicker(const MovePicker&) = delete;
MovePicker& operator=(const MovePicker&) = delete;
@@ -157,14 +42,17 @@ class MovePicker {
Move,
Depth,
const ButterflyHistory*,
const LowPlyHistory*,
const CapturePieceToHistory*,
const PieceToHistory**,
const PawnHistory*);
const PawnHistory*,
int);
MovePicker(const Position&, Move, int, const CapturePieceToHistory*);
Move next_move(bool skipQuiets = false);
Move next_move();
void skip_quiet_moves();
private:
template<PickType T, typename Pred>
template<typename Pred>
Move select(Pred);
template<GenType>
void score();
@@ -173,6 +61,7 @@ class MovePicker {
const Position& pos;
const ButterflyHistory* mainHistory;
const LowPlyHistory* lowPlyHistory;
const CapturePieceToHistory* captureHistory;
const PieceToHistory** continuationHistory;
const PawnHistory* pawnHistory;
@@ -181,6 +70,8 @@ class MovePicker {
int stage;
int threshold;
Depth depth;
int ply;
bool skipQuiets = false;
ExtMove moves[MAX_MOVES];
};
+3 -7
View File
@@ -1,6 +1,6 @@
/*
Stockfish, a UCI chess playing engine derived from Glaurung 2.1
Copyright (C) 2004-2024 The Stockfish developers (see AUTHORS file)
Copyright (C) 2004-2025 The Stockfish developers (see AUTHORS file)
Stockfish is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -77,12 +77,8 @@ template void HalfKAv2_hm::append_changed_indices<BLACK>(Square ksq,
IndexList& removed,
IndexList& added);
int HalfKAv2_hm::update_cost(const StateInfo* st) { return st->dirtyPiece.dirty_num; }
int HalfKAv2_hm::refresh_cost(const Position& pos) { return pos.count<ALL_PIECES>(); }
bool HalfKAv2_hm::requires_refresh(const StateInfo* st, Color perspective) {
return st->dirtyPiece.piece[0] == make_piece(perspective, KING);
bool HalfKAv2_hm::requires_refresh(const DirtyPiece& dirtyPiece, Color perspective) {
return dirtyPiece.piece[0] == make_piece(perspective, KING);
}
} // namespace Stockfish::Eval::NNUE::Features
+3 -9
View File
@@ -1,6 +1,6 @@
/*
Stockfish, a UCI chess playing engine derived from Glaurung 2.1
Copyright (C) 2004-2024 The Stockfish developers (see AUTHORS file)
Copyright (C) 2004-2025 The Stockfish developers (see AUTHORS file)
Stockfish is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -28,7 +28,6 @@
#include "../nnue_common.h"
namespace Stockfish {
struct StateInfo;
class Position;
}
@@ -135,14 +134,9 @@ class HalfKAv2_hm {
static void
append_changed_indices(Square ksq, const DirtyPiece& dp, IndexList& removed, IndexList& added);
// Returns the cost of updating one perspective, the most costly one.
// Assumes no refresh needed.
static int update_cost(const StateInfo* st);
static int refresh_cost(const Position& pos);
// Returns whether the change stored in this StateInfo means
// Returns whether the change stored in this DirtyPiece means
// that a full accumulator refresh is required.
static bool requires_refresh(const StateInfo* st, Color perspective);
static bool requires_refresh(const DirtyPiece& dirtyPiece, Color perspective);
};
} // namespace Stockfish::Eval::NNUE::Features
+2 -2
View File
@@ -1,6 +1,6 @@
/*
Stockfish, a UCI chess playing engine derived from Glaurung 2.1
Copyright (C) 2004-2024 The Stockfish developers (see AUTHORS file)
Copyright (C) 2004-2025 The Stockfish developers (see AUTHORS file)
Stockfish is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -102,7 +102,7 @@ static void affine_transform_non_ssse3(std::int32_t* output,
product = vmlal_s8(product, inputVector[j * 2 + 1], row[j * 2 + 1]);
sum = vpadalq_s16(sum, product);
}
output[i] = sum[0] + sum[1] + sum[2] + sum[3];
output[i] = Simd::neon_m128_reduce_add_epi32(sum);
#endif
}
+44 -16
View File
@@ -1,6 +1,6 @@
/*
Stockfish, a UCI chess playing engine derived from Glaurung 2.1
Copyright (C) 2004-2024 The Stockfish developers (see AUTHORS file)
Copyright (C) 2004-2025 The Stockfish developers (see AUTHORS file)
Stockfish is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -38,17 +38,41 @@
namespace Stockfish::Eval::NNUE::Layers {
#if (USE_SSSE3 | (USE_NEON >= 8))
alignas(CacheLineSize) static inline const
std::array<std::array<std::uint16_t, 8>, 256> lookup_indices = []() {
std::array<std::array<std::uint16_t, 8>, 256> v{};
for (unsigned i = 0; i < 256; ++i)
{
std::uint64_t j = i, k = 0;
while (j)
v[i][k++] = pop_lsb(j);
}
return v;
}();
static constexpr int lsb_index64[64] = {
0, 47, 1, 56, 48, 27, 2, 60, 57, 49, 41, 37, 28, 16, 3, 61, 54, 58, 35, 52, 50, 42,
21, 44, 38, 32, 29, 23, 17, 11, 4, 62, 46, 55, 26, 59, 40, 36, 15, 53, 34, 51, 20, 43,
31, 22, 10, 45, 25, 39, 14, 33, 19, 30, 9, 24, 13, 18, 8, 12, 7, 6, 5, 63};
constexpr int constexpr_lsb(uint64_t bb) {
assert(bb != 0);
constexpr uint64_t debruijn64 = 0x03F79D71B4CB0A89ULL;
return lsb_index64[((bb ^ (bb - 1)) * debruijn64) >> 58];
}
alignas(CacheLineSize) static constexpr struct OffsetIndices {
#if (USE_SSE41)
std::uint8_t offset_indices[256][8];
#else
std::uint16_t offset_indices[256][8];
#endif
constexpr OffsetIndices() :
offset_indices() {
for (int i = 0; i < 256; ++i)
{
std::uint64_t j = i, k = 0;
while (j)
{
offset_indices[i][k++] = constexpr_lsb(j);
j &= j - 1;
}
while (k < 8)
offset_indices[i][k++] = 0;
}
}
} Lookup;
// Find indices of nonzero numbers in an int32_t array
template<const IndexType InputDimensions>
@@ -74,7 +98,11 @@ void find_nnz(const std::int32_t* input, std::uint16_t* out, IndexType& count_ou
using vec128_t = __m128i;
#define vec128_zero _mm_setzero_si128()
#define vec128_set_16(a) _mm_set1_epi16(a)
#define vec128_load(a) _mm_load_si128(a)
#if (USE_SSE41)
#define vec128_load(a) _mm_cvtepu8_epi16(_mm_loadl_epi64(a))
#else
#define vec128_load(a) _mm_load_si128(a)
#endif
#define vec128_storeu(a, b) _mm_storeu_si128(a, b)
#define vec128_add(a, b) _mm_add_epi16(a, b)
#elif defined(USE_NEON)
@@ -110,9 +138,9 @@ void find_nnz(const std::int32_t* input, std::uint16_t* out, IndexType& count_ou
}
for (IndexType j = 0; j < OutputsPerChunk; ++j)
{
const auto lookup = (nnz >> (j * 8)) & 0xFF;
const auto offsets =
vec128_load(reinterpret_cast<const vec128_t*>(&lookup_indices[lookup]));
const unsigned lookup = (nnz >> (j * 8)) & 0xFF;
const vec128_t offsets =
vec128_load(reinterpret_cast<const vec128_t*>(&Lookup.offset_indices[lookup]));
vec128_storeu(reinterpret_cast<vec128_t*>(out + count), vec128_add(base, offsets));
count += popcount(lookup);
base = vec128_add(base, increment);
+1 -1
View File
@@ -1,6 +1,6 @@
/*
Stockfish, a UCI chess playing engine derived from Glaurung 2.1
Copyright (C) 2004-2024 The Stockfish developers (see AUTHORS file)
Copyright (C) 2004-2025 The Stockfish developers (see AUTHORS file)
Stockfish is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
+1 -1
View File
@@ -1,6 +1,6 @@
/*
Stockfish, a UCI chess playing engine derived from Glaurung 2.1
Copyright (C) 2004-2024 The Stockfish developers (see AUTHORS file)
Copyright (C) 2004-2025 The Stockfish developers (see AUTHORS file)
Stockfish is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
+1 -1
View File
@@ -1,6 +1,6 @@
/*
Stockfish, a UCI chess playing engine derived from Glaurung 2.1
Copyright (C) 2004-2024 The Stockfish developers (see AUTHORS file)
Copyright (C) 2004-2025 The Stockfish developers (see AUTHORS file)
Stockfish is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
+44 -36
View File
@@ -1,6 +1,6 @@
/*
Stockfish, a UCI chess playing engine derived from Glaurung 2.1
Copyright (C) 2004-2024 The Stockfish developers (see AUTHORS file)
Copyright (C) 2004-2025 The Stockfish developers (see AUTHORS file)
Stockfish is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -26,8 +26,10 @@
#include <type_traits>
#include <vector>
#include "../evaluate.h"
#define INCBIN_SILENCE_BITCODE_WARNING
#include "../incbin/incbin.h"
#include "../evaluate.h"
#include "../memory.h"
#include "../misc.h"
#include "../position.h"
@@ -36,7 +38,6 @@
#include "nnue_common.h"
#include "nnue_misc.h"
namespace {
// Macro to embed the default efficiently updatable neural network (NNUE) file
// data in the engine binary (using incbin.h, by Dale Weiler).
// This macro invocation will declare the following three variables
@@ -56,6 +57,8 @@ const unsigned char* const gEmbeddedNNUESmallEnd = &gEmbeddedNNUESmallData[1
const unsigned int gEmbeddedNNUESmallSize = 1;
#endif
namespace {
struct EmbeddedNNUE {
EmbeddedNNUE(const unsigned char* embeddedData,
const unsigned char* embeddedEnd,
@@ -98,7 +101,7 @@ bool read_parameters(std::istream& stream, T& reference) {
// Write evaluation function parameters
template<typename T>
bool write_parameters(std::ostream& stream, const T& reference) {
bool write_parameters(std::ostream& stream, T& reference) {
write_little_endian<std::uint32_t>(stream, T::get_hash_value());
return reference.write_parameters(stream);
@@ -207,6 +210,7 @@ bool Network<Arch, Transformer>::save(const std::optional<std::string>& filename
template<typename Arch, typename Transformer>
NetworkOutput
Network<Arch, Transformer>::evaluate(const Position& pos,
AccumulatorStack& accumulatorStack,
AccumulatorCaches::Cache<FTDimensions>* cache) const {
// We manually align the arrays on the stack because with gcc < 9.3
// overaligning stack variables with alignas() doesn't work correctly.
@@ -226,55 +230,59 @@ Network<Arch, Transformer>::evaluate(const Position& pos
ASSERT_ALIGNED(transformedFeatures, alignment);
const int bucket = (pos.count<ALL_PIECES>() - 1) / 4;
const auto psqt = featureTransformer->transform(pos, cache, transformedFeatures, bucket);
const int bucket = (pos.count<ALL_PIECES>() - 1) / 4;
const auto psqt =
featureTransformer->transform(pos, accumulatorStack, cache, transformedFeatures, bucket);
const auto positional = network[bucket].propagate(transformedFeatures);
return {static_cast<Value>(psqt / OutputScale), static_cast<Value>(positional / OutputScale)};
}
template<typename Arch, typename Transformer>
void Network<Arch, Transformer>::verify(std::string evalfilePath) const {
void Network<Arch, Transformer>::verify(std::string evalfilePath,
const std::function<void(std::string_view)>& f) const {
if (evalfilePath.empty())
evalfilePath = evalFile.defaultName;
if (evalFile.current != evalfilePath)
{
std::string msg1 =
"Network evaluation parameters compatible with the engine must be available.";
std::string msg2 = "The network file " + evalfilePath + " was not loaded successfully.";
std::string msg3 = "The UCI option EvalFile might need to specify the full path, "
"including the directory name, to the network file.";
std::string msg4 = "The default net can be downloaded from: "
"https://tests.stockfishchess.org/api/nn/"
+ evalFile.defaultName;
std::string msg5 = "The engine will be terminated now.";
if (f)
{
std::string msg1 =
"Network evaluation parameters compatible with the engine must be available.";
std::string msg2 = "The network file " + evalfilePath + " was not loaded successfully.";
std::string msg3 = "The UCI option EvalFile might need to specify the full path, "
"including the directory name, to the network file.";
std::string msg4 = "The default net can be downloaded from: "
"https://tests.stockfishchess.org/api/nn/"
+ evalFile.defaultName;
std::string msg5 = "The engine will be terminated now.";
std::string msg = "ERROR: " + msg1 + '\n' + "ERROR: " + msg2 + '\n' + "ERROR: " + msg3
+ '\n' + "ERROR: " + msg4 + '\n' + "ERROR: " + msg5 + '\n';
f(msg);
}
sync_cout << "info string ERROR: " << msg1 << sync_endl;
sync_cout << "info string ERROR: " << msg2 << sync_endl;
sync_cout << "info string ERROR: " << msg3 << sync_endl;
sync_cout << "info string ERROR: " << msg4 << sync_endl;
sync_cout << "info string ERROR: " << msg5 << sync_endl;
exit(EXIT_FAILURE);
}
size_t size = sizeof(*featureTransformer) + sizeof(Arch) * LayerStacks;
sync_cout << "info string NNUE evaluation using " << evalfilePath << " ("
<< size / (1024 * 1024) << "MiB, (" << featureTransformer->InputDimensions << ", "
<< network[0].TransformedFeatureDimensions << ", " << network[0].FC_0_OUTPUTS << ", "
<< network[0].FC_1_OUTPUTS << ", 1))" << sync_endl;
if (f)
{
size_t size = sizeof(*featureTransformer) + sizeof(Arch) * LayerStacks;
f("NNUE evaluation using " + evalfilePath + " (" + std::to_string(size / (1024 * 1024))
+ "MiB, (" + std::to_string(featureTransformer->InputDimensions) + ", "
+ std::to_string(network[0].TransformedFeatureDimensions) + ", "
+ std::to_string(network[0].FC_0_OUTPUTS) + ", " + std::to_string(network[0].FC_1_OUTPUTS)
+ ", 1))");
}
}
template<typename Arch, typename Transformer>
void Network<Arch, Transformer>::hint_common_access(
const Position& pos, AccumulatorCaches::Cache<FTDimensions>* cache) const {
featureTransformer->hint_common_access(pos, cache);
}
template<typename Arch, typename Transformer>
NnueEvalTrace
Network<Arch, Transformer>::trace_evaluate(const Position& pos,
AccumulatorStack& accumulatorStack,
AccumulatorCaches::Cache<FTDimensions>* cache) const {
// We manually align the arrays on the stack because with gcc < 9.3
// overaligning stack variables with alignas() doesn't work correctly.
@@ -298,7 +306,7 @@ Network<Arch, Transformer>::trace_evaluate(const Position&
for (IndexType bucket = 0; bucket < LayerStacks; ++bucket)
{
const auto materialist =
featureTransformer->transform(pos, cache, transformedFeatures, bucket);
featureTransformer->transform(pos, accumulatorStack, cache, transformedFeatures, bucket);
const auto positional = network[bucket].propagate(transformedFeatures);
t.psqt[bucket] = static_cast<Value>(materialist / OutputScale);
@@ -442,14 +450,14 @@ bool Network<Arch, Transformer>::write_parameters(std::ostream& stream,
return bool(stream);
}
// Explicit template instantiation
// Explicit template instantiations
template class Network<
NetworkArchitecture<TransformedFeatureDimensionsBig, L2Big, L3Big>,
FeatureTransformer<TransformedFeatureDimensionsBig, &StateInfo::accumulatorBig>>;
FeatureTransformer<TransformedFeatureDimensionsBig, &AccumulatorState::accumulatorBig>>;
template class Network<
NetworkArchitecture<TransformedFeatureDimensionsSmall, L2Small, L3Small>,
FeatureTransformer<TransformedFeatureDimensionsSmall, &StateInfo::accumulatorSmall>>;
FeatureTransformer<TransformedFeatureDimensionsSmall, &AccumulatorState::accumulatorSmall>>;
} // namespace Stockfish::Eval::NNUE
+14 -8
View File
@@ -1,6 +1,6 @@
/*
Stockfish, a UCI chess playing engine derived from Glaurung 2.1
Copyright (C) 2004-2024 The Stockfish developers (see AUTHORS file)
Copyright (C) 2004-2025 The Stockfish developers (see AUTHORS file)
Stockfish is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -20,20 +20,25 @@
#define NETWORK_H_INCLUDED
#include <cstdint>
#include <functional>
#include <iostream>
#include <optional>
#include <string>
#include <string_view>
#include <tuple>
#include <utility>
#include "../memory.h"
#include "../position.h"
#include "../types.h"
#include "nnue_accumulator.h"
#include "nnue_architecture.h"
#include "nnue_feature_transformer.h"
#include "nnue_misc.h"
namespace Stockfish {
class Position;
}
namespace Stockfish::Eval::NNUE {
enum class EmbeddedNNUEType {
@@ -62,14 +67,13 @@ class Network {
bool save(const std::optional<std::string>& filename) const;
NetworkOutput evaluate(const Position& pos,
AccumulatorStack& accumulatorStack,
AccumulatorCaches::Cache<FTDimensions>* cache) const;
void hint_common_access(const Position& pos,
AccumulatorCaches::Cache<FTDimensions>* cache) const;
void verify(std::string evalfilePath) const;
void verify(std::string evalfilePath, const std::function<void(std::string_view)>&) const;
NnueEvalTrace trace_evaluate(const Position& pos,
AccumulatorStack& accumulatorStack,
AccumulatorCaches::Cache<FTDimensions>* cache) const;
private:
@@ -101,16 +105,18 @@ class Network {
template<IndexType Size>
friend struct AccumulatorCaches::Cache;
friend class AccumulatorStack;
};
// Definitions of the network types
using SmallFeatureTransformer =
FeatureTransformer<TransformedFeatureDimensionsSmall, &StateInfo::accumulatorSmall>;
FeatureTransformer<TransformedFeatureDimensionsSmall, &AccumulatorState::accumulatorSmall>;
using SmallNetworkArchitecture =
NetworkArchitecture<TransformedFeatureDimensionsSmall, L2Small, L3Small>;
using BigFeatureTransformer =
FeatureTransformer<TransformedFeatureDimensionsBig, &StateInfo::accumulatorBig>;
FeatureTransformer<TransformedFeatureDimensionsBig, &AccumulatorState::accumulatorBig>;
using BigNetworkArchitecture = NetworkArchitecture<TransformedFeatureDimensionsBig, L2Big, L3Big>;
using NetworkBig = Network<BigNetworkArchitecture, BigFeatureTransformer>;
+619
View File
@@ -0,0 +1,619 @@
/*
Stockfish, a UCI chess playing engine derived from Glaurung 2.1
Copyright (C) 2004-2025 The Stockfish developers (see AUTHORS file)
Stockfish is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
Stockfish is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "nnue_accumulator.h"
#include <cassert>
#include <initializer_list>
#include <memory>
#include "../bitboard.h"
#include "../position.h"
#include "../types.h"
#include "network.h"
#include "nnue_architecture.h"
#include "nnue_common.h"
#include "nnue_feature_transformer.h"
namespace Stockfish::Eval::NNUE {
#if defined(__GNUC__) && !defined(__clang__)
#define sf_assume(cond) \
do \
{ \
if (!(cond)) \
__builtin_unreachable(); \
} while (0)
#else
// do nothing for other compilers
#define sf_assume(cond)
#endif
namespace {
template<Color Perspective,
IncUpdateDirection Direction = FORWARD,
IndexType TransformedFeatureDimensions,
Accumulator<TransformedFeatureDimensions> AccumulatorState::*accPtr>
void update_accumulator_incremental(
const FeatureTransformer<TransformedFeatureDimensions, accPtr>& featureTransformer,
const Square ksq,
AccumulatorState& target_state,
const AccumulatorState& computed);
template<Color Perspective, IndexType Dimensions, Accumulator<Dimensions> AccumulatorState::*accPtr>
void update_accumulator_refresh_cache(
const FeatureTransformer<Dimensions, accPtr>& featureTransformer,
const Position& pos,
AccumulatorState& accumulatorState,
AccumulatorCaches::Cache<Dimensions>& cache);
}
void AccumulatorState::reset(const DirtyPiece& dp) noexcept {
dirtyPiece = dp;
accumulatorBig.computed.fill(false);
accumulatorSmall.computed.fill(false);
}
const AccumulatorState& AccumulatorStack::latest() const noexcept {
return m_accumulators[m_current_idx - 1];
}
AccumulatorState& AccumulatorStack::mut_latest() noexcept {
return m_accumulators[m_current_idx - 1];
}
void AccumulatorStack::reset(const Position& rootPos,
const Networks& networks,
AccumulatorCaches& caches) noexcept {
m_current_idx = 1;
update_accumulator_refresh_cache<WHITE, TransformedFeatureDimensionsBig,
&AccumulatorState::accumulatorBig>(
*networks.big.featureTransformer, rootPos, m_accumulators[0], caches.big);
update_accumulator_refresh_cache<BLACK, TransformedFeatureDimensionsBig,
&AccumulatorState::accumulatorBig>(
*networks.big.featureTransformer, rootPos, m_accumulators[0], caches.big);
update_accumulator_refresh_cache<WHITE, TransformedFeatureDimensionsSmall,
&AccumulatorState::accumulatorSmall>(
*networks.small.featureTransformer, rootPos, m_accumulators[0], caches.small);
update_accumulator_refresh_cache<BLACK, TransformedFeatureDimensionsSmall,
&AccumulatorState::accumulatorSmall>(
*networks.small.featureTransformer, rootPos, m_accumulators[0], caches.small);
}
void AccumulatorStack::push(const DirtyPiece& dirtyPiece) noexcept {
assert(m_current_idx + 1 < m_accumulators.size());
m_accumulators[m_current_idx].reset(dirtyPiece);
m_current_idx++;
}
void AccumulatorStack::pop() noexcept {
assert(m_current_idx > 1);
m_current_idx--;
}
template<IndexType Dimensions, Accumulator<Dimensions> AccumulatorState::*accPtr>
void AccumulatorStack::evaluate(const Position& pos,
const FeatureTransformer<Dimensions, accPtr>& featureTransformer,
AccumulatorCaches::Cache<Dimensions>& cache) noexcept {
evaluate_side<WHITE>(pos, featureTransformer, cache);
evaluate_side<BLACK>(pos, featureTransformer, cache);
}
template<Color Perspective, IndexType Dimensions, Accumulator<Dimensions> AccumulatorState::*accPtr>
void AccumulatorStack::evaluate_side(
const Position& pos,
const FeatureTransformer<Dimensions, accPtr>& featureTransformer,
AccumulatorCaches::Cache<Dimensions>& cache) noexcept {
const auto last_usable_accum = find_last_usable_accumulator<Perspective, Dimensions, accPtr>();
if ((m_accumulators[last_usable_accum].*accPtr).computed[Perspective])
forward_update_incremental<Perspective>(pos, featureTransformer, last_usable_accum);
else
{
update_accumulator_refresh_cache<Perspective>(featureTransformer, pos, mut_latest(), cache);
backward_update_incremental<Perspective>(pos, featureTransformer, last_usable_accum);
}
}
// Find the earliest usable accumulator, this can either be a computed accumulator or the accumulator
// state just before a change that requires full refresh.
template<Color Perspective, IndexType Dimensions, Accumulator<Dimensions> AccumulatorState::*accPtr>
std::size_t AccumulatorStack::find_last_usable_accumulator() const noexcept {
for (std::size_t curr_idx = m_current_idx - 1; curr_idx > 0; curr_idx--)
{
if ((m_accumulators[curr_idx].*accPtr).computed[Perspective])
return curr_idx;
if (FeatureSet::requires_refresh(m_accumulators[curr_idx].dirtyPiece, Perspective))
return curr_idx;
}
return 0;
}
template<Color Perspective, IndexType Dimensions, Accumulator<Dimensions> AccumulatorState::*accPtr>
void AccumulatorStack::forward_update_incremental(
const Position& pos,
const FeatureTransformer<Dimensions, accPtr>& featureTransformer,
const std::size_t begin) noexcept {
assert(begin < m_accumulators.size());
assert((m_accumulators[begin].*accPtr).computed[Perspective]);
const Square ksq = pos.square<KING>(Perspective);
for (std::size_t next = begin + 1; next < m_current_idx; next++)
update_accumulator_incremental<Perspective>(featureTransformer, ksq, m_accumulators[next],
m_accumulators[next - 1]);
assert((latest().*accPtr).computed[Perspective]);
}
template<Color Perspective, IndexType Dimensions, Accumulator<Dimensions> AccumulatorState::*accPtr>
void AccumulatorStack::backward_update_incremental(
const Position& pos,
const FeatureTransformer<Dimensions, accPtr>& featureTransformer,
const std::size_t end) noexcept {
assert(end < m_accumulators.size());
assert(end < m_current_idx);
assert((latest().*accPtr).computed[Perspective]);
const Square ksq = pos.square<KING>(Perspective);
for (std::size_t next = m_current_idx - 2; next >= end; next--)
update_accumulator_incremental<Perspective, BACKWARDS>(
featureTransformer, ksq, m_accumulators[next], m_accumulators[next + 1]);
assert((m_accumulators[end].*accPtr).computed[Perspective]);
}
// Explicit template instantiations
template void
AccumulatorStack::evaluate<TransformedFeatureDimensionsBig, &AccumulatorState::accumulatorBig>(
const Position& pos,
const FeatureTransformer<TransformedFeatureDimensionsBig, &AccumulatorState::accumulatorBig>&
featureTransformer,
AccumulatorCaches::Cache<TransformedFeatureDimensionsBig>& cache) noexcept;
template void
AccumulatorStack::evaluate<TransformedFeatureDimensionsSmall, &AccumulatorState::accumulatorSmall>(
const Position& pos,
const FeatureTransformer<TransformedFeatureDimensionsSmall, &AccumulatorState::accumulatorSmall>&
featureTransformer,
AccumulatorCaches::Cache<TransformedFeatureDimensionsSmall>& cache) noexcept;
namespace {
template<Color Perspective,
IncUpdateDirection Direction,
IndexType TransformedFeatureDimensions,
Accumulator<TransformedFeatureDimensions> AccumulatorState::*accPtr>
void update_accumulator_incremental(
const FeatureTransformer<TransformedFeatureDimensions, accPtr>& featureTransformer,
const Square ksq,
AccumulatorState& target_state,
const AccumulatorState& computed) {
[[maybe_unused]] constexpr bool Forward = Direction == FORWARD;
[[maybe_unused]] constexpr bool Backwards = Direction == BACKWARDS;
assert(Forward != Backwards);
assert((computed.*accPtr).computed[Perspective]);
assert(!(target_state.*accPtr).computed[Perspective]);
// The size must be enough to contain the largest possible update.
// That might depend on the feature set and generally relies on the
// feature set's update cost calculation to be correct and never allow
// updates with more added/removed features than MaxActiveDimensions.
// In this case, the maximum size of both feature addition and removal
// is 2, since we are incrementally updating one move at a time.
FeatureSet::IndexList removed, added;
if constexpr (Forward)
FeatureSet::append_changed_indices<Perspective>(ksq, target_state.dirtyPiece, removed,
added);
else
FeatureSet::append_changed_indices<Perspective>(ksq, computed.dirtyPiece, added, removed);
if (removed.size() == 0 && added.size() == 0)
{
std::memcpy((target_state.*accPtr).accumulation[Perspective],
(computed.*accPtr).accumulation[Perspective],
TransformedFeatureDimensions * sizeof(BiasType));
std::memcpy((target_state.*accPtr).psqtAccumulation[Perspective],
(computed.*accPtr).psqtAccumulation[Perspective],
PSQTBuckets * sizeof(PSQTWeightType));
}
else
{
assert(added.size() == 1 || added.size() == 2);
assert(removed.size() == 1 || removed.size() == 2);
if (Forward)
assert(added.size() <= removed.size());
else
assert(removed.size() <= added.size());
// Workaround compiler warning for uninitialized variables, replicated on
// profile builds on windows with gcc 14.2.0.
// TODO remove once unneeded
sf_assume(added.size() == 1 || added.size() == 2);
sf_assume(removed.size() == 1 || removed.size() == 2);
#ifdef VECTOR
auto* accIn =
reinterpret_cast<const vec_t*>(&(computed.*accPtr).accumulation[Perspective][0]);
auto* accOut =
reinterpret_cast<vec_t*>(&(target_state.*accPtr).accumulation[Perspective][0]);
const IndexType offsetA0 = TransformedFeatureDimensions * added[0];
auto* columnA0 = reinterpret_cast<const vec_t*>(&featureTransformer.weights[offsetA0]);
const IndexType offsetR0 = TransformedFeatureDimensions * removed[0];
auto* columnR0 = reinterpret_cast<const vec_t*>(&featureTransformer.weights[offsetR0]);
if ((Forward && removed.size() == 1) || (Backwards && added.size() == 1))
{
assert(added.size() == 1 && removed.size() == 1);
for (IndexType i = 0;
i < TransformedFeatureDimensions * sizeof(WeightType) / sizeof(vec_t); ++i)
accOut[i] = vec_add_16(vec_sub_16(accIn[i], columnR0[i]), columnA0[i]);
}
else if (Forward && added.size() == 1)
{
assert(removed.size() == 2);
const IndexType offsetR1 = TransformedFeatureDimensions * removed[1];
auto* columnR1 = reinterpret_cast<const vec_t*>(&featureTransformer.weights[offsetR1]);
for (IndexType i = 0;
i < TransformedFeatureDimensions * sizeof(WeightType) / sizeof(vec_t); ++i)
accOut[i] = vec_sub_16(vec_add_16(accIn[i], columnA0[i]),
vec_add_16(columnR0[i], columnR1[i]));
}
else if (Backwards && removed.size() == 1)
{
assert(added.size() == 2);
const IndexType offsetA1 = TransformedFeatureDimensions * added[1];
auto* columnA1 = reinterpret_cast<const vec_t*>(&featureTransformer.weights[offsetA1]);
for (IndexType i = 0;
i < TransformedFeatureDimensions * sizeof(WeightType) / sizeof(vec_t); ++i)
accOut[i] = vec_add_16(vec_add_16(accIn[i], columnA0[i]),
vec_sub_16(columnA1[i], columnR0[i]));
}
else
{
assert(added.size() == 2 && removed.size() == 2);
const IndexType offsetA1 = TransformedFeatureDimensions * added[1];
auto* columnA1 = reinterpret_cast<const vec_t*>(&featureTransformer.weights[offsetA1]);
const IndexType offsetR1 = TransformedFeatureDimensions * removed[1];
auto* columnR1 = reinterpret_cast<const vec_t*>(&featureTransformer.weights[offsetR1]);
for (IndexType i = 0;
i < TransformedFeatureDimensions * sizeof(WeightType) / sizeof(vec_t); ++i)
accOut[i] = vec_add_16(accIn[i], vec_sub_16(vec_add_16(columnA0[i], columnA1[i]),
vec_add_16(columnR0[i], columnR1[i])));
}
auto* accPsqtIn =
reinterpret_cast<const psqt_vec_t*>(&(computed.*accPtr).psqtAccumulation[Perspective][0]);
auto* accPsqtOut =
reinterpret_cast<psqt_vec_t*>(&(target_state.*accPtr).psqtAccumulation[Perspective][0]);
const IndexType offsetPsqtA0 = PSQTBuckets * added[0];
auto* columnPsqtA0 =
reinterpret_cast<const psqt_vec_t*>(&featureTransformer.psqtWeights[offsetPsqtA0]);
const IndexType offsetPsqtR0 = PSQTBuckets * removed[0];
auto* columnPsqtR0 =
reinterpret_cast<const psqt_vec_t*>(&featureTransformer.psqtWeights[offsetPsqtR0]);
if ((Forward && removed.size() == 1)
|| (Backwards && added.size() == 1)) // added.size() == removed.size() == 1
{
for (std::size_t i = 0; i < PSQTBuckets * sizeof(PSQTWeightType) / sizeof(psqt_vec_t);
++i)
accPsqtOut[i] =
vec_add_psqt_32(vec_sub_psqt_32(accPsqtIn[i], columnPsqtR0[i]), columnPsqtA0[i]);
}
else if (Forward && added.size() == 1)
{
const IndexType offsetPsqtR1 = PSQTBuckets * removed[1];
auto* columnPsqtR1 =
reinterpret_cast<const psqt_vec_t*>(&featureTransformer.psqtWeights[offsetPsqtR1]);
for (std::size_t i = 0; i < PSQTBuckets * sizeof(PSQTWeightType) / sizeof(psqt_vec_t);
++i)
accPsqtOut[i] = vec_sub_psqt_32(vec_add_psqt_32(accPsqtIn[i], columnPsqtA0[i]),
vec_add_psqt_32(columnPsqtR0[i], columnPsqtR1[i]));
}
else if (Backwards && removed.size() == 1)
{
const IndexType offsetPsqtA1 = PSQTBuckets * added[1];
auto* columnPsqtA1 =
reinterpret_cast<const psqt_vec_t*>(&featureTransformer.psqtWeights[offsetPsqtA1]);
for (std::size_t i = 0; i < PSQTBuckets * sizeof(PSQTWeightType) / sizeof(psqt_vec_t);
++i)
accPsqtOut[i] = vec_add_psqt_32(vec_add_psqt_32(accPsqtIn[i], columnPsqtA0[i]),
vec_sub_psqt_32(columnPsqtA1[i], columnPsqtR0[i]));
}
else
{
const IndexType offsetPsqtA1 = PSQTBuckets * added[1];
auto* columnPsqtA1 =
reinterpret_cast<const psqt_vec_t*>(&featureTransformer.psqtWeights[offsetPsqtA1]);
const IndexType offsetPsqtR1 = PSQTBuckets * removed[1];
auto* columnPsqtR1 =
reinterpret_cast<const psqt_vec_t*>(&featureTransformer.psqtWeights[offsetPsqtR1]);
for (std::size_t i = 0; i < PSQTBuckets * sizeof(PSQTWeightType) / sizeof(psqt_vec_t);
++i)
accPsqtOut[i] = vec_add_psqt_32(
accPsqtIn[i], vec_sub_psqt_32(vec_add_psqt_32(columnPsqtA0[i], columnPsqtA1[i]),
vec_add_psqt_32(columnPsqtR0[i], columnPsqtR1[i])));
}
#else
std::memcpy((target_state.*accPtr).accumulation[Perspective],
(computed.*accPtr).accumulation[Perspective],
TransformedFeatureDimensions * sizeof(BiasType));
std::memcpy((target_state.*accPtr).psqtAccumulation[Perspective],
(computed.*accPtr).psqtAccumulation[Perspective],
PSQTBuckets * sizeof(PSQTWeightType));
// Difference calculation for the deactivated features
for (const auto index : removed)
{
const IndexType offset = TransformedFeatureDimensions * index;
for (IndexType i = 0; i < TransformedFeatureDimensions; ++i)
(target_state.*accPtr).accumulation[Perspective][i] -=
featureTransformer.weights[offset + i];
for (std::size_t i = 0; i < PSQTBuckets; ++i)
(target_state.*accPtr).psqtAccumulation[Perspective][i] -=
featureTransformer.psqtWeights[index * PSQTBuckets + i];
}
// Difference calculation for the activated features
for (const auto index : added)
{
const IndexType offset = TransformedFeatureDimensions * index;
for (IndexType i = 0; i < TransformedFeatureDimensions; ++i)
(target_state.*accPtr).accumulation[Perspective][i] +=
featureTransformer.weights[offset + i];
for (std::size_t i = 0; i < PSQTBuckets; ++i)
(target_state.*accPtr).psqtAccumulation[Perspective][i] +=
featureTransformer.psqtWeights[index * PSQTBuckets + i];
}
#endif
}
(target_state.*accPtr).computed[Perspective] = true;
}
template<Color Perspective, IndexType Dimensions, Accumulator<Dimensions> AccumulatorState::*accPtr>
void update_accumulator_refresh_cache(
const FeatureTransformer<Dimensions, accPtr>& featureTransformer,
const Position& pos,
AccumulatorState& accumulatorState,
AccumulatorCaches::Cache<Dimensions>& cache) {
using Tiling [[maybe_unused]] = SIMDTiling<Dimensions, Dimensions>;
const Square ksq = pos.square<KING>(Perspective);
auto& entry = cache[ksq][Perspective];
FeatureSet::IndexList removed, added;
for (Color c : {WHITE, BLACK})
{
for (PieceType pt = PAWN; pt <= KING; ++pt)
{
const Piece piece = make_piece(c, pt);
const Bitboard oldBB = entry.byColorBB[c] & entry.byTypeBB[pt];
const Bitboard newBB = pos.pieces(c, pt);
Bitboard toRemove = oldBB & ~newBB;
Bitboard toAdd = newBB & ~oldBB;
while (toRemove)
{
Square sq = pop_lsb(toRemove);
removed.push_back(FeatureSet::make_index<Perspective>(sq, piece, ksq));
}
while (toAdd)
{
Square sq = pop_lsb(toAdd);
added.push_back(FeatureSet::make_index<Perspective>(sq, piece, ksq));
}
}
}
auto& accumulator = accumulatorState.*accPtr;
accumulator.computed[Perspective] = true;
#ifdef VECTOR
const bool combineLast3 =
std::abs((int) removed.size() - (int) added.size()) == 1 && removed.size() + added.size() > 2;
vec_t acc[Tiling::NumRegs];
psqt_vec_t psqt[Tiling::NumPsqtRegs];
for (IndexType j = 0; j < Dimensions / Tiling::TileHeight; ++j)
{
auto* accTile =
reinterpret_cast<vec_t*>(&accumulator.accumulation[Perspective][j * Tiling::TileHeight]);
auto* entryTile = reinterpret_cast<vec_t*>(&entry.accumulation[j * Tiling::TileHeight]);
for (IndexType k = 0; k < Tiling::NumRegs; ++k)
acc[k] = entryTile[k];
std::size_t i = 0;
for (; i < std::min(removed.size(), added.size()) - combineLast3; ++i)
{
IndexType indexR = removed[i];
const IndexType offsetR = Dimensions * indexR + j * Tiling::TileHeight;
auto* columnR = reinterpret_cast<const vec_t*>(&featureTransformer.weights[offsetR]);
IndexType indexA = added[i];
const IndexType offsetA = Dimensions * indexA + j * Tiling::TileHeight;
auto* columnA = reinterpret_cast<const vec_t*>(&featureTransformer.weights[offsetA]);
for (IndexType k = 0; k < Tiling::NumRegs; ++k)
acc[k] = vec_add_16(acc[k], vec_sub_16(columnA[k], columnR[k]));
}
if (combineLast3)
{
IndexType indexR = removed[i];
const IndexType offsetR = Dimensions * indexR + j * Tiling::TileHeight;
auto* columnR = reinterpret_cast<const vec_t*>(&featureTransformer.weights[offsetR]);
IndexType indexA = added[i];
const IndexType offsetA = Dimensions * indexA + j * Tiling::TileHeight;
auto* columnA = reinterpret_cast<const vec_t*>(&featureTransformer.weights[offsetA]);
if (removed.size() > added.size())
{
IndexType indexR2 = removed[i + 1];
const IndexType offsetR2 = Dimensions * indexR2 + j * Tiling::TileHeight;
auto* columnR2 =
reinterpret_cast<const vec_t*>(&featureTransformer.weights[offsetR2]);
for (IndexType k = 0; k < Tiling::NumRegs; ++k)
acc[k] = vec_sub_16(vec_add_16(acc[k], columnA[k]),
vec_add_16(columnR[k], columnR2[k]));
}
else
{
IndexType indexA2 = added[i + 1];
const IndexType offsetA2 = Dimensions * indexA2 + j * Tiling::TileHeight;
auto* columnA2 =
reinterpret_cast<const vec_t*>(&featureTransformer.weights[offsetA2]);
for (IndexType k = 0; k < Tiling::NumRegs; ++k)
acc[k] = vec_add_16(vec_sub_16(acc[k], columnR[k]),
vec_add_16(columnA[k], columnA2[k]));
}
}
else
{
for (; i < removed.size(); ++i)
{
IndexType index = removed[i];
const IndexType offset = Dimensions * index + j * Tiling::TileHeight;
auto* column = reinterpret_cast<const vec_t*>(&featureTransformer.weights[offset]);
for (IndexType k = 0; k < Tiling::NumRegs; ++k)
acc[k] = vec_sub_16(acc[k], column[k]);
}
for (; i < added.size(); ++i)
{
IndexType index = added[i];
const IndexType offset = Dimensions * index + j * Tiling::TileHeight;
auto* column = reinterpret_cast<const vec_t*>(&featureTransformer.weights[offset]);
for (IndexType k = 0; k < Tiling::NumRegs; ++k)
acc[k] = vec_add_16(acc[k], column[k]);
}
}
for (IndexType k = 0; k < Tiling::NumRegs; k++)
vec_store(&entryTile[k], acc[k]);
for (IndexType k = 0; k < Tiling::NumRegs; k++)
vec_store(&accTile[k], acc[k]);
}
for (IndexType j = 0; j < PSQTBuckets / Tiling::PsqtTileHeight; ++j)
{
auto* accTilePsqt = reinterpret_cast<psqt_vec_t*>(
&accumulator.psqtAccumulation[Perspective][j * Tiling::PsqtTileHeight]);
auto* entryTilePsqt =
reinterpret_cast<psqt_vec_t*>(&entry.psqtAccumulation[j * Tiling::PsqtTileHeight]);
for (std::size_t k = 0; k < Tiling::NumPsqtRegs; ++k)
psqt[k] = entryTilePsqt[k];
for (std::size_t i = 0; i < removed.size(); ++i)
{
IndexType index = removed[i];
const IndexType offset = PSQTBuckets * index + j * Tiling::PsqtTileHeight;
auto* columnPsqt =
reinterpret_cast<const psqt_vec_t*>(&featureTransformer.psqtWeights[offset]);
for (std::size_t k = 0; k < Tiling::NumPsqtRegs; ++k)
psqt[k] = vec_sub_psqt_32(psqt[k], columnPsqt[k]);
}
for (std::size_t i = 0; i < added.size(); ++i)
{
IndexType index = added[i];
const IndexType offset = PSQTBuckets * index + j * Tiling::PsqtTileHeight;
auto* columnPsqt =
reinterpret_cast<const psqt_vec_t*>(&featureTransformer.psqtWeights[offset]);
for (std::size_t k = 0; k < Tiling::NumPsqtRegs; ++k)
psqt[k] = vec_add_psqt_32(psqt[k], columnPsqt[k]);
}
for (std::size_t k = 0; k < Tiling::NumPsqtRegs; ++k)
vec_store_psqt(&entryTilePsqt[k], psqt[k]);
for (std::size_t k = 0; k < Tiling::NumPsqtRegs; ++k)
vec_store_psqt(&accTilePsqt[k], psqt[k]);
}
#else
for (const auto index : removed)
{
const IndexType offset = Dimensions * index;
for (IndexType j = 0; j < Dimensions; ++j)
entry.accumulation[j] -= featureTransformer.weights[offset + j];
for (std::size_t k = 0; k < PSQTBuckets; ++k)
entry.psqtAccumulation[k] -= featureTransformer.psqtWeights[index * PSQTBuckets + k];
}
for (const auto index : added)
{
const IndexType offset = Dimensions * index;
for (IndexType j = 0; j < Dimensions; ++j)
entry.accumulation[j] += featureTransformer.weights[offset + j];
for (std::size_t k = 0; k < PSQTBuckets; ++k)
entry.psqtAccumulation[k] += featureTransformer.psqtWeights[index * PSQTBuckets + k];
}
// The accumulator of the refresh entry has been updated.
// Now copy its content to the actual accumulator we were refreshing.
std::memcpy(accumulator.accumulation[Perspective], entry.accumulation,
sizeof(BiasType) * Dimensions);
std::memcpy(accumulator.psqtAccumulation[Perspective], entry.psqtAccumulation,
sizeof(int32_t) * PSQTBuckets);
#endif
for (Color c : {WHITE, BLACK})
entry.byColorBB[c] = pos.pieces(c);
for (PieceType pt = PAWN; pt <= KING; ++pt)
entry.byTypeBB[pt] = pos.pieces(pt);
}
}
}
+87 -9
View File
@@ -1,6 +1,6 @@
/*
Stockfish, a UCI chess playing engine derived from Glaurung 2.1
Copyright (C) 2004-2024 The Stockfish developers (see AUTHORS file)
Copyright (C) 2004-2025 The Stockfish developers (see AUTHORS file)
Stockfish is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -21,23 +21,43 @@
#ifndef NNUE_ACCUMULATOR_H_INCLUDED
#define NNUE_ACCUMULATOR_H_INCLUDED
#include <array>
#include <cstddef>
#include <cstdint>
#include <cstring>
#include <vector>
#include "../types.h"
#include "nnue_architecture.h"
#include "nnue_common.h"
namespace Stockfish {
class Position;
}
namespace Stockfish::Eval::NNUE {
using BiasType = std::int16_t;
using PSQTWeightType = std::int32_t;
using IndexType = std::uint32_t;
struct Networks;
template<IndexType Size>
struct alignas(CacheLineSize) Accumulator;
struct AccumulatorState;
template<IndexType TransformedFeatureDimensions,
Accumulator<TransformedFeatureDimensions> AccumulatorState::*accPtr>
class FeatureTransformer;
// Class that holds the result of affine transformation of input features
template<IndexType Size>
struct alignas(CacheLineSize) Accumulator {
std::int16_t accumulation[COLOR_NB][Size];
std::int32_t psqtAccumulation[COLOR_NB][PSQTBuckets];
bool computed[COLOR_NB];
std::int16_t accumulation[COLOR_NB][Size];
std::int32_t psqtAccumulation[COLOR_NB][PSQTBuckets];
std::array<bool, COLOR_NB> computed;
};
@@ -80,11 +100,6 @@ struct AccumulatorCaches {
entry.clear(network.featureTransformer->biases);
}
void clear(const BiasType* biases) {
for (auto& entry : entries)
entry.clear(biases);
}
std::array<Entry, COLOR_NB>& operator[](Square sq) { return entries[sq]; }
std::array<std::array<Entry, COLOR_NB>, SQUARE_NB> entries;
@@ -100,6 +115,69 @@ struct AccumulatorCaches {
Cache<TransformedFeatureDimensionsSmall> small;
};
struct AccumulatorState {
Accumulator<TransformedFeatureDimensionsBig> accumulatorBig;
Accumulator<TransformedFeatureDimensionsSmall> accumulatorSmall;
DirtyPiece dirtyPiece;
void reset(const DirtyPiece& dp) noexcept;
};
class AccumulatorStack {
public:
AccumulatorStack() :
m_accumulators(MAX_PLY + 1),
m_current_idx{} {}
[[nodiscard]] const AccumulatorState& latest() const noexcept;
void
reset(const Position& rootPos, const Networks& networks, AccumulatorCaches& caches) noexcept;
void push(const DirtyPiece& dirtyPiece) noexcept;
void pop() noexcept;
template<IndexType Dimensions, Accumulator<Dimensions> AccumulatorState::*accPtr>
void evaluate(const Position& pos,
const FeatureTransformer<Dimensions, accPtr>& featureTransformer,
AccumulatorCaches::Cache<Dimensions>& cache) noexcept;
private:
[[nodiscard]] AccumulatorState& mut_latest() noexcept;
template<Color Perspective,
IndexType Dimensions,
Accumulator<Dimensions> AccumulatorState::*accPtr>
void evaluate_side(const Position& pos,
const FeatureTransformer<Dimensions, accPtr>& featureTransformer,
AccumulatorCaches::Cache<Dimensions>& cache) noexcept;
template<Color Perspective,
IndexType Dimensions,
Accumulator<Dimensions> AccumulatorState::*accPtr>
[[nodiscard]] std::size_t find_last_usable_accumulator() const noexcept;
template<Color Perspective,
IndexType Dimensions,
Accumulator<Dimensions> AccumulatorState::*accPtr>
void
forward_update_incremental(const Position& pos,
const FeatureTransformer<Dimensions, accPtr>& featureTransformer,
const std::size_t begin) noexcept;
template<Color Perspective,
IndexType Dimensions,
Accumulator<Dimensions> AccumulatorState::*accPtr>
void
backward_update_incremental(const Position& pos,
const FeatureTransformer<Dimensions, accPtr>& featureTransformer,
const std::size_t end) noexcept;
std::vector<AccumulatorState> m_accumulators;
std::size_t m_current_idx;
};
} // namespace Stockfish::Eval::NNUE
#endif // NNUE_ACCUMULATOR_H_INCLUDED
+1 -1
View File
@@ -1,6 +1,6 @@
/*
Stockfish, a UCI chess playing engine derived from Glaurung 2.1
Copyright (C) 2004-2024 The Stockfish developers (see AUTHORS file)
Copyright (C) 2004-2025 The Stockfish developers (see AUTHORS file)
Stockfish is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
+6 -1
View File
@@ -1,6 +1,6 @@
/*
Stockfish, a UCI chess playing engine derived from Glaurung 2.1
Copyright (C) 2004-2024 The Stockfish developers (see AUTHORS file)
Copyright (C) 2004-2025 The Stockfish developers (see AUTHORS file)
Stockfish is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -279,6 +279,11 @@ inline void write_leb_128(std::ostream& stream, const IntType* values, std::size
flush();
}
enum IncUpdateDirection {
FORWARD,
BACKWARDS
};
} // namespace Stockfish::Eval::NNUE
#endif // #ifndef NNUE_COMMON_H_INCLUDED
+119 -574
View File
@@ -1,6 +1,6 @@
/*
Stockfish, a UCI chess playing engine derived from Glaurung 2.1
Copyright (C) 2004-2024 The Stockfish developers (see AUTHORS file)
Copyright (C) 2004-2025 The Stockfish developers (see AUTHORS file)
Stockfish is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -22,11 +22,9 @@
#define NNUE_FEATURE_TRANSFORMER_H_INCLUDED
#include <algorithm>
#include <cassert>
#include <cstdint>
#include <cstring>
#include <iosfwd>
#include <utility>
#include "../position.h"
#include "../types.h"
@@ -145,11 +143,51 @@ using psqt_vec_t = int32x4_t;
#endif
// Returns the inverse of a permutation
template<std::size_t Len>
constexpr std::array<std::size_t, Len>
invert_permutation(const std::array<std::size_t, Len>& order) {
std::array<std::size_t, Len> inverse{};
for (std::size_t i = 0; i < order.size(); i++)
inverse[order[i]] = i;
return inverse;
}
// Divide a byte region of size TotalSize to chunks of size
// BlockSize, and permute the blocks by a given order
template<std::size_t BlockSize, typename T, std::size_t N, std::size_t OrderSize>
void permute(T (&data)[N], const std::array<std::size_t, OrderSize>& order) {
constexpr std::size_t TotalSize = N * sizeof(T);
static_assert(TotalSize % (BlockSize * OrderSize) == 0,
"ChunkSize * OrderSize must perfectly divide TotalSize");
constexpr std::size_t ProcessChunkSize = BlockSize * OrderSize;
std::array<std::byte, ProcessChunkSize> buffer{};
std::byte* const bytes = reinterpret_cast<std::byte*>(data);
for (std::size_t i = 0; i < TotalSize; i += ProcessChunkSize)
{
std::byte* const values = &bytes[i];
for (std::size_t j = 0; j < OrderSize; j++)
{
auto* const buffer_chunk = &buffer[j * BlockSize];
auto* const value_chunk = &values[order[j] * BlockSize];
std::copy(value_chunk, value_chunk + BlockSize, buffer_chunk);
}
std::copy(std::begin(buffer), std::end(buffer), values);
}
}
// Compute optimal SIMD register count for feature transformer accumulation.
template<IndexType TransformedFeatureWidth, IndexType HalfDimensions>
class SIMDTiling {
#ifdef VECTOR
// Compute optimal SIMD register count for feature transformer accumulation.
// We use __m* types as template arguments, which causes GCC to emit warnings
// about losing some attribute information. This is irrelevant to us as we
// only take their size, so the following pragma are harmless.
@@ -158,55 +196,56 @@ using psqt_vec_t = int32x4_t;
#pragma GCC diagnostic ignored "-Wignored-attributes"
#endif
template<typename SIMDRegisterType, typename LaneType, int NumLanes, int MaxRegisters>
static constexpr int BestRegisterCount() {
#define RegisterSize sizeof(SIMDRegisterType)
#define LaneSize sizeof(LaneType)
template<typename SIMDRegisterType, typename LaneType, int NumLanes, int MaxRegisters>
static constexpr int BestRegisterCount() {
constexpr std::size_t RegisterSize = sizeof(SIMDRegisterType);
constexpr std::size_t LaneSize = sizeof(LaneType);
static_assert(RegisterSize >= LaneSize);
static_assert(MaxRegisters <= NumRegistersSIMD);
static_assert(MaxRegisters > 0);
static_assert(NumRegistersSIMD > 0);
static_assert(RegisterSize % LaneSize == 0);
static_assert((NumLanes * LaneSize) % RegisterSize == 0);
static_assert(RegisterSize >= LaneSize);
static_assert(MaxRegisters <= NumRegistersSIMD);
static_assert(MaxRegisters > 0);
static_assert(NumRegistersSIMD > 0);
static_assert(RegisterSize % LaneSize == 0);
static_assert((NumLanes * LaneSize) % RegisterSize == 0);
const int ideal = (NumLanes * LaneSize) / RegisterSize;
if (ideal <= MaxRegisters)
return ideal;
const int ideal = (NumLanes * LaneSize) / RegisterSize;
if (ideal <= MaxRegisters)
return ideal;
// Look for the largest divisor of the ideal register count that is smaller than MaxRegisters
for (int divisor = MaxRegisters; divisor > 1; --divisor)
if (ideal % divisor == 0)
return divisor;
// Look for the largest divisor of the ideal register count that is smaller than MaxRegisters
for (int divisor = MaxRegisters; divisor > 1; --divisor)
if (ideal % divisor == 0)
return divisor;
return 1;
}
return 1;
}
#if defined(__GNUC__)
#pragma GCC diagnostic pop
#endif
#endif
// Input feature converter
template<IndexType TransformedFeatureDimensions,
Accumulator<TransformedFeatureDimensions> StateInfo::*accPtr>
class FeatureTransformer {
// Number of output dimensions for one side
static constexpr IndexType HalfDimensions = TransformedFeatureDimensions;
private:
#ifdef VECTOR
public:
static constexpr int NumRegs =
BestRegisterCount<vec_t, WeightType, TransformedFeatureDimensions, NumRegistersSIMD>();
BestRegisterCount<vec_t, WeightType, TransformedFeatureWidth, NumRegistersSIMD>();
static constexpr int NumPsqtRegs =
BestRegisterCount<psqt_vec_t, PSQTWeightType, PSQTBuckets, NumRegistersSIMD>();
static constexpr IndexType TileHeight = NumRegs * sizeof(vec_t) / 2;
static constexpr IndexType PsqtTileHeight = NumPsqtRegs * sizeof(psqt_vec_t) / 4;
static_assert(HalfDimensions % TileHeight == 0, "TileHeight must divide HalfDimensions");
static_assert(PSQTBuckets % PsqtTileHeight == 0, "PsqtTileHeight must divide PSQTBuckets");
#endif
};
// Input feature converter
template<IndexType TransformedFeatureDimensions,
Accumulator<TransformedFeatureDimensions> AccumulatorState::*accPtr>
class FeatureTransformer {
// Number of output dimensions for one side
static constexpr IndexType HalfDimensions = TransformedFeatureDimensions;
public:
// Output type
@@ -219,76 +258,54 @@ class FeatureTransformer {
// Size of forward propagation buffer
static constexpr std::size_t BufferSize = OutputDimensions * sizeof(OutputType);
// Store the order by which 128-bit blocks of a 1024-bit data must
// be permuted so that calling packus on adjacent vectors of 16-bit
// integers loaded from the data results in the pre-permutation order
static constexpr auto PackusEpi16Order = []() -> std::array<std::size_t, 8> {
#if defined(USE_AVX512)
// _mm512_packus_epi16 after permutation:
// | 0 | 2 | 4 | 6 | // Vector 0
// | 1 | 3 | 5 | 7 | // Vector 1
// | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | // Packed Result
return {0, 2, 4, 6, 1, 3, 5, 7};
#elif defined(USE_AVX2)
// _mm256_packus_epi16 after permutation:
// | 0 | 2 | | 4 | 6 | // Vector 0, 2
// | 1 | 3 | | 5 | 7 | // Vector 1, 3
// | 0 | 1 | 2 | 3 | | 4 | 5 | 6 | 7 | // Packed Result
return {0, 2, 1, 3, 4, 6, 5, 7};
#else
return {0, 1, 2, 3, 4, 5, 6, 7};
#endif
}();
static constexpr auto InversePackusEpi16Order = invert_permutation(PackusEpi16Order);
// Hash value embedded in the evaluation file
static constexpr std::uint32_t get_hash_value() {
return FeatureSet::HashValue ^ (OutputDimensions * 2);
}
static constexpr void order_packs([[maybe_unused]] uint64_t* v) {
#if defined(USE_AVX512) // _mm512_packs_epi16 ordering
uint64_t tmp0 = v[2], tmp1 = v[3];
v[2] = v[8], v[3] = v[9];
v[8] = v[4], v[9] = v[5];
v[4] = tmp0, v[5] = tmp1;
tmp0 = v[6], tmp1 = v[7];
v[6] = v[10], v[7] = v[11];
v[10] = v[12], v[11] = v[13];
v[12] = tmp0, v[13] = tmp1;
#elif defined(USE_AVX2) // _mm256_packs_epi16 ordering
std::swap(v[2], v[4]);
std::swap(v[3], v[5]);
#endif
void permute_weights() {
permute<16>(biases, PackusEpi16Order);
permute<16>(weights, PackusEpi16Order);
}
static constexpr void inverse_order_packs([[maybe_unused]] uint64_t* v) {
#if defined(USE_AVX512) // Inverse _mm512_packs_epi16 ordering
uint64_t tmp0 = v[2], tmp1 = v[3];
v[2] = v[4], v[3] = v[5];
v[4] = v[8], v[5] = v[9];
v[8] = tmp0, v[9] = tmp1;
tmp0 = v[6], tmp1 = v[7];
v[6] = v[12], v[7] = v[13];
v[12] = v[10], v[13] = v[11];
v[10] = tmp0, v[11] = tmp1;
#elif defined(USE_AVX2) // Inverse _mm256_packs_epi16 ordering
std::swap(v[2], v[4]);
std::swap(v[3], v[5]);
#endif
void unpermute_weights() {
permute<16>(biases, InversePackusEpi16Order);
permute<16>(weights, InversePackusEpi16Order);
}
void permute_weights([[maybe_unused]] void (*order_fn)(uint64_t*)) const {
#if defined(USE_AVX2)
#if defined(USE_AVX512)
constexpr IndexType di = 16;
#else
constexpr IndexType di = 8;
#endif
uint64_t* b = reinterpret_cast<uint64_t*>(const_cast<BiasType*>(&biases[0]));
for (IndexType i = 0; i < HalfDimensions * sizeof(BiasType) / sizeof(uint64_t); i += di)
order_fn(&b[i]);
inline void scale_weights(bool read) {
for (IndexType j = 0; j < InputDimensions; ++j)
{
uint64_t* w =
reinterpret_cast<uint64_t*>(const_cast<WeightType*>(&weights[j * HalfDimensions]));
for (IndexType i = 0; i < HalfDimensions * sizeof(WeightType) / sizeof(uint64_t);
i += di)
order_fn(&w[i]);
}
#endif
}
inline void scale_weights(bool read) const {
for (IndexType j = 0; j < InputDimensions; ++j)
{
WeightType* w = const_cast<WeightType*>(&weights[j * HalfDimensions]);
WeightType* w = &weights[j * HalfDimensions];
for (IndexType i = 0; i < HalfDimensions; ++i)
w[i] = read ? w[i] * 2 : w[i] / 2;
}
BiasType* b = const_cast<BiasType*>(biases);
for (IndexType i = 0; i < HalfDimensions; ++i)
b[i] = read ? b[i] * 2 : b[i] / 2;
biases[i] = read ? biases[i] * 2 : biases[i] / 2;
}
// Read network parameters
@@ -298,41 +315,43 @@ class FeatureTransformer {
read_leb_128<WeightType>(stream, weights, HalfDimensions * InputDimensions);
read_leb_128<PSQTWeightType>(stream, psqtWeights, PSQTBuckets * InputDimensions);
permute_weights(inverse_order_packs);
permute_weights();
scale_weights(true);
return !stream.fail();
}
// Write network parameters
bool write_parameters(std::ostream& stream) const {
bool write_parameters(std::ostream& stream) {
permute_weights(order_packs);
unpermute_weights();
scale_weights(false);
write_leb_128<BiasType>(stream, biases, HalfDimensions);
write_leb_128<WeightType>(stream, weights, HalfDimensions * InputDimensions);
write_leb_128<PSQTWeightType>(stream, psqtWeights, PSQTBuckets * InputDimensions);
permute_weights(inverse_order_packs);
permute_weights();
scale_weights(true);
return !stream.fail();
}
// Convert input features
std::int32_t transform(const Position& pos,
AccumulatorStack& accumulatorStack,
AccumulatorCaches::Cache<HalfDimensions>* cache,
OutputType* output,
int bucket) const {
update_accumulator<WHITE>(pos, cache);
update_accumulator<BLACK>(pos, cache);
accumulatorStack.evaluate(pos, *this, *cache);
const auto& accumulatorState = accumulatorStack.latest();
const Color perspectives[2] = {pos.side_to_move(), ~pos.side_to_move()};
const auto& psqtAccumulation = (pos.state()->*accPtr).psqtAccumulation;
const auto& psqtAccumulation = (accumulatorState.*accPtr).psqtAccumulation;
const auto psqt =
(psqtAccumulation[perspectives[0]][bucket] - psqtAccumulation[perspectives[1]][bucket])
/ 2;
const auto& accumulation = (pos.state()->*accPtr).accumulation;
const auto& accumulation = (accumulatorState.*accPtr).accumulation;
for (IndexType p = 0; p < 2; ++p)
{
@@ -445,480 +464,6 @@ class FeatureTransformer {
return psqt;
} // end of function transform()
void hint_common_access(const Position& pos,
AccumulatorCaches::Cache<HalfDimensions>* cache) const {
hint_common_access_for_perspective<WHITE>(pos, cache);
hint_common_access_for_perspective<BLACK>(pos, cache);
}
private:
template<Color Perspective>
[[nodiscard]] std::pair<StateInfo*, StateInfo*>
try_find_computed_accumulator(const Position& pos) const {
// Look for a usable accumulator of an earlier position. We keep track
// of the estimated gain in terms of features to be added/subtracted.
StateInfo *st = pos.state(), *next = nullptr;
int gain = FeatureSet::refresh_cost(pos);
while (st->previous && !(st->*accPtr).computed[Perspective])
{
// This governs when a full feature refresh is needed and how many
// updates are better than just one full refresh.
if (FeatureSet::requires_refresh(st, Perspective)
|| (gain -= FeatureSet::update_cost(st) + 1) < 0)
break;
next = st;
st = st->previous;
}
return {st, next};
}
// NOTE: The parameter states_to_update is an array of position states.
// All states must be sequential, that is states_to_update[i] must
// either be reachable by repeatedly applying ->previous from
// states_to_update[i+1], and computed_st must be reachable by
// repeatedly applying ->previous on states_to_update[0].
template<Color Perspective, size_t N>
void update_accumulator_incremental(const Position& pos,
StateInfo* computed_st,
StateInfo* states_to_update[N]) const {
static_assert(N > 0);
assert([&]() {
for (size_t i = 0; i < N; ++i)
{
if (states_to_update[i] == nullptr)
return false;
}
return true;
}());
#ifdef VECTOR
// Gcc-10.2 unnecessarily spills AVX2 registers if this array
// is defined in the VECTOR code below, once in each branch.
vec_t acc[NumRegs];
psqt_vec_t psqt[NumPsqtRegs];
#endif
// Update incrementally going back through states_to_update.
// Gather all features to be updated.
const Square ksq = pos.square<KING>(Perspective);
// The size must be enough to contain the largest possible update.
// That might depend on the feature set and generally relies on the
// feature set's update cost calculation to be correct and never allow
// updates with more added/removed features than MaxActiveDimensions.
FeatureSet::IndexList removed[N], added[N];
for (int i = N - 1; i >= 0; --i)
{
(states_to_update[i]->*accPtr).computed[Perspective] = true;
const StateInfo* end_state = i == 0 ? computed_st : states_to_update[i - 1];
for (StateInfo* st2 = states_to_update[i]; st2 != end_state; st2 = st2->previous)
FeatureSet::append_changed_indices<Perspective>(ksq, st2->dirtyPiece, removed[i],
added[i]);
}
StateInfo* st = computed_st;
// Now update the accumulators listed in states_to_update[],
// where the last element is a sentinel.
#ifdef VECTOR
if (N == 1 && (removed[0].size() == 1 || removed[0].size() == 2) && added[0].size() == 1)
{
assert(states_to_update[0]);
auto accIn =
reinterpret_cast<const vec_t*>(&(st->*accPtr).accumulation[Perspective][0]);
auto accOut = reinterpret_cast<vec_t*>(
&(states_to_update[0]->*accPtr).accumulation[Perspective][0]);
const IndexType offsetR0 = HalfDimensions * removed[0][0];
auto columnR0 = reinterpret_cast<const vec_t*>(&weights[offsetR0]);
const IndexType offsetA = HalfDimensions * added[0][0];
auto columnA = reinterpret_cast<const vec_t*>(&weights[offsetA]);
if (removed[0].size() == 1)
{
for (IndexType k = 0; k < HalfDimensions * sizeof(std::int16_t) / sizeof(vec_t);
++k)
accOut[k] = vec_add_16(vec_sub_16(accIn[k], columnR0[k]), columnA[k]);
}
else
{
const IndexType offsetR1 = HalfDimensions * removed[0][1];
auto columnR1 = reinterpret_cast<const vec_t*>(&weights[offsetR1]);
for (IndexType k = 0; k < HalfDimensions * sizeof(std::int16_t) / sizeof(vec_t);
++k)
accOut[k] = vec_sub_16(vec_add_16(accIn[k], columnA[k]),
vec_add_16(columnR0[k], columnR1[k]));
}
auto accPsqtIn =
reinterpret_cast<const psqt_vec_t*>(&(st->*accPtr).psqtAccumulation[Perspective][0]);
auto accPsqtOut = reinterpret_cast<psqt_vec_t*>(
&(states_to_update[0]->*accPtr).psqtAccumulation[Perspective][0]);
const IndexType offsetPsqtR0 = PSQTBuckets * removed[0][0];
auto columnPsqtR0 = reinterpret_cast<const psqt_vec_t*>(&psqtWeights[offsetPsqtR0]);
const IndexType offsetPsqtA = PSQTBuckets * added[0][0];
auto columnPsqtA = reinterpret_cast<const psqt_vec_t*>(&psqtWeights[offsetPsqtA]);
if (removed[0].size() == 1)
{
for (std::size_t k = 0; k < PSQTBuckets * sizeof(std::int32_t) / sizeof(psqt_vec_t);
++k)
accPsqtOut[k] = vec_add_psqt_32(vec_sub_psqt_32(accPsqtIn[k], columnPsqtR0[k]),
columnPsqtA[k]);
}
else
{
const IndexType offsetPsqtR1 = PSQTBuckets * removed[0][1];
auto columnPsqtR1 = reinterpret_cast<const psqt_vec_t*>(&psqtWeights[offsetPsqtR1]);
for (std::size_t k = 0; k < PSQTBuckets * sizeof(std::int32_t) / sizeof(psqt_vec_t);
++k)
accPsqtOut[k] =
vec_sub_psqt_32(vec_add_psqt_32(accPsqtIn[k], columnPsqtA[k]),
vec_add_psqt_32(columnPsqtR0[k], columnPsqtR1[k]));
}
}
else
{
for (IndexType j = 0; j < HalfDimensions / TileHeight; ++j)
{
// Load accumulator
auto accTileIn = reinterpret_cast<const vec_t*>(
&(st->*accPtr).accumulation[Perspective][j * TileHeight]);
for (IndexType k = 0; k < NumRegs; ++k)
acc[k] = vec_load(&accTileIn[k]);
for (IndexType i = 0; i < N; ++i)
{
// Difference calculation for the deactivated features
for (const auto index : removed[i])
{
const IndexType offset = HalfDimensions * index + j * TileHeight;
auto column = reinterpret_cast<const vec_t*>(&weights[offset]);
for (IndexType k = 0; k < NumRegs; ++k)
acc[k] = vec_sub_16(acc[k], column[k]);
}
// Difference calculation for the activated features
for (const auto index : added[i])
{
const IndexType offset = HalfDimensions * index + j * TileHeight;
auto column = reinterpret_cast<const vec_t*>(&weights[offset]);
for (IndexType k = 0; k < NumRegs; ++k)
acc[k] = vec_add_16(acc[k], column[k]);
}
// Store accumulator
auto accTileOut = reinterpret_cast<vec_t*>(
&(states_to_update[i]->*accPtr).accumulation[Perspective][j * TileHeight]);
for (IndexType k = 0; k < NumRegs; ++k)
vec_store(&accTileOut[k], acc[k]);
}
}
for (IndexType j = 0; j < PSQTBuckets / PsqtTileHeight; ++j)
{
// Load accumulator
auto accTilePsqtIn = reinterpret_cast<const psqt_vec_t*>(
&(st->*accPtr).psqtAccumulation[Perspective][j * PsqtTileHeight]);
for (std::size_t k = 0; k < NumPsqtRegs; ++k)
psqt[k] = vec_load_psqt(&accTilePsqtIn[k]);
for (IndexType i = 0; i < N; ++i)
{
// Difference calculation for the deactivated features
for (const auto index : removed[i])
{
const IndexType offset = PSQTBuckets * index + j * PsqtTileHeight;
auto columnPsqt = reinterpret_cast<const psqt_vec_t*>(&psqtWeights[offset]);
for (std::size_t k = 0; k < NumPsqtRegs; ++k)
psqt[k] = vec_sub_psqt_32(psqt[k], columnPsqt[k]);
}
// Difference calculation for the activated features
for (const auto index : added[i])
{
const IndexType offset = PSQTBuckets * index + j * PsqtTileHeight;
auto columnPsqt = reinterpret_cast<const psqt_vec_t*>(&psqtWeights[offset]);
for (std::size_t k = 0; k < NumPsqtRegs; ++k)
psqt[k] = vec_add_psqt_32(psqt[k], columnPsqt[k]);
}
// Store accumulator
auto accTilePsqtOut = reinterpret_cast<psqt_vec_t*>(
&(states_to_update[i]->*accPtr)
.psqtAccumulation[Perspective][j * PsqtTileHeight]);
for (std::size_t k = 0; k < NumPsqtRegs; ++k)
vec_store_psqt(&accTilePsqtOut[k], psqt[k]);
}
}
}
#else
for (IndexType i = 0; i < N; ++i)
{
std::memcpy((states_to_update[i]->*accPtr).accumulation[Perspective],
(st->*accPtr).accumulation[Perspective], HalfDimensions * sizeof(BiasType));
for (std::size_t k = 0; k < PSQTBuckets; ++k)
(states_to_update[i]->*accPtr).psqtAccumulation[Perspective][k] =
(st->*accPtr).psqtAccumulation[Perspective][k];
st = states_to_update[i];
// Difference calculation for the deactivated features
for (const auto index : removed[i])
{
const IndexType offset = HalfDimensions * index;
for (IndexType j = 0; j < HalfDimensions; ++j)
(st->*accPtr).accumulation[Perspective][j] -= weights[offset + j];
for (std::size_t k = 0; k < PSQTBuckets; ++k)
(st->*accPtr).psqtAccumulation[Perspective][k] -=
psqtWeights[index * PSQTBuckets + k];
}
// Difference calculation for the activated features
for (const auto index : added[i])
{
const IndexType offset = HalfDimensions * index;
for (IndexType j = 0; j < HalfDimensions; ++j)
(st->*accPtr).accumulation[Perspective][j] += weights[offset + j];
for (std::size_t k = 0; k < PSQTBuckets; ++k)
(st->*accPtr).psqtAccumulation[Perspective][k] +=
psqtWeights[index * PSQTBuckets + k];
}
}
#endif
}
template<Color Perspective>
void update_accumulator_refresh_cache(const Position& pos,
AccumulatorCaches::Cache<HalfDimensions>* cache) const {
assert(cache != nullptr);
Square ksq = pos.square<KING>(Perspective);
auto& entry = (*cache)[ksq][Perspective];
FeatureSet::IndexList removed, added;
for (Color c : {WHITE, BLACK})
{
for (PieceType pt = PAWN; pt <= KING; ++pt)
{
const Piece piece = make_piece(c, pt);
const Bitboard oldBB = entry.byColorBB[c] & entry.byTypeBB[pt];
const Bitboard newBB = pos.pieces(c, pt);
Bitboard toRemove = oldBB & ~newBB;
Bitboard toAdd = newBB & ~oldBB;
while (toRemove)
{
Square sq = pop_lsb(toRemove);
removed.push_back(FeatureSet::make_index<Perspective>(sq, piece, ksq));
}
while (toAdd)
{
Square sq = pop_lsb(toAdd);
added.push_back(FeatureSet::make_index<Perspective>(sq, piece, ksq));
}
}
}
auto& accumulator = pos.state()->*accPtr;
accumulator.computed[Perspective] = true;
#ifdef VECTOR
vec_t acc[NumRegs];
psqt_vec_t psqt[NumPsqtRegs];
for (IndexType j = 0; j < HalfDimensions / TileHeight; ++j)
{
auto accTile =
reinterpret_cast<vec_t*>(&accumulator.accumulation[Perspective][j * TileHeight]);
auto entryTile = reinterpret_cast<vec_t*>(&entry.accumulation[j * TileHeight]);
for (IndexType k = 0; k < NumRegs; ++k)
acc[k] = entryTile[k];
int i = 0;
for (; i < int(std::min(removed.size(), added.size())); ++i)
{
IndexType indexR = removed[i];
const IndexType offsetR = HalfDimensions * indexR + j * TileHeight;
auto columnR = reinterpret_cast<const vec_t*>(&weights[offsetR]);
IndexType indexA = added[i];
const IndexType offsetA = HalfDimensions * indexA + j * TileHeight;
auto columnA = reinterpret_cast<const vec_t*>(&weights[offsetA]);
for (unsigned k = 0; k < NumRegs; ++k)
acc[k] = vec_add_16(acc[k], vec_sub_16(columnA[k], columnR[k]));
}
for (; i < int(removed.size()); ++i)
{
IndexType index = removed[i];
const IndexType offset = HalfDimensions * index + j * TileHeight;
auto column = reinterpret_cast<const vec_t*>(&weights[offset]);
for (unsigned k = 0; k < NumRegs; ++k)
acc[k] = vec_sub_16(acc[k], column[k]);
}
for (; i < int(added.size()); ++i)
{
IndexType index = added[i];
const IndexType offset = HalfDimensions * index + j * TileHeight;
auto column = reinterpret_cast<const vec_t*>(&weights[offset]);
for (unsigned k = 0; k < NumRegs; ++k)
acc[k] = vec_add_16(acc[k], column[k]);
}
for (IndexType k = 0; k < NumRegs; k++)
vec_store(&entryTile[k], acc[k]);
for (IndexType k = 0; k < NumRegs; k++)
vec_store(&accTile[k], acc[k]);
}
for (IndexType j = 0; j < PSQTBuckets / PsqtTileHeight; ++j)
{
auto accTilePsqt = reinterpret_cast<psqt_vec_t*>(
&accumulator.psqtAccumulation[Perspective][j * PsqtTileHeight]);
auto entryTilePsqt =
reinterpret_cast<psqt_vec_t*>(&entry.psqtAccumulation[j * PsqtTileHeight]);
for (std::size_t k = 0; k < NumPsqtRegs; ++k)
psqt[k] = entryTilePsqt[k];
for (int i = 0; i < int(removed.size()); ++i)
{
IndexType index = removed[i];
const IndexType offset = PSQTBuckets * index + j * PsqtTileHeight;
auto columnPsqt = reinterpret_cast<const psqt_vec_t*>(&psqtWeights[offset]);
for (std::size_t k = 0; k < NumPsqtRegs; ++k)
psqt[k] = vec_sub_psqt_32(psqt[k], columnPsqt[k]);
}
for (int i = 0; i < int(added.size()); ++i)
{
IndexType index = added[i];
const IndexType offset = PSQTBuckets * index + j * PsqtTileHeight;
auto columnPsqt = reinterpret_cast<const psqt_vec_t*>(&psqtWeights[offset]);
for (std::size_t k = 0; k < NumPsqtRegs; ++k)
psqt[k] = vec_add_psqt_32(psqt[k], columnPsqt[k]);
}
for (std::size_t k = 0; k < NumPsqtRegs; ++k)
vec_store_psqt(&entryTilePsqt[k], psqt[k]);
for (std::size_t k = 0; k < NumPsqtRegs; ++k)
vec_store_psqt(&accTilePsqt[k], psqt[k]);
}
#else
for (const auto index : removed)
{
const IndexType offset = HalfDimensions * index;
for (IndexType j = 0; j < HalfDimensions; ++j)
entry.accumulation[j] -= weights[offset + j];
for (std::size_t k = 0; k < PSQTBuckets; ++k)
entry.psqtAccumulation[k] -= psqtWeights[index * PSQTBuckets + k];
}
for (const auto index : added)
{
const IndexType offset = HalfDimensions * index;
for (IndexType j = 0; j < HalfDimensions; ++j)
entry.accumulation[j] += weights[offset + j];
for (std::size_t k = 0; k < PSQTBuckets; ++k)
entry.psqtAccumulation[k] += psqtWeights[index * PSQTBuckets + k];
}
// The accumulator of the refresh entry has been updated.
// Now copy its content to the actual accumulator we were refreshing.
std::memcpy(accumulator.accumulation[Perspective], entry.accumulation,
sizeof(BiasType) * HalfDimensions);
std::memcpy(accumulator.psqtAccumulation[Perspective], entry.psqtAccumulation,
sizeof(int32_t) * PSQTBuckets);
#endif
for (Color c : {WHITE, BLACK})
entry.byColorBB[c] = pos.pieces(c);
for (PieceType pt = PAWN; pt <= KING; ++pt)
entry.byTypeBB[pt] = pos.pieces(pt);
}
template<Color Perspective>
void hint_common_access_for_perspective(const Position& pos,
AccumulatorCaches::Cache<HalfDimensions>* cache) const {
// Works like update_accumulator, but performs less work.
// Updates ONLY the accumulator for pos.
// Look for a usable accumulator of an earlier position. We keep track
// of the estimated gain in terms of features to be added/subtracted.
// Fast early exit.
if ((pos.state()->*accPtr).computed[Perspective])
return;
auto [oldest_st, _] = try_find_computed_accumulator<Perspective>(pos);
if ((oldest_st->*accPtr).computed[Perspective])
{
// Only update current position accumulator to minimize work
StateInfo* states_to_update[1] = {pos.state()};
update_accumulator_incremental<Perspective, 1>(pos, oldest_st, states_to_update);
}
else
update_accumulator_refresh_cache<Perspective>(pos, cache);
}
template<Color Perspective>
void update_accumulator(const Position& pos,
AccumulatorCaches::Cache<HalfDimensions>* cache) const {
auto [oldest_st, next] = try_find_computed_accumulator<Perspective>(pos);
if ((oldest_st->*accPtr).computed[Perspective])
{
if (next == nullptr)
return;
// Now update the accumulators listed in states_to_update[], where
// the last element is a sentinel. Currently we update two accumulators:
// 1. for the current position
// 2. the next accumulator after the computed one
// The heuristic may change in the future.
if (next == pos.state())
{
StateInfo* states_to_update[1] = {next};
update_accumulator_incremental<Perspective, 1>(pos, oldest_st, states_to_update);
}
else
{
StateInfo* states_to_update[2] = {next, pos.state()};
update_accumulator_incremental<Perspective, 2>(pos, oldest_st, states_to_update);
}
}
else
update_accumulator_refresh_cache<Perspective>(pos, cache);
}
template<IndexType Size>
friend struct AccumulatorCaches::Cache;
alignas(CacheLineSize) BiasType biases[HalfDimensions];
alignas(CacheLineSize) WeightType weights[HalfDimensions * InputDimensions];
alignas(CacheLineSize) PSQTWeightType psqtWeights[InputDimensions * PSQTBuckets];
+10 -19
View File
@@ -1,6 +1,6 @@
/*
Stockfish, a UCI chess playing engine derived from Glaurung 2.1
Copyright (C) 2004-2024 The Stockfish developers (see AUTHORS file)
Copyright (C) 2004-2025 The Stockfish developers (see AUTHORS file)
Stockfish is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -30,7 +30,6 @@
#include <string_view>
#include <tuple>
#include "../evaluate.h"
#include "../position.h"
#include "../types.h"
#include "../uci.h"
@@ -43,15 +42,6 @@ namespace Stockfish::Eval::NNUE {
constexpr std::string_view PieceToChar(" PNBRQK pnbrqk");
void hint_common_parent_position(const Position& pos,
const Networks& networks,
AccumulatorCaches& caches) {
if (Eval::use_smallnet(pos))
networks.small.hint_common_access(pos, &caches.small);
else
networks.big.hint_common_access(pos, &caches.big);
}
namespace {
// Converts a Value into (centi)pawns and writes it in a buffer.
// The buffer must have capacity for at least 5 chars.
@@ -126,13 +116,16 @@ trace(Position& pos, const Eval::NNUE::Networks& networks, Eval::NNUE::Accumulat
board[y][x] = board[y][x + 8] = board[y + 3][x + 8] = board[y + 3][x] = '+';
if (pc != NO_PIECE)
board[y + 1][x + 4] = PieceToChar[pc];
if (value != VALUE_NONE)
if (is_valid(value))
format_cp_compact(value, &board[y + 2][x + 2], pos);
};
AccumulatorStack accumulators;
accumulators.reset(pos, networks, caches);
// We estimate the value of each piece by doing a differential evaluation from
// the current base eval, simulating the removal of the piece from its square.
auto [psqt, positional] = networks.big.evaluate(pos, &caches.big);
auto [psqt, positional] = networks.big.evaluate(pos, accumulators, &caches.big);
Value base = psqt + positional;
base = pos.side_to_move() == WHITE ? base : -base;
@@ -145,18 +138,15 @@ trace(Position& pos, const Eval::NNUE::Networks& networks, Eval::NNUE::Accumulat
if (pc != NO_PIECE && type_of(pc) != KING)
{
auto st = pos.state();
pos.remove_piece(sq);
st->accumulatorBig.computed[WHITE] = st->accumulatorBig.computed[BLACK] = false;
std::tie(psqt, positional) = networks.big.evaluate(pos, &caches.big);
accumulators.reset(pos, networks, caches);
std::tie(psqt, positional) = networks.big.evaluate(pos, accumulators, &caches.big);
Value eval = psqt + positional;
eval = pos.side_to_move() == WHITE ? eval : -eval;
v = base - eval;
pos.put_piece(pc, sq);
st->accumulatorBig.computed[WHITE] = st->accumulatorBig.computed[BLACK] = false;
}
writeSquare(f, r, pc, v);
@@ -167,7 +157,8 @@ trace(Position& pos, const Eval::NNUE::Networks& networks, Eval::NNUE::Accumulat
ss << board[row] << '\n';
ss << '\n';
auto t = networks.big.trace_evaluate(pos, &caches.big);
accumulators.reset(pos, networks, caches);
auto t = networks.big.trace_evaluate(pos, accumulators, &caches.big);
ss << " NNUE network contributions "
<< (pos.side_to_move() == WHITE ? "(White to move)" : "(Black to move)") << std::endl
+1 -4
View File
@@ -1,6 +1,6 @@
/*
Stockfish, a UCI chess playing engine derived from Glaurung 2.1
Copyright (C) 2004-2024 The Stockfish developers (see AUTHORS file)
Copyright (C) 2004-2025 The Stockfish developers (see AUTHORS file)
Stockfish is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -54,9 +54,6 @@ struct Networks;
struct AccumulatorCaches;
std::string trace(Position& pos, const Networks& networks, AccumulatorCaches& caches);
void hint_common_parent_position(const Position& pos,
const Networks& networks,
AccumulatorCaches& caches);
} // namespace Stockfish::Eval::NNUE
} // namespace Stockfish
+7 -6
View File
@@ -1,6 +1,6 @@
/*
Stockfish, a UCI chess playing engine derived from Glaurung 2.1
Copyright (C) 2004-2024 The Stockfish developers (see AUTHORS file)
Copyright (C) 2004-2025 The Stockfish developers (see AUTHORS file)
Stockfish is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -23,6 +23,7 @@
#include <atomic>
#include <cstdint>
#include <cstdlib>
#include <functional>
#include <iostream>
#include <limits>
#include <map>
@@ -653,7 +654,7 @@ class NumaConfig {
NumaIndex n = 0;
for (auto&& nodeStr : split(s, ":"))
{
auto indices = indices_from_shortened_string(nodeStr);
auto indices = indices_from_shortened_string(std::string(nodeStr));
if (!indices.empty())
{
for (auto idx : indices)
@@ -1015,7 +1016,7 @@ class NumaConfig {
if (s.empty())
return indices;
for (const std::string& ss : split(s, ","))
for (const auto& ss : split(s, ","))
{
if (ss.empty())
continue;
@@ -1023,13 +1024,13 @@ class NumaConfig {
auto parts = split(ss, "-");
if (parts.size() == 1)
{
const CpuIndex c = CpuIndex{str_to_size_t(parts[0])};
const CpuIndex c = CpuIndex{str_to_size_t(std::string(parts[0]))};
indices.emplace_back(c);
}
else if (parts.size() == 2)
{
const CpuIndex cfirst = CpuIndex{str_to_size_t(parts[0])};
const CpuIndex clast = CpuIndex{str_to_size_t(parts[1])};
const CpuIndex cfirst = CpuIndex{str_to_size_t(std::string(parts[0]))};
const CpuIndex clast = CpuIndex{str_to_size_t(std::string(parts[1]))};
for (size_t c = cfirst; c <= clast; ++c)
{
indices.emplace_back(c);
+1 -2
View File
@@ -1,6 +1,6 @@
/*
Stockfish, a UCI chess playing engine derived from Glaurung 2.1
Copyright (C) 2004-2024 The Stockfish developers (see AUTHORS file)
Copyright (C) 2004-2025 The Stockfish developers (see AUTHORS file)
Stockfish is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -34,7 +34,6 @@ template<bool Root>
uint64_t perft(Position& pos, Depth depth) {
StateInfo st;
ASSERT_ALIGNED(&st, Eval::NNUE::CacheLineSize);
uint64_t cnt, nodes = 0;
const bool leaf = (depth == 2);
+103 -77
View File
@@ -1,6 +1,6 @@
/*
Stockfish, a UCI chess playing engine derived from Glaurung 2.1
Copyright (C) 2004-2024 The Stockfish developers (see AUTHORS file)
Copyright (C) 2004-2025 The Stockfish developers (see AUTHORS file)
Stockfish is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -34,7 +34,6 @@
#include "bitboard.h"
#include "misc.h"
#include "movegen.h"
#include "nnue/nnue_common.h"
#include "syzygy/tbprobe.h"
#include "tt.h"
#include "uci.h"
@@ -83,7 +82,6 @@ std::ostream& operator<<(std::ostream& os, const Position& pos) {
if (int(Tablebases::MaxCardinality) >= popcount(pos.pieces()) && !pos.can_castle(ANY_CASTLING))
{
StateInfo st;
ASSERT_ALIGNED(&st, Eval::NNUE::CacheLineSize);
Position p;
p.set(pos.fen(), pos.is_chess960(), &st);
@@ -119,6 +117,9 @@ void Position::init() {
for (Piece pc : Pieces)
for (Square s = SQ_A1; s <= SQ_H8; ++s)
Zobrist::psq[pc][s] = rng.rand<Key>();
// pawns on these squares will promote
std::fill_n(Zobrist::psq[W_PAWN] + SQ_A8, 8, 0);
std::fill_n(Zobrist::psq[B_PAWN], 8, 0);
for (File f = FILE_A; f <= FILE_H; ++f)
Zobrist::enpassant[f] = rng.rand<Key>();
@@ -334,8 +335,10 @@ void Position::set_check_info() const {
// The function is only used when a new position is set up
void Position::set_state() const {
st->key = st->materialKey = 0;
st->pawnKey = Zobrist::noPawns;
st->key = st->materialKey = 0;
st->minorPieceKey = 0;
st->nonPawnKey[WHITE] = st->nonPawnKey[BLACK] = 0;
st->pawnKey = Zobrist::noPawns;
st->nonPawnMaterial[WHITE] = st->nonPawnMaterial[BLACK] = VALUE_ZERO;
st->checkersBB = attackers_to(square<KING>(sideToMove)) & pieces(~sideToMove);
@@ -350,8 +353,18 @@ void Position::set_state() const {
if (type_of(pc) == PAWN)
st->pawnKey ^= Zobrist::psq[pc][s];
else if (type_of(pc) != KING)
st->nonPawnMaterial[color_of(pc)] += PieceValue[pc];
else
{
st->nonPawnKey[color_of(pc)] ^= Zobrist::psq[pc][s];
if (type_of(pc) != KING)
{
st->nonPawnMaterial[color_of(pc)] += PieceValue[pc];
if (type_of(pc) <= BISHOP)
st->minorPieceKey ^= Zobrist::psq[pc][s];
}
}
}
if (st->epSquare != SQ_NONE)
@@ -364,7 +377,7 @@ void Position::set_state() const {
for (Piece pc : Pieces)
for (int cnt = 0; cnt < pieceCount[pc]; ++cnt)
st->materialKey ^= Zobrist::psq[pc][cnt];
st->materialKey ^= Zobrist::psq[pc][8 + cnt];
}
@@ -472,14 +485,23 @@ void Position::update_slider_blockers(Color c) const {
// Slider attacks use the occupied bitboard to indicate occupancy.
Bitboard Position::attackers_to(Square s, Bitboard occupied) const {
return (pawn_attacks_bb(BLACK, s) & pieces(WHITE, PAWN))
| (pawn_attacks_bb(WHITE, s) & pieces(BLACK, PAWN))
| (attacks_bb<KNIGHT>(s) & pieces(KNIGHT))
| (attacks_bb<ROOK>(s, occupied) & pieces(ROOK, QUEEN))
return (attacks_bb<ROOK>(s, occupied) & pieces(ROOK, QUEEN))
| (attacks_bb<BISHOP>(s, occupied) & pieces(BISHOP, QUEEN))
| (attacks_bb<KING>(s) & pieces(KING));
| (pawn_attacks_bb(BLACK, s) & pieces(WHITE, PAWN))
| (pawn_attacks_bb(WHITE, s) & pieces(BLACK, PAWN))
| (attacks_bb<KNIGHT>(s) & pieces(KNIGHT)) | (attacks_bb<KING>(s) & pieces(KING));
}
bool Position::attackers_to_exist(Square s, Bitboard occupied, Color c) const {
return ((attacks_bb<ROOK>(s) & pieces(c, ROOK, QUEEN))
&& (attacks_bb<ROOK>(s, occupied) & pieces(c, ROOK, QUEEN)))
|| ((attacks_bb<BISHOP>(s) & pieces(c, BISHOP, QUEEN))
&& (attacks_bb<BISHOP>(s, occupied) & pieces(c, BISHOP, QUEEN)))
|| (((pawn_attacks_bb(~c, s) & pieces(PAWN)) | (attacks_bb<KNIGHT>(s) & pieces(KNIGHT))
| (attacks_bb<KING>(s) & pieces(KING)))
& pieces(c));
}
// Tests whether a pseudo-legal move is legal
bool Position::legal(Move m) const {
@@ -521,7 +543,7 @@ bool Position::legal(Move m) const {
Direction step = to > from ? WEST : EAST;
for (Square s = to; s != from; s += step)
if (attackers_to(s) & pieces(~us))
if (attackers_to_exist(s, pieces(), ~us))
return false;
// In case of Chess960, verify if the Rook blocks some checks.
@@ -532,11 +554,11 @@ bool Position::legal(Move m) const {
// If the moving piece is a king, check whether the destination square is
// attacked by the opponent.
if (type_of(piece_on(from)) == KING)
return !(attackers_to(to, pieces() ^ from) & pieces(~us));
return !(attackers_to_exist(to, pieces() ^ from, ~us));
// A non-king move is legal if and only if it is not pinned or it
// is moving along the ray towards or away from the king.
return !(blockers_for_king(us) & from) || aligned(from, to, square<KING>(us));
return !(blockers_for_king(us) & from) || line_bb(from, to) & pieces(us, KING);
}
@@ -601,7 +623,7 @@ bool Position::pseudo_legal(const Move m) const {
}
// In case of king moves under check we have to remove the king so as to catch
// invalid moves like b1a1 when opposite queen is on c1.
else if (attackers_to(to, pieces() ^ from) & pieces(~us))
else if (attackers_to_exist(to, pieces() ^ from, ~us))
return false;
}
@@ -624,7 +646,7 @@ bool Position::gives_check(Move m) const {
// Is there a discovered check?
if (blockers_for_king(~sideToMove) & from)
return !aligned(from, to, square<KING>(~sideToMove)) || m.type_of() == CASTLING;
return !(line_bb(from, to) & pieces(~sideToMove, KING)) || m.type_of() == CASTLING;
switch (m.type_of())
{
@@ -632,7 +654,7 @@ bool Position::gives_check(Move m) const {
return false;
case PROMOTION :
return attacks_bb(m.promotion_type(), to, pieces() ^ from) & square<KING>(~sideToMove);
return attacks_bb(m.promotion_type(), to, pieces() ^ from) & pieces(~sideToMove, KING);
// En passant capture with check? We have already handled the case of direct
// checks and ordinary discovered check, so the only case we need to handle
@@ -659,7 +681,12 @@ bool Position::gives_check(Move m) const {
// Makes a move, and saves all information necessary
// to a StateInfo object. The move is assumed to be legal. Pseudo-legal
// moves should be filtered out before this function is called.
void Position::do_move(Move m, StateInfo& newSt, bool givesCheck) {
// If a pointer to the TT table is passed, the entry for the new position
// will be prefetched
DirtyPiece Position::do_move(Move m,
StateInfo& newSt,
bool givesCheck,
const TranspositionTable* tt = nullptr) {
assert(m.is_ok());
assert(&newSt != st);
@@ -671,6 +698,7 @@ void Position::do_move(Move m, StateInfo& newSt, bool givesCheck) {
// our state pointer to point to the new (ready to be updated) state.
std::memcpy(&newSt, st, offsetof(StateInfo, key));
newSt.previous = st;
st->next = &newSt;
st = &newSt;
// Increment ply counters. In particular, rule50 will be reset to zero later on
@@ -679,11 +707,7 @@ void Position::do_move(Move m, StateInfo& newSt, bool givesCheck) {
++st->rule50;
++st->pliesFromNull;
// Used by NNUE
st->accumulatorBig.computed[WHITE] = st->accumulatorBig.computed[BLACK] =
st->accumulatorSmall.computed[WHITE] = st->accumulatorSmall.computed[BLACK] = false;
auto& dp = st->dirtyPiece;
DirtyPiece dp;
dp.dirty_num = 1;
Color us = sideToMove;
@@ -703,9 +727,10 @@ void Position::do_move(Move m, StateInfo& newSt, bool givesCheck) {
assert(captured == make_piece(us, ROOK));
Square rfrom, rto;
do_castling<true>(us, from, to, rfrom, rto);
do_castling<true>(us, from, to, rfrom, rto, &dp);
k ^= Zobrist::psq[captured][rfrom] ^ Zobrist::psq[captured][rto];
st->nonPawnKey[us] ^= Zobrist::psq[captured][rfrom] ^ Zobrist::psq[captured][rto];
captured = NO_PIECE;
}
@@ -731,7 +756,13 @@ void Position::do_move(Move m, StateInfo& newSt, bool givesCheck) {
st->pawnKey ^= Zobrist::psq[captured][capsq];
}
else
{
st->nonPawnMaterial[them] -= PieceValue[captured];
st->nonPawnKey[them] ^= Zobrist::psq[captured][capsq];
if (type_of(captured) <= BISHOP)
st->minorPieceKey ^= Zobrist::psq[captured][capsq];
}
dp.dirty_num = 2; // 1 piece moved, 1 piece captured
dp.piece[1] = captured;
@@ -742,7 +773,7 @@ void Position::do_move(Move m, StateInfo& newSt, bool givesCheck) {
remove_piece(capsq);
k ^= Zobrist::psq[captured][capsq];
st->materialKey ^= Zobrist::psq[captured][pieceCount[captured]];
st->materialKey ^= Zobrist::psq[captured][8 + pieceCount[captured]];
// Reset rule 50 counter
st->rule50 = 0;
@@ -789,7 +820,8 @@ void Position::do_move(Move m, StateInfo& newSt, bool givesCheck) {
else if (m.type_of() == PROMOTION)
{
Piece promotion = make_piece(us, m.promotion_type());
Piece promotion = make_piece(us, m.promotion_type());
PieceType promotionType = type_of(promotion);
assert(relative_rank(us, to) == RANK_8);
assert(type_of(promotion) >= KNIGHT && type_of(promotion) <= QUEEN);
@@ -805,10 +837,13 @@ void Position::do_move(Move m, StateInfo& newSt, bool givesCheck) {
dp.dirty_num++;
// Update hash keys
k ^= Zobrist::psq[pc][to] ^ Zobrist::psq[promotion][to];
st->pawnKey ^= Zobrist::psq[pc][to];
st->materialKey ^=
Zobrist::psq[promotion][pieceCount[promotion] - 1] ^ Zobrist::psq[pc][pieceCount[pc]];
// Zobrist::psq[pc][to] is zero, so we don't need to clear it
k ^= Zobrist::psq[promotion][to];
st->materialKey ^= Zobrist::psq[promotion][8 + pieceCount[promotion] - 1]
^ Zobrist::psq[pc][8 + pieceCount[pc]];
if (promotionType <= BISHOP)
st->minorPieceKey ^= Zobrist::psq[promotion][to];
// Update material
st->nonPawnMaterial[us] += PieceValue[promotion];
@@ -821,11 +856,21 @@ void Position::do_move(Move m, StateInfo& newSt, bool givesCheck) {
st->rule50 = 0;
}
// Set capture piece
st->capturedPiece = captured;
else
{
st->nonPawnKey[us] ^= Zobrist::psq[pc][from] ^ Zobrist::psq[pc][to];
if (type_of(pc) <= BISHOP)
st->minorPieceKey ^= Zobrist::psq[pc][from] ^ Zobrist::psq[pc][to];
}
// Update the key with the final value
st->key = k;
if (tt)
prefetch(tt->first_entry(key()));
// Set capture piece
st->capturedPiece = captured;
// Calculate checkers bitboard (if move gives check)
st->checkersBB = givesCheck ? attackers_to(square<KING>(them)) & pieces(us) : 0;
@@ -855,6 +900,8 @@ void Position::do_move(Move m, StateInfo& newSt, bool givesCheck) {
}
assert(pos_is_ok());
return dp;
}
@@ -924,23 +971,25 @@ void Position::undo_move(Move m) {
// Helper used to do/undo a castling move. This is a bit
// tricky in Chess960 where from/to squares can overlap.
template<bool Do>
void Position::do_castling(Color us, Square from, Square& to, Square& rfrom, Square& rto) {
void Position::do_castling(
Color us, Square from, Square& to, Square& rfrom, Square& rto, DirtyPiece* const dp) {
bool kingSide = to > from;
rfrom = to; // Castling is encoded as "king captures friendly rook"
rto = relative_square(us, kingSide ? SQ_F1 : SQ_D1);
to = relative_square(us, kingSide ? SQ_G1 : SQ_C1);
assert(!Do || dp);
if (Do)
{
auto& dp = st->dirtyPiece;
dp.piece[0] = make_piece(us, KING);
dp.from[0] = from;
dp.to[0] = to;
dp.piece[1] = make_piece(us, ROOK);
dp.from[1] = rfrom;
dp.to[1] = rto;
dp.dirty_num = 2;
dp->piece[0] = make_piece(us, KING);
dp->from[0] = from;
dp->to[0] = to;
dp->piece[1] = make_piece(us, ROOK);
dp->from[1] = rfrom;
dp->to[1] = rto;
dp->dirty_num = 2;
}
// Remove both pieces first since squares could overlap in Chess960
@@ -955,21 +1004,17 @@ void Position::do_castling(Color us, Square from, Square& to, Square& rfrom, Squ
// Used to do a "null move": it flips
// the side to move without executing any move on the board.
void Position::do_null_move(StateInfo& newSt, TranspositionTable& tt) {
void Position::do_null_move(StateInfo& newSt, const TranspositionTable& tt) {
assert(!checkers());
assert(&newSt != st);
std::memcpy(&newSt, st, offsetof(StateInfo, accumulatorBig));
std::memcpy(&newSt, st, sizeof(StateInfo));
newSt.previous = st;
st->next = &newSt;
st = &newSt;
st->dirtyPiece.dirty_num = 0;
st->dirtyPiece.piece[0] = NO_PIECE; // Avoid checks in UpdateAccumulator()
st->accumulatorBig.computed[WHITE] = st->accumulatorBig.computed[BLACK] =
st->accumulatorSmall.computed[WHITE] = st->accumulatorSmall.computed[BLACK] = false;
if (st->epSquare != SQ_NONE)
{
st->key ^= Zobrist::enpassant[file_of(st->epSquare)];
@@ -977,7 +1022,6 @@ void Position::do_null_move(StateInfo& newSt, TranspositionTable& tt) {
}
st->key ^= Zobrist::side;
++st->rule50;
prefetch(tt.first_entry(key()));
st->pliesFromNull = 0;
@@ -1002,26 +1046,6 @@ void Position::undo_null_move() {
}
// Computes the new hash key after the given move. Needed
// for speculative prefetch. It doesn't recognize special moves like castling,
// en passant and promotions.
Key Position::key_after(Move m) const {
Square from = m.from_sq();
Square to = m.to_sq();
Piece pc = piece_on(from);
Piece captured = piece_on(to);
Key k = st->key ^ Zobrist::side;
if (captured)
k ^= Zobrist::psq[captured][to];
k ^= Zobrist::psq[pc][to] ^ Zobrist::psq[pc][from];
return (captured || type_of(pc) == PAWN) ? k : adjust_key50<true>(k);
}
// Tests if the SEE (Static Exchange Evaluation)
// value of move is greater or equal to the given threshold. We'll use an
// algorithm similar to alpha-beta pruning with a null window.
@@ -1109,8 +1133,9 @@ bool Position::see_ge(Move m, int threshold) const {
else if ((bb = stmAttackers & pieces(QUEEN)))
{
if ((swap = QueenValue - swap) < res)
break;
swap = QueenValue - swap;
// implies that the previous recapture was done by a higher rated piece than a Queen (King is excluded)
assert(swap >= res);
occupied ^= least_significant_square_bb(bb);
attackers |= (attacks_bb<BISHOP>(to, occupied) & pieces(BISHOP, QUEEN))
@@ -1133,11 +1158,12 @@ bool Position::is_draw(int ply) const {
if (st->rule50 > 99 && (!checkers() || MoveList<LEGAL>(*this).size()))
return true;
// Return a draw score if a position repeats once earlier but strictly
// after the root, or repeats twice before or at the root.
return st->repetition && st->repetition < ply;
return is_repetition(ply);
}
// Return a draw score if a position repeats once earlier but strictly
// after the root, or repeats twice before or at the root.
bool Position::is_repetition(int ply) const { return st->repetition && st->repetition < ply; }
// Tests whether there has been at least one repetition
// of positions since the last capture or pawn move.
@@ -1253,7 +1279,7 @@ bool Position::pos_is_ok() const {
return true;
if (pieceCount[W_KING] != 1 || pieceCount[B_KING] != 1
|| attackers_to(square<KING>(~sideToMove)) & pieces(sideToMove))
|| attackers_to_exist(square<KING>(~sideToMove), pieces(), sideToMove))
assert(0 && "pos_is_ok: Kings");
if ((pieces(PAWN) & (Rank1BB | Rank8BB)) || pieceCount[W_PAWN] > 8 || pieceCount[B_PAWN] > 8)
+26 -16
View File
@@ -1,6 +1,6 @@
/*
Stockfish, a UCI chess playing engine derived from Glaurung 2.1
Copyright (C) 2004-2024 The Stockfish developers (see AUTHORS file)
Copyright (C) 2004-2025 The Stockfish developers (see AUTHORS file)
Stockfish is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -26,8 +26,6 @@
#include <string>
#include "bitboard.h"
#include "nnue/nnue_accumulator.h"
#include "nnue/nnue_architecture.h"
#include "types.h"
namespace Stockfish {
@@ -43,6 +41,8 @@ struct StateInfo {
// Copied when making a move
Key materialKey;
Key pawnKey;
Key minorPieceKey;
Key nonPawnKey[COLOR_NB];
Value nonPawnMaterial[COLOR_NB];
int castlingRights;
int rule50;
@@ -53,16 +53,12 @@ struct StateInfo {
Key key;
Bitboard checkersBB;
StateInfo* previous;
StateInfo* next;
Bitboard blockersForKing[COLOR_NB];
Bitboard pinners[COLOR_NB];
Bitboard checkSquares[PIECE_TYPE_NB];
Piece capturedPiece;
int repetition;
// Used by NNUE
Eval::NNUE::Accumulator<Eval::NNUE::TransformedFeatureDimensionsBig> accumulatorBig;
Eval::NNUE::Accumulator<Eval::NNUE::TransformedFeatureDimensionsSmall> accumulatorSmall;
DirtyPiece dirtyPiece;
};
@@ -122,6 +118,7 @@ class Position {
// Attacks to/from a given square
Bitboard attackers_to(Square s) const;
Bitboard attackers_to(Square s, Bitboard occupied) const;
bool attackers_to_exist(Square s, Bitboard occupied, Color c) const;
void update_slider_blockers(Color c) const;
template<PieceType Pt>
Bitboard attacks_by(Color c) const;
@@ -136,26 +133,28 @@ class Position {
Piece captured_piece() const;
// Doing and undoing moves
void do_move(Move m, StateInfo& newSt);
void do_move(Move m, StateInfo& newSt, bool givesCheck);
void undo_move(Move m);
void do_null_move(StateInfo& newSt, TranspositionTable& tt);
void undo_null_move();
void do_move(Move m, StateInfo& newSt, const TranspositionTable* tt);
DirtyPiece do_move(Move m, StateInfo& newSt, bool givesCheck, const TranspositionTable* tt);
void undo_move(Move m);
void do_null_move(StateInfo& newSt, const TranspositionTable& tt);
void undo_null_move();
// Static Exchange Evaluation
bool see_ge(Move m, int threshold = 0) const;
// Accessing hash keys
Key key() const;
Key key_after(Move m) const;
Key material_key() const;
Key pawn_key() const;
Key minor_piece_key() const;
Key non_pawn_key(Color c) const;
// Other properties of the position
Color side_to_move() const;
int game_ply() const;
bool is_chess960() const;
bool is_draw(int ply) const;
bool is_repetition(int ply) const;
bool upcoming_repetition(int ply) const;
bool has_repeated() const;
int rule50_count() const;
@@ -181,7 +180,12 @@ class Position {
// Other helpers
void move_piece(Square from, Square to);
template<bool Do>
void do_castling(Color us, Square from, Square& to, Square& rfrom, Square& rto);
void do_castling(Color us,
Square from,
Square& to,
Square& rfrom,
Square& rto,
DirtyPiece* const dp = nullptr);
template<bool AfterMove>
Key adjust_key50(Key k) const;
@@ -297,6 +301,10 @@ inline Key Position::pawn_key() const { return st->pawnKey; }
inline Key Position::material_key() const { return st->materialKey; }
inline Key Position::minor_piece_key() const { return st->minorPieceKey; }
inline Key Position::non_pawn_key(Color c) const { return st->nonPawnKey[c]; }
inline Value Position::non_pawn_material(Color c) const { return st->nonPawnMaterial[c]; }
inline Value Position::non_pawn_material() const {
@@ -355,7 +363,9 @@ inline void Position::move_piece(Square from, Square to) {
board[to] = pc;
}
inline void Position::do_move(Move m, StateInfo& newSt) { do_move(m, newSt, gives_check(m)); }
inline void Position::do_move(Move m, StateInfo& newSt, const TranspositionTable* tt = nullptr) {
do_move(m, newSt, gives_check(m), tt);
}
inline StateInfo* Position::state() const { return st; }
+2 -2
View File
@@ -1,6 +1,6 @@
/*
Stockfish, a UCI chess playing engine derived from Glaurung 2.1
Copyright (C) 2004-2024 The Stockfish developers (see AUTHORS file)
Copyright (C) 2004-2025 The Stockfish developers (see AUTHORS file)
Stockfish is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -29,7 +29,7 @@ namespace Stockfish {
Score::Score(Value v, const Position& pos) {
assert(-VALUE_INFINITE < v && v < VALUE_INFINITE);
if (std::abs(v) < VALUE_TB_WIN_IN_MAX_PLY)
if (!is_decisive(v))
{
score = InternalUnits{UCIEngine::to_cp(v, pos)};
}
+1 -1
View File
@@ -1,6 +1,6 @@
/*
Stockfish, a UCI chess playing engine derived from Glaurung 2.1
Copyright (C) 2004-2024 The Stockfish developers (see AUTHORS file)
Copyright (C) 2004-2025 The Stockfish developers (see AUTHORS file)
Stockfish is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
+466 -367
View File
File diff suppressed because it is too large Load Diff
+49 -26
View File
@@ -1,6 +1,6 @@
/*
Stockfish, a UCI chess playing engine derived from Glaurung 2.1
Copyright (C) 2004-2024 The Stockfish developers (see AUTHORS file)
Copyright (C) 2004-2025 The Stockfish developers (see AUTHORS file)
Stockfish is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -31,8 +31,8 @@
#include <string_view>
#include <vector>
#include "history.h"
#include "misc.h"
#include "movepick.h"
#include "nnue/network.h"
#include "nnue/nnue_accumulator.h"
#include "numa.h"
@@ -61,18 +61,21 @@ namespace Search {
// shallower and deeper in the tree during the search. Each search thread has
// its own array of Stack objects, indexed by the current ply.
struct Stack {
Move* pv;
PieceToHistory* continuationHistory;
int ply;
Move currentMove;
Move excludedMove;
Value staticEval;
int statScore;
int moveCount;
bool inCheck;
bool ttPv;
bool ttHit;
int cutoffCnt;
Move* pv;
PieceToHistory* continuationHistory;
CorrectionHistory<PieceTo>* continuationCorrectionHistory;
int ply;
Move currentMove;
Move excludedMove;
Value staticEval;
int statScore;
int moveCount;
bool inCheck;
bool ttPv;
bool ttHit;
int cutoffCnt;
int reduction;
bool isTTMove;
};
@@ -90,15 +93,16 @@ struct RootMove {
return m.score != score ? m.score < score : m.previousScore < previousScore;
}
uint64_t effort = 0;
Value score = -VALUE_INFINITE;
Value previousScore = -VALUE_INFINITE;
Value averageScore = -VALUE_INFINITE;
Value uciScore = -VALUE_INFINITE;
bool scoreLowerbound = false;
bool scoreUpperbound = false;
int selDepth = 0;
int tbRank = 0;
uint64_t effort = 0;
Value score = -VALUE_INFINITE;
Value previousScore = -VALUE_INFINITE;
Value averageScore = -VALUE_INFINITE;
Value meanSquaredScore = -VALUE_INFINITE * VALUE_INFINITE;
Value uciScore = -VALUE_INFINITE;
bool scoreLowerbound = false;
bool scoreUpperbound = false;
int selDepth = 0;
int tbRank = 0;
Value tbScore;
std::vector<Move> pv;
};
@@ -124,7 +128,6 @@ struct LimitsType {
int movestogo, depth, mate, perft, infinite;
uint64_t nodes;
bool ponderMode;
Square capSq;
};
@@ -277,15 +280,27 @@ class Worker {
void ensure_network_replicated();
// Public because they need to be updatable by the stats
ButterflyHistory mainHistory;
ButterflyHistory mainHistory;
LowPlyHistory lowPlyHistory;
CapturePieceToHistory captureHistory;
ContinuationHistory continuationHistory[2][2];
PawnHistory pawnHistory;
CorrectionHistory correctionHistory;
CorrectionHistory<Pawn> pawnCorrectionHistory;
CorrectionHistory<Minor> minorPieceCorrectionHistory;
CorrectionHistory<NonPawn> nonPawnCorrectionHistory;
CorrectionHistory<Continuation> continuationCorrectionHistory;
private:
void iterative_deepening();
void do_move(Position& pos, const Move move, StateInfo& st);
void do_move(Position& pos, const Move move, StateInfo& st, const bool givesCheck);
void do_null_move(Position& pos, StateInfo& st);
void undo_move(Position& pos, const Move move);
void undo_null_move(Position& pos);
// This is the main search function, for both PV and non-PV nodes
template<NodeType nodeType>
Value search(Position& pos, Stack* ss, Value alpha, Value beta, Depth depth, bool cutNode);
@@ -305,6 +320,8 @@ class Worker {
TimePoint elapsed() const;
TimePoint elapsed_time() const;
Value evaluate(const Position&);
LimitsType limits;
size_t pvIdx, pvLast;
@@ -336,12 +353,18 @@ class Worker {
const LazyNumaReplicated<Eval::NNUE::Networks>& networks;
// Used by NNUE
Eval::NNUE::AccumulatorStack accumulatorStack;
Eval::NNUE::AccumulatorCaches refreshTable;
friend class Stockfish::ThreadPool;
friend class SearchManager;
};
struct ConthistBonus {
int index;
int weight;
};
} // namespace Search
+2 -2
View File
@@ -1,6 +1,6 @@
/*
Stockfish, a UCI chess playing engine derived from Glaurung 2.1
Copyright (C) 2004-2024 The Stockfish developers (see AUTHORS file)
Copyright (C) 2004-2025 The Stockfish developers (see AUTHORS file)
Stockfish is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -1620,7 +1620,7 @@ bool Tablebases::root_probe(Position& pos,
WDLScore wdl = -probe_wdl(pos, &result);
dtz = dtz_before_zeroing(wdl);
}
else if (pos.is_draw(1))
else if ((rule50 && pos.is_draw(1)) || pos.is_repetition(1))
{
// In case a root move leads to a draw by repetition or 50-move rule,
// we set dtz to zero. Note: since we are only 1 ply from the root,
+1 -1
View File
@@ -1,6 +1,6 @@
/*
Stockfish, a UCI chess playing engine derived from Glaurung 2.1
Copyright (C) 2004-2024 The Stockfish developers (see AUTHORS file)
Copyright (C) 2004-2025 The Stockfish developers (see AUTHORS file)
Stockfish is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
+6 -6
View File
@@ -1,6 +1,6 @@
/*
Stockfish, a UCI chess playing engine derived from Glaurung 2.1
Copyright (C) 2004-2024 The Stockfish developers (see AUTHORS file)
Copyright (C) 2004-2025 The Stockfish developers (see AUTHORS file)
Stockfish is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -329,13 +329,13 @@ Thread* ThreadPool::get_best_thread() const {
const auto bestThreadMoveVote = votes[bestThreadPV[0]];
const auto newThreadMoveVote = votes[newThreadPV[0]];
const bool bestThreadInProvenWin = bestThreadScore >= VALUE_TB_WIN_IN_MAX_PLY;
const bool newThreadInProvenWin = newThreadScore >= VALUE_TB_WIN_IN_MAX_PLY;
const bool bestThreadInProvenWin = is_win(bestThreadScore);
const bool newThreadInProvenWin = is_win(newThreadScore);
const bool bestThreadInProvenLoss =
bestThreadScore != -VALUE_INFINITE && bestThreadScore <= VALUE_TB_LOSS_IN_MAX_PLY;
bestThreadScore != -VALUE_INFINITE && is_loss(bestThreadScore);
const bool newThreadInProvenLoss =
newThreadScore != -VALUE_INFINITE && newThreadScore <= VALUE_TB_LOSS_IN_MAX_PLY;
newThreadScore != -VALUE_INFINITE && is_loss(newThreadScore);
// We make sure not to pick a thread with truncated principal variation
const bool betterVotingValue =
@@ -355,7 +355,7 @@ Thread* ThreadPool::get_best_thread() const {
bestThread = th.get();
}
else if (newThreadInProvenWin || newThreadInProvenLoss
|| (newThreadScore > VALUE_TB_LOSS_IN_MAX_PLY
|| (!is_loss(newThreadScore)
&& (newThreadMoveVote > bestThreadMoveVote
|| (newThreadMoveVote == bestThreadMoveVote && betterVotingValue))))
bestThread = th.get();
+1 -1
View File
@@ -1,6 +1,6 @@
/*
Stockfish, a UCI chess playing engine derived from Glaurung 2.1
Copyright (C) 2004-2024 The Stockfish developers (see AUTHORS file)
Copyright (C) 2004-2025 The Stockfish developers (see AUTHORS file)
Stockfish is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
+1 -1
View File
@@ -1,6 +1,6 @@
/*
Stockfish, a UCI chess playing engine derived from Glaurung 2.1
Copyright (C) 2004-2024 The Stockfish developers (see AUTHORS file)
Copyright (C) 2004-2025 The Stockfish developers (see AUTHORS file)
Stockfish is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
+19 -16
View File
@@ -1,6 +1,6 @@
/*
Stockfish, a UCI chess playing engine derived from Glaurung 2.1
Copyright (C) 2004-2024 The Stockfish developers (see AUTHORS file)
Copyright (C) 2004-2025 The Stockfish developers (see AUTHORS file)
Stockfish is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -87,18 +87,20 @@ void TimeManagement::init(Search::LimitsType& limits,
const TimePoint scaledTime = limits.time[us] / scaleFactor;
const TimePoint scaledInc = limits.inc[us] / scaleFactor;
// Maximum move horizon of 50 moves
int mtg = limits.movestogo ? std::min(limits.movestogo, 50) : 50;
// Maximum move horizon
int centiMTG = limits.movestogo ? std::min(limits.movestogo * 100, 5000) : 5051;
// If less than one second, gradually reduce mtg
if (scaledTime < 1000 && double(mtg) / scaledInc > 0.05)
if (scaledTime < 1000 && double(centiMTG) / scaledInc > 5.051)
{
mtg = scaledTime * 0.05;
centiMTG = scaledTime * 5.051;
}
// Make sure timeLeft is > 0 since we may use it as a divisor
TimePoint timeLeft = std::max(TimePoint(1), limits.time[us] + limits.inc[us] * (mtg - 1)
- moveOverhead * (2 + mtg));
TimePoint timeLeft =
std::max(TimePoint(1),
limits.time[us]
+ (limits.inc[us] * (centiMTG - 100) - moveOverhead * (200 + centiMTG)) / 100);
// x basetime (+ z increment)
// If there is a healthy increment, timeLeft can exceed the actual available
@@ -107,31 +109,32 @@ void TimeManagement::init(Search::LimitsType& limits,
{
// Extra time according to timeLeft
if (originalTimeAdjust < 0)
originalTimeAdjust = 0.3285 * std::log10(timeLeft) - 0.4830;
originalTimeAdjust = 0.3128 * std::log10(timeLeft) - 0.4354;
// Calculate time constants based on current time left.
double logTimeInSec = std::log10(scaledTime / 1000.0);
double optConstant = std::min(0.00308 + 0.000319 * logTimeInSec, 0.00506);
double maxConstant = std::max(3.39 + 3.01 * logTimeInSec, 2.93);
double optConstant = std::min(0.0032116 + 0.000321123 * logTimeInSec, 0.00508017);
double maxConstant = std::max(3.3977 + 3.03950 * logTimeInSec, 2.94761);
optScale = std::min(0.0122 + std::pow(ply + 2.95, 0.462) * optConstant,
0.213 * limits.time[us] / timeLeft)
optScale = std::min(0.0121431 + std::pow(ply + 2.94693, 0.461073) * optConstant,
0.213035 * limits.time[us] / timeLeft)
* originalTimeAdjust;
maxScale = std::min(6.64, maxConstant + ply / 12.0);
maxScale = std::min(6.67704, maxConstant + ply / 11.9847);
}
// x moves in y seconds (+ z increment)
else
{
optScale = std::min((0.88 + ply / 116.4) / mtg, 0.88 * limits.time[us] / timeLeft);
maxScale = std::min(6.3, 1.5 + 0.11 * mtg);
optScale =
std::min((0.88 + ply / 116.4) / (centiMTG / 100.0), 0.88 * limits.time[us] / timeLeft);
maxScale = 1.3 + 0.11 * (centiMTG / 100.0);
}
// Limit the maximum possible time for this move
optimumTime = TimePoint(optScale * timeLeft);
maximumTime =
TimePoint(std::min(0.825 * limits.time[us] - moveOverhead, maxScale * optimumTime)) - 10;
TimePoint(std::min(0.825179 * limits.time[us] - moveOverhead, maxScale * optimumTime)) - 10;
if (options["Ponder"])
optimumTime += optimumTime / 4;
+1 -1
View File
@@ -1,6 +1,6 @@
/*
Stockfish, a UCI chess playing engine derived from Glaurung 2.1
Copyright (C) 2004-2024 The Stockfish developers (see AUTHORS file)
Copyright (C) 2004-2025 The Stockfish developers (see AUTHORS file)
Stockfish is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
+8 -6
View File
@@ -1,6 +1,6 @@
/*
Stockfish, a UCI chess playing engine derived from Glaurung 2.1
Copyright (C) 2004-2024 The Stockfish developers (see AUTHORS file)
Copyright (C) 2004-2025 The Stockfish developers (see AUTHORS file)
Stockfish is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -193,13 +193,13 @@ void TranspositionTable::clear(ThreadPool& threads) {
// Returns an approximation of the hashtable
// occupation during a search. The hash is x permill full, as per UCI protocol.
// Only counts entries which match the current generation.
int TranspositionTable::hashfull() const {
int cnt = 0;
int TranspositionTable::hashfull(int maxAge) const {
int maxAgeInternal = maxAge << GENERATION_BITS;
int cnt = 0;
for (int i = 0; i < 1000; ++i)
for (int j = 0; j < ClusterSize; ++j)
cnt += table[i].entry[j].is_occupied()
&& (table[i].entry[j].genBound8 & GENERATION_MASK) == generation8;
&& table[i].entry[j].relative_age(generation8) <= maxAgeInternal;
return cnt / ClusterSize;
}
@@ -238,7 +238,9 @@ std::tuple<bool, TTData, TTWriter> TranspositionTable::probe(const Key key) cons
> tte[i].depth8 - tte[i].relative_age(generation8) * 2)
replace = &tte[i];
return {false, TTData(), TTWriter(replace)};
return {false,
TTData{Move::none(), VALUE_NONE, VALUE_NONE, DEPTH_ENTRY_OFFSET, BOUND_NONE, false},
TTWriter(replace)};
}
+14 -2
View File
@@ -1,6 +1,6 @@
/*
Stockfish, a UCI chess playing engine derived from Glaurung 2.1
Copyright (C) 2004-2024 The Stockfish developers (see AUTHORS file)
Copyright (C) 2004-2025 The Stockfish developers (see AUTHORS file)
Stockfish is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -51,6 +51,18 @@ struct TTData {
Depth depth;
Bound bound;
bool is_pv;
TTData() = delete;
// clang-format off
TTData(Move m, Value v, Value ev, Depth d, Bound b, bool pv) :
move(m),
value(v),
eval(ev),
depth(d),
bound(b),
is_pv(pv) {};
// clang-format on
};
@@ -73,7 +85,7 @@ class TranspositionTable {
void resize(size_t mbSize, ThreadPool& threads); // Set TT size
void clear(ThreadPool& threads); // Re-initialize memory, multithreaded
int hashfull()
int hashfull(int maxAge = 0)
const; // Approximate what fraction of entries (permille) have been written to during this root search
void
+2 -2
View File
@@ -1,6 +1,6 @@
/*
Stockfish, a UCI chess playing engine derived from Glaurung 2.1
Copyright (C) 2004-2024 The Stockfish developers (see AUTHORS file)
Copyright (C) 2004-2025 The Stockfish developers (see AUTHORS file)
Stockfish is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -55,7 +55,7 @@ void Tune::make_option(OptionsMap* opts, const string& n, int v, const SetRange&
if (TuneResults.count(n))
v = TuneResults[n];
(*opts)[n] << Option(v, r(v).first, r(v).second, on_tune);
opts->add(n, Option(v, r(v).first, r(v).second, on_tune));
LastOption = &((*opts)[n]);
// Print formatted parameters, ready to be copy-pasted in Fishtest
+1 -1
View File
@@ -1,6 +1,6 @@
/*
Stockfish, a UCI chess playing engine derived from Glaurung 2.1
Copyright (C) 2004-2024 The Stockfish developers (see AUTHORS file)
Copyright (C) 2004-2025 The Stockfish developers (see AUTHORS file)
Stockfish is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
+16 -1
View File
@@ -1,6 +1,6 @@
/*
Stockfish, a UCI chess playing engine derived from Glaurung 2.1
Copyright (C) 2004-2024 The Stockfish developers (see AUTHORS file)
Copyright (C) 2004-2025 The Stockfish developers (see AUTHORS file)
Stockfish is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -155,6 +155,21 @@ constexpr Value VALUE_TB = VALUE_MATE_IN_MAX_PLY - 1;
constexpr Value VALUE_TB_WIN_IN_MAX_PLY = VALUE_TB - MAX_PLY;
constexpr Value VALUE_TB_LOSS_IN_MAX_PLY = -VALUE_TB_WIN_IN_MAX_PLY;
constexpr bool is_valid(Value value) { return value != VALUE_NONE; }
constexpr bool is_win(Value value) {
assert(is_valid(value));
return value >= VALUE_TB_WIN_IN_MAX_PLY;
}
constexpr bool is_loss(Value value) {
assert(is_valid(value));
return value <= VALUE_TB_LOSS_IN_MAX_PLY;
}
constexpr bool is_decisive(Value value) { return is_win(value) || is_loss(value); }
// In the code, we make the assumption that these values
// are such that non_pawn_material() can be used to uniquely
// identify the material on the board.
+179 -5
View File
@@ -1,6 +1,6 @@
/*
Stockfish, a UCI chess playing engine derived from Glaurung 2.1
Copyright (C) 2004-2024 The Stockfish developers (see AUTHORS file)
Copyright (C) 2004-2025 The Stockfish developers (see AUTHORS file)
Stockfish is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -22,6 +22,7 @@
#include <cctype>
#include <cmath>
#include <cstdint>
#include <iterator>
#include <optional>
#include <sstream>
#include <string_view>
@@ -30,6 +31,7 @@
#include "benchmark.h"
#include "engine.h"
#include "memory.h"
#include "movegen.h"
#include "position.h"
#include "score.h"
@@ -39,6 +41,8 @@
namespace Stockfish {
constexpr auto BenchmarkCommand = "speedtest";
constexpr auto StartFEN = "rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq - 0 1";
template<typename... Ts>
struct overload: Ts... {
@@ -48,7 +52,7 @@ struct overload: Ts... {
template<typename... Ts>
overload(Ts...) -> overload<Ts...>;
void UCIEngine::print_info_string(const std::string& str) {
void UCIEngine::print_info_string(std::string_view str) {
sync_cout_start();
for (auto& line : split(str, "\n"))
{
@@ -69,11 +73,16 @@ UCIEngine::UCIEngine(int argc, char** argv) :
print_info_string(*str);
});
init_search_update_listeners();
}
void UCIEngine::init_search_update_listeners() {
engine.set_on_iter([](const auto& i) { on_iter(i); });
engine.set_on_update_no_moves([](const auto& i) { on_update_no_moves(i); });
engine.set_on_update_full(
[this](const auto& i) { on_update_full(i, engine.get_options()["UCI_ShowWDL"]); });
engine.set_on_bestmove([](const auto& bm, const auto& p) { on_bestmove(bm, p); });
engine.set_on_verify_networks([](const auto& s) { print_info_string(s); });
}
void UCIEngine::loop() {
@@ -117,7 +126,7 @@ void UCIEngine::loop() {
{
// send info strings after the go command is sent for old GUIs and python-chess
print_info_string(engine.numa_config_information_as_string());
print_info_string(engine.thread_binding_information_as_string());
print_info_string(engine.thread_allocation_information_as_string());
go(is);
}
else if (token == "position")
@@ -133,6 +142,8 @@ void UCIEngine::loop() {
engine.flip();
else if (token == "bench")
bench(is);
else if (token == BenchmarkCommand)
benchmark(is);
else if (token == "d")
sync_cout << engine.visualize() << sync_endl;
else if (token == "eval")
@@ -285,6 +296,169 @@ void UCIEngine::bench(std::istream& args) {
engine.set_on_update_full([&](const auto& i) { on_update_full(i, options["UCI_ShowWDL"]); });
}
void UCIEngine::benchmark(std::istream& args) {
// Probably not very important for a test this long, but include for completeness and sanity.
static constexpr int NUM_WARMUP_POSITIONS = 3;
std::string token;
uint64_t nodes = 0, cnt = 1;
uint64_t nodesSearched = 0;
engine.set_on_update_full([&](const Engine::InfoFull& i) { nodesSearched = i.nodes; });
engine.set_on_iter([](const auto&) {});
engine.set_on_update_no_moves([](const auto&) {});
engine.set_on_bestmove([](const auto&, const auto&) {});
engine.set_on_verify_networks([](const auto&) {});
Benchmark::BenchmarkSetup setup = Benchmark::setup_benchmark(args);
const int numGoCommands = count_if(setup.commands.begin(), setup.commands.end(),
[](const std::string& s) { return s.find("go ") == 0; });
TimePoint totalTime = 0;
// Set options once at the start.
auto ss = std::istringstream("name Threads value " + std::to_string(setup.threads));
setoption(ss);
ss = std::istringstream("name Hash value " + std::to_string(setup.ttSize));
setoption(ss);
ss = std::istringstream("name UCI_Chess960 value false");
setoption(ss);
// Warmup
for (const auto& cmd : setup.commands)
{
std::istringstream is(cmd);
is >> std::skipws >> token;
if (token == "go")
{
// One new line is produced by the search, so omit it here
std::cerr << "\rWarmup position " << cnt++ << '/' << NUM_WARMUP_POSITIONS;
Search::LimitsType limits = parse_limits(is);
TimePoint elapsed = now();
// Run with silenced network verification
engine.go(limits);
engine.wait_for_search_finished();
totalTime += now() - elapsed;
nodes += nodesSearched;
nodesSearched = 0;
}
else if (token == "position")
position(is);
else if (token == "ucinewgame")
{
engine.search_clear(); // search_clear may take a while
}
if (cnt > NUM_WARMUP_POSITIONS)
break;
}
std::cerr << "\n";
cnt = 1;
nodes = 0;
int numHashfullReadings = 0;
constexpr int hashfullAges[] = {0, 999}; // Only normal hashfull and touched hash.
int totalHashfull[std::size(hashfullAges)] = {0};
int maxHashfull[std::size(hashfullAges)] = {0};
auto updateHashfullReadings = [&]() {
numHashfullReadings += 1;
for (int i = 0; i < static_cast<int>(std::size(hashfullAges)); ++i)
{
const int hashfull = engine.get_hashfull(hashfullAges[i]);
maxHashfull[i] = std::max(maxHashfull[i], hashfull);
totalHashfull[i] += hashfull;
}
};
engine.search_clear(); // search_clear may take a while
for (const auto& cmd : setup.commands)
{
std::istringstream is(cmd);
is >> std::skipws >> token;
if (token == "go")
{
// One new line is produced by the search, so omit it here
std::cerr << "\rPosition " << cnt++ << '/' << numGoCommands;
Search::LimitsType limits = parse_limits(is);
TimePoint elapsed = now();
// Run with silenced network verification
engine.go(limits);
engine.wait_for_search_finished();
totalTime += now() - elapsed;
updateHashfullReadings();
nodes += nodesSearched;
nodesSearched = 0;
}
else if (token == "position")
position(is);
else if (token == "ucinewgame")
{
engine.search_clear(); // search_clear may take a while
}
}
totalTime = std::max<TimePoint>(totalTime, 1); // Ensure positivity to avoid a 'divide by zero'
dbg_print();
std::cerr << "\n";
static_assert(
std::size(hashfullAges) == 2 && hashfullAges[0] == 0 && hashfullAges[1] == 999,
"Hardcoded for display. Would complicate the code needlessly in the current state.");
std::string threadBinding = engine.thread_binding_information_as_string();
if (threadBinding.empty())
threadBinding = "none";
// clang-format off
std::cerr << "==========================="
<< "\nVersion : "
<< engine_version_info()
// "\nCompiled by : "
<< compiler_info()
<< "Large pages : " << (has_large_pages() ? "yes" : "no")
<< "\nUser invocation : " << BenchmarkCommand << " "
<< setup.originalInvocation << "\nFilled invocation : " << BenchmarkCommand
<< " " << setup.filledInvocation
<< "\nAvailable processors : " << engine.get_numa_config_as_string()
<< "\nThread count : " << setup.threads
<< "\nThread binding : " << threadBinding
<< "\nTT size [MiB] : " << setup.ttSize
<< "\nHash max, avg [per mille] : "
<< "\n single search : " << maxHashfull[0] << ", "
<< totalHashfull[0] / numHashfullReadings
<< "\n single game : " << maxHashfull[1] << ", "
<< totalHashfull[1] / numHashfullReadings
<< "\nTotal nodes searched : " << nodes
<< "\nTotal search time [s] : " << totalTime / 1000.0
<< "\nNodes/second : " << 1000 * nodes / totalTime << std::endl;
// clang-format on
init_search_update_listeners();
}
void UCIEngine::setoption(std::istringstream& is) {
engine.wait_for_search_finished();
@@ -339,8 +513,8 @@ WinRateParams win_rate_params(const Position& pos) {
double m = std::clamp(material, 17, 78) / 58.0;
// Return a = p_a(material) and b = p_b(material), see github.com/official-stockfish/WDL_model
constexpr double as[] = {-37.45051876, 121.19101539, -132.78783573, 420.70576692};
constexpr double bs[] = {90.26261072, -137.26549898, 71.10130540, 51.35259597};
constexpr double as[] = {-13.50030198, 40.92780883, -36.82753545, 386.83004070};
constexpr double bs[] = {96.53354896, -165.79058388, 90.89679019, 49.29561889};
double a = (((as[0] * m + as[1]) * m + as[2]) * m) + as[3];
double b = (((bs[0] * m + bs[1]) * m + bs[2]) * m) + bs[3];
+5 -2
View File
@@ -1,6 +1,6 @@
/*
Stockfish, a UCI chess playing engine derived from Glaurung 2.1
Copyright (C) 2004-2024 The Stockfish developers (see AUTHORS file)
Copyright (C) 2004-2025 The Stockfish developers (see AUTHORS file)
Stockfish is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -58,10 +58,11 @@ class UCIEngine {
Engine engine;
CommandLine cli;
static void print_info_string(const std::string& str);
static void print_info_string(std::string_view str);
void go(std::istringstream& is);
void bench(std::istream& args);
void benchmark(std::istream& args);
void position(std::istringstream& is);
void setoption(std::istringstream& is);
std::uint64_t perft(const Search::LimitsType&);
@@ -70,6 +71,8 @@ class UCIEngine {
static void on_update_full(const Engine::InfoFull& info, bool showWDL);
static void on_iter(const Engine::InfoIter& info);
static void on_bestmove(std::string_view bestmove, std::string_view ponder);
void init_search_update_listeners();
};
} // namespace Stockfish
+22 -20
View File
@@ -1,6 +1,6 @@
/*
Stockfish, a UCI chess playing engine derived from Glaurung 2.1
Copyright (C) 2004-2024 The Stockfish developers (see AUTHORS file)
Copyright (C) 2004-2025 The Stockfish developers (see AUTHORS file)
Stockfish is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -21,6 +21,7 @@
#include <algorithm>
#include <cassert>
#include <cctype>
#include <cstdlib>
#include <iostream>
#include <sstream>
#include <utility>
@@ -57,17 +58,31 @@ void OptionsMap::setoption(std::istringstream& is) {
sync_cout << "No such option: " << name << sync_endl;
}
Option OptionsMap::operator[](const std::string& name) const {
const Option& OptionsMap::operator[](const std::string& name) const {
auto it = options_map.find(name);
return it != options_map.end() ? it->second : Option(this);
assert(it != options_map.end());
return it->second;
}
Option& OptionsMap::operator[](const std::string& name) {
// Inits options and assigns idx in the correct printing order
void OptionsMap::add(const std::string& name, const Option& option) {
if (!options_map.count(name))
options_map[name] = Option(this);
return options_map[name];
{
static size_t insert_order = 0;
options_map[name] = option;
options_map[name].parent = this;
options_map[name].idx = insert_order++;
}
else
{
std::cerr << "Option \"" << name << "\" was already added!" << std::endl;
std::exit(EXIT_FAILURE);
}
}
std::size_t OptionsMap::count(const std::string& name) const { return options_map.count(name); }
Option::Option(const OptionsMap* map) :
@@ -130,19 +145,6 @@ bool Option::operator==(const char* s) const {
bool Option::operator!=(const char* s) const { return !(*this == s); }
// Inits options and assigns idx in the correct printing order
void Option::operator<<(const Option& o) {
static size_t insert_order = 0;
auto p = this->parent;
*this = o;
this->parent = p;
idx = insert_order++;
}
// Updates currentValue and triggers on_change() action. It's up to
// the GUI to check for option's limits, but we could receive the new value
// from the user by console window, so let's check the bounds anyway.
@@ -161,7 +163,7 @@ Option& Option::operator=(const std::string& v) {
std::string token;
std::istringstream ss(defaultValue);
while (ss >> token)
comboMap[token] << Option();
comboMap.add(token, Option());
if (!comboMap.count(v) || v == "var")
return *this;
}
+6 -4
View File
@@ -1,6 +1,6 @@
/*
Stockfish, a UCI chess playing engine derived from Glaurung 2.1
Copyright (C) 2004-2024 The Stockfish developers (see AUTHORS file)
Copyright (C) 2004-2025 The Stockfish developers (see AUTHORS file)
Stockfish is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -54,12 +54,13 @@ class Option {
friend std::ostream& operator<<(std::ostream&, const OptionsMap&);
int operator<<(const Option&) = delete;
private:
friend class OptionsMap;
friend class Engine;
friend class Tune;
void operator<<(const Option&);
std::string defaultValue, currentValue, type;
int min, max;
@@ -82,8 +83,9 @@ class OptionsMap {
void setoption(std::istringstream&);
Option operator[](const std::string&) const;
Option& operator[](const std::string&);
const Option& operator[](const std::string&) const;
void add(const std::string&, const Option& option);
std::size_t count(const std::string&) const;
+1
View File
@@ -0,0 +1 @@
*.sh text eol=lf
+520
View File
@@ -0,0 +1,520 @@
import argparse
import re
import sys
import subprocess
import pathlib
import os
from testing import (
EPD,
TSAN,
Stockfish as Engine,
MiniTestFramework,
OrderedClassMembers,
Valgrind,
Syzygy,
)
PATH = pathlib.Path(__file__).parent.resolve()
CWD = os.getcwd()
def get_prefix():
if args.valgrind:
return Valgrind.get_valgrind_command()
if args.valgrind_thread:
return Valgrind.get_valgrind_thread_command()
return []
def get_threads():
if args.valgrind_thread or args.sanitizer_thread:
return 2
return 1
def get_path():
return os.path.abspath(os.path.join(CWD, args.stockfish_path))
def postfix_check(output):
if args.sanitizer_undefined:
for idx, line in enumerate(output):
if "runtime error:" in line:
# print next possible 50 lines
for i in range(50):
debug_idx = idx + i
if debug_idx < len(output):
print(output[debug_idx])
return False
if args.sanitizer_thread:
for idx, line in enumerate(output):
if "WARNING: ThreadSanitizer:" in line:
# print next possible 50 lines
for i in range(50):
debug_idx = idx + i
if debug_idx < len(output):
print(output[debug_idx])
return False
return True
def Stockfish(*args, **kwargs):
return Engine(get_prefix(), get_path(), *args, **kwargs)
class TestCLI(metaclass=OrderedClassMembers):
def beforeAll(self):
pass
def afterAll(self):
pass
def beforeEach(self):
self.stockfish = None
def afterEach(self):
assert postfix_check(self.stockfish.get_output()) == True
self.stockfish.clear_output()
def test_eval(self):
self.stockfish = Stockfish("eval".split(" "), True)
assert self.stockfish.process.returncode == 0
def test_go_nodes_1000(self):
self.stockfish = Stockfish("go nodes 1000".split(" "), True)
assert self.stockfish.process.returncode == 0
def test_go_depth_10(self):
self.stockfish = Stockfish("go depth 10".split(" "), True)
assert self.stockfish.process.returncode == 0
def test_go_perft_4(self):
self.stockfish = Stockfish("go perft 4".split(" "), True)
assert self.stockfish.process.returncode == 0
def test_go_movetime_1000(self):
self.stockfish = Stockfish("go movetime 1000".split(" "), True)
assert self.stockfish.process.returncode == 0
def test_go_wtime_8000_btime_8000_winc_500_binc_500(self):
self.stockfish = Stockfish(
"go wtime 8000 btime 8000 winc 500 binc 500".split(" "),
True,
)
assert self.stockfish.process.returncode == 0
def test_go_wtime_1000_btime_1000_winc_0_binc_0(self):
self.stockfish = Stockfish(
"go wtime 1000 btime 1000 winc 0 binc 0".split(" "),
True,
)
assert self.stockfish.process.returncode == 0
def test_go_wtime_1000_btime_1000_winc_0_binc_0_movestogo_5(self):
self.stockfish = Stockfish(
"go wtime 1000 btime 1000 winc 0 binc 0 movestogo 5".split(" "),
True,
)
assert self.stockfish.process.returncode == 0
def test_go_movetime_200(self):
self.stockfish = Stockfish("go movetime 200".split(" "), True)
assert self.stockfish.process.returncode == 0
def test_go_nodes_20000_searchmoves_e2e4_d2d4(self):
self.stockfish = Stockfish(
"go nodes 20000 searchmoves e2e4 d2d4".split(" "), True
)
assert self.stockfish.process.returncode == 0
def test_bench_128_threads_8_default_depth(self):
self.stockfish = Stockfish(
f"bench 128 {get_threads()} 8 default depth".split(" "),
True,
)
assert self.stockfish.process.returncode == 0
def test_bench_128_threads_3_bench_tmp_epd_depth(self):
self.stockfish = Stockfish(
f"bench 128 {get_threads()} 3 {os.path.join(PATH,'bench_tmp.epd')} depth".split(
" "
),
True,
)
assert self.stockfish.process.returncode == 0
def test_d(self):
self.stockfish = Stockfish("d".split(" "), True)
assert self.stockfish.process.returncode == 0
def test_compiler(self):
self.stockfish = Stockfish("compiler".split(" "), True)
assert self.stockfish.process.returncode == 0
def test_license(self):
self.stockfish = Stockfish("license".split(" "), True)
assert self.stockfish.process.returncode == 0
def test_uci(self):
self.stockfish = Stockfish("uci".split(" "), True)
assert self.stockfish.process.returncode == 0
def test_export_net_verify_nnue(self):
current_path = os.path.abspath(os.getcwd())
self.stockfish = Stockfish(
f"export_net {os.path.join(current_path , 'verify.nnue')}".split(" "), True
)
assert self.stockfish.process.returncode == 0
# verify the generated net equals the base net
def test_network_equals_base(self):
self.stockfish = Stockfish(
["uci"],
True,
)
output = self.stockfish.process.stdout
# find line
for line in output.split("\n"):
if "option name EvalFile type string default" in line:
network = line.split(" ")[-1]
break
# find network file in src dir
network = os.path.join(PATH.parent.resolve(), "src", network)
if not os.path.exists(network):
print(
f"Network file {network} not found, please download the network file over the make command."
)
assert False
diff = subprocess.run(["diff", network, f"verify.nnue"])
assert diff.returncode == 0
class TestInteractive(metaclass=OrderedClassMembers):
def beforeAll(self):
self.stockfish = Stockfish()
def afterAll(self):
self.stockfish.quit()
assert self.stockfish.close() == 0
def afterEach(self):
assert postfix_check(self.stockfish.get_output()) == True
self.stockfish.clear_output()
def test_startup_output(self):
self.stockfish.starts_with("Stockfish")
def test_uci_command(self):
self.stockfish.send_command("uci")
self.stockfish.equals("uciok")
def test_set_threads_option(self):
self.stockfish.send_command(f"setoption name Threads value {get_threads()}")
def test_ucinewgame_and_startpos_nodes_1000(self):
self.stockfish.send_command("ucinewgame")
self.stockfish.send_command("position startpos")
self.stockfish.send_command("go nodes 1000")
self.stockfish.starts_with("bestmove")
def test_ucinewgame_and_startpos_moves(self):
self.stockfish.send_command("ucinewgame")
self.stockfish.send_command("position startpos moves e2e4 e7e6")
self.stockfish.send_command("go nodes 1000")
self.stockfish.starts_with("bestmove")
def test_fen_position_1(self):
self.stockfish.send_command("ucinewgame")
self.stockfish.send_command("position fen 5rk1/1K4p1/8/8/3B4/8/8/8 b - - 0 1")
self.stockfish.send_command("go nodes 1000")
self.stockfish.starts_with("bestmove")
def test_fen_position_2_flip(self):
self.stockfish.send_command("ucinewgame")
self.stockfish.send_command("position fen 5rk1/1K4p1/8/8/3B4/8/8/8 b - - 0 1")
self.stockfish.send_command("flip")
self.stockfish.send_command("go nodes 1000")
self.stockfish.starts_with("bestmove")
def test_depth_5_with_callback(self):
self.stockfish.send_command("ucinewgame")
self.stockfish.send_command("position startpos")
self.stockfish.send_command("go depth 5")
def callback(output):
regex = r"info depth \d+ seldepth \d+ multipv \d+ score cp \d+ nodes \d+ nps \d+ hashfull \d+ tbhits \d+ time \d+ pv"
if output.startswith("info depth") and not re.match(regex, output):
assert False
if output.startswith("bestmove"):
return True
return False
self.stockfish.check_output(callback)
def test_ucinewgame_and_go_depth_9(self):
self.stockfish.send_command("ucinewgame")
self.stockfish.send_command("setoption name UCI_ShowWDL value true")
self.stockfish.send_command("position startpos")
self.stockfish.send_command("go depth 9")
depth = 1
def callback(output):
nonlocal depth
regex = rf"info depth {depth} seldepth \d+ multipv \d+ score cp \d+ wdl \d+ \d+ \d+ nodes \d+ nps \d+ hashfull \d+ tbhits \d+ time \d+ pv"
if output.startswith("info depth"):
if not re.match(regex, output):
assert False
depth += 1
if output.startswith("bestmove"):
assert depth == 10
return True
return False
self.stockfish.check_output(callback)
def test_clear_hash(self):
self.stockfish.send_command("setoption name Clear Hash")
def test_fen_position_mate_1(self):
self.stockfish.send_command("ucinewgame")
self.stockfish.send_command(
"position fen 5K2/8/2qk4/2nPp3/3r4/6B1/B7/3R4 w - e6"
)
self.stockfish.send_command("go depth 18")
self.stockfish.expect("* score mate 1 * pv d5e6")
self.stockfish.equals("bestmove d5e6")
def test_fen_position_mate_minus_1(self):
self.stockfish.send_command("ucinewgame")
self.stockfish.send_command(
"position fen 2brrb2/8/p7/Q7/1p1kpPp1/1P1pN1K1/3P4/8 b - -"
)
self.stockfish.send_command("go depth 18")
self.stockfish.expect("* score mate -1 *")
self.stockfish.starts_with("bestmove")
def test_fen_position_fixed_node(self):
self.stockfish.send_command("ucinewgame")
self.stockfish.send_command(
"position fen 5K2/8/2P1P1Pk/6pP/3p2P1/1P6/3P4/8 w - - 0 1"
)
self.stockfish.send_command("go nodes 500000")
self.stockfish.starts_with("bestmove")
def test_fen_position_with_mate_go_depth(self):
self.stockfish.send_command("ucinewgame")
self.stockfish.send_command(
"position fen 8/5R2/2K1P3/4k3/8/b1PPpp1B/5p2/8 w - -"
)
self.stockfish.send_command("go depth 18 searchmoves c6d7")
self.stockfish.expect("* score mate 2 * pv c6d7 * f7f5")
self.stockfish.starts_with("bestmove")
def test_fen_position_with_mate_go_mate(self):
self.stockfish.send_command("ucinewgame")
self.stockfish.send_command(
"position fen 8/5R2/2K1P3/4k3/8/b1PPpp1B/5p2/8 w - -"
)
self.stockfish.send_command("go mate 2 searchmoves c6d7")
self.stockfish.expect("* score mate 2 * pv c6d7 *")
self.stockfish.starts_with("bestmove")
def test_fen_position_with_mate_go_nodes(self):
self.stockfish.send_command("ucinewgame")
self.stockfish.send_command(
"position fen 8/5R2/2K1P3/4k3/8/b1PPpp1B/5p2/8 w - -"
)
self.stockfish.send_command("go nodes 500000 searchmoves c6d7")
self.stockfish.expect("* score mate 2 * pv c6d7 * f7f5")
self.stockfish.starts_with("bestmove")
def test_fen_position_depth_27(self):
self.stockfish.send_command("ucinewgame")
self.stockfish.send_command(
"position fen r1b2r1k/pp1p2pp/2p5/2B1q3/8/8/P1PN2PP/R4RK1 w - - 0 18"
)
self.stockfish.send_command("go")
self.stockfish.contains("score mate 1")
self.stockfish.starts_with("bestmove")
def test_fen_position_with_mate_go_depth_and_promotion(self):
self.stockfish.send_command("ucinewgame")
self.stockfish.send_command(
"position fen 8/5R2/2K1P3/4k3/8/b1PPpp1B/5p2/8 w - - moves c6d7 f2f1q"
)
self.stockfish.send_command("go depth 18")
self.stockfish.expect("* score mate 1 * pv f7f5")
self.stockfish.starts_with("bestmove f7f5")
def test_fen_position_with_mate_go_depth_and_searchmoves(self):
self.stockfish.send_command("ucinewgame")
self.stockfish.send_command(
"position fen 8/5R2/2K1P3/4k3/8/b1PPpp1B/5p2/8 w - -"
)
self.stockfish.send_command("go depth 18 searchmoves c6d7")
self.stockfish.expect("* score mate 2 * pv c6d7 * f7f5")
self.stockfish.starts_with("bestmove c6d7")
def test_fen_position_with_moves_with_mate_go_depth_and_searchmoves(self):
self.stockfish.send_command("ucinewgame")
self.stockfish.send_command(
"position fen 8/5R2/2K1P3/4k3/8/b1PPpp1B/5p2/8 w - - moves c6d7"
)
self.stockfish.send_command("go depth 18 searchmoves e3e2")
self.stockfish.expect("* score mate -1 * pv e3e2 f7f5")
self.stockfish.starts_with("bestmove e3e2")
def test_verify_nnue_network(self):
current_path = os.path.abspath(os.getcwd())
Stockfish(
f"export_net {os.path.join(current_path , 'verify.nnue')}".split(" "), True
)
self.stockfish.send_command("setoption name EvalFile value verify.nnue")
self.stockfish.send_command("position startpos")
self.stockfish.send_command("go depth 5")
self.stockfish.starts_with("bestmove")
def test_multipv_setting(self):
self.stockfish.send_command("setoption name MultiPV value 4")
self.stockfish.send_command("position startpos")
self.stockfish.send_command("go depth 5")
self.stockfish.starts_with("bestmove")
def test_fen_position_with_skill_level(self):
self.stockfish.send_command("setoption name Skill Level value 10")
self.stockfish.send_command("position startpos")
self.stockfish.send_command("go depth 5")
self.stockfish.starts_with("bestmove")
self.stockfish.send_command("setoption name Skill Level value 20")
class TestSyzygy(metaclass=OrderedClassMembers):
def beforeAll(self):
self.stockfish = Stockfish()
def afterAll(self):
self.stockfish.quit()
assert self.stockfish.close() == 0
def afterEach(self):
assert postfix_check(self.stockfish.get_output()) == True
self.stockfish.clear_output()
def test_syzygy_setup(self):
self.stockfish.starts_with("Stockfish")
self.stockfish.send_command("uci")
self.stockfish.send_command(
f"setoption name SyzygyPath value {os.path.join(PATH, 'syzygy')}"
)
self.stockfish.expect(
"info string Found 35 WDL and 35 DTZ tablebase files (up to 4-man)."
)
def test_syzygy_bench(self):
self.stockfish.send_command("bench 128 1 8 default depth")
self.stockfish.expect("Nodes searched :*")
def test_syzygy_position(self):
self.stockfish.send_command("ucinewgame")
self.stockfish.send_command("position fen 4k3/PP6/8/8/8/8/8/4K3 w - - 0 1")
self.stockfish.send_command("go depth 5")
def check_output(output):
if "score cp 20000" in output or "score mate" in output:
return True
self.stockfish.check_output(check_output)
self.stockfish.expect("bestmove *")
def test_syzygy_position_2(self):
self.stockfish.send_command("ucinewgame")
self.stockfish.send_command("position fen 8/1P6/2B5/8/4K3/8/6k1/8 w - - 0 1")
self.stockfish.send_command("go depth 5")
def check_output(output):
if "score cp 20000" in output or "score mate" in output:
return True
self.stockfish.check_output(check_output)
self.stockfish.expect("bestmove *")
def test_syzygy_position_3(self):
self.stockfish.send_command("ucinewgame")
self.stockfish.send_command("position fen 8/1P6/2B5/8/4K3/8/6k1/8 b - - 0 1")
self.stockfish.send_command("go depth 5")
def check_output(output):
if "score cp -20000" in output or "score mate" in output:
return True
self.stockfish.check_output(check_output)
self.stockfish.expect("bestmove *")
def parse_args():
parser = argparse.ArgumentParser(description="Run Stockfish with testing options")
parser.add_argument("--valgrind", action="store_true", help="Run valgrind testing")
parser.add_argument(
"--valgrind-thread", action="store_true", help="Run valgrind-thread testing"
)
parser.add_argument(
"--sanitizer-undefined",
action="store_true",
help="Run sanitizer-undefined testing",
)
parser.add_argument(
"--sanitizer-thread", action="store_true", help="Run sanitizer-thread testing"
)
parser.add_argument(
"--none", action="store_true", help="Run without any testing options"
)
parser.add_argument("stockfish_path", type=str, help="Path to Stockfish binary")
return parser.parse_args()
if __name__ == "__main__":
args = parse_args()
EPD.create_bench_epd()
TSAN.set_tsan_option()
Syzygy.download_syzygy()
framework = MiniTestFramework()
# Each test suite will be ran inside a temporary directory
framework.run([TestCLI, TestInteractive, TestSyzygy])
EPD.delete_bench_epd()
TSAN.unset_tsan_option()
if framework.has_failed():
sys.exit(1)
sys.exit(0)
-301
View File
@@ -1,301 +0,0 @@
#!/bin/bash
# check for errors under Valgrind or sanitizers.
error()
{
echo "instrumented testing failed on line $1"
exit 1
}
trap 'error ${LINENO}' ERR
# define suitable post and prefixes for testing options
case $1 in
--valgrind)
echo "valgrind testing started"
prefix=''
exeprefix='valgrind --error-exitcode=42 --errors-for-leak-kinds=all --leak-check=full'
postfix=''
threads="1"
;;
--valgrind-thread)
echo "valgrind-thread testing started"
prefix=''
exeprefix='valgrind --fair-sched=try --error-exitcode=42'
postfix=''
threads="2"
;;
--sanitizer-undefined)
echo "sanitizer-undefined testing started"
prefix='!'
exeprefix=''
postfix='2>&1 | grep -A50 "runtime error:"'
threads="1"
;;
--sanitizer-thread)
echo "sanitizer-thread testing started"
prefix='!'
exeprefix=''
postfix='2>&1 | grep -A50 "WARNING: ThreadSanitizer:"'
threads="2"
cat << EOF > tsan.supp
race:Stockfish::TTEntry::read
race:Stockfish::TTEntry::save
race:Stockfish::TranspositionTable::probe
race:Stockfish::TranspositionTable::hashfull
EOF
export TSAN_OPTIONS="suppressions=./tsan.supp"
;;
*)
echo "unknown testing started"
prefix=''
exeprefix=''
postfix=''
threads="1"
;;
esac
cat << EOF > bench_tmp.epd
Rn6/1rbq1bk1/2p2n1p/2Bp1p2/3Pp1pP/1N2P1P1/2Q1NPB1/6K1 w - - 2 26
rnbqkb1r/ppp1pp2/5n1p/3p2p1/P2PP3/5P2/1PP3PP/RNBQKBNR w KQkq - 0 3
3qnrk1/4bp1p/1p2p1pP/p2bN3/1P1P1B2/P2BQ3/5PP1/4R1K1 w - - 9 28
r4rk1/1b2ppbp/pq4pn/2pp1PB1/1p2P3/1P1P1NN1/1PP3PP/R2Q1RK1 w - - 0 13
EOF
# simple command line testing
for args in "eval" \
"go nodes 1000" \
"go depth 10" \
"go perft 4" \
"go movetime 1000" \
"go wtime 8000 btime 8000 winc 500 binc 500" \
"go wtime 1000 btime 1000 winc 0 binc 0" \
"go wtime 1000 btime 1000 winc 0 binc 0" \
"go wtime 1000 btime 1000 winc 0 binc 0 movestogo 5" \
"go movetime 200" \
"go nodes 20000 searchmoves e2e4 d2d4" \
"bench 128 $threads 8 default depth" \
"bench 128 $threads 3 bench_tmp.epd depth" \
"export_net verify.nnue" \
"d" \
"compiler" \
"license" \
"uci"
do
echo "$prefix $exeprefix ./stockfish $args $postfix"
eval "$prefix $exeprefix ./stockfish $args $postfix"
done
# verify the generated net equals the base net
network=`./stockfish uci | grep 'option name EvalFile type string default' | awk '{print $NF}'`
echo "Comparing $network to the written verify.nnue"
diff $network verify.nnue
# more general testing, following an uci protocol exchange
cat << EOF > game.exp
set timeout 240
# to correctly catch eof we need the following line
# expect_before timeout { exit 2 } eof { exit 3 }
expect_before timeout { exit 2 }
spawn $exeprefix ./stockfish
expect "Stockfish"
send "uci\n"
expect "uciok"
# send "setoption name Debug Log File value debug.log\n"
send "setoption name Threads value $threads\n"
send "ucinewgame\n"
send "position startpos\n"
send "go nodes 1000\n"
expect "bestmove"
send "ucinewgame\n"
send "position startpos moves e2e4 e7e6\n"
send "go nodes 1000\n"
expect "bestmove"
send "ucinewgame\n"
send "position fen 5rk1/1K4p1/8/8/3B4/8/8/8 b - - 0 1\n"
send "go depth 10\n"
expect "bestmove"
send "ucinewgame\n"
send "position fen 5rk1/1K4p1/8/8/3B4/8/8/8 b - - 0 1\n"
send "flip\n"
send "go depth 10\n"
expect "bestmove"
send "ucinewgame\n"
send "position startpos\n"
send "go depth 5\n"
expect -re {info depth \d+ seldepth \d+ multipv \d+ score cp \d+ nodes \d+ nps \d+ hashfull \d+ tbhits \d+ time \d+ pv}
expect "bestmove"
send "ucinewgame\n"
send "setoption name UCI_ShowWDL value true\n"
send "position startpos\n"
send "go depth 9\n"
expect -re {info depth 1 seldepth \d+ multipv \d+ score cp \d+ wdl \d+ \d+ \d+ nodes \d+ nps \d+ hashfull \d+ tbhits \d+ time \d+ pv}
expect -re {info depth 2 seldepth \d+ multipv \d+ score cp \d+ wdl \d+ \d+ \d+ nodes \d+ nps \d+ hashfull \d+ tbhits \d+ time \d+ pv}
expect -re {info depth 3 seldepth \d+ multipv \d+ score cp \d+ wdl \d+ \d+ \d+ nodes \d+ nps \d+ hashfull \d+ tbhits \d+ time \d+ pv}
expect -re {info depth 4 seldepth \d+ multipv \d+ score cp \d+ wdl \d+ \d+ \d+ nodes \d+ nps \d+ hashfull \d+ tbhits \d+ time \d+ pv}
expect -re {info depth 5 seldepth \d+ multipv \d+ score cp \d+ wdl \d+ \d+ \d+ nodes \d+ nps \d+ hashfull \d+ tbhits \d+ time \d+ pv}
expect -re {info depth 6 seldepth \d+ multipv \d+ score cp \d+ wdl \d+ \d+ \d+ nodes \d+ nps \d+ hashfull \d+ tbhits \d+ time \d+ pv}
expect -re {info depth 7 seldepth \d+ multipv \d+ score cp \d+ wdl \d+ \d+ \d+ nodes \d+ nps \d+ hashfull \d+ tbhits \d+ time \d+ pv}
expect -re {info depth 8 seldepth \d+ multipv \d+ score cp \d+ wdl \d+ \d+ \d+ nodes \d+ nps \d+ hashfull \d+ tbhits \d+ time \d+ pv}
expect -re {info depth 9 seldepth \d+ multipv \d+ score cp \d+ wdl \d+ \d+ \d+ nodes \d+ nps \d+ hashfull \d+ tbhits \d+ time \d+ pv}
expect "bestmove"
send "setoption name Clear Hash\n"
send "ucinewgame\n"
send "position fen 5K2/8/2qk4/2nPp3/3r4/6B1/B7/3R4 w - e6\n"
send "go depth 18\n"
expect "score mate 1"
expect "pv d5e6"
expect "bestmove d5e6"
send "ucinewgame\n"
send "position fen 2brrb2/8/p7/Q7/1p1kpPp1/1P1pN1K1/3P4/8 b - -\n"
send "go depth 18\n"
expect "score mate -1"
expect "bestmove"
send "ucinewgame\n"
send "position fen 7K/P1p1p1p1/2P1P1Pk/6pP/3p2P1/1P6/3P4/8 w - - 0 1\n"
send "go nodes 500000\n"
expect "bestmove"
send "ucinewgame\n"
send "position fen 8/5R2/2K1P3/4k3/8/b1PPpp1B/5p2/8 w - -\n"
send "go depth 18 searchmoves c6d7\n"
expect "score mate 2 * pv c6d7 * f7f5"
expect "bestmove c6d7"
send "ucinewgame\n"
send "position fen 8/5R2/2K1P3/4k3/8/b1PPpp1B/5p2/8 w - -\n"
send "go mate 2 searchmoves c6d7\n"
expect "score mate 2 * pv c6d7"
expect "bestmove c6d7"
send "ucinewgame\n"
send "position fen 8/5R2/2K1P3/4k3/8/b1PPpp1B/5p2/8 w - -\n"
send "go nodes 500000 searchmoves c6d7\n"
expect "score mate 2 * pv c6d7 * f7f5"
expect "bestmove c6d7"
send "ucinewgame\n"
send "position fen 1NR2B2/5p2/5p2/1p1kpp2/1P2rp2/2P1pB2/2P1P1K1/8 b - - \n"
send "go depth 27\n"
expect "score mate -2"
expect "pv d5e6 c8d8"
expect "bestmove d5e6"
send "ucinewgame\n"
send "position fen 8/5R2/2K1P3/4k3/8/b1PPpp1B/5p2/8 w - - moves c6d7 f2f1q\n"
send "go depth 18\n"
expect "score mate 1 * pv f7f5"
expect "bestmove f7f5"
send "ucinewgame\n"
send "position fen 8/5R2/2K1P3/4k3/8/b1PPpp1B/5p2/8 w - -\n"
send "go depth 18 searchmoves c6d7\n"
expect "score mate 2 * pv c6d7 * f7f5"
expect "bestmove c6d7"
send "ucinewgame\n"
send "position fen 8/5R2/2K1P3/4k3/8/b1PPpp1B/5p2/8 w - - moves c6d7\n"
send "go depth 18 searchmoves e3e2\n"
expect "score mate -1 * pv e3e2 f7f5"
expect "bestmove e3e2"
send "setoption name EvalFile value verify.nnue\n"
send "position startpos\n"
send "go depth 5\n"
expect "bestmove"
send "setoption name MultiPV value 4\n"
send "position startpos\n"
send "go depth 5\n"
expect "bestmove"
send "setoption name Skill Level value 10\n"
send "position startpos\n"
send "go depth 5\n"
expect "bestmove"
send "setoption name Skill Level value 20\n"
send "quit\n"
expect eof
# return error code of the spawned program, useful for Valgrind
lassign [wait] pid spawnid os_error_flag value
exit \$value
EOF
#download TB as needed
if [ ! -d ../tests/syzygy ]; then
curl -sL https://api.github.com/repos/niklasf/python-chess/tarball/9b9aa13f9f36d08aadfabff872882f4ab1494e95 | tar -xzf -
mv niklasf-python-chess-9b9aa13 ../tests/syzygy
fi
cat << EOF > syzygy.exp
set timeout 240
# to correctly catch eof we need the following line
# expect_before timeout { exit 2 } eof { exit 3 }
expect_before timeout { exit 2 }
spawn $exeprefix ./stockfish
expect "Stockfish"
send "uci\n"
send "setoption name SyzygyPath value ../tests/syzygy/\n"
expect "info string Found 35 WDL and 35 DTZ tablebase files (up to 4-man)."
send "bench 128 1 8 default depth\n"
expect "Nodes searched :"
send "ucinewgame\n"
send "position fen 4k3/PP6/8/8/8/8/8/4K3 w - - 0 1\n"
send "go depth 5\n"
expect -re {score cp 20000|score mate}
expect "bestmove"
send "ucinewgame\n"
send "position fen 8/1P6/2B5/8/4K3/8/6k1/8 w - - 0 1\n"
send "go depth 5\n"
expect -re {score cp 20000|score mate}
expect "bestmove"
send "ucinewgame\n"
send "position fen 8/1P6/2B5/8/4K3/8/6k1/8 b - - 0 1\n"
send "go depth 5\n"
expect -re {score cp -20000|score mate}
expect "bestmove"
send "quit\n"
expect eof
# return error code of the spawned program, useful for Valgrind
lassign [wait] pid spawnid os_error_flag value
exit \$value
EOF
for exp in game.exp syzygy.exp
do
echo "======== $exp =============="
cat $exp
echo "============================"
echo "$prefix expect $exp $postfix"
eval "$prefix expect $exp $postfix"
rm $exp
done
rm -f tsan.supp bench_tmp.epd
echo "instrumented testing OK"
+78 -17
View File
@@ -1,5 +1,7 @@
#!/bin/bash
# verify perft numbers (positions from www.chessprogramming.org/Perft_Results)
# verify perft numbers (positions from https://www.chessprogramming.org/Perft_Results)
TESTS_FAILED=0
error()
{
@@ -10,23 +12,82 @@ trap 'error ${LINENO}' ERR
echo "perft testing started"
cat << EOF > perft.exp
set timeout 10
lassign \$argv pos depth result
spawn ./stockfish
send "position \$pos\\ngo perft \$depth\\n"
expect "Nodes searched? \$result" {} timeout {exit 1}
send "quit\\n"
expect eof
EXPECT_SCRIPT=$(mktemp)
cat << 'EOF' > $EXPECT_SCRIPT
#!/usr/bin/expect -f
set timeout 30
lassign [lrange $argv 0 4] pos depth result chess960 logfile
log_file -noappend $logfile
spawn ./stockfish
if {$chess960 == "true"} {
send "setoption name UCI_Chess960 value true\n"
}
send "position $pos\ngo perft $depth\n"
expect {
"Nodes searched: $result" {}
timeout {puts "TIMEOUT: Expected $result nodes"; exit 1}
eof {puts "EOF: Stockfish crashed"; exit 2}
}
send "quit\n"
expect eof
EOF
expect perft.exp startpos 5 4865609 > /dev/null
expect perft.exp "fen r3k2r/p1ppqpb1/bn2pnp1/3PN3/1p2P3/2N2Q1p/PPPBBPPP/R3K2R w KQkq -" 5 193690690 > /dev/null
expect perft.exp "fen 8/2p5/3p4/KP5r/1R3p1k/8/4P1P1/8 w - -" 6 11030083 > /dev/null
expect perft.exp "fen r3k2r/Pppp1ppp/1b3nbN/nP6/BBP1P3/q4N2/Pp1P2PP/R2Q1RK1 w kq - 0 1" 5 15833292 > /dev/null
expect perft.exp "fen rnbq1k1r/pp1Pbppp/2p5/8/2B5/8/PPP1NnPP/RNBQK2R w KQ - 1 8" 5 89941194 > /dev/null
expect perft.exp "fen r4rk1/1pp1qppp/p1np1n2/2b1p1B1/2B1P1b1/P1NP1N2/1PP1QPPP/R4RK1 w - - 0 10" 5 164075551 > /dev/null
chmod +x $EXPECT_SCRIPT
rm perft.exp
run_test() {
local pos="$1"
local depth="$2"
local expected="$3"
local chess960="$4"
local tmp_file=$(mktemp)
echo "perft testing OK"
echo -n "Testing depth $depth: ${pos:0:40}... "
if $EXPECT_SCRIPT "$pos" "$depth" "$expected" "$chess960" "$tmp_file" > /dev/null 2>&1; then
echo "OK"
rm -f "$tmp_file"
else
local exit_code=$?
echo "FAILED (exit code: $exit_code)"
echo "===== Output for failed test ====="
cat "$tmp_file"
echo "=================================="
rm -f "$tmp_file"
TESTS_FAILED=1
fi
}
# standard positions
run_test "startpos" 7 3195901860 "false"
run_test "fen r3k2r/p1ppqpb1/bn2pnp1/3PN3/1p2P3/2N2Q1p/PPPBBPPP/R3K2R w KQkq -" 5 193690690 "false"
run_test "fen 8/2p5/3p4/KP5r/1R3p1k/8/4P1P1/8 w - -" 7 178633661 "false"
run_test "fen r3k2r/Pppp1ppp/1b3nbN/nP6/BBP1P3/q4N2/Pp1P2PP/R2Q1RK1 w kq - 0 1" 6 706045033 "false"
run_test "fen rnbq1k1r/pp1Pbppp/2p5/8/2B5/8/PPP1NnPP/RNBQK2R w KQ - 1 8" 5 89941194 "false"
run_test "fen r4rk1/1pp1qppp/p1np1n2/2b1p1B1/2B1P1b1/P1NP1N2/1PP1QPPP/R4RK1 w - - 0 10" 5 164075551 "false"
run_test "fen r7/4p3/5p1q/3P4/4pQ2/4pP2/6pp/R3K1kr w Q - 1 3" 5 11609488 "false"
# chess960 positions
run_test "fen rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w AHah - 0 1" 6 119060324 "true"
run_test "fen 1rqbkrbn/1ppppp1p/1n6/p1N3p1/8/2P4P/PP1PPPP1/1RQBKRBN w FBfb - 0 9" 6 191762235 "true"
run_test "fen rbbqn1kr/pp2p1pp/6n1/2pp1p2/2P4P/P7/BP1PPPP1/R1BQNNKR w HAha - 0 9" 6 924181432 "true"
run_test "fen rqbbknr1/1ppp2pp/p5n1/4pp2/P7/1PP5/1Q1PPPPP/R1BBKNRN w GAga - 0 9" 6 308553169 "true"
run_test "fen 4rrb1/1kp3b1/1p1p4/pP1Pn2p/5p2/1PR2P2/2P1NB1P/2KR1B2 w D - 0 21" 6 872323796 "true"
run_test "fen 1rkr3b/1ppn3p/3pB1n1/6q1/R2P4/4N1P1/1P5P/2KRQ1B1 b Dbd - 0 14" 6 2678022813 "true"
run_test "fen qbbnrkr1/p1pppppp/1p4n1/8/2P5/6N1/PPNPPPPP/1BRKBRQ1 b FCge - 1 3" 6 521301336 "true"
run_test "fen rr6/2kpp3/1ppn2p1/p2b1q1p/P4P1P/1PNN2P1/2PP4/1K2R2R b E - 1 20" 2 1438 "true"
run_test "fen rr6/2kpp3/1ppn2p1/p2b1q1p/P4P1P/1PNN2P1/2PP4/1K2RR2 w E - 0 20" 3 37340 "true"
run_test "fen rr6/2kpp3/1ppnb1p1/p2Q1q1p/P4P1P/1PNN2P1/2PP4/1K2RR2 b E - 2 19" 4 2237725 "true"
run_test "fen rr6/2kpp3/1ppnb1p1/p4q1p/P4P1P/1PNN2P1/2PP2Q1/1K2RR2 w E - 1 19" 4 2098209 "true"
run_test "fen rr6/2kpp3/1ppnb1p1/p4q1p/P4P1P/1PNN2P1/2PP2Q1/1K2RR2 w E - 1 19" 5 79014522 "true"
run_test "fen rr6/2kpp3/1ppnb1p1/p4q1p/P4P1P/1PNN2P1/2PP2Q1/1K2RR2 w E - 1 19" 6 2998685421 "true"
rm -f $EXPECT_SCRIPT
echo "perft testing completed"
if [ $TESTS_FAILED -ne 0 ]; then
echo "Some tests failed"
exit 1
fi
+400
View File
@@ -0,0 +1,400 @@
import subprocess
from typing import List
import os
import collections
import time
import sys
import traceback
import fnmatch
from functools import wraps
from contextlib import redirect_stdout
import io
import tarfile
import pathlib
import concurrent.futures
import tempfile
import shutil
import requests
CYAN_COLOR = "\033[36m"
GRAY_COLOR = "\033[2m"
RED_COLOR = "\033[31m"
GREEN_COLOR = "\033[32m"
RESET_COLOR = "\033[0m"
WHITE_BOLD = "\033[1m"
MAX_TIMEOUT = 60 * 5
PATH = pathlib.Path(__file__).parent.resolve()
class Valgrind:
@staticmethod
def get_valgrind_command():
return [
"valgrind",
"--error-exitcode=42",
"--errors-for-leak-kinds=all",
"--leak-check=full",
]
@staticmethod
def get_valgrind_thread_command():
return ["valgrind", "--error-exitcode=42", "--fair-sched=try"]
class TSAN:
@staticmethod
def set_tsan_option():
with open(f"tsan.supp", "w") as f:
f.write(
"""
race:Stockfish::TTEntry::read
race:Stockfish::TTEntry::save
race:Stockfish::TranspositionTable::probe
race:Stockfish::TranspositionTable::hashfull
"""
)
os.environ["TSAN_OPTIONS"] = "suppressions=./tsan.supp"
@staticmethod
def unset_tsan_option():
os.environ.pop("TSAN_OPTIONS", None)
os.remove(f"tsan.supp")
class EPD:
@staticmethod
def create_bench_epd():
with open(f"{os.path.join(PATH,'bench_tmp.epd')}", "w") as f:
f.write(
"""
Rn6/1rbq1bk1/2p2n1p/2Bp1p2/3Pp1pP/1N2P1P1/2Q1NPB1/6K1 w - - 2 26
rnbqkb1r/ppp1pp2/5n1p/3p2p1/P2PP3/5P2/1PP3PP/RNBQKBNR w KQkq - 0 3
3qnrk1/4bp1p/1p2p1pP/p2bN3/1P1P1B2/P2BQ3/5PP1/4R1K1 w - - 9 28
r4rk1/1b2ppbp/pq4pn/2pp1PB1/1p2P3/1P1P1NN1/1PP3PP/R2Q1RK1 w - - 0 13
"""
)
@staticmethod
def delete_bench_epd():
os.remove(f"{os.path.join(PATH,'bench_tmp.epd')}")
class Syzygy:
@staticmethod
def get_syzygy_path():
return os.path.abspath("syzygy")
@staticmethod
def download_syzygy():
if not os.path.isdir(os.path.join(PATH, "syzygy")):
url = "https://api.github.com/repos/niklasf/python-chess/tarball/9b9aa13f9f36d08aadfabff872882f4ab1494e95"
file = "niklasf-python-chess-9b9aa13"
with tempfile.TemporaryDirectory() as tmpdirname:
tarball_path = os.path.join(tmpdirname, f"{file}.tar.gz")
response = requests.get(url, stream=True)
with open(tarball_path, "wb") as f:
for chunk in response.iter_content(chunk_size=8192):
f.write(chunk)
with tarfile.open(tarball_path, "r:gz") as tar:
tar.extractall(tmpdirname)
shutil.move(
os.path.join(tmpdirname, file), os.path.join(PATH, "syzygy")
)
class OrderedClassMembers(type):
@classmethod
def __prepare__(self, name, bases):
return collections.OrderedDict()
def __new__(self, name, bases, classdict):
classdict["__ordered__"] = [
key for key in classdict.keys() if key not in ("__module__", "__qualname__")
]
return type.__new__(self, name, bases, classdict)
class TimeoutException(Exception):
def __init__(self, message: str, timeout: int):
self.message = message
self.timeout = timeout
def timeout_decorator(timeout: float):
def decorator(func):
@wraps(func)
def wrapper(*args, **kwargs):
with concurrent.futures.ThreadPoolExecutor() as executor:
future = executor.submit(func, *args, **kwargs)
try:
result = future.result(timeout=timeout)
except concurrent.futures.TimeoutError:
raise TimeoutException(
f"Function {func.__name__} timed out after {timeout} seconds",
timeout,
)
return result
return wrapper
return decorator
class MiniTestFramework:
def __init__(self):
self.passed_test_suites = 0
self.failed_test_suites = 0
self.passed_tests = 0
self.failed_tests = 0
self.stop_on_failure = True
def has_failed(self) -> bool:
return self.failed_test_suites > 0
def run(self, classes: List[type]) -> bool:
self.start_time = time.time()
for test_class in classes:
with tempfile.TemporaryDirectory() as tmpdirname:
original_cwd = os.getcwd()
os.chdir(tmpdirname)
try:
if self.__run(test_class):
self.failed_test_suites += 1
else:
self.passed_test_suites += 1
except Exception as e:
self.failed_test_suites += 1
print(f"\n{RED_COLOR}Error: {e}{RESET_COLOR}")
finally:
os.chdir(original_cwd)
self.__print_summary(round(time.time() - self.start_time, 2))
return self.has_failed()
def __run(self, test_class) -> bool:
test_instance = test_class()
test_name = test_instance.__class__.__name__
test_methods = [m for m in test_instance.__ordered__ if m.startswith("test_")]
print(f"\nTest Suite: {test_name}")
if hasattr(test_instance, "beforeAll"):
test_instance.beforeAll()
fails = 0
for method in test_methods:
fails += self.__run_test_method(test_instance, method)
if hasattr(test_instance, "afterAll"):
test_instance.afterAll()
self.failed_tests += fails
return fails > 0
def __run_test_method(self, test_instance, method: str) -> int:
print(f" Running {method}... \r", end="", flush=True)
buffer = io.StringIO()
fails = 0
try:
t0 = time.time()
with redirect_stdout(buffer):
if hasattr(test_instance, "beforeEach"):
test_instance.beforeEach()
getattr(test_instance, method)()
if hasattr(test_instance, "afterEach"):
test_instance.afterEach()
duration = time.time() - t0
self.print_success(f" {method} ({duration * 1000:.2f}ms)")
self.passed_tests += 1
except Exception as e:
if isinstance(e, TimeoutException):
self.print_failure(
f" {method} (hit execution limit of {e.timeout} seconds)"
)
if isinstance(e, AssertionError):
self.__handle_assertion_error(t0, method)
if self.stop_on_failure:
self.__print_buffer_output(buffer)
raise e
fails += 1
finally:
self.__print_buffer_output(buffer)
return fails
def __handle_assertion_error(self, start_time, method: str):
duration = time.time() - start_time
self.print_failure(f" {method} ({duration * 1000:.2f}ms)")
traceback_output = "".join(traceback.format_tb(sys.exc_info()[2]))
colored_traceback = "\n".join(
f" {CYAN_COLOR}{line}{RESET_COLOR}"
for line in traceback_output.splitlines()
)
print(colored_traceback)
def __print_buffer_output(self, buffer: io.StringIO):
output = buffer.getvalue()
if output:
indented_output = "\n".join(f" {line}" for line in output.splitlines())
print(f" {RED_COLOR}⎯⎯⎯⎯⎯OUTPUT⎯⎯⎯⎯⎯{RESET_COLOR}")
print(f"{GRAY_COLOR}{indented_output}{RESET_COLOR}")
print(f" {RED_COLOR}⎯⎯⎯⎯⎯OUTPUT⎯⎯⎯⎯⎯{RESET_COLOR}")
def __print_summary(self, duration: float):
print(f"\n{WHITE_BOLD}Test Summary{RESET_COLOR}\n")
print(
f" Test Suites: {GREEN_COLOR}{self.passed_test_suites} passed{RESET_COLOR}, {RED_COLOR}{self.failed_test_suites} failed{RESET_COLOR}, {self.passed_test_suites + self.failed_test_suites} total"
)
print(
f" Tests: {GREEN_COLOR}{self.passed_tests} passed{RESET_COLOR}, {RED_COLOR}{self.failed_tests} failed{RESET_COLOR}, {self.passed_tests + self.failed_tests} total"
)
print(f" Time: {duration}s\n")
def print_failure(self, add: str):
print(f" {RED_COLOR}{RESET_COLOR}{add}", flush=True)
def print_success(self, add: str):
print(f" {GREEN_COLOR}{RESET_COLOR}{add}", flush=True)
class Stockfish:
def __init__(
self,
prefix: List[str],
path: str,
args: List[str] = [],
cli: bool = False,
):
self.path = path
self.process = None
self.args = args
self.cli = cli
self.prefix = prefix
self.output = []
self.start()
def _check_process_alive(self):
if not self.process or self.process.poll() is not None:
print("\n".join(self.output))
raise RuntimeError("Stockfish process has terminated")
def start(self):
if self.cli:
self.process = subprocess.run(
self.prefix + [self.path] + self.args,
capture_output=True,
text=True,
)
if self.process.returncode != 0:
print(self.process.stdout)
print(self.process.stderr)
print(f"Process failed with return code {self.process.returncode}")
return
self.process = subprocess.Popen(
self.prefix + [self.path] + self.args,
stdin=subprocess.PIPE,
stdout=subprocess.PIPE,
stderr=subprocess.STDOUT,
universal_newlines=True,
bufsize=1,
)
def setoption(self, name: str, value: str):
self.send_command(f"setoption name {name} value {value}")
def send_command(self, command: str):
if not self.process:
raise RuntimeError("Stockfish process is not started")
self._check_process_alive()
self.process.stdin.write(command + "\n")
self.process.stdin.flush()
@timeout_decorator(MAX_TIMEOUT)
def equals(self, expected_output: str):
for line in self.readline():
if line == expected_output:
return
@timeout_decorator(MAX_TIMEOUT)
def expect(self, expected_output: str):
for line in self.readline():
if fnmatch.fnmatch(line, expected_output):
return
@timeout_decorator(MAX_TIMEOUT)
def contains(self, expected_output: str):
for line in self.readline():
if expected_output in line:
return
@timeout_decorator(MAX_TIMEOUT)
def starts_with(self, expected_output: str):
for line in self.readline():
if line.startswith(expected_output):
return
@timeout_decorator(MAX_TIMEOUT)
def check_output(self, callback):
if not callback:
raise ValueError("Callback function is required")
for line in self.readline():
if callback(line) == True:
return
def readline(self):
if not self.process:
raise RuntimeError("Stockfish process is not started")
while True:
self._check_process_alive()
line = self.process.stdout.readline().strip()
self.output.append(line)
yield line
def clear_output(self):
self.output = []
def get_output(self) -> List[str]:
return self.output
def quit(self):
self.send_command("quit")
def close(self):
if self.process:
self.process.stdin.close()
self.process.stdout.close()
return self.process.wait()
return 0