Compare commits

...

98 Commits

Author SHA1 Message Date
Joost VandeVondele 758f9c9350 Stockfish 15.1
Official release version of Stockfish 15.1

Bench: 3467381

---

Today, we have the pleasure to announce Stockfish 15.1.

As usual, downloads will be freely available at stockfishchess.org/download

*Elo gain and competition results*

With this release, version 5 of the NNUE neural net architecture has
been introduced, and the training data has been extended to include
Fischer random chess (FRC) positions. As a result, Elo gains are largest
for FRC, reaching up to 50 Elo for doubly randomized FRC[1] (DFRC).
More importantly, also for standard chess this release progressed and
will win two times more game pairs than it loses[2] against
Stockfish 15. Stockfish continues to win in a dominating way[3] all
chess engine tournaments, including the TCEC Superfinal, Cup, FRC, DFRC,
and Swiss as well as the CCC Bullet, Blitz, and Rapid events.

*New evaluation*

This release also introduces a new convention for the evaluation that
is reported by search. An evaluation of +1 is now no longer tied to the
value of one pawn, but to the likelihood of winning the game. With
a +1 evaluation, Stockfish has now a 50% chance of winning the game
against an equally strong opponent. This convention scales down
evaluations a bit compared to Stockfish 15 and allows for consistent
evaluations in the future.

*ChessBase settlement*

In this release period, the Stockfish team has successfully enforced
its GPL license against ChessBase. This has been an intense process that
included filing a lawsuit[4], a court hearing[5], and finally
negotiating a settlement[6] that established that ChessBase infringed on
the license by not distributing the Stockfish derivatives Fat Fritz 2
and Houdini 6 as free software, and that ensures ChessBase will respect
the Free Software principles in the future. This settlement has been
covered by major chess sites (see e.g. lichess.org[7] and chess.com[8]),
and we are proud that it has been hailed as a ‘historic violation
settlement[9]’ by the Software Freedom Conservancy.

*Thank you*

The Stockfish project builds on a thriving community of enthusiasts
(thanks everybody!) that contribute their expertise, time, and resources
to build a free and open-source chess engine that is robust, widely
available, and very strong. We invite our chess fans to join the
fishtest testing framework and programmers to contribute to the
project[10].

The Stockfish team

[1] https://tests.stockfishchess.org/tests/view/638a6170d2b9c924c4c62cb4
[2] https://tests.stockfishchess.org/tests/view/638a4dd7d2b9c924c4c6297b
[3] https://en.wikipedia.org/wiki/Stockfish_(chess)#Competition_results
[4] https://stockfishchess.org/blog/2021/our-lawsuit-against-chessbase/
[5] https://stockfishchess.org/blog/2022/public-court-hearing-soon/
[6] https://stockfishchess.org/blog/2022/chessbase-stockfish-agreement/
[7] https://lichess.org/blog/Y3u1mRAAACIApBVn/settlement-reached-in-stockfish-v-chessbase
[8] https://www.chess.com/news/view/chessbase-stockfish-reach-settlement
[9] https://sfconservancy.org/news/2022/nov/28/sfc-named-trusted-party-in-gpl-case/
[10] https://stockfishchess.org/get-involved/
2022-12-04 14:17:15 +01:00
Joost VandeVondele d60f5de967 Fix bestThread selection
If multiple threads have the same best move,
pick the thread with the largest contribution to the confidence vote.
This thread will later be used to display PV, so this patch is
about user-friendliness and/or least surprises, it non-functional for playing strenght.

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

No functional change
2022-12-02 20:06:59 +01:00
VoyagerOne c7118fb46d Simply do full sort on captures.
STC:
LLR: 2.94 (-2.94,2.94) <-1.75,0.25>
Total: 42712 W: 11413 L: 11203 D: 20096
Ptnml(0-2): 145, 4661, 11544, 4851, 155
https://tests.stockfishchess.org/tests/view/6384df57d2b9c924c4c53900

LTC:
LLR: 2.95 (-2.94,2.94) <-1.75,0.25>
Total: 239072 W: 64065 L: 64067 D: 110940
Ptnml(0-2): 106, 23735, 71859, 23727, 109
https://tests.stockfishchess.org/tests/view/63851120d2b9c924c4c541ee

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

Bench: 3467381
2022-12-02 20:05:50 +01:00
VoyagerOne 6a6faac04d Remove PvNode Parameter for cutoff LMR
STC:
LLR: 2.94 (-2.94,2.94) <-1.75,0.25>
Total: 198520 W: 52673 L: 52632 D: 93215
Ptnml(0-2): 645, 22241, 53499, 22178, 697
https://tests.stockfishchess.org/tests/view/63746e8f9849fa7a36a6698f

LTC:
LLR: 2.97 (-2.94,2.94) <-1.75,0.25>
Total: 253568 W: 67487 L: 67501 D: 118580
Ptnml(0-2): 109, 25222, 76141, 25198, 114
https://tests.stockfishchess.org/tests/view/63839859d2b9c924c4c4feb7

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

Bench: 3733322
2022-12-02 20:03:49 +01:00
Guenther Demetz f5a31b7e57 Correctly output lowerbound/upperbound in threaded searches
fixes the lowerbound/upperbound output by taking the alpha,beta bracket
into account also if a bestThread is selected that is different from the master thread.

Instead of keeping track which bounds where used in the specific search,
in this version we simply store the quality (exact, upperbound,
lowerbound) of the score along with the actual score as information on
rootMove.

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

No functional change
2022-11-23 21:45:06 +01:00
peregrineshahin 1370127fcd Simplify both quiet check evasions' conditions
passed Non-regression STC:
https://tests.stockfishchess.org/tests/view/6370b647f1b748d4819e0b64
LLR: 2.95 (-2.94,2.94) <-1.75,0.25>
Total: 162904 W: 43249 L: 43171 D: 76484
Ptnml(0-2): 491, 17089, 46220, 17155, 497

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

No functional change
2022-11-23 21:36:22 +01:00
VoyagerOne 85ae65db1d Skip full depth search in LMR depending on depth
dynamically adjust newDepth, and skip full depth search if newDepth doesn't exceed the previous search depth.
This affects the used newDepth for future searches, and influences the stat bonus for the move.

Passed STC:
https://tests.stockfishchess.org/tests/view/63795500aa34433735bc1cfe
LLR: 2.95 (-2.94,2.94) <0.00,2.00>
Total: 112776 W: 30082 L: 29663 D: 53031
Ptnml(0-2): 352, 12453, 30423, 12744, 416

Passed LTC:
https://tests.stockfishchess.org/tests/view/6379ea39aa34433735bc2f9b
LLR: 2.94 (-2.94,2.94) <0.50,2.50>
Total: 83576 W: 22559 L: 22169 D: 38848
Ptnml(0-2): 38, 8011, 25303, 8395, 41

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

Bench: 4390318
2022-11-23 21:25:14 +01:00
Joost VandeVondele d8f3209fb4 Update Top CPU Contributors
list as of 2022-11-19. Thanks!

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

No functional change
2022-11-20 10:00:42 +01:00
Joost VandeVondele 3411631162 Update WDL model for current SF
This updates the WDL model based on the LTC statistics  (2M games).

Relatively small change, note that this also adjusts the NormalizeToPawnValue (now 361),
to keep win prob at 50% for 100cp.

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

No functional change.
2022-11-20 09:59:35 +01:00
Joost VandeVondele d756d97a66 Fix a missing conversion
This conversion to cp was overlooked.

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

No functional change
2022-11-20 09:58:07 +01:00
VoyagerOne 41c6a74d37 Simplification away Cutoff Reset
STC:
LLR: 2.95 (-2.94,2.94) <-1.75,0.25>
Total: 150184 W: 39913 L: 39819 D: 70452
Ptnml(0-2): 493, 16796, 40474, 16782, 547
https://tests.stockfishchess.org/tests/view/63723e9e54d69a2f33911d3c

LTC:
LLR: 2.94 (-2.94,2.94) <-1.75,0.25>
Total: 58880 W: 15890 L: 15717 D: 27273
Ptnml(0-2): 35, 5765, 17659, 5954, 27
https://tests.stockfishchess.org/tests/view/6373baf49849fa7a36a65427

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

Bench: 4035152
2022-11-19 09:29:04 +01:00
Michael Chaly 219fa2f0a7 Do shallower search in case of lmr being not successful enough
In case of a move passing LMR but it results being not too far from
the current best search result produce a full depth search with reduced depth.

Original idea by lonfom169 .

Passed STC:
https://tests.stockfishchess.org/tests/view/6373409b54d69a2f33913fbd
LLR: 2.94 (-2.94,2.94) <0.00,2.00>
Total: 169504 W: 45351 L: 44848 D: 79305
Ptnml(0-2): 598, 18853, 45353, 19344, 604

Passed LTC:
https://tests.stockfishchess.org/tests/view/6374c58528e3405283eb8d2d
LLR: 2.96 (-2.94,2.94) <0.50,2.50>
Total: 51144 W: 13802 L: 13471 D: 23871
Ptnml(0-2): 19, 4928, 15362, 5229, 34

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

bench 4277005
2022-11-19 09:23:26 +01:00
disservin 6c1df553fa speedup CI
Github Actions allows us to use up to 20 workers.
This way we can launch multiple different checks
at the same time and optimize the overall time
the CI takes a bit.

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

No functional change
2022-11-07 21:42:04 +01:00
disservin a413900791 Remove trend
Simplify trend away.

passed Non-regression STC:
https://tests.stockfishchess.org/tests/view/63642a63a90afcecbd1cb887
LLR: 2.95 (-2.94,2.94) <-1.75,0.25>
Total: 130000 W: 34683 L: 34567 D: 60750
Ptnml(0-2): 455, 14424, 35135, 14522, 464

passed Non-regression LTC:
https://tests.stockfishchess.org/tests/view/636566fda90afcecbd1cded9
LLR: 2.94 (-2.94,2.94) <-1.75,0.25>
Total: 81592 W: 21938 L: 21787 D: 37867
Ptnml(0-2): 42, 8035, 24490, 8188, 41

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

Bench: 4239512
2022-11-07 08:00:05 +01:00
disservin e048d11825 Change versioning and save binaries as CI artifacts
For development versions of Stockfish, the version will now look like
dev-20221107-dca9a0533
indicating a development version, the date of the last commit,
and the git SHA of that commit. If git is not available,
the fallback is the date of compilation. Releases will continue to be
versioned as before.

Additionally, this PR extends the CI to create binary artifacts,
i.e. pushes to master will automatically build Stockfish and upload
the binaries to github.

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

No functional change
2022-11-07 07:56:58 +01:00
Joost VandeVondele ad2aa8c06f Normalize evaluation
Normalizes the internal value as reported by evaluate or search
to the UCI centipawn result used in output. This value is derived from
the win_rate_model() such that Stockfish outputs an advantage of
"100 centipawns" for a position if the engine has a 50% probability to win
from this position in selfplay at fishtest LTC time control.

The reason to introduce this normalization is that our evaluation is, since NNUE,
no longer related to the classical parameter PawnValueEg (=208). This leads to
the current evaluation changing quite a bit from release to release, for example,
the eval needed to have 50% win probability at fishtest LTC (in cp and internal Value):

June 2020  :   113cp (237)
June 2021  :   115cp (240)
April 2022 :   134cp (279)
July 2022  :   167cp (348)

With this patch, a 100cp advantage will have a fixed interpretation,
i.e. a 50% win chance. To keep this value steady, it will be needed to update the win_rate_model()
from time to time, based on fishtest data. This analysis can be performed with
a set of scripts currently available at https://github.com/vondele/WLD_model

fixes https://github.com/official-stockfish/Stockfish/issues/4155
closes https://github.com/official-stockfish/Stockfish/pull/4216

No functional change
2022-11-05 09:15:53 +01:00
Joost VandeVondele 61a2cb84a6 Mark variable as potentially unused
fixes CI when compiled with -Werror

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

No functional change
2022-11-05 09:15:14 +01:00
kurt22i d09653df0d Adjust reduction less at medium depths
This patch dampens the reduction increase/decrease from statScore at mid-range depths.
Inspired by patterns noticed in this tune: https://tests.stockfishchess.org/tests/view/635188930e5f47a8d0ffe8f5

Passed STC:
https://tests.stockfishchess.org/tests/view/63599dfd6b27ef94d9ec04af
LLR: 2.95 (-2.94,2.94) <0.00,2.00>
Total: 87464 W: 23519 L: 23134 D: 40811
Ptnml(0-2): 319, 9599, 23524, 9958, 332

Passed LTC:
https://tests.stockfishchess.org/tests/view/635a73046b27ef94d9ec2313
LLR: 2.94 (-2.94,2.94) <0.50,2.50>
Total: 154792 W: 41746 L: 41214 D: 71832
Ptnml(0-2): 79, 15181, 46349, 15703, 84

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

Bench 4271738
2022-10-30 16:19:09 +01:00
Joost VandeVondele f154ed7a2d Update MacOS CI
move to 12 following actions runner update deprecation
(see https://github.com/actions/runner-images/issues/5583)

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

No functional change
2022-10-30 16:17:49 +01:00
Clausable 8333b2a94c Fix README typos, update AUTHORS
closes https://github.com/official-stockfish/Stockfish/pull/4208

No functional change
2022-10-27 08:15:46 +02:00
dav1312 a5500edc55 Add issue template
Add an issue template using GitHub's form schema
https://docs.github.com/en/communities/using-templates-to-encourage-useful-issues-and-pull-requests/syntax-for-githubs-form-schema

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

No functional change.
2022-10-26 20:28:12 +02:00
Michael Chaly 4ec8945eaf Use TT moves more often in qsearch
During the recapture phase of quiescence search (where we limit the generated moves to recaptures on the last seen capture square),
the move picker will now emit the tt move, even if the tt move is not a recapture.

Passed STC :
https://tests.stockfishchess.org/tests/view/6350df2928d3a71cb1eef838
LLR: 2.94 (-2.94,2.94) <-1.75,0.25>
Total: 90280 W: 24001 L: 23845 D: 42434
Ptnml(0-2): 273, 9779, 24941, 9813, 334

Passed LTC :
https://tests.stockfishchess.org/tests/view/6351308b28d3a71cb1ef06ce
LLR: 2.96 (-2.94,2.94) <-1.75,0.25>
Total: 104504 W: 27937 L: 27807 D: 48760
Ptnml(0-2): 54, 10378, 31260, 10504, 56

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

Bench: 4540268
2022-10-23 20:22:04 +02:00
Clement 5604b255e6 Add RISC-V 64-bit support
adds a riscv64 target architecture to the Makefile to support RISC-V 64-bit.
Compiled and tested on VisionFive 2 board.

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

No functional change.
2022-10-23 20:18:08 +02:00
disservin 804394b939 enable bit manipulation instruction set 1
bmi1 enables the use of _blsr_u64 for pop_lsb, and is availabe when avx2 is.

verified a small speedup (0.2 - 0.6%)

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

No functional change
2022-10-23 20:08:18 +02:00
MinetaS 234d2156fd Apply -flto-partition=one / -flto=full
This patch fixes a potential bug derived from an incompatibility between LTO and top-level assembly code (INCBIN).

Passed non-regression STC (master e90341f):
LLR: 2.94 (-2.94,2.94) <-1.75,0.25>
Total: 119352 W: 31986 L: 31862 D: 55504
Ptnml(0-2): 439, 12624, 33400, 12800, 413
https://tests.stockfishchess.org/tests/view/634aacf84bc7650f0755188b

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

No functional change
2022-10-23 19:58:47 +02:00
Rodrigo Roim 79c5f3a692 Fix tablebase probe for dtz >1000 w/o 50 move rule
For qn4N1/6R1/3K4/8/B2k4/8/8/8 w - - 0 1, white loses with DTZ 1034.
See https://syzygy-tables.info/?fen=qn4N1/6R1/3K4/8/B2k4/8/8/8_w_-_-_0_1

Prior to this fix, due to a too small hard-coded value, Stockfish interpreted this as winning.
The new value picked (1<<18) is large enough to deal with the largest DTZ values that can be stored in the current syzygy format.

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

No functional change.
2022-10-16 12:58:48 +02:00
xoto10 9be2977da7 Adjust timeman constants
Adjust timeman constants to use more time in early part of game.

STC @ 10+0.1 th 1 :
LLR: 2.94 (-2.94,2.94) <0.00,2.00>
Total: 93984 W: 25177 L: 24787 D: 44020
Ptnml(0-2): 350, 10096, 25729, 10448, 369
https://tests.stockfishchess.org/tests/live_elo/6339077135f43d649ff6162a

LTC @ 60+0.6 th 1 :
LLR: 2.94 (-2.94,2.94) <0.50,2.50>
Total: 329368 W: 88953 L: 88093 D: 152322
Ptnml(0-2): 170, 31457, 100594, 32269, 194
https://tests.stockfishchess.org/tests/live_elo/6339baed35f43d649ff63142

Sudden death 10+0 :
LLR: 2.94 (-2.94,2.94) <0.00,2.00>
Total: 20400 W: 5908 L: 5588 D: 8904
Ptnml(0-2): 177, 2252, 5128, 2360, 283
https://tests.stockfishchess.org/tests/live_elo/6347c9384bc7650f07549ba7

Sudden death 10+0, no adjudication :
LLR: 2.96 (-2.94,2.94) <0.00,2.00>
Total: 17920 W: 4755 L: 4442 D: 8723
Ptnml(0-2): 137, 1985, 4466, 2172, 200
https://tests.stockfishchess.org/tests/live_elo/634806e84bc7650f0754a639

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

No functional change
2022-10-16 11:51:41 +02:00
Stéphane Nicolet d6b6360ff5 Tweak the formula for NNUE complexity
Joint work by Ofek Shochat and Stéphane Nicolet.

passed STC:
LLR: 2.95 (-2.94,2.94) <0.00,2.00>
Total: 93288 W: 24996 L: 24601 D: 43691
Ptnml(0-2): 371, 10263, 24989, 10642, 379
https://tests.stockfishchess.org/tests/view/63448f4f4bc7650f07541987

passed LTC:
LLR: 2.94 (-2.94,2.94) <0.50,2.50>
Total: 84168 W: 22771 L: 22377 D: 39020
Ptnml(0-2): 47, 8181, 25234, 8575, 47
https://tests.stockfishchess.org/tests/view/6345186d4bc7650f07542fbd

================

It seems there are two effects with this patch:

effect A :

If Stockfish is winning at root, we have optimism > 0 for all leaves in
the search tree where Stockfish is to move. There, if (psq - nnue) > 0
(ie if the advantage is more materialistic than positional), then the
product D = optimism * (psq - nnue) will be positive, nnueComplexity will
increase, and the eval will increase from SF point of view.

So the effect A is that if Stockfish is winning at root, she will slightly
favor in the search tree (in other words, search more) the positions where
she can convert her advantage via materialist means.

effect B :

If Stockfish is losing at root, we have optimism > 0 for all leaves in
the search tree where the opponent is to move. There, if (psq - nnue) < 0
(ie if the opponent advantage is more positional than materialistic), then
the product D = optimism * (psq-nnue) will be negative, nnueComplexity will
decrease, and the eval will decrease from the opponent point of view.

So the effect B is that Stockfish will slightly favor in the search tree
(search more) the branches where she can defend by slowly reducing the
opponent positional advantage.

=================

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

bench: 4673898
2022-10-16 11:49:07 +02:00
Dubslow f97a86e213 Remove depth condition from razoring
The eval condition depends on depth anyways, so this patch is nearly (not quite) non-functional

passed STC:
https://tests.stockfishchess.org/tests/view/63428169fb7ccb2ea9be2629
LLR: 2.94 (-2.94,2.94) <-1.75,0.25>
Total: 185992 W: 49612 L: 49558 D: 86822
Ptnml(0-2): 618, 19956, 51842, 19914, 666

passed LTC:
https://tests.stockfishchess.org/tests/view/634418b14bc7650f07540760
LLR: 2.94 (-2.94,2.94) <-1.75,0.25>
Total: 126816 W: 34147 L: 34043 D: 58626
Ptnml(0-2): 74, 11941, 39281, 12031, 81

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

bench 4148700
2022-10-16 11:45:16 +02:00
mstembera 93f71ecfe1 Optimize make_index() using templates and lookup tables.
https://tests.stockfishchess.org/tests/view/634517e54bc7650f07542f99
LLR: 2.94 (-2.94,2.94) <0.00,2.00>
Total: 642672 W: 171819 L: 170658 D: 300195
Ptnml(0-2): 2278, 68077, 179416, 69336, 2229

this also introduces `-flto-partition=one` as suggested by MinetaS (Syine Mineta)
to avoid linking errors due to LTO on 32 bit mingw. This change was tested in isolation as well

https://tests.stockfishchess.org/tests/view/634aacf84bc7650f0755188b
LLR: 2.94 (-2.94,2.94) <-1.75,0.25>
Total: 119352 W: 31986 L: 31862 D: 55504
Ptnml(0-2): 439, 12624, 33400, 12800, 413

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

No functional change
2022-10-16 11:42:19 +02:00
Stefan Geschwentner e90341f9c9 Tweak history initialization
Simplify initialization of continuation history by using everywhere the same starting value.

STC:
LLR: 2.94 (-2.94,2.94) <-1.75,0.25>
Total: 90952 W: 24312 L: 24153 D: 42487
Ptnml(0-2): 356, 10168, 24290, 10285, 377
https://tests.stockfishchess.org/tests/view/633948f235f43d649ff61fd0

LTC:
LLR: 2.96 (-2.94,2.94) <-1.75,0.25>
Total: 162416 W: 43540 L: 43466 D: 75410
Ptnml(0-2): 77, 16289, 48417, 16333, 92
https://tests.stockfishchess.org/tests/view/6339ee8a35f43d649ff63986

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

Bench: 4156027
2022-10-08 18:09:02 +02:00
Giacomo Lorenzetti d5271af0ee Remove old line in "Futility pruning for captures"
The line is no longer needed after https://github.com/official-stockfish/Stockfish/commit/910cf8b21839eb9f1991934a5436eea112021723.
This patch incidentally applies "Futility Pruning for Captures" also in case of en-passant, changing the bench signature.

Passed STC:
https://tests.stockfishchess.org/tests/view/6332c1f1208c26088697b731
LLR: 2.96 (-2.94,2.94) <-1.75,0.25>
Total: 68760 W: 18440 L: 18256 D: 32064
Ptnml(0-2): 267, 7530, 18595, 7728, 260

Passed LTC:
https://tests.stockfishchess.org/tests/view/633312e9208c26088697c59b
LLR: 2.94 (-2.94,2.94) <-1.75,0.25>
Total: 455552 W: 121910 L: 122123 D: 211519
Ptnml(0-2): 253, 45439, 136600, 45236, 248

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

Bench: 4374521
2022-10-08 18:07:30 +02:00
Joost VandeVondele da937e219e Revert "Mix alpha and statScore for reduction"
This reverts commit 8bab09749d.

In this form the patch reduces mate finding effectiveness, as the large alpha value has negative influence on the reductions.

see also https://github.com/official-stockfish/Stockfish/pull/4183

Bench: 4114228
2022-10-05 22:59:05 +02:00
FauziAkram 8bab09749d Mix alpha and statScore for reduction
Idea by @xoto10, and tuning by @FauziAkram.

Passed STC:
LLR: 2.94 (-2.94,2.94) <0.00,2.00>
Total: 57832 W: 15540 L: 15199 D: 27093
Ptnml(0-2): 207, 6343, 15477, 6680, 209
https://tests.stockfishchess.org/tests/view/6338db6f35f43d649ff60fdc

passed LTC:
LLR: 2.95 (-2.94,2.94) <0.50,2.50>
Total: 50968 W: 13770 L: 13440 D: 23758
Ptnml(0-2): 25, 4905, 15306, 5211, 37
https://tests.stockfishchess.org/tests/view/6339777035f43d649ff62686

Links to the tuning sessions:
https://tests.stockfishchess.org/tests/view/63345725a004bed9a2e47b28
https://tests.stockfishchess.org/tests/view/63345728a004bed9a2e47b2a

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

Bench: 4426602
2022-10-04 01:07:27 +02:00
disservin f436bf77ad Use less reduction for escaping moves
This patch reuses the threatenedPieces variable (which is calculated in movepicker)
to reduce less in the search tree the moves which escape a capture.

passed STC:
LLR: 2.94 (-2.94,2.94) <0.00,2.00>
Total: 314352 W: 84042 L: 83328 D: 146982
Ptnml(0-2): 1105, 35084, 84207, 35552, 1228
https://tests.stockfishchess.org/tests/view/63355f37a004bed9a2e4a17f

passed LTC:
LLR: 2.95 (-2.94,2.94) <0.50,2.50>
Total: 90752 W: 24556 L: 24147 D: 42049
Ptnml(0-2): 59, 8855, 27123, 9296, 43
https://tests.stockfishchess.org/tests/view/63383a7735f43d649ff5fa8b

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

bench: 4114228
2022-10-03 11:50:31 +02:00
peregrineshahin 232bf19be4 Simplify both position calls in useClassical
Simplify the use of classical evaluation when using default settings to only be dependent on piece count and decisive PSQ

passed STC:
https://tests.stockfishchess.org/tests/view/632d32a7006ef9eb96d86ce9
LLR: 2.96 (-2.94,2.94) <-1.75,0.25>
Total: 108048 W: 28904 L: 28763 D: 50381
Ptnml(0-2): 383, 12060, 29006, 12183, 392

passed LTC:
https://tests.stockfishchess.org/tests/view/632d705a006ef9eb96d87649
LLR: 2.93 (-2.94,2.94) <-1.75,0.25>
Total: 76600 W: 20671 L: 20516 D: 35413
Ptnml(0-2): 34, 7533, 23023, 7664, 46

Inspired by sorais, credit to him.

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

bench  4173163
2022-09-27 07:54:36 +02:00
Brad Knox 4339a756ac Update README.md
Adding some svg icons and additional information, insert links as references

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

No functional change
2022-09-27 07:52:38 +02:00
Torsten Hellwig 70e51a5bc8 Always output hashfull
This removes the restriction that no hashfull information is printed within the first second of a search.
On modern systems, a non-zero value is returned within 6 ms with default settings.

passed STC:
https://tests.stockfishchess.org/tests/view/63277b08b9c0caa5f4a798e4
LLR: 2.95 (-2.94,2.94) <-1.75,0.25>
Total: 290096 W: 77505 L: 77561 D: 135030
Ptnml(0-2): 1008, 30713, 81592, 30797, 938

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

No functional change
2022-09-27 07:48:05 +02:00
mstembera 29295ecfd3 Simplify EVASIONS scoring
remove some multipliers & adjust, doesn't change the move ordering

STC https://tests.stockfishchess.org/tests/view/6325c1c9b9c0caa5f4a759ae
LLR: 2.94 (-2.94,2.94) <-1.75,0.25>
Total: 192760 W: 51528 L: 51482 D: 89750
Ptnml(0-2): 642, 20490, 54148, 20380, 720

Credit to locutus2

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

No functional change
2022-09-27 07:44:46 +02:00
mstembera dc0c441b7c Prioritize checks in movepicker
give a little bonus for moving pieces to squares where they give check

STC: https://tests.stockfishchess.org/tests/view/631da742162491686d2e40b5
LLR: 2.95 (-2.94,2.94) <0.00,2.00>
Total: 80072 W: 21753 L: 21368 D: 36951
Ptnml(0-2): 421, 8876, 21075, 9225, 439

LTC: https://tests.stockfishchess.org/tests/view/631dd9e6b85daa436625de1d
LLR: 2.95 (-2.94,2.94) <0.50,2.50>
Total: 263480 W: 70916 L: 70158 D: 122406
Ptnml(0-2): 322, 26156, 78029, 26908, 325

similar ideas have been tested by Viz and Guenther

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

bench: 4326572
2022-09-17 09:30:52 +02:00
atumanian 154e7afed0 Simplify trend and optimism.
This patch simplifies the formulas used to compute the trend and optimism values before each search iteration.
As a side effect, this removes the parameters which make the relationship between the displayed evaluation value
and the expected game result asymmetric.

I've also provided links to the results of isotonic regression analysis of the relationship between the evaluation and game result (statistical data and a graph) for both tests, which demonstrate that the new version has a more symmetric relationship:

STC: [Data and graph](https://github.com/official-stockfish/Stockfish/discussions/4150#discussioncomment-3548954)
LTC: [Data and graph](https://github.com/official-stockfish/Stockfish/discussions/4150#discussioncomment-3626311)
See also https://github.com/official-stockfish/Stockfish/issues/4142

passed STC:
https://tests.stockfishchess.org/tests/view/6313f44b8202a039920e27e6
LLR: 2.96 (-2.94,2.94) <-1.75,0.25>
Total: 108016 W: 28903 L: 28760 D: 50353
Ptnml(0-2): 461, 12075, 28850, 12104, 518

passed LTC:
https://tests.stockfishchess.org/tests/view/631de45db85daa436625dfe6
LLR: 3.01 (-2.94,2.94) <-1.75,0.25>
Total: 34792 W: 9412 L: 9209 D: 16171
Ptnml(0-2): 24, 3374, 10397, 3577, 24

Furthermore, this does not measurably impact Elo strength against weaker engines,
as demonstrated in a match of master and patch vs SF13:

This patch vs SF 13:
https://tests.stockfishchess.org/tests/view/631fa34ae1612778c344c6eb
Elo: 141.66 +-1.2 (95%) LOS: 100.0%
Total: 100000 W: 48182 L: 9528 D: 42290
Ptnml(0-2): 96, 1426, 13277, 30130, 5071
nElo: 284.13 +-3.3 (95%) PairsRatio: 23.13

Master vs SF 13:
https://tests.stockfishchess.org/tests/view/631fa3ece1612778c344c6ff
Elo: 143.26 +-1.2 (95%) LOS: 100.0%
Total: 100000 W: 48525 L: 9479 D: 41996
Ptnml(0-2): 94, 1537, 13098, 29771, 5500
nElo: 281.70 +-3.3 (95%) PairsRatio: 21.63

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

Bench: 4425574
2022-09-17 09:13:07 +02:00
Joost VandeVondele 5a871e174f Explicitly annotate a few variables
as [[maybe_unused]], avoiding the (void)foo trick.

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

No functional change
2022-09-17 09:05:35 +02:00
mstembera 82bb21dc7a Optimize AVX2 path in NNUE evaluation
always selecting AffineTransform specialization for small inputs.

A related patch was tested as

Initially tested as a simplification
STC https://tests.stockfishchess.org/tests/view/6317c3f437f41b13973d6dff
LLR: 2.95 (-2.94,2.94) <-1.75,0.25>
Total: 58072 W: 15619 L: 15425 D: 27028
Ptnml(0-2): 241, 6191, 15992, 6357, 255

Elo gain speedup test
STC https://tests.stockfishchess.org/tests/view/63181c1b37f41b13973d79dc
LLR: 2.94 (-2.94,2.94) <0.00,2.00>
Total: 184496 W: 49922 L: 49401 D: 85173
Ptnml(0-2): 851, 19397, 51208, 19964, 828

and this patch gained in testing

speedup        = +0.0071
P(speedup > 0) =  1.0000
on CPU: 16 x AMD Ryzen 9 3950X

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

No functional change
2022-09-11 14:19:57 +02:00
Michael Chaly 1591e5ac3b Do less singular extensions for former PVnode
Patch is a reintroduction of logic what was simplified a while ago
in a slightly different form. Do bigger extension offset in
case of non-pv node having a pv.

passed STC
https://tests.stockfishchess.org/tests/view/631977c048f27688a06e66d5
LLR: 2.94 (-2.94,2.94) <0.00,2.00>
Total: 23296 W: 6404 L: 6108 D: 10784
Ptnml(0-2): 88, 2539, 6118, 2795, 108

passed LTC
https://tests.stockfishchess.org/tests/view/631989cb48f27688a06e696c
LLR: 2.94 (-2.94,2.94) <0.50,2.50>
Total: 235592 W: 63890 L: 63188 D: 108514
Ptnml(0-2): 275, 23392, 69804, 24006, 319

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

Bench: 3993611
2022-09-11 14:15:54 +02:00
Dubslow 9fa258ee1d Razor also on PV nodes
Simplification introduced by xoto10

blue LTC vs new master:
https://tests.stockfishchess.org/tests/view/631ad4ef9cfa5e9b648d1b4e
LLR: 2.93 (-2.94,2.94) <-1.75,0.25>
Total: 59184 W: 16002 L: 15828 D: 27354
Ptnml(0-2): 65, 5777, 17747, 5925, 78

blue STC vs old master:
https://tests.stockfishchess.org/tests/view/6306b87b902a848543334c25
LLR: 2.94 (-2.94,2.94) <-1.75,0.25>
Total: 213944 W: 57184 L: 57159 D: 99601
Ptnml(0-2): 877, 23448, 58331, 23405, 911

blue LTC vs old master:
https://tests.stockfishchess.org/tests/view/63070e6b902a8485433357e7
LLR: 2.94 (-2.94,2.94) <-1.75,0.25>
Total: 192080 W: 52050 L: 52006 D: 88024
Ptnml(0-2): 232, 18981, 57611, 18943, 273

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

bench 4208975
2022-09-11 14:13:24 +02:00
Michael Chaly eaf2c8207f Further LTC tuning of search parameters
Tuning done by bigpenor with some hand adjustments on top by Viz.

Had a good performance at fixed games 180+1.8:
https://tests.stockfishchess.org/tests/view/631836b437f41b13973d7da1
Elo: 1.35 +-1.2 (95%) LOS: 98.6%
Total: 60000 W: 16422 L: 16189 D: 27389
Ptnml(0-2): 39, 5335, 18992, 5622, 12
nElo: 3.13 +-2.8 (95%) PairsRatio: 1.05

Passed 60+0.6 8 threads SPRT:
https://tests.stockfishchess.org/tests/view/631ba0ff74bc4fe483a99db3
LLR: 2.95 (-2.94,2.94) <0.50,2.50>
Total: 29712 W: 8301 L: 8039 D: 13372
Ptnml(0-2): 12, 2318, 9925, 2598, 3

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

bench 3938073
2022-09-11 14:05:39 +02:00
FauziAkram 5eeb96d0e7 VLTC tuning
Tuning some parameters that scale well with longer time control:

Failed STC:
https://tests.stockfishchess.org/tests/view/6313424d8202a039920e130a
LLR: -2.94 (-2.94,2.94) <-1.75,0.25>
Total: 42680 W: 11231 L: 11540 D: 19909
Ptnml(0-2): 191, 5008, 11232, 4737, 172

Passed LTC:
https://tests.stockfishchess.org/tests/view/6311e2cd874169ca52ae7933
LLR: 2.94 (-2.94,2.94) <0.50,2.50>
Total: 53448 W: 14782 L: 14437 D: 24229
Ptnml(0-2): 101, 5214, 15740, 5577, 92

Passed VLTC:
https://tests.stockfishchess.org/tests/view/6312530cfa99a92e3002c927
LLR: 2.95 (-2.94,2.94) <0.50,2.50>
Total: 123336 W: 33465 L: 33007 D: 56864
Ptnml(0-2): 38, 11466, 38204, 11920, 40

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

Bench: 5609606
2022-09-07 07:38:04 +02:00
Joost VandeVondele a4d18d23a9 Provide network download fallback
in case the base infrastructure for providing the networks

https://tests.stockfishchess.org/nns

is down, use an alternate github repo for downloading networks during the build.

fixes #4149
fixes #4140

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

No functional change
2022-09-07 07:32:53 +02:00
Joost VandeVondele dddf8fc2b4 Increase the maximum number of threads to 1024
relatively soon servers with 512 threads will be available 'quite commonly',
anticipate even more threads, and increase our current maximum from 512 to 1024.

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

No functional change.
2022-09-07 07:31:48 +02:00
dav1312 97860cb575 Disable ARM CI tests
Temporarily disable ARM CI tests until a mitigation is implemented

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

No functional change.
2022-08-29 19:15:14 +02:00
mstembera 02ef1f4496 Make key_after() more consistent with key()
STC: https://tests.stockfishchess.org/tests/view/62f8547123d42b50a8dac674
LLR: 2.95 (-2.94,2.94) <0.00,2.00>
Total: 176640 W: 47699 L: 47189 D: 81752
Ptnml(0-2): 776, 18599, 49129, 18971, 845

A bug fix plus non functional speed optimization. Position::key_after(Move m) is now
consistent with Position::key() thus prefetching correct TT entries which speeds things up.
Related PR #3759

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

No functional change
2022-08-17 19:56:15 +02:00
Joost VandeVondele 15ac117ac4 Simplify the use of classical eval
no benefit of the fallback term (exercised rarely).
Cleanup the associated code.

passed STC
https://tests.stockfishchess.org/tests/view/62f62c2b6f0a08af9f776367
LLR: 2.96 (-2.94,2.94) <-1.75,0.25>
Total: 67832 W: 18334 L: 18148 D: 31350
Ptnml(0-2): 369, 7171, 18609, 7439, 328

passed LTC
https://tests.stockfishchess.org/tests/view/62f68beb6f0a08af9f77710e
LLR: 2.94 (-2.94,2.94) <-1.75,0.25>
Total: 104664 W: 28363 L: 28233 D: 48068
Ptnml(0-2): 169, 10162, 31511, 10350, 140

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

Bench: 6079565
2022-08-15 18:01:37 +02:00
Michael Chaly 5f290352cd Simplify away smp adjustment in TT use
Passed STC
https://tests.stockfishchess.org/tests/view/62f7d81f23d42b50a8dab568
LLR: 2.94 (-2.94,2.94) <-1.75,0.25>
Total: 98160 W: 26307 L: 26165 D: 45688
Ptnml(0-2): 201, 10282, 27960, 10448, 189

Passed LTC
https://tests.stockfishchess.org/tests/view/62f8d1a623d42b50a8dad4fb
LLR: 2.94 (-2.94,2.94) <-1.75,0.25>
Total: 81544 W: 22346 L: 22200 D: 36998
Ptnml(0-2): 44, 7542, 25446, 7704, 36

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

No functional change (single threaded).
2022-08-15 17:54:56 +02:00
mckx00 3370f69881 Make LMR code easier to follow
Remove flags doFullDepthSearch and didLMR, and reorder instruction.

Small measured speedup.

Closes https://github.com/official-stockfish/Stockfish/pull/4129

No functional change.
2022-08-15 17:51:51 +02:00
mstembera 4568f6369b Report longest PV lines for multithreaded search
In case several threads find the same bestmove,
report the longest PV line found.

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

No functional change.
2022-08-15 17:46:27 +02:00
Joost VandeVondele 1054a483ca Remove an unneeded randomization of evals.
most of the effect comes from the randomization of 3-folds.

passed STC:
https://tests.stockfishchess.org/tests/view/62e697e97e84186e5d19af6f
LLR: 2.94 (-2.94,2.94) <-1.75,0.25>
Total: 572976 W: 153168 L: 153539 D: 266269
Ptnml(0-2): 2505, 64783, 152364, 64250, 2586

passed LTC:
https://tests.stockfishchess.org/tests/view/62ee5977523c86dcd6957154
LLR: 2.94 (-2.94,2.94) <-1.75,0.25>
Total: 704808 W: 191212 L: 191680 D: 321916
Ptnml(0-2): 1340, 70579, 208972, 70235, 1278

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

Bench: 5868987
2022-08-12 14:30:33 +02:00
Stefan Geschwentner 0a01dd044f Cleanup code
This PR includes following cleanups:
- Remove the unused depth variable in the thread class.
- cleanup ValueList (added from mstembera)

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

No functional change.
2022-08-12 14:29:40 +02:00
Joost VandeVondele e639c45577 Update WDL model for current SF
This updates the WDL model based on the LTC statistics for the two weeks (3M games).

for old results see:

https://github.com/official-stockfish/Stockfish/pull/3981
https://github.com/official-stockfish/Stockfish/pull/3582
https://github.com/official-stockfish/Stockfish/pull/2778

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

No functional change.
2022-08-06 13:57:30 +02:00
Joost VandeVondele 7cc929f437 Update CPU contributors list
Thanks for your contributions!

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

No functional change
2022-08-06 13:53:55 +02:00
lonfom169 b8f4903fbb Reintroduce singularQuietLMR
STC:
LLR: 2.96 (-2.94,2.94) <0.00,2.00>
Total: 88912 W: 23972 L: 23580 D: 41360
Ptnml(0-2): 365, 9820, 23712, 10176, 383
https://tests.stockfishchess.org/tests/view/62e9537a400addce2c13399b

LTC:
LLR: 2.97 (-2.94,2.94) <0.50,2.50>
Total: 85672 W: 23607 L: 23192 D: 38873
Ptnml(0-2): 219, 8316, 25365, 8703, 233
https://tests.stockfishchess.org/tests/view/62e9a174400addce2c1346e4

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

Bench: 5921315
2022-08-06 13:52:36 +02:00
Stefan Geschwentner 675f6a038b Tweak history updates
In general the history update bonus is slightly decreased by 11% which gives a slower saturation speed.
In addition only for main history the divisor is halfed (used history values are doubled to maintain same maximum)
which have an effect in the opposite direction on saturation speed.

STC:
LLR: 2.95 (-2.94,2.94) <0.00,2.50>
Total: 157088 W: 42673 L: 42168 D: 72247
Ptnml(0-2): 857, 17346, 41642, 17833, 866
https://tests.stockfishchess.org/tests/view/62e5517ab383a712b13867c5

LTC:
LLR: 2.94 (-2.94,2.94) <0.50,3.00>
Total: 325592 W: 88705 L: 87753 D: 149134
Ptnml(0-2): 594, 32288, 96076, 33248, 590
https://tests.stockfishchess.org/tests/view/62e5e4f4b383a712b1387d53

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

Bench: 5518728
2022-08-06 13:50:01 +02:00
Michael Chaly 582c88ee94 Do more TT cutoffs in case of exact bound
The idea is that these TT entries are considered move valuable in TT replacement scheme - they are always overwriting other entries. So it makes sence for them to produce more aggressive cutoffs.

passed STC
https://tests.stockfishchess.org/tests/view/62e4d407b383a712b1385410
LLR: 2.95 (-2.94,2.94) <0.00,2.50>
Total: 96632 W: 26045 L: 25659 D: 44928
Ptnml(0-2): 434, 10635, 25770, 11065, 412

passed LTC
https://tests.stockfishchess.org/tests/view/62e523e2b383a712b1386193
LLR: 2.94 (-2.94,2.94) <0.50,3.00>
Total: 77960 W: 21363 L: 20989 D: 35608
Ptnml(0-2): 190, 7591, 23009, 8035, 155

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

bench 5820568
2022-07-31 11:03:28 +02:00
Dubslow 18389e269d remove useClassical depth condition
passed STC:
https://tests.stockfishchess.org/tests/view/62e0c3e98e4fa6ae472695ed
LLR: 2.96 (-2.94,2.94) <-2.25,0.25>
Total: 293568 W: 78934 L: 79151 D: 135483
Ptnml(0-2): 1344, 31488, 81366, 31213, 1373

passed LTC:
https://tests.stockfishchess.org/tests/view/62e190aa8e4fa6ae4726b5b5
LLR: 2.98 (-2.94,2.94) <-2.25,0.25>
Total: 187392 W: 50971 L: 51028 D: 85393
Ptnml(0-2): 384, 17801, 57369, 17772, 370

other attempts to otherwise tune this parameter failed, bounds 6,7,10,11 failed STC, 8 passed STC but failed LTC

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

bench 5796377
2022-07-31 11:00:31 +02:00
Dubslow c4a644922d Simplify reduction condition for cutNodes
LMR: for cutNodes, dont exclude killer moves. This was a prelude to reducing
allNodes, altho that's failed so far.

STC https://tests.stockfishchess.org/tests/view/62d64ad147ae1768b34a27c3
LLR: 2.95 (-2.94,2.94) <-2.25,0.25>
Total: 37064 W: 10044 L: 9889 D: 17131
Ptnml(0-2): 162, 4115, 9828, 4260, 167

LTC https://tests.stockfishchess.org/tests/view/62d66cc047ae1768b34a2b14
LLR: 2.94 (-2.94,2.94) <-2.25,0.25>
Total: 39832 W: 10796 L: 10659 D: 18377
Ptnml(0-2): 69, 3969, 11706, 4100, 72

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

bench: 5697891
2022-07-24 09:18:38 +02:00
Joost VandeVondele 4b4b7d1209 Update default net to nn-ad9b42354671.nnue
using trainer branch https://github.com/glinscott/nnue-pytorch/pull/208 with a slightly
tweaked loss function (power 2.5 instead of 2.6), otherwise same training as in
the previous net update https://github.com/official-stockfish/Stockfish/pull/4100

passed STC:
LLR: 2.97 (-2.94,2.94) <0.00,2.50>
Total: 367536 W: 99465 L: 98573 D: 169498
Ptnml(0-2): 1820, 40994, 97117, 42148, 1689
https://tests.stockfishchess.org/tests/view/62cc43fe50dcbecf5fc1c5b8

passed LTC:
LLR: 2.94 (-2.94,2.94) <0.50,3.00>
Total: 25032 W: 6802 L: 6553 D: 11677
Ptnml(0-2): 40, 2424, 7341, 2669, 42
https://tests.stockfishchess.org/tests/view/62ce5f421dacb46e4d5fd277

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

Bench: 5905619
2022-07-13 18:01:20 +02:00
Michael Chaly 95d24b77df Simplify away some unneeded code in time management
The lower bound of the clamp is never used since complexity can't be negative and thus is unneeded.

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

No functional change
2022-07-13 18:00:39 +02:00
Joost VandeVondele 2e02dd7936 Limit the researching at same depth.
If the elapsed time is close to the available time, the time management thread can signal that the next iterations should be searched at the same depth (Threads.increaseDepth = false). While the rootDepth increases, the adjustedDepth is kept constant with the searchAgainCounter.

In exceptional cases, when threading is used and the master thread, which controls the time management, signals to not increaseDepth, but by itself takes a long time to finish the iteration, the helper threads can search repeatedly at the same depth. This search finishes more and more quickly, leading to helper threads that report a rootDepth of MAX_DEPTH (245). The latter is not optimal as it is confusing for the user, stops search on these threads, and leads to an incorrect bias in the thread voting scheme. Probably with only a small impact on strength.

This behavior was observed almost two years ago,
see https://github.com/official-stockfish/Stockfish/issues/2717

This patch fixes #2717 by ensuring the effective depth increases at once every four iterations,
even in increaseDepth is false.

Depth 245 searches (for non-trivial positions) were indeed absent with this patch,
but frequent with master in the tests below:
https://discord.com/channels/435943710472011776/813919248455827515/994872720800088095
Total pgns: 2173
Base: 2867
Patch: 0

it passed non-regression testing in various setups:

SMP STC:
https://tests.stockfishchess.org/tests/view/62bfecc96178ffe6394ba036
LLR: 2.94 (-2.94,2.94) <-2.25,0.25>
Total: 37288 W: 10171 L: 10029 D: 17088
Ptnml(0-2): 75, 3777, 10793, 3929, 70

SMP LTC:
https://tests.stockfishchess.org/tests/view/62c08f6f49b62510394be066
LLR: 2.94 (-2.94,2.94) <-2.25,0.25>
Total: 190568 W: 52125 L: 52186 D: 86257
Ptnml(0-2): 70, 17854, 59504, 17779, 77

LTC:
https://tests.stockfishchess.org/tests/view/62c08b6049b62510394bdfb6
LLR: 2.96 (-2.94,2.94) <-2.25,0.25>
Total: 48120 W: 13204 L: 13083 D: 21833
Ptnml(0-2): 54, 4458, 14919, 4571, 58

Special thanks to miguel-I,  Disservin, ruicoelhopedro and others for analysing the problem,
the data, and coming up with the key insight, needed to fix this longstanding issue.

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

Bench: 5182295
2022-07-09 10:58:04 +02:00
Dubslow aa18b68033 Time mgmt fix division.
oversight changed the corresponding float division to integer division in a previous tune https://github.com/official-stockfish/Stockfish/commit/442c40b43de8ede1e424efa674c8d45322e3b43c it is stronger to keep the original float division.

green LTC: https://tests.stockfishchess.org/tests/view/62bf34bc0340fb1e0cc934e7
LLR: 2.94 (-2.94,2.94) <0.50,3.00>
Total: 38952 W: 10738 L: 10467 D: 17747
Ptnml(0-2): 46, 3576, 11968, 3833, 53

yellow STC: https://tests.stockfishchess.org/tests/view/62bff6506178ffe6394ba1d1
LLR: -2.95 (-2.94,2.94) <0.00,2.50>
Total: 226960 W: 61265 L: 61062 D: 104633
Ptnml(0-2): 938, 24398, 62582, 24647, 915

further slightly tweaked tests confirm this Elo gain.

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

No functional change
2022-07-09 10:53:17 +02:00
Michael Chaly c2aaaa65f9 Simplify away FRC correction term
Since new net is trained partially using FRC data this part of adjustment that penalises bishops that are locked in the corner is no longer needed - net should "know" this things itself much better.

STC on FRC book :
https://tests.stockfishchess.org/tests/view/62c3031b9e7d9997a12d852f
LLR: 2.96 (-2.94,2.94) <-2.25,0.25>
Total: 22048 W: 3003 L: 2845 D: 16200
Ptnml(0-2): 96, 1778, 7149, 1874, 127

LTC on FRC book :
https://tests.stockfishchess.org/tests/view/62c32e939e7d9997a12d8c5e
LLR: 2.94 (-2.94,2.94) <-2.25,0.25>
Total: 36784 W: 3138 L: 3037 D: 30609
Ptnml(0-2): 36, 1842, 14537, 1939, 38

STC on DFRC book :
https://tests.stockfishchess.org/tests/view/62c32efb9e7d9997a12d8c6f
LLR: 2.94 (-2.94,2.94) <-2.25,0.25>
Total: 20424 W: 3903 L: 3721 D: 12800
Ptnml(0-2): 172, 1984, 5724, 2154, 178

LTC on DFRC book :
https://tests.stockfishchess.org/tests/view/62c358c79e7d9997a12d9319
LLR: 2.93 (-2.94,2.94) <-2.25,0.25>
Total: 53784 W: 7581 L: 7480 D: 38723
Ptnml(0-2): 87, 3887, 18856, 3962, 100

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

bench 5182295
2022-07-05 13:55:50 +02:00
Joost VandeVondele 85f8ee6199 Update default net to nn-3c0054ea9860.nnu
First things first...

this PR is being made from court. Today, Tord and Stéphane, with broad support
of the developer community are defending their complaint, filed in Munich, against ChessBase.
With their products Houdini 6 and Fat Fritz 2, both Stockfish derivatives,
ChessBase violated repeatedly the Stockfish GPLv3 license. Tord and Stéphane have terminated
their license with ChessBase permanently. Today we have the opportunity to present
our evidence to the judge and enforce that termination. To read up, have a look at our blog post
https://stockfishchess.org/blog/2022/public-court-hearing-soon/ and
https://stockfishchess.org/blog/2021/our-lawsuit-against-chessbase/

This PR introduces a net trained with an enhanced data set and a modified loss function in the trainer.
A slight adjustment for the scaling was needed to get a pass on standard chess.

passed STC:
https://tests.stockfishchess.org/tests/view/62c0527a49b62510394bd610
LLR: 2.94 (-2.94,2.94) <0.00,2.50>
Total: 135008 W: 36614 L: 36152 D: 62242
Ptnml(0-2): 640, 15184, 35407, 15620, 653

passed LTC:
https://tests.stockfishchess.org/tests/view/62c17e459e7d9997a12d458e
LLR: 2.94 (-2.94,2.94) <0.50,3.00>
Total: 28864 W: 8007 L: 7749 D: 13108
Ptnml(0-2): 47, 2810, 8466, 3056, 53

Local testing at a fixed 25k nodes resulted in
Test run1026/easy_train_data/experiments/experiment_2/training/run_0/nn-epoch799.nnue
localElo: 4.2  +-      1.6

The real strength of the net is in FRC and DFRC chess where it gains significantly.

Tested at STC with slightly different scaling:
FRC:
https://tests.stockfishchess.org/tests/view/62c13a4002ba5d0a774d20d4
Elo: 29.78 +-3.4 (95%) LOS: 100.0%
Total: 10000 W: 2007 L: 1152 D: 6841
Ptnml(0-2): 31, 686, 2804, 1355, 124
nElo: 59.24 +-6.9 (95%) PairsRatio: 2.06

DFRC:
https://tests.stockfishchess.org/tests/view/62c13a5702ba5d0a774d20d9
Elo: 55.25 +-3.9 (95%) LOS: 100.0%
Total: 10000 W: 2984 L: 1407 D: 5609
Ptnml(0-2): 51, 636, 2266, 1779, 268
nElo: 96.95 +-7.2 (95%) PairsRatio: 2.98

Tested at LTC with identical scaling:
FRC:
https://tests.stockfishchess.org/tests/view/62c26a3c9e7d9997a12d6caf
Elo: 16.20 +-2.5 (95%) LOS: 100.0%
Total: 10000 W: 1192 L: 726 D: 8082
Ptnml(0-2): 10, 403, 3727, 831, 29
nElo: 44.12 +-6.7 (95%) PairsRatio: 2.08

DFRC:
https://tests.stockfishchess.org/tests/view/62c26a539e7d9997a12d6cb2
Elo: 40.94 +-3.0 (95%) LOS: 100.0%
Total: 10000 W: 2215 L: 1042 D: 6743
Ptnml(0-2): 10, 410, 3053, 1451, 76
nElo: 92.77 +-6.9 (95%) PairsRatio: 3.64

This is due to the mixing in a significant fraction of DFRC training data in the final training round. The net is
trained using the easy_train.py script in the following way:

```
python easy_train.py \
     --training-dataset=../Leela-dfrc_n5000.binpack \
     --experiment-name=2 \
     --nnue-pytorch-branch=vondele/nnue-pytorch/lossScan4 \
     --additional-training-arg=--param-index=2 \
     --start-lambda=1.0 \
     --end-lambda=0.75 \
     --gamma=0.995 \
     --lr=4.375e-4 \
     --start-from-engine-test-net True \
     --tui=False \
     --seed=$RANDOM \
     --max_epoch=800 \
     --auto-exit-timeout-on-training-finished=900 \
     --network-testing-threads 8  \
     --num-workers 12
```

where the data set used (Leela-dfrc_n5000.binpack) is a combination of our previous best data set (mix of Leela and some SF data) and DFRC data, interleaved to form:
The data is available in https://drive.google.com/drive/folders/1S9-ZiQa_3ApmjBtl2e8SyHxj4zG4V8gG?usp=sharing
Leela mix: https://drive.google.com/file/d/1JUkMhHSfgIYCjfDNKZUMYZt6L5I7Ra6G/view?usp=sharing
DFRC: https://drive.google.com/file/d/17vDaff9LAsVo_1OfsgWAIYqJtqR8aHlm/view?usp=sharing

The training branch used is
https://github.com/vondele/nnue-pytorch/commits/lossScan4
A PR to the main trainer repo will be made later. This contains a revised loss function, now computing the loss from the score based on the win rate model, which is a more accurate representation than what we had before. Scaling constants are tweaked there as well.

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

Bench: 5186781
2022-07-04 15:42:34 +02:00
Dubslow 442c40b43d Use NNUE complexity in search, retune related parameters
This builds on ideas of xoto10 and mstembera to use more output from NNUE in the search algorithm.

passed STC:
https://tests.stockfishchess.org/tests/view/62ae454fe7ee5525ef88a957
LLR: 2.95 (-2.94,2.94) <0.00,2.50>
Total: 89208 W: 24127 L: 23753 D: 41328
Ptnml(0-2): 400, 9886, 23642, 10292, 384

passed LTC:
https://tests.stockfishchess.org/tests/view/62acc6ddd89eb6cf1e0750a1
LLR: 2.93 (-2.94,2.94) <0.50,3.00>
Total: 56352 W: 15430 L: 15115 D: 25807
Ptnml(0-2): 44, 5501, 16782, 5794, 55

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

bench 5332964
2022-06-20 08:30:57 +02:00
Dubslow 5304b561ab LMR: remove deeper
...apparently it wasn't doing much anymore. inspired by rufish's recent attempts to improve this.

passed STC:
https://tests.stockfishchess.org/tests/view/62abca2cd89eb6cf1e072c04
LLR: 2.95 (-2.94,2.94) <-2.25,0.25>
Total: 85576 W: 22766 L: 22683 D: 40127
Ptnml(0-2): 362, 9607, 22741, 9742, 336

passed LTC:
https://tests.stockfishchess.org/tests/view/62ac90ffd89eb6cf1e07488f
LLR: 2.93 (-2.94,2.94) <-2.25,0.25>
Total: 48248 W: 13018 L: 12896 D: 22334
Ptnml(0-2): 32, 4773, 14400, 4879, 40

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

bench 5578988
2022-06-20 08:25:50 +02:00
bmc4 4d6a11a04c Don't change ttPv at probCut
STC:
LLR: 2.96 (-2.94,2.94) <-2.25,0.25>
Total: 35672 W: 9618 L: 9462 D: 16592
Ptnml(0-2): 151, 3890, 9601, 4040, 154
https://tests.stockfishchess.org/tests/view/62ab03f750949cfc241b1965

LTC:
LLR: 2.93 (-2.94,2.94) <-2.25,0.25>
Total: 54160 W: 14626 L: 14511 D: 25023
Ptnml(0-2): 42, 5414, 16056, 5523, 45
https://tests.stockfishchess.org/tests/view/62ab5e6fd89eb6cf1e071b87

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

bench: 5798229
2022-06-20 08:24:07 +02:00
bmc4 6edc29d720 Simplify away condition in ttSave in probCut
Remove condition for tte->save in probCut so it always saves on probCut cutoff.

STC:
LLR: 2.95 (-2.94,2.94) <-2.25,0.25>
Total: 47848 W: 12921 L: 12782 D: 22145
Ptnml(0-2): 207, 5340, 12715, 5431, 231
https://tests.stockfishchess.org/tests/view/62a1f7c87bd8e641e44436f7

LTC:
LLR: 2.97 (-2.94,2.94) <-2.25,0.25>
Total: 132736 W: 35895 L: 35881 D: 60960
Ptnml(0-2): 109, 13384, 39360, 13414, 101
https://tests.stockfishchess.org/tests/view/62a2421a7bd8e641e444434f

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

bench: 5845802
2022-06-16 07:12:01 +02:00
mstembera 2d5dcf3d18 Minor simplifications and cleanup in search
STC: https://tests.stockfishchess.org/tests/view/629d6775593a4a9b6482c1ec
LLR: 2.93 (-2.94,2.94) <-2.25,0.25>
Total: 77416 W: 20683 L: 20589 D: 36144
Ptnml(0-2): 317, 8690, 20620, 8744, 337

LTC: https://tests.stockfishchess.org/tests/view/629db4be593a4a9b6482ceef
LLR: 2.95 (-2.94,2.94) <-2.25,0.25>
Total: 106544 W: 28752 L: 28705 D: 49087
Ptnml(0-2): 97, 10692, 31641, 10751, 91

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

Bench: 5913510
2022-06-16 07:06:43 +02:00
ppigazzini d54b85b4bd Restore NDKv21 for GitHub Actions
GitHub updated the versions of NDK installed on the Actions runners
breaking the ARM tests.
Restore the NDKv21 using the GitHub suggested mitigation, see:
https://github.com/actions/virtual-environments/issues/5595

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

No functional change
2022-06-16 07:03:52 +02:00
candirufish 00297cfef0 Use qsearch on step 11 if depth is equal to or below 0
larger reduction of depth if no TT entry is found, and go in qsearch as needed.

stc:
https://tests.stockfishchess.org/tests/view/629dfacd593a4a9b6482db72
LLR: 2.93 (-2.94,2.94) <0.00,2.50>
Total: 31920 W: 8591 L: 8322 D: 15007
Ptnml(0-2): 127, 3551, 8376, 3738, 168

ltc:
https://tests.stockfishchess.org/tests/view/629e304e593a4a9b6482e451
LLR: 2.95 (-2.94,2.94) <0.50,3.00>
Total: 17488 W: 4842 L: 4614 D: 8032
Ptnml(0-2): 13, 1670, 5151, 1896, 14

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

Bench: 5870283
2022-06-07 08:34:14 +02:00
Boštjan Mejak 809849fa27 Wording of help output and comments.
Improved the output text that is diplayed when executing the 'help' command.
Also, some comments were fixed along the way.

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

No functional change
2022-06-07 08:30:07 +02:00
Dubslow 90cf8e7d2b Remove LMR condition for complex pos
Inspired by Kia's similar test: https://tests.stockfishchess.org/tests/view/6292898c1e7cd5f29966fbe0

Passed STC:
https://tests.stockfishchess.org/tests/view/62941588b0d5a7d1b780ed4b
LLR: 2.94 (-2.94,2.94) <-2.25,0.25>
Total: 266872 W: 70850 L: 71033 D: 124989
Ptnml(0-2): 1180, 30114, 70941, 30111, 1090

Passed LTC:
https://tests.stockfishchess.org/tests/view/62964a754628d33daa24f062
LLR: 2.95 (-2.94,2.94) <-2.25,0.25>
Total: 70160 W: 18756 L: 18662 D: 32742
Ptnml(0-2): 42, 6976, 20950, 7070, 42

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

Bench 6237567
2022-06-02 07:49:31 +02:00
xoto10 7f1333ccf8 Blend nnue complexity with classical.
Following mstembera's test of the complexity value derived from nnue values,
this change blends that idea with the old complexity calculation.

STC 10+0.1:
LLR: 2.95 (-2.94,2.94) <0.00,2.50>
Total: 42320 W: 11436 L: 11148 D: 19736
Ptnml(0-2): 209, 4585, 11263, 4915, 188
https://tests.stockfishchess.org/tests/live_elo/6295c9239c8c2fcb2bad7fd9

LTC 60+0.6:
LLR: 2.98 (-2.94,2.94) <0.50,3.00>
Total: 34600 W: 9393 L: 9125 D: 16082
Ptnml(0-2): 32, 3323, 10319, 3597, 29
https://tests.stockfishchess.org/tests/view/6295fd5d9c8c2fcb2bad88cf

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

Bench 6078140
2022-06-02 07:47:23 +02:00
candirufish 653bd0817c cutnode and movecount lmr extension simplification
Passed STC
https://tests.stockfishchess.org/tests/view/6294133cb0d5a7d1b780ece3
LLR: 2.94 (-2.94,2.94) <-2.25,0.25>
Total: 41072 W: 11052 L: 10908 D: 19112
Ptnml(0-2): 153, 4324, 11461, 4422, 176

Passed LTC
ltc: https://tests.stockfishchess.org/tests/view/62947ae6b0d5a7d1b780fe86
LLR: 2.94 (-2.94,2.94) <-2.25,0.25>
Total: 102736 W: 27509 L: 27459 D: 47768
Ptnml(0-2): 98, 9734, 31669, 9754, 113

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

Bench: 6410652
2022-06-02 07:44:22 +02:00
Michael Chaly 8fadbcf1b2 Add info about elo gained from some heuristics
Add info about qsearch and impact of main and continuation histories.

Based on these tests:
https://tests.stockfishchess.org/tests/view/62946ffcb0d5a7d1b780fc7e
https://tests.stockfishchess.org/tests/view/628facb71e7cd5f299669534
https://tests.stockfishchess.org/tests/view/628eade11e7cd5f299666f2e

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

No functional change.
2022-06-02 07:43:14 +02:00
xoto10 4c7de9e8ab Adjust scale param higher
xoto10's scaleopt tune resulted in a yellow LTC, but the main parameter shift looked almost exactly like the tune rate reduction schedule,
so further increases of that param were tried. Joint work xoto10 and dubslow.

passed LTC:
https://tests.stockfishchess.org/tests/view/628c709372775f382300f03e
LLR: 2.93 (-2.94,2.94) <0.50,3.00>
Total: 70112 W: 18932 L: 18584 D: 32596
Ptnml(0-2): 66, 6904, 20757, 7274, 55

failed STC:
https://tests.stockfishchess.org/tests/view/6290e4441e7cd5f29966bdc8
LLR: -2.96 (-2.94,2.94) <0.00,2.50>
Total: 59976 W: 15919 L: 16018 D: 28039
Ptnml(0-2): 250, 6791, 15974, 6754, 219

similar LTC's were yellow
first yellow LTC: https://tests.stockfishchess.org/tests/view/6288a33f817227d3e5c5b05d
double exaggerate yellow: https://tests.stockfishchess.org/tests/live_elo/628e140372775f38230129a6
triple exaggerate yellow: https://tests.stockfishchess.org/tests/live_elo/628e2caf72775f3823012d45

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

bench 6410652
2022-05-29 19:14:20 +02:00
proukornew 6ede1bed89 Improve handling of variables set in the make environment
removes duplication on the commandline for example in a profile-build

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

No functional change
2022-05-29 19:04:25 +02:00
Giacomo Lorenzetti 1a168201bd Small speedup in futility_move_count
The speedup is around 0.25% using gcc 11.3.1 (bmi2, nnue bench, depth 16
and 23) while it is neutral using clang (same conditions).

According to `perf` that integer division was one of the most time-consuming
instructions in search (gcc disassembly).

Passed STC:
https://tests.stockfishchess.org/tests/view/628a17fe24a074e5cd59b3aa
LLR: 2.94 (-2.94,2.94) <0.00,2.50>
Total: 22232 W: 5992 L: 5751 D: 10489
Ptnml(0-2): 88, 2235, 6218, 2498, 77

yellow LTC:
https://tests.stockfishchess.org/tests/view/628a35d7ccae0450e35106f7
LLR: -2.95 (-2.94,2.94) <0.50,3.00>
Total: 320168 W: 85853 L: 85326 D: 148989
Ptnml(0-2): 185, 29698, 99821, 30165, 215

This patch also suggests that UHO STC is sensible to small speedups (< 0.50%).

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

No functional change
2022-05-29 18:54:19 +02:00
Joost VandeVondele 48df0754bc Add command line flags to link to information
This patch provides command line flags `--help` and `--license` as well as the corresponding `help` and `license` commands.

```
$ ./stockfish --help
Stockfish 200522 by the Stockfish developers (see AUTHORS file)

Stockfish is a powerful chess engine and free software licensed under the GNU GPLv3.
Stockfish is normally used with a separate graphical user interface (GUI).
Stockfish implements the universal chess interface (UCI) to exchange information.
For further information see https://github.com/official-stockfish/Stockfish#readme
or the corresponding README.md and Copying.txt files distributed with this program.

```

The idea is to provide a minimal help that links to the README.md file,
not replicating information that is already available elsewhere.

We use this opportunity to explicitly report the license as well.

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

No functional change.
2022-05-29 18:46:35 +02:00
Giacomo Lorenzetti f7d1491b3d Assorted small cleanups
closes https://github.com/official-stockfish/Stockfish/pull/3973

No functional change
2022-05-29 18:42:48 +02:00
candirufish cc7bcd5303 Simplify a condition
Principal variation depth late move reduction extension simplification.

stc:
https://tests.stockfishchess.org/tests/view/6285a1d19d18a78568e7fa24
LLR: 2.94 (-2.94,2.94) <-2.25,0.25>
Total: 428536 W: 113433 L: 113851 D: 201252
Ptnml(0-2): 1671, 48606, 114090, 48272, 1629

ltc:
https://tests.stockfishchess.org/tests/view/62871d20375cdc5de8cf5db3
LLR: 2.95 (-2.94,2.94) <-2.25,0.25>
Total: 56792 W: 15123 L: 15011 D: 26658
Ptnml(0-2): 42, 5681, 16825, 5819, 29

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

bench: 6501437
2022-05-21 12:42:33 +02:00
xoto10 22b7909809 Tune scale and optimism.
Tune scale and optimism in effort to make stockfish play more aggressively.

STC @ 10+0.1 th 1:
LLR: 2.94 (-2.94,2.94) <0.00,2.50>
Total: 27896 W: 7506 L: 7248 D: 13142
Ptnml(0-2): 103, 3047, 7388, 3309, 101
https://tests.stockfishchess.org/tests/live_elo/627fd0cfab44257388ab1f13

LTC @ 60+0.6 th 1:
LLR: 2.93 (-2.94,2.94) <0.50,3.00>
Total: 65576 W: 17512 L: 17178 D: 30886
Ptnml(0-2): 37, 6397, 19587, 6729, 38
https://tests.stockfishchess.org/tests/live_elo/627ff666ab44257388ab256d

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

Bench 6407734
2022-05-15 20:20:37 +02:00
disservin 5372f81cc8 SE depth scaling using the previous depth
This patch makes the SE depth condition more robust and allows it to scale with completed depth
from a previous search.

At long TC this patch is almost equivalent to https://github.com/official-stockfish/Stockfish/pull/4016 which had

VLTC:
https://tests.stockfishchess.org/tests/view/626abd7e8707aa698c0093a8
Elo: 2.35 +-1.5 (95%) LOS: 99.9%
Total: 40000 W: 10991 L: 10720 D: 18289
Ptnml(0-2): 8, 3534, 12648, 3799, 11
nElo: 5.47 +-3.4 (95%) PairsRatio: 1.08

VLTC multicore:
https://tests.stockfishchess.org/tests/view/6272a6afc8f14123163c1997
LLR: 2.94 (-2.94,2.94) <0.50,3.00>
Total: 86808 W: 24165 L: 23814 D: 38829
Ptnml(0-2): 11, 7253, 28524, 7606, 10

however, it is now also gaining at LTC:

LTC:
https://tests.stockfishchess.org/tests/view/627e7cb523c0c72a05b651a9
LLR: 2.94 (-2.94,2.94) <0.50,3.00>
Total: 27064 W: 7285 L: 7046 D: 12733
Ptnml(0-2): 8, 2446, 8390, 2675, 13

and should have nearly no influence at STC as depth 27 is rarely reached.
It was noticed that initializing the threshold with MAX_PLY, had an adverse effect,
possibly because the first move is sensitive to this.

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

Bench: 6481017
2022-05-14 13:17:35 +02:00
Tomasz Sobczyk c079acc26f Update NNUE architecture to SFNNv5. Update network to nn-3c0aa92af1da.nnue.
Architecture changes:

    Duplicated activation after the 1024->15 layer with squared crelu (so 15->15*2). As proposed by vondele.

Trainer changes:

    Added bias to L1 factorization, which was previously missing (no measurable improvement but at least neutral in principle)
    For retraining linearly reduce lambda parameter from 1.0 at epoch 0 to 0.75 at epoch 800.
    reduce max_skipping_rate from 15 to 10 (compared to vondele's outstanding PR)

Note: This network was trained with a ~0.8% error in quantization regarding the newly added activation function.
      This will be fixed in the released trainer version. Expect a trainer PR tomorrow.

Note: The inference implementation cuts a corner to merge results from two activation functions.
       This could possibly be resolved nicer in the future. AVX2 implementation likely not necessary, but NEON is missing.

First training session invocation:

python3 train.py \
    ../nnue-pytorch-training/data/nodes5000pv2_UHO.binpack \
    ../nnue-pytorch-training/data/nodes5000pv2_UHO.binpack \
    --gpus "$3," \
    --threads 4 \
    --num-workers 8 \
    --batch-size 16384 \
    --progress_bar_refresh_rate 20 \
    --random-fen-skipping 3 \
    --features=HalfKAv2_hm^ \
    --lambda=1.0 \
    --max_epochs=400 \
    --default_root_dir ../nnue-pytorch-training/experiment_$1/run_$2

Second training session invocation:

python3 train.py \
    ../nnue-pytorch-training/data/T60T70wIsRightFarseerT60T74T75T76.binpack \
    ../nnue-pytorch-training/data/T60T70wIsRightFarseerT60T74T75T76.binpack \
    --gpus "$3," \
    --threads 4 \
    --num-workers 8 \
    --batch-size 16384 \
    --progress_bar_refresh_rate 20 \
    --random-fen-skipping 3 \
    --features=HalfKAv2_hm^ \
    --start-lambda=1.0 \
    --end-lambda=0.75 \
    --gamma=0.995 \
    --lr=4.375e-4 \
    --max_epochs=800 \
    --resume-from-model /data/sopel/nnue/nnue-pytorch-training/data/exp367/nn-exp367-run3-epoch399.pt \
    --default_root_dir ../nnue-pytorch-training/experiment_$1/run_$2

Passed STC:
LLR: 2.95 (-2.94,2.94) <0.00,2.50>
Total: 27288 W: 7445 L: 7178 D: 12665
Ptnml(0-2): 159, 3002, 7054, 3271, 158
https://tests.stockfishchess.org/tests/view/627e8c001919125939623644

Passed LTC:
LLR: 2.95 (-2.94,2.94) <0.50,3.00>
Total: 21792 W: 5969 L: 5727 D: 10096
Ptnml(0-2): 25, 2152, 6294, 2406, 19
https://tests.stockfishchess.org/tests/view/627f2a855734b18b2e2ece47

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

Bench: 6481017
2022-05-14 12:47:22 +02:00
Stéphane Nicolet 9eb7b607cf Reduce depth after score improvement at PV nodes
STC:
LLR: 2.95 (-2.94,2.94) <0.00,2.50>
Total: 73760 W: 19590 L: 19244 D: 34926
Ptnml(0-2): 285, 8352, 19292, 8634, 317
https://tests.stockfishchess.org/tests/view/626eb2dc9116b52aa83b73da

LTC:
LLR: 2.93 (-2.94,2.94) <0.50,3.00>
Total: 114400 W: 30561 L: 30111 D: 53728
Ptnml(0-2): 68, 11432, 33785, 11812, 103
https://tests.stockfishchess.org/tests/view/626f730859e9c431e0b10b21

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

bench: 6174823
2022-05-04 07:47:56 +02:00
candirufish a32d2086bc Use fail high count for LMR
Increase reduction if next ply has a lot of fail high else reset count to 0

Passed STC:
https://tests.stockfishchess.org/tests/view/626ea8299116b52aa83b71f6
LLR: 2.94 (-2.94,2.94) <0.00,2.50>
Total: 144288 W: 38377 L: 37902 D: 68009
Ptnml(0-2): 565, 16298, 38054, 16551, 676

Passed LTC:
https://tests.stockfishchess.org/tests/view/626fa0fb79f761bab2e382f0
LLR: 2.98 (-2.94,2.94) <0.50,3.00>
Total: 74872 W: 20050 L: 19686 D: 35136
Ptnml(0-2): 51, 7541, 21893, 7895, 56

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

bench: 7084802
2022-05-03 17:58:01 +02:00
Stefan Geschwentner 285a79eaa0 Simplify time management.
Replace the best move instability adjustment factor by a simpler version which doesn't have a dependency on the iteration depth.

STC:
LLR: 2.94 (-2.94,2.94) <-2.25,0.25>
Total: 30800 W: 8232 L: 8073 D: 14495
Ptnml(0-2): 101, 3309, 8444, 3422, 124
https://tests.stockfishchess.org/tests/view/6266c77bc5b924ba22908d30

LTC:
LLR: 2.95 (-2.94,2.94) <-2.25,0.25>
Total: 61664 W: 16375 L: 16272 D: 29017
Ptnml(0-2): 40, 5869, 18897, 6000, 26
https://tests.stockfishchess.org/tests/view/6266fc39b3d1812808915f23

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

Bench: 7729968
2022-05-03 17:54:23 +02:00
candirufish e1f12aa4e6 Negative extension for ttMove that is less than alpha and value
in the context of singular extensions

Passed STC:
https://tests.stockfishchess.org/tests/view/626047e8b03f22647441ade0
LLR: 2.97 (-2.94,2.94) <0.00,2.50>
Total: 50296 W: 13410 L: 13108 D: 23778
Ptnml(0-2): 196, 5548, 13370, 5826, 208

Passed LTC:
https://tests.stockfishchess.org/tests/view/6260a513b03f22647441b970
LLR: 2.96 (-2.94,2.94) <0.50,3.00>
Total: 83896 W: 22433 L: 22054 D: 39409
Ptnml(0-2): 49, 8273, 24938, 8626, 62

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

bench: 7729968
2022-04-22 08:17:22 +02:00
Michael Chaly e41f727f0f Simplify away best move count logic
the only place where it was used it was true with >99% probability so it seemed to not be doing much any more.

Passed STC:
https://tests.stockfishchess.org/tests/view/625f4778d00da81c22dd4c93
LLR: 2.95 (-2.94,2.94) <-2.25,0.25>
Total: 85152 W: 22487 L: 22406 D: 40259
Ptnml(0-2): 313, 9035, 23818, 9078, 332

Passed LTC:
https://tests.stockfishchess.org/tests/view/625ff1f1b03f22647441a215
LLR: 2.94 (-2.94,2.94) <-2.25,0.25>
Total: 66776 W: 17768 L: 17673 D: 31335
Ptnml(0-2): 46, 6200, 20792, 6313, 37

close https://github.com/official-stockfish/Stockfish/pull/3993

bench 7280798
2022-04-22 08:09:40 +02:00
Joost VandeVondele 6e0680efa0 Update default net to nn-d0b74ce1e5eb.nnue
train a net using training data with a
heavier weight on positions having 16 pieces on the board. More specifically,
with a relative weight of `i * (32-i)/(16 * 16)+1` (where i is the number of pieces on the board).

This is done with the trainer branch https://github.com/glinscott/nnue-pytorch/pull/173

The command used is:
```
python train.py $datafile $datafile $restarttype $restartfile --gpus 1 --threads 4 --num-workers 12 --random-fen-skipping=3 --batch-size 16384 --progress_bar_refresh_rate 300 --smart-fen-skipping --features=HalfKAv2_hm^   --lambda=1.00  --max_epochs=$epochs --seed $RANDOM --default_root_dir exp/run_$i
```
The datafile is T60T70wIsRightFarseerT60T74T75T76.binpack, the restart is from the master net.

passed STC:
LLR: 2.94 (-2.94,2.94) <0.00,2.50>
Total: 22728 W: 6197 L: 5945 D: 10586
Ptnml(0-2): 105, 2453, 6001, 2695, 110
https://tests.stockfishchess.org/tests/view/625cf944ff677a888877cd90

passed LTC:
LLR: 2.94 (-2.94,2.94) <0.50,3.00>
Total: 35664 W: 9535 L: 9264 D: 16865
Ptnml(0-2): 30, 3524, 10455, 3791, 32
https://tests.stockfishchess.org/tests/view/625d3c32ff677a888877d7ca

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

Bench: 7269563
2022-04-19 19:59:04 +02:00
Joost VandeVondele c4db7fd1f9 Restore development version
No functional change.
2022-04-18 23:05:24 +02:00
38 changed files with 1612 additions and 1021 deletions
+65
View File
@@ -0,0 +1,65 @@
name: Report issue
description: Create a report to help us fix issues with the engine
body:
- type: textarea
attributes:
label: Describe the issue
description: A clear and concise description of what you're experiencing.
validations:
required: true
- type: textarea
attributes:
label: Expected behavior
description: A clear and concise description of what you expected to happen.
validations:
required: true
- type: textarea
attributes:
label: Steps to reproduce
description: |
Steps to reproduce the behavior.
You can also use this section to paste the command line output.
placeholder: |
```
position startpos moves g2g4 e7e5 f2f3
go mate 1
info string NNUE evaluation using nn-6877cd24400e.nnue enabled
info depth 1 seldepth 1 multipv 1 score mate 1 nodes 33 nps 11000 tbhits 0 time 3 pv d8h4
bestmove d8h4
```
validations:
required: true
- type: textarea
attributes:
label: Anything else?
description: |
Anything that will give us more context about the issue you are encountering.
You can also use this section to propose ideas on how to solve the issue.
validations:
required: false
- type: dropdown
attributes:
label: Operating system
options:
- All
- Windows
- Linux
- MacOS
- Android
- Other or N/A
validations:
required: true
- type: input
attributes:
label: Stockfish version
description: |
This can be found by running the engine.
You can also use the commit ID.
placeholder: Stockfish 15 / e6e324e
validations:
required: true
+8
View File
@@ -0,0 +1,8 @@
blank_issues_enabled: false
contact_links:
- name: Discord server
url: https://discord.gg/GWDRS3kU6R
about: Feel free to ask for support or have a chat with us in our Discord server!
- name: Discussions, Q&A, ideas, show us something...
url: https://github.com/official-stockfish/Stockfish/discussions/new
about: Do you have an idea for Stockfish? Do you want to show something that you made? Please open a discussion about it!
+9 -321
View File
@@ -5,329 +5,17 @@ on:
- master - master
- tools - tools
- github_ci - github_ci
- github_ci_armv7
pull_request: pull_request:
branches: branches:
- master - master
- tools - tools
jobs: jobs:
Stockfish: Sanitizers:
name: ${{ matrix.config.name }} uses: ./.github/workflows/stockfish_sanitizers.yml
runs-on: ${{ matrix.config.os }} Tests:
env: uses: ./.github/workflows/stockfish_test.yml
COMPILER: ${{ matrix.config.compiler }} Compiles:
COMP: ${{ matrix.config.comp }} uses: ./.github/workflows/stockfish_compile_test.yml
CXXFLAGS: "-Werror" Binaries:
strategy: if: github.ref == 'refs/heads/master'
matrix: uses: ./.github/workflows/stockfish_binaries.yml
config:
# set the variable for the required tests:
# run_expensive_tests: true
# run_32bit_tests: true
# run_64bit_tests: true
# run_armv8_tests: true
# run_armv7_tests: true
- {
name: "Ubuntu 20.04 GCC",
os: ubuntu-20.04,
compiler: g++,
comp: gcc,
run_expensive_tests: true,
run_32bit_tests: true,
run_64bit_tests: true,
shell: 'bash {0}'
}
- {
name: "Ubuntu 20.04 Clang",
os: ubuntu-20.04,
compiler: clang++,
comp: clang,
run_32bit_tests: true,
run_64bit_tests: true,
shell: 'bash {0}'
}
- {
name: "Ubuntu 20.04 NDK armv8",
os: ubuntu-20.04,
compiler: aarch64-linux-android21-clang++,
comp: ndk,
run_armv8_tests: true,
shell: 'bash {0}'
}
- {
name: "Ubuntu 20.04 NDK armv7",
os: ubuntu-20.04,
compiler: armv7a-linux-androideabi21-clang++,
comp: ndk,
run_armv7_tests: true,
shell: 'bash {0}'
}
- {
name: "MacOS 10.15 Apple Clang",
os: macos-10.15,
compiler: clang++,
comp: clang,
run_64bit_tests: true,
shell: 'bash {0}'
}
- {
name: "MacOS 10.15 GCC 10",
os: macos-10.15,
compiler: g++-10,
comp: gcc,
run_64bit_tests: true,
shell: 'bash {0}'
}
- {
name: "Windows 2022 Mingw-w64 GCC x86_64",
os: windows-2022,
compiler: g++,
comp: mingw,
run_64bit_tests: true,
msys_sys: 'mingw64',
msys_env: 'x86_64-gcc',
shell: 'msys2 {0}'
}
- {
name: "Windows 2022 Mingw-w64 GCC i686",
os: windows-2022,
compiler: g++,
comp: mingw,
run_32bit_tests: true,
msys_sys: 'mingw32',
msys_env: 'i686-gcc',
shell: 'msys2 {0}'
}
- {
name: "Windows 2022 Mingw-w64 Clang x86_64",
os: windows-2022,
compiler: clang++,
comp: clang,
run_64bit_tests: true,
msys_sys: 'clang64',
msys_env: 'clang-x86_64-clang',
shell: 'msys2 {0}'
}
defaults:
run:
working-directory: src
shell: ${{ matrix.config.shell }}
steps:
- uses: actions/checkout@v2
with:
fetch-depth: 0
- name: Download required linux packages
if: runner.os == 'Linux'
run: |
sudo apt update
sudo apt install expect valgrind g++-multilib qemu-user
- name: Setup msys and install required packages
if: runner.os == 'Windows'
uses: msys2/setup-msys2@v2
with:
msystem: ${{matrix.config.msys_sys}}
install: mingw-w64-${{matrix.config.msys_env}} make git expect
- name: Download the used network from the fishtest framework
run: |
make net
- name: Extract the bench number from the commit history
run: |
git log HEAD | grep "\b[Bb]ench[ :]\+[0-9]\{7\}" | head -n 1 | sed "s/[^0-9]*\([0-9]*\).*/\1/g" > git_sig
[ -s git_sig ] && echo "benchref=$(cat git_sig)" >> $GITHUB_ENV && echo "Reference bench:" $(cat git_sig) || echo "No bench found"
- name: Check compiler
run: |
export PATH=$PATH:$ANDROID_NDK_HOME/toolchains/llvm/prebuilt/linux-x86_64/bin
$COMPILER -v
- name: Test help target
run: |
make help
# x86-32 tests
- name: Test debug x86-32 build
if: ${{ matrix.config.run_32bit_tests }}
run: |
export CXXFLAGS="-Werror -D_GLIBCXX_DEBUG"
make clean
make -j2 ARCH=x86-32 optimize=no debug=yes build
../tests/signature.sh $benchref
- name: Test x86-32 build
if: ${{ matrix.config.run_32bit_tests }}
run: |
make clean
make -j2 ARCH=x86-32 build
../tests/signature.sh $benchref
- name: Test x86-32-sse41-popcnt build
if: ${{ matrix.config.run_32bit_tests }}
run: |
make clean
make -j2 ARCH=x86-32-sse41-popcnt build
../tests/signature.sh $benchref
- name: Test x86-32-sse2 build
if: ${{ matrix.config.run_32bit_tests }}
run: |
make clean
make -j2 ARCH=x86-32-sse2 build
../tests/signature.sh $benchref
- name: Test general-32 build
if: ${{ matrix.config.run_32bit_tests }}
run: |
make clean
make -j2 ARCH=general-32 build
../tests/signature.sh $benchref
# x86-64 tests
- name: Test debug x86-64-modern build
if: ${{ matrix.config.run_64bit_tests }}
run: |
export CXXFLAGS="-Werror -D_GLIBCXX_DEBUG"
make clean
make -j2 ARCH=x86-64-modern optimize=no debug=yes build
../tests/signature.sh $benchref
- name: Test x86-64-modern build
if: ${{ matrix.config.run_64bit_tests }}
run: |
make clean
make -j2 ARCH=x86-64-modern build
../tests/signature.sh $benchref
- name: Test x86-64-ssse3 build
if: ${{ matrix.config.run_64bit_tests }}
run: |
make clean
make -j2 ARCH=x86-64-ssse3 build
../tests/signature.sh $benchref
- name: Test x86-64-sse3-popcnt build
if: ${{ matrix.config.run_64bit_tests }}
run: |
make clean
make -j2 ARCH=x86-64-sse3-popcnt build
../tests/signature.sh $benchref
- name: Test x86-64 build
if: ${{ matrix.config.run_64bit_tests }}
run: |
make clean
make -j2 ARCH=x86-64 build
../tests/signature.sh $benchref
- name: Test general-64 build
if: matrix.config.run_64bit_tests
run: |
make clean
make -j2 ARCH=general-64 build
../tests/signature.sh $benchref
# x86-64 with newer extensions tests
- name: Compile x86-64-avx2 build
if: ${{ matrix.config.run_64bit_tests }}
run: |
make clean
make -j2 ARCH=x86-64-avx2 build
- name: Compile x86-64-bmi2 build
if: ${{ matrix.config.run_64bit_tests }}
run: |
make clean
make -j2 ARCH=x86-64-bmi2 build
- name: Compile x86-64-avx512 build
if: ${{ matrix.config.run_64bit_tests }}
run: |
make clean
make -j2 ARCH=x86-64-avx512 build
- name: Compile x86-64-vnni512 build
if: ${{ matrix.config.run_64bit_tests }}
run: |
make clean
make -j2 ARCH=x86-64-vnni512 build
- name: Compile x86-64-vnni256 build
if: ${{ matrix.config.run_64bit_tests }}
run: |
make clean
make -j2 ARCH=x86-64-vnni256 build
# armv8 tests
- name: Test armv8 build
if: ${{ matrix.config.run_armv8_tests }}
run: |
export PATH=$ANDROID_NDK_HOME/toolchains/llvm/prebuilt/linux-x86_64/bin:$PATH
export LDFLAGS="-static -Wno-unused-command-line-argument"
make clean
make -j2 ARCH=armv8 build
../tests/signature.sh $benchref
# armv7 tests
- name: Test armv7 build
if: ${{ matrix.config.run_armv7_tests }}
run: |
export PATH=$ANDROID_NDK_HOME/toolchains/llvm/prebuilt/linux-x86_64/bin:$PATH
export LDFLAGS="-static -Wno-unused-command-line-argument"
make clean
make -j2 ARCH=armv7 build
../tests/signature.sh $benchref
- name: Test armv7-neon build
if: ${{ matrix.config.run_armv7_tests }}
run: |
export PATH=$ANDROID_NDK_HOME/toolchains/llvm/prebuilt/linux-x86_64/bin:$PATH
export LDFLAGS="-static -Wno-unused-command-line-argument"
make clean
make -j2 ARCH=armv7-neon build
../tests/signature.sh $benchref
# Other tests
- name: Check perft and search reproducibility
if: ${{ matrix.config.run_64bit_tests }}
run: |
make clean
make -j2 ARCH=x86-64-modern build
../tests/perft.sh
../tests/reprosearch.sh
# Sanitizers
- name: Run under valgrind
if: ${{ matrix.config.run_expensive_tests }}
run: |
export CXXFLAGS="-O1 -fno-inline"
make clean
make -j2 ARCH=x86-64-modern debug=yes optimize=no build > /dev/null
../tests/instrumented.sh --valgrind
../tests/instrumented.sh --valgrind-thread
- name: Run with UB sanitizer
if: ${{ matrix.config.run_expensive_tests }}
run: |
export CXXFLAGS="-O1 -fno-inline"
make clean
make -j2 ARCH=x86-64-modern sanitize=undefined optimize=no debug=yes build > /dev/null
../tests/instrumented.sh --sanitizer-undefined
- name: Run with thread sanitizer
if: ${{ matrix.config.run_expensive_tests }}
run: |
export CXXFLAGS="-O1 -fno-inline"
make clean
make -j2 ARCH=x86-64-modern sanitize=thread optimize=no debug=yes build > /dev/null
../tests/instrumented.sh --sanitizer-thread
+110
View File
@@ -0,0 +1,110 @@
name: Stockfish
on:
workflow_call:
jobs:
Stockfish:
name: ${{ matrix.config.name }} ${{ matrix.binaries }}
runs-on: ${{ matrix.config.os }}
env:
COMPILER: ${{ matrix.config.compiler }}
COMP: ${{ matrix.config.comp }}
EXT: ${{ matrix.config.ext }}
OS: ${{ matrix.config.os }}
BINARY: ${{ matrix.binaries }}
strategy:
matrix:
config:
- {
name: "Ubuntu 20.04 GCC",
os: ubuntu-20.04,
compiler: g++,
comp: gcc,
shell: 'bash {0}'
}
- {
name: "MacOS 12 Apple Clang",
os: macos-12,
compiler: clang++,
comp: clang,
shell: 'bash {0}'
}
- {
name: "Windows 2022 Mingw-w64 GCC x86_64",
os: windows-2022,
compiler: g++,
comp: mingw,
msys_sys: 'mingw64',
msys_env: 'x86_64-gcc',
shell: 'msys2 {0}',
ext: .exe
}
binaries:
- x86-64
- x86-64-modern
- x86-64-avx2
exclude:
- binaries: x86-64-avx2
config: {os: macos-12}
defaults:
run:
working-directory: src
shell: ${{ matrix.config.shell }}
steps:
- uses: actions/checkout@v3
with:
fetch-depth: 0
- name: Download required linux packages
if: runner.os == 'Linux'
run: |
sudo apt update
- name: Setup msys and install required packages
if: runner.os == 'Windows'
uses: msys2/setup-msys2@v2
with:
msystem: ${{matrix.config.msys_sys}}
install: mingw-w64-${{matrix.config.msys_env}} make git expect
- name: Download the used network from the fishtest framework
run: |
make net
- name: Check compiler
run: |
export PATH=$PATH:$ANDROID_NDK_HOME/toolchains/llvm/prebuilt/linux-x86_64/bin
$COMPILER -v
- name: Test help target
run: |
make help
# Compile profile guided builds
- name: Compile ${{ matrix.binaries }} build
run: |
make clean
make -j2 profile-build ARCH=$BINARY COMP=$COMP
strip ./stockfish$EXT
mv ./stockfish$EXT ../stockfish-$OS-$BINARY$EXT
- name: Remove non src files
run: rm -f *.o .depend *.nnue
- name: Create tar archive.
run: |
cd ..
mkdir stockfish
cp -r src stockfish/
cp stockfish-$OS-$BINARY$EXT stockfish/
cp "Top CPU Contributors.txt" stockfish/
cp Copying.txt stockfish/
cp AUTHORS stockfish/
tar -cvf stockfish-$OS-$BINARY.tar stockfish
- name: Upload binaries
uses: actions/upload-artifact@v3
with:
name: stockfish-${{ matrix.config.os }}-${{ matrix.binaries }}
path: |
stockfish-${{ matrix.config.os }}-${{ matrix.binaries }}.tar
@@ -0,0 +1,115 @@
name: Stockfish
on:
workflow_call:
jobs:
Stockfish:
name: ${{ matrix.config.name }}
runs-on: ${{ matrix.config.os }}
env:
COMPILER: ${{ matrix.config.compiler }}
COMP: ${{ matrix.config.comp }}
strategy:
matrix:
config:
- {
name: "Ubuntu 20.04 GCC",
os: ubuntu-20.04,
compiler: g++,
comp: gcc,
shell: 'bash {0}'
}
- {
name: "Ubuntu 20.04 Clang",
os: ubuntu-20.04,
compiler: clang++,
comp: clang,
shell: 'bash {0}'
}
- {
name: "MacOS 12 Apple Clang",
os: macos-12,
compiler: clang++,
comp: clang,
shell: 'bash {0}'
}
- {
name: "MacOS 12 GCC 11",
os: macos-12,
compiler: g++-11,
comp: gcc,
shell: 'bash {0}'
}
- {
name: "Windows 2022 Mingw-w64 GCC x86_64",
os: windows-2022,
compiler: g++,
comp: mingw,
msys_sys: 'mingw64',
msys_env: 'x86_64-gcc',
shell: 'msys2 {0}'
}
- {
name: "Windows 2022 Mingw-w64 Clang x86_64",
os: windows-2022,
compiler: clang++,
comp: clang,
msys_sys: 'clang64',
msys_env: 'clang-x86_64-clang',
shell: 'msys2 {0}'
}
defaults:
run:
working-directory: src
shell: ${{ matrix.config.shell }}
steps:
- uses: actions/checkout@v3
with:
fetch-depth: 0
- name: Setup msys and install required packages
if: runner.os == 'Windows'
uses: msys2/setup-msys2@v2
with:
msystem: ${{matrix.config.msys_sys}}
install: mingw-w64-${{matrix.config.msys_env}} make git expect
- name: Download the used network from the fishtest framework
run: |
make net
- name: Check compiler
run: |
export PATH=$PATH:$ANDROID_NDK_HOME/toolchains/llvm/prebuilt/linux-x86_64/bin
$COMPILER -v
- name: Test help target
run: |
make help
# x86-64 with newer extensions tests
- name: Compile x86-64-avx2 build
run: |
make clean
make -j2 ARCH=x86-64-avx2 build
- name: Compile x86-64-bmi2 build
run: |
make clean
make -j2 ARCH=x86-64-bmi2 build
- name: Compile x86-64-avx512 build
run: |
make clean
make -j2 ARCH=x86-64-avx512 build
- name: Compile x86-64-vnni512 build
run: |
make clean
make -j2 ARCH=x86-64-vnni512 build
- name: Compile x86-64-vnni256 build
run: |
make clean
make -j2 ARCH=x86-64-vnni256 build
@@ -0,0 +1,77 @@
name: Stockfish
on:
workflow_call:
jobs:
Stockfish:
name: ${{ matrix.sanitizers.name }}
runs-on: ${{ matrix.config.os }}
env:
COMPILER: ${{ matrix.config.compiler }}
COMP: ${{ matrix.config.comp }}
CXXFLAGS: "-Werror"
strategy:
matrix:
config:
- {
name: "Ubuntu 20.04 GCC",
os: ubuntu-20.04,
compiler: g++,
comp: gcc,
shell: 'bash {0}'
}
sanitizers:
- {
name: Run with thread sanitizer,
make_option: sanitize=thread,
instrumented_option: sanitizer-thread
}
- {
name: Run with UB sanitizer,
make_option: sanitize=undefined,
instrumented_option: sanitizer-undefined
}
- {
name: Run under valgrind,
make_option: "",
instrumented_option: valgrind
}
- {
name: Run under valgrind-thread,
make_option: "",
instrumented_option: valgrind-thread
}
defaults:
run:
working-directory: src
shell: ${{ matrix.config.shell }}
steps:
- uses: actions/checkout@v3
with:
fetch-depth: 0
- name: Download required linux packages
run: |
sudo apt update
sudo apt install expect valgrind g++-multilib qemu-user
- name: Download the used network from the fishtest framework
run: |
make net
- name: Check compiler
run: |
export PATH=$PATH:$ANDROID_NDK_HOME/toolchains/llvm/prebuilt/linux-x86_64/bin
$COMPILER -v
- name: Test help target
run: |
make help
# Sanitizers
- name: ${{ matrix.sanitizers.name }}
run: |
export CXXFLAGS="-O1 -fno-inline"
make clean
make -j2 ARCH=x86-64-modern ${{ matrix.sanitizers.make_option }} debug=yes optimize=no build > /dev/null
../tests/instrumented.sh --${{ matrix.sanitizers.instrumented_option }}
+284
View File
@@ -0,0 +1,284 @@
name: Stockfish
on:
workflow_call:
jobs:
Stockfish:
name: ${{ matrix.config.name }}
runs-on: ${{ matrix.config.os }}
env:
COMPILER: ${{ matrix.config.compiler }}
COMP: ${{ matrix.config.comp }}
CXXFLAGS: "-Werror"
strategy:
matrix:
config:
- {
name: "Ubuntu 20.04 GCC",
os: ubuntu-20.04,
compiler: g++,
comp: gcc,
run_32bit_tests: true,
run_64bit_tests: true,
shell: 'bash {0}'
}
- {
name: "Ubuntu 20.04 Clang",
os: ubuntu-20.04,
compiler: clang++,
comp: clang,
run_32bit_tests: true,
run_64bit_tests: true,
shell: 'bash {0}'
}
- {
name: "Ubuntu 20.04 NDK armv8",
os: ubuntu-20.04,
compiler: aarch64-linux-android21-clang++,
comp: ndk,
run_armv8_tests: false,
shell: 'bash {0}'
}
- {
name: "Ubuntu 20.04 NDK armv7",
os: ubuntu-20.04,
compiler: armv7a-linux-androideabi21-clang++,
comp: ndk,
run_armv7_tests: false,
shell: 'bash {0}'
}
- {
name: "MacOS 12 Apple Clang",
os: macos-12,
compiler: clang++,
comp: clang,
run_64bit_tests: true,
shell: 'bash {0}'
}
- {
name: "MacOS 12 GCC 11",
os: macos-12,
compiler: g++-11,
comp: gcc,
run_64bit_tests: true,
shell: 'bash {0}'
}
- {
name: "Windows 2022 Mingw-w64 GCC x86_64",
os: windows-2022,
compiler: g++,
comp: mingw,
run_64bit_tests: true,
msys_sys: 'mingw64',
msys_env: 'x86_64-gcc',
shell: 'msys2 {0}'
}
- {
name: "Windows 2022 Mingw-w64 GCC i686",
os: windows-2022,
compiler: g++,
comp: mingw,
run_32bit_tests: true,
msys_sys: 'mingw32',
msys_env: 'i686-gcc',
shell: 'msys2 {0}'
}
- {
name: "Windows 2022 Mingw-w64 Clang x86_64",
os: windows-2022,
compiler: clang++,
comp: clang,
run_64bit_tests: true,
msys_sys: 'clang64',
msys_env: 'clang-x86_64-clang',
shell: 'msys2 {0}'
}
exclude:
- config:
{
name: "Ubuntu 20.04 NDK armv7"
}
- config:
{
name: "Ubuntu 20.04 NDK armv8"
}
defaults:
run:
working-directory: src
shell: ${{ matrix.config.shell }}
steps:
- uses: actions/checkout@v3
with:
fetch-depth: 0
- name: Download required linux packages
if: runner.os == 'Linux'
run: |
sudo apt update
sudo apt install expect valgrind g++-multilib qemu-user
- name: Setup msys and install required packages
if: runner.os == 'Windows'
uses: msys2/setup-msys2@v2
with:
msystem: ${{matrix.config.msys_sys}}
install: mingw-w64-${{matrix.config.msys_env}} make git expect
- name: Download the used network from the fishtest framework
run: |
make net
- name: Extract the bench number from the commit history
run: |
git log HEAD | grep "\b[Bb]ench[ :]\+[0-9]\{7\}" | head -n 1 | sed "s/[^0-9]*\([0-9]*\).*/\1/g" > git_sig
[ -s git_sig ] && echo "benchref=$(cat git_sig)" >> $GITHUB_ENV && echo "Reference bench:" $(cat git_sig) || echo "No bench found"
- name: Check compiler
run: |
export PATH=$PATH:$ANDROID_NDK_HOME/toolchains/llvm/prebuilt/linux-x86_64/bin
$COMPILER -v
- name: Test help target
run: |
make help
# x86-32 tests
- name: Test debug x86-32 build
if: ${{ matrix.config.run_32bit_tests }}
run: |
export CXXFLAGS="-Werror -D_GLIBCXX_DEBUG"
make clean
make -j2 ARCH=x86-32 optimize=no debug=yes build
../tests/signature.sh $benchref
- name: Test x86-32 build
if: ${{ matrix.config.run_32bit_tests }}
run: |
make clean
make -j2 ARCH=x86-32 build
../tests/signature.sh $benchref
- name: Test x86-32-sse41-popcnt build
if: ${{ matrix.config.run_32bit_tests }}
run: |
make clean
make -j2 ARCH=x86-32-sse41-popcnt build
../tests/signature.sh $benchref
- name: Test x86-32-sse2 build
if: ${{ matrix.config.run_32bit_tests }}
run: |
make clean
make -j2 ARCH=x86-32-sse2 build
../tests/signature.sh $benchref
- name: Test general-32 build
if: ${{ matrix.config.run_32bit_tests }}
run: |
make clean
make -j2 ARCH=general-32 build
../tests/signature.sh $benchref
# x86-64 tests
- name: Test debug x86-64-modern build
if: ${{ matrix.config.run_64bit_tests }}
run: |
export CXXFLAGS="-Werror -D_GLIBCXX_DEBUG"
make clean
make -j2 ARCH=x86-64-modern optimize=no debug=yes build
../tests/signature.sh $benchref
- name: Test x86-64-modern build
if: ${{ matrix.config.run_64bit_tests }}
run: |
make clean
make -j2 ARCH=x86-64-modern build
../tests/signature.sh $benchref
- name: Test x86-64-ssse3 build
if: ${{ matrix.config.run_64bit_tests }}
run: |
make clean
make -j2 ARCH=x86-64-ssse3 build
../tests/signature.sh $benchref
- name: Test x86-64-sse3-popcnt build
if: ${{ matrix.config.run_64bit_tests }}
run: |
make clean
make -j2 ARCH=x86-64-sse3-popcnt build
../tests/signature.sh $benchref
- name: Test x86-64 build
if: ${{ matrix.config.run_64bit_tests }}
run: |
make clean
make -j2 ARCH=x86-64 build
../tests/signature.sh $benchref
- name: Test general-64 build
if: matrix.config.run_64bit_tests
run: |
make clean
make -j2 ARCH=general-64 build
../tests/signature.sh $benchref
# armv8 tests
- name: Test armv8 build
if: ${{ matrix.config.run_armv8_tests }}
run: |
ANDROID_ROOT=/usr/local/lib/android
ANDROID_SDK_ROOT=${ANDROID_ROOT}/sdk
SDKMANAGER=${ANDROID_SDK_ROOT}/cmdline-tools/latest/bin/sdkmanager
echo "y" | $SDKMANAGER "ndk;21.4.7075529"
ANDROID_NDK_ROOT=${ANDROID_SDK_ROOT}/ndk-bundle
ln -sfn $ANDROID_SDK_ROOT/ndk/21.4.7075529 $ANDROID_NDK_ROOT
export PATH=$ANDROID_NDK_HOME/toolchains/llvm/prebuilt/linux-x86_64/bin:$PATH
export LDFLAGS="-static -Wno-unused-command-line-argument"
make clean
make -j2 ARCH=armv8 build
../tests/signature.sh $benchref
# armv7 tests
- name: Test armv7 build
if: ${{ matrix.config.run_armv7_tests }}
run: |
ANDROID_ROOT=/usr/local/lib/android
ANDROID_SDK_ROOT=${ANDROID_ROOT}/sdk
SDKMANAGER=${ANDROID_SDK_ROOT}/cmdline-tools/latest/bin/sdkmanager
echo "y" | $SDKMANAGER "ndk;21.4.7075529"
ANDROID_NDK_ROOT=${ANDROID_SDK_ROOT}/ndk-bundle
ln -sfn $ANDROID_SDK_ROOT/ndk/21.4.7075529 $ANDROID_NDK_ROOT
export PATH=$ANDROID_NDK_HOME/toolchains/llvm/prebuilt/linux-x86_64/bin:$PATH
export LDFLAGS="-static -Wno-unused-command-line-argument"
make clean
make -j2 ARCH=armv7 build
../tests/signature.sh $benchref
- name: Test armv7-neon build
if: ${{ matrix.config.run_armv7_tests }}
run: |
ANDROID_ROOT=/usr/local/lib/android
ANDROID_SDK_ROOT=${ANDROID_ROOT}/sdk
SDKMANAGER=${ANDROID_SDK_ROOT}/cmdline-tools/latest/bin/sdkmanager
echo "y" | $SDKMANAGER "ndk;21.4.7075529"
ANDROID_NDK_ROOT=${ANDROID_SDK_ROOT}/ndk-bundle
ln -sfn $ANDROID_SDK_ROOT/ndk/21.4.7075529 $ANDROID_NDK_ROOT
export PATH=$ANDROID_NDK_HOME/toolchains/llvm/prebuilt/linux-x86_64/bin:$PATH
export LDFLAGS="-static -Wno-unused-command-line-argument"
make clean
make -j2 ARCH=armv7-neon build
../tests/signature.sh $benchref
# Other tests
- name: Check perft and search reproducibility
if: ${{ matrix.config.run_64bit_tests }}
run: |
make clean
make -j2 ARCH=x86-64-modern build
../tests/perft.sh
../tests/reprosearch.sh
+11 -4
View File
@@ -35,19 +35,23 @@ Ben Chaney (Chaneybenjamini)
Ben Koshy (BKSpurgeon) Ben Koshy (BKSpurgeon)
Bill Henry (VoyagerOne) Bill Henry (VoyagerOne)
Bojun Guo (noobpwnftw, Nooby) Bojun Guo (noobpwnftw, Nooby)
Boštjan Mejak (PedanticHacker)
braich braich
Brian Sheppard (SapphireBrand, briansheppard-toast) Brian Sheppard (SapphireBrand, briansheppard-toast)
Bruno de Melo Costa (BM123499) Bruno de Melo Costa (BM123499)
Bruno Pellanda (pellanda)
Bryan Cross (crossbr) Bryan Cross (crossbr)
candirufish candirufish
Chess13234 Chess13234
Chris Cain (ceebo) Chris Cain (ceebo)
clefrks
Dale Weiler (graphitemaster) Dale Weiler (graphitemaster)
Dan Schmidt (dfannius) Dan Schmidt (dfannius)
Daniel Axtens (daxtens) Daniel Axtens (daxtens)
Daniel Dugovic (ddugovic) Daniel Dugovic (ddugovic)
Dariusz Orzechowski (dorzechowski) Dariusz Orzechowski (dorzechowski)
David Zar David Zar
David (dav1312)
Daylen Yang (daylen) Daylen Yang (daylen)
Deshawn Mohan-Smith (GoldenRare) Deshawn Mohan-Smith (GoldenRare)
Dieter Dobbelaere (ddobbelaere) Dieter Dobbelaere (ddobbelaere)
@@ -55,6 +59,7 @@ DiscanX
Dominik Schlösser (domschl) Dominik Schlösser (domschl)
double-beep double-beep
Douglas Matos Gomes (dsmsgms) Douglas Matos Gomes (dsmsgms)
Dubslow
Eduardo Cáceres (eduherminio) Eduardo Cáceres (eduherminio)
Eelco de Groot (KingDefender) Eelco de Groot (KingDefender)
Elvin Liu (solarlight2) Elvin Liu (solarlight2)
@@ -86,7 +91,7 @@ Hongzhi Cheng
Ivan Ivec (IIvec) Ivan Ivec (IIvec)
Jacques B. (Timshel) Jacques B. (Timshel)
Jan Ondruš (hxim) Jan Ondruš (hxim)
Jared Kish (Kurtbusch) Jared Kish (Kurtbusch, kurt22i)
Jarrod Torriero (DU-jdto) Jarrod Torriero (DU-jdto)
Jean Gauthier (OuaisBla) Jean Gauthier (OuaisBla)
Jean-Francois Romang (jromang) Jean-Francois Romang (jromang)
@@ -125,6 +130,7 @@ marotear
Matt Ginsberg (mattginsberg) Matt Ginsberg (mattginsberg)
Matthew Lai (matthewlai) Matthew Lai (matthewlai)
Matthew Sullivan (Matt14916) Matthew Sullivan (Matt14916)
Max A. (Disservin)
Maxim Molchanov (Maxim) Maxim Molchanov (Maxim)
Michael An (man) Michael An (man)
Michael Byrne (MichaelB7) Michael Byrne (MichaelB7)
@@ -155,7 +161,6 @@ Panthee
Pascal Romaret Pascal Romaret
Pasquale Pigazzini (ppigazzini) Pasquale Pigazzini (ppigazzini)
Patrick Jansen (mibere) Patrick Jansen (mibere)
pellanda
Peter Schneider (pschneider1968) Peter Schneider (pschneider1968)
Peter Zsifkovits (CoffeeOne) Peter Zsifkovits (CoffeeOne)
Praveen Kumar Tummala (praveentml) Praveen Kumar Tummala (praveentml)
@@ -163,9 +168,10 @@ Rahul Dsilva (silversolver1)
Ralph Stößer (Ralph Stoesser) Ralph Stößer (Ralph Stoesser)
Raminder Singh Raminder Singh
renouve renouve
Reuven Peleg Reuven Peleg (R-Peleg)
Richard Lloyd Richard Lloyd (Richard-Lloyd)
Rodrigo Exterckötter Tjäder Rodrigo Exterckötter Tjäder
Rodrigo Roim (roim)
Ron Britvich (Britvich) Ron Britvich (Britvich)
Ronald de Man (syzygy1, syzygy) Ronald de Man (syzygy1, syzygy)
rqs rqs
@@ -185,6 +191,7 @@ Stefan Geschwentner (locutus2)
Stefano Cardanobile (Stefano80) Stefano Cardanobile (Stefano80)
Steinar Gunderson (sesse) Steinar Gunderson (sesse)
Stéphane Nicolet (snicolet) Stéphane Nicolet (snicolet)
Syine Mineta (MinetaS)
Prokop Randáček (ProkopRandacek) Prokop Randáček (ProkopRandacek)
Thanar2 Thanar2
thaspel thaspel
+87 -46
View File
@@ -1,48 +1,58 @@
<div align="center">
[![Stockfish][stockfish128-logo]][website-link]
[![Build][build-badge]][build-link]
[![License][license-badge]][license-link]
<br>
[![Release][release-badge]][release-link]
[![Commits][commits-badge]][commits-link]
<br>
[![Website][website-badge]][website-link]
[![Fishtest][fishtest-badge]][fishtest-link]
[![Discord][discord-badge]][discord-link]
</div>
## Overview ## Overview
[![Build Status](https://github.com/official-stockfish/Stockfish/actions/workflows/stockfish.yml/badge.svg)](https://github.com/official-stockfish/Stockfish/actions) [Stockfish][website-link] is a free, powerful UCI chess engine derived from
[![Build Status](https://ci.appveyor.com/api/projects/status/github/official-stockfish/Stockfish?branch=master&svg=true)](https://ci.appveyor.com/project/mcostalba/stockfish/branch/master) Glaurung 2.1. Stockfish is not a complete chess program and requires a UCI-compatible
graphical user interface (GUI) (e.g. XBoard with PolyGlot, Scid, Cute Chess, eboard,
Arena, Sigma Chess, Shredder, Chess Partner or Fritz) in order to be used comfortably.
Read the documentation for your GUI of choice for information about how to use
Stockfish with it.
[Stockfish](https://stockfishchess.org) is a free, powerful UCI chess engine The Stockfish engine features two evaluation functions for chess. The efficiently
derived from Glaurung 2.1. Stockfish is not a complete chess program and requires a
UCI-compatible graphical user interface (GUI) (e.g. XBoard with PolyGlot, Scid,
Cute Chess, eboard, Arena, Sigma Chess, Shredder, Chess Partner or Fritz) in order
to be used comfortably. Read the documentation for your GUI of choice for information
about how to use Stockfish with it.
The Stockfish engine features two evaluation functions for chess. The efficiently
updatable neural network (NNUE) based evaluation is the default and by far the strongest. updatable neural network (NNUE) based evaluation is the default and by far the strongest.
The classical evaluation based on handcrafted terms remains available. The strongest The classical evaluation based on handcrafted terms remains available. The strongest
network is integrated in the binary and downloaded automatically during the build process. network is integrated in the binary and downloaded automatically during the build process.
The NNUE evaluation benefits from the vector intrinsics available on most CPUs (sse2, The NNUE evaluation benefits from the vector intrinsics available on most CPUs (sse2,
avx2, neon, or similar). avx2, neon, or similar).
## Files ## Files
This distribution of Stockfish consists of the following files: This distribution of Stockfish consists of the following files:
* [Readme.md](https://github.com/official-stockfish/Stockfish/blob/master/README.md), * [README.md][readme-link], the file you are currently reading.
the file you are currently reading.
* [Copying.txt](https://github.com/official-stockfish/Stockfish/blob/master/Copying.txt), * [Copying.txt][license-link], a text file containing the GNU General Public License
a text file containing the GNU General Public License version 3. version 3.
* [AUTHORS](https://github.com/official-stockfish/Stockfish/blob/master/AUTHORS), * [AUTHORS][authors-link], a text file with the list of authors for the project.
a text file with the list of authors for the project
* [src](https://github.com/official-stockfish/Stockfish/tree/master/src), * [src][src-link], a subdirectory containing the full source code, including a Makefile
a subdirectory containing the full source code, including a Makefile
that can be used to compile Stockfish on Unix-like systems. that can be used to compile Stockfish on Unix-like systems.
* a file with the .nnue extension, storing the neural network for the NNUE * a file with the .nnue extension, storing the neural network for the NNUE evaluation.
evaluation. Binary distributions will have this file embedded. Binary distributions will have this file embedded.
## The UCI protocol and available options ## The UCI protocol and available options
The Universal Chess Interface (UCI) is a standard protocol used to communicate with The Universal Chess Interface (UCI) is a standard protocol used to communicate with
a chess engine, and is the recommended way to do so for typical graphical user interfaces a chess engine, and is the recommended way to do so for typical graphical user interfaces
(GUI) or chess tools. Stockfish implements the majority of its options as described (GUI) or chess tools. Stockfish implements the majority of its options as described
in [the UCI protocol](https://www.shredderchess.com/download/div/uci.zip). in [the UCI protocol][uci-link].
Developers can see the default values for UCI options available in Stockfish by typing Developers can see the default values for UCI options available in Stockfish by typing
`./stockfish uci` in a terminal, but the majority of users will typically see them and `./stockfish uci` in a terminal, but the majority of users will typically see them and
@@ -142,8 +152,8 @@ change them via a chess GUI. This is a list of available UCI options in Stockfis
For developers the following non-standard commands might be of interest, mainly useful for debugging: For developers the following non-standard commands might be of interest, mainly useful for debugging:
* #### bench *ttSize threads limit fenFile limitType evalType* * #### bench *ttSize threads limit fenFile limitType evalType*
Performs a standard benchmark using various options. The signature of a version Performs a standard benchmark using various options. The signature of a version
(standard node count) is obtained using all defaults. `bench` is currently (standard node count) is obtained using all defaults. `bench` is currently
`bench 16 1 13 default depth mixed`. `bench 16 1 13 default depth mixed`.
* #### compiler * #### compiler
@@ -180,12 +190,10 @@ on the evaluations of millions of positions at moderate search depth.
The NNUE evaluation was first introduced in shogi, and ported to Stockfish afterward. The NNUE evaluation was first introduced in shogi, and ported to Stockfish afterward.
It can be evaluated efficiently on CPUs, and exploits the fact that only parts It can be evaluated efficiently on CPUs, and exploits the fact that only parts
of the neural network need to be updated after a typical chess move. of the neural network need to be updated after a typical chess move.
[The nodchip repository](https://github.com/nodchip/Stockfish) provided the first [The nodchip repository][nodchip-link] provided the first version of the needed tools
version of the needed tools to train and develop the NNUE networks. Today, more to train and develop the NNUE networks. Today, more advanced training tools are
advanced training tools are available in available in [the nnue-pytorch repository][pytorch-link], while data generation tools
[the nnue-pytorch repository](https://github.com/glinscott/nnue-pytorch/), are available in [a dedicated branch][tools-link].
while data generation tools are available in
[a dedicated branch](https://github.com/official-stockfish/Stockfish/tree/tools).
On CPUs supporting modern vector instructions (avx2 and similar), the NNUE evaluation On CPUs supporting modern vector instructions (avx2 and similar), the NNUE evaluation
results in much stronger playing strength, even if the nodes per second computed by results in much stronger playing strength, even if the nodes per second computed by
@@ -193,9 +201,9 @@ the engine is somewhat lower (roughly 80% of nps is typical).
Notes: Notes:
1) the NNUE evaluation depends on the Stockfish binary and the network parameter file 1) the NNUE evaluation depends on the Stockfish binary and the network parameter file
(see the EvalFile UCI option). Not every parameter file is compatible with a given (see the EvalFile UCI option). Not every parameter file is compatible with a given
Stockfish binary, but the default value of the EvalFile UCI option is the name of a Stockfish binary, but the default value of the EvalFile UCI option is the name of a
network that is guaranteed to be compatible with that binary. network that is guaranteed to be compatible with that binary.
2) to use the NNUE evaluation, the additional data file with neural network parameters 2) to use the NNUE evaluation, the additional data file with neural network parameters
@@ -251,8 +259,8 @@ are already enabled, and no configuration is needed.
### Support on Windows ### Support on Windows
The use of large pages requires "Lock Pages in Memory" privilege. See The use of large pages requires "Lock Pages in Memory" privilege. See
[Enable the Lock Pages in Memory Option (Windows)](https://docs.microsoft.com/en-us/sql/database-engine/configure-windows/enable-the-lock-pages-in-memory-option-windows) [Enable the Lock Pages in Memory Option (Windows)][lockpages-link]
on how to enable this privilege, then run [RAMMap](https://docs.microsoft.com/en-us/sysinternals/downloads/rammap) on how to enable this privilege, then run [RAMMap][rammap-link]
to double-check that large pages are used. We suggest that you reboot to double-check that large pages are used. We suggest that you reboot
your computer after you have enabled large pages, because long Windows your computer after you have enabled large pages, because long Windows
sessions suffer from memory fragmentation, which may prevent Stockfish sessions suffer from memory fragmentation, which may prevent Stockfish
@@ -295,26 +303,26 @@ effort. There are a few ways to help contribute to its growth.
### Donating hardware ### Donating hardware
Improving Stockfish requires a massive amount of testing. You can donate Improving Stockfish requires a massive amount of testing. You can donate
your hardware resources by installing the [Fishtest Worker](https://github.com/glinscott/fishtest/wiki/Running-the-worker:-overview) your hardware resources by installing the [Fishtest Worker][worker-link]
and view the current tests on [Fishtest](https://tests.stockfishchess.org/tests). and view the current tests on [Fishtest][fishtest-link].
### Improving the code ### Improving the code
If you want to help improve the code, there are several valuable resources: If you want to help improve the code, there are several valuable resources:
* [In this wiki,](https://www.chessprogramming.org) many techniques used in * [In this wiki,][programming-link] many techniques used in
Stockfish are explained with a lot of background information. Stockfish are explained with a lot of background information.
* [The section on Stockfish](https://www.chessprogramming.org/Stockfish) * [The section on Stockfish][programmingsf-link]
describes many features and techniques used by Stockfish. However, it is describes many features and techniques used by Stockfish. However, it is
generic rather than being focused on Stockfish's precise implementation. generic rather than being focused on Stockfish's precise implementation.
Nevertheless, a helpful resource. Nevertheless, a helpful resource.
* The latest source can always be found on [GitHub](https://github.com/official-stockfish/Stockfish). * The latest source can always be found on [GitHub][github-link].
Discussions about Stockfish take place these days mainly in the [FishCooking](https://groups.google.com/forum/#!forum/fishcooking) Discussions about Stockfish take place these days mainly in the [FishCooking][fishcooking-link]
group and on the [Stockfish Discord channel](https://discord.gg/nv8gDtt). group and on the [Stockfish Discord channel][discord-link].
The engine testing is done on [Fishtest](https://tests.stockfishchess.org/tests). The engine testing is done on [Fishtest][fishtest-link].
If you want to help improve Stockfish, please read this [guideline](https://github.com/glinscott/fishtest/wiki/Creating-my-first-test) If you want to help improve Stockfish, please read this [guideline][guideline-link]
first, where the basics of Stockfish development are explained. first, where the basics of Stockfish development are explained.
@@ -329,9 +337,42 @@ using it as the starting point for a software project of your own.
The only real limitation is that whenever you distribute Stockfish in The only real limitation is that whenever you distribute Stockfish in
some way, you MUST always include the license and the full source code some way, you MUST always include the license and the full source code
(or a pointer to where the source code can be found) to generate the (or a pointer to where the source code can be found) to generate the
exact binary you are distributing. If you make any changes to the exact binary you are distributing. If you make any changes to the
source code, these changes must also be made available under the GPL v3. source code, these changes must also be made available under the GPL v3.
For full details, read the copy of the GPL v3 found in the file named For full details, read the copy of the GPL v3 found in the file named
[*Copying.txt*](https://github.com/official-stockfish/Stockfish/blob/master/Copying.txt). [*Copying.txt*][license-link].
[authors-link]: https://github.com/official-stockfish/Stockfish/blob/master/AUTHORS
[build-link]: https://github.com/official-stockfish/Stockfish/actions/workflows/stockfish.yml
[commits-link]: https://github.com/official-stockfish/Stockfish/commits/master
[discord-link]: https://discord.gg/GWDRS3kU6R
[fishcooking-link]: https://groups.google.com/g/fishcooking
[fishtest-link]: https://tests.stockfishchess.org/tests
[github-link]: https://github.com/official-stockfish/Stockfish
[guideline-link]: https://github.com/glinscott/fishtest/wiki/Creating-my-first-test
[license-link]: https://github.com/official-stockfish/Stockfish/blob/master/Copying.txt
[lockpages-link]: https://docs.microsoft.com/en-us/sql/database-engine/configure-windows/enable-the-lock-pages-in-memory-option-windows
[nodchip-link]: https://github.com/nodchip/Stockfish
[programming-link]: https://www.chessprogramming.org/Main_Page
[programmingsf-link]: https://www.chessprogramming.org/Stockfish
[pytorch-link]: https://github.com/glinscott/nnue-pytorch
[rammap-link]: https://docs.microsoft.com/en-us/sysinternals/downloads/rammap
[readme-link]: https://github.com/official-stockfish/Stockfish/blob/master/README.md
[release-link]: https://github.com/official-stockfish/Stockfish/releases/latest
[src-link]: https://github.com/official-stockfish/Stockfish/tree/master/src
[stockfish128-logo]: https://stockfishchess.org/images/logo/icon_128x128.png
[tools-link]: https://github.com/official-stockfish/Stockfish/tree/tools
[uci-link]: https://www.shredderchess.com/download/div/uci.zip
[website-link]: https://stockfishchess.org
[worker-link]: https://github.com/glinscott/fishtest/wiki/Running-the-worker:-overview
[build-badge]: https://img.shields.io/github/workflow/status/official-stockfish/Stockfish/Stockfish?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
[discord-badge]: https://img.shields.io/discord/435943710472011776?style=for-the-badge&label=discord&logo=Discord
[fishtest-badge]: https://img.shields.io/website?style=for-the-badge&down_color=red&down_message=Offline&label=Fishtest&up_color=success&up_message=Online&url=https%3A%2F%2Ftests.stockfishchess.org%2Ftests%2Ffinished
[license-badge]: https://img.shields.io/github/license/official-stockfish/Stockfish?style=for-the-badge&label=license&color=success
[release-badge]: https://img.shields.io/github/v/release/official-stockfish/Stockfish?style=for-the-badge&label=official%20release
[website-badge]: https://img.shields.io/website?style=for-the-badge&down_color=red&down_message=Offline&label=website&up_color=success&up_message=Online&url=https%3A%2F%2Fstockfishchess.org
+121 -96
View File
@@ -1,235 +1,260 @@
Contributors to Fishtest with >10,000 CPU hours, as of 2022-04-14. Contributors to Fishtest with >10,000 CPU hours, as of 2022-11-19.
Thank you! Thank you!
Username CPU Hours Games played Username CPU Hours Games played
------------------------------------------------------------------ ------------------------------------------------------------------
noobpwnftw 31714850 2267266129 noobpwnftw 36475307 2748033975
mlang 2954099 198421098 technologov 14570711 760073590
technologov 2324150 102449398 mlang 3026000 200065824
dew 1670874 99276012 dew 1689222 100034318
grandphish2 1134273 68070459 grandphish2 1442171 86798057
okrout 901194 77738874 okrout 1439985 133471766
TueRens 821388 50207666 pemo 1405374 44189811
tvijlbrief 795993 51894442 linrock 1299003 28382783
pemo 744463 32486677 TueRens 1163420 71159522
JojoM 724378 43660674 JojoM 897158 55177114
tvijlbrief 796125 51897690
mibere 703840 46867607 mibere 703840 46867607
linrock 626939 17408017 gvreuls 635982 40652394
gvreuls 534079 34352532 oz 590763 41201352
cw 507221 34006775 sebastronomy 581517 23307132
fastgm 489749 29344518 cw 517915 34865769
fastgm 504266 30264740
CSU_Dynasty 479901 31846710
ctoks 433503 28180725
crunchy 427035 27344275 crunchy 427035 27344275
CSU_Dynasty 424643 28525220 leszek 416883 27493447
ctoks 415771 27364603 bcross 409982 28062127
oz 369200 27017658 velislav 345954 22232274
bcross 342642 23671289
Fisherman 327231 21829379 Fisherman 327231 21829379
velislav 325670 20911076 Dantist 296386 18031762
leszek 321295 19874113 mgrabiak 288928 18869896
Dantist 274747 16910258 rpngn 259965 16281463
mgrabiak 237604 15418700 robal 237653 15148350
robal 217959 13840386 ncfish1 231764 15275003
glinscott 217799 13780820 nordlandia 226923 14624832
nordlandia 211692 13484886 glinscott 208125 13277240
drabel 201967 13798360 drabel 204167 13930674
mhoram 202894 12601997
bking_US 198894 11876016 bking_US 198894 11876016
mhoram 194862 12261809 thirdlife 198844 5453268
Thanar 179852 12365359 Thanar 179852 12365359
vdv 175544 9904472 vdv 175544 9904472
armo9494 168201 11136452
spams 157128 10319326 spams 157128 10319326
rpngn 154081 9652139 marrco 151599 9551115
marrco 150300 9402229
sqrt2 147963 9724586 sqrt2 147963 9724586
vdbergh 137430 8955097 vdbergh 137690 8971569
CoffeeOne 137100 5024116 CoffeeOne 137100 5024116
malala 136182 8002293 malala 136182 8002293
DesolatedDodo 135276 8657464
xoto 133759 9159372 xoto 133759 9159372
davar 125240 8117121 davar 129023 8376525
dsmith 122059 7570238 dsmith 122059 7570238
amicic 119659 7937885 amicic 119661 7938029
Data 113305 8220352 Data 113305 8220352
BrunoBanani 112960 7436849 BrunoBanani 112960 7436849
CypressChess 108321 7759588 CypressChess 108331 7759788
DesolatedDodo 106811 6776980 skiminki 106518 7062598
MaZePallas 102823 6633619 MaZePallas 102823 6633619
sterni1971 100532 5880772 sterni1971 100532 5880772
sunu 100167 7040199 sunu 100167 7040199
zeryl 99331 6221261
ElbertoOne 99028 7023771 ElbertoOne 99028 7023771
skiminki 98123 6478402 DMBK 97572 6950312
Calis007 96779 5611552
cuistot 93111 5536500
brabos 92118 6186135 brabos 92118 6186135
cuistot 90358 5351004 Wolfgang 91769 5720158
psk 89957 5984901 psk 89957 5984901
racerschmacer 85712 6119648 racerschmacer 85805 6122790
jcAEie 85527 5630616
Vizvezdenec 83761 5344740 Vizvezdenec 83761 5344740
zeryl 83680 5250995 sschnee 83557 4853690
sschnee 83003 4840890
0x3C33 82614 5271253 0x3C33 82614 5271253
BRAVONE 81239 5054681 BRAVONE 81239 5054681
Dubslow 78461 5042980
nssy 76497 5259388 nssy 76497 5259388
jromang 76106 5236025
teddybaer 75125 5407666 teddybaer 75125 5407666
jromang 74796 5175825 yurikvelo 73933 5031096
tolkki963 73885 4721430
Pking_cda 73776 5293873 Pking_cda 73776 5293873
Calis007 72477 4088576 Bobo1239 71675 4860987
solarlight 70517 5028306 solarlight 70517 5028306
dv8silencer 70287 3883992 dv8silencer 70287 3883992
Bobo1239 68515 4652287 Gelma 69304 3980932
manap 66273 4121774 manap 66273 4121774
yurikvelo 65716 4457300 megaman7de 65419 4120200
markkulix 65331 4114860
bigpen0r 64932 4683883
tinker 64333 4268790 tinker 64333 4268790
Wolfgang 62644 3817410
qurashee 61208 3429862 qurashee 61208 3429862
AGI 58325 4258646
robnjr 57262 4053117 robnjr 57262 4053117
Freja 56938 3733019 Freja 56938 3733019
MaxKlaxxMiner 56879 3423958
ttruscott 56010 3680085 ttruscott 56010 3680085
rkl 55132 4164467 rkl 55132 4164467
renouve 53811 3501516 renouve 53811 3501516
megaman7de 52434 3243016 Spprtr 52736 3410019
MaxKlaxxMiner 51977 3153032
finfish 51360 3370515 finfish 51360 3370515
eva42 51272 3599691 eva42 51272 3599691
eastorwest 51058 3451555 eastorwest 51117 3454811
rap 49985 3219146 rap 49985 3219146
unixwizard 49734 2536230
pb00067 49727 3298270 pb00067 49727 3298270
Spprtr 48920 3161711
bigpen0r 47667 3336927
ronaldjerum 47654 3240695 ronaldjerum 47654 3240695
biffhero 46564 3111352 biffhero 46564 3111352
GPUex 45861 2926502
Fifis 45843 3088497 Fifis 45843 3088497
oryx 45578 3493978
VoyagerOne 45476 3452465 VoyagerOne 45476 3452465
Wencey 44943 2654490
speedycpu 43842 3003273 speedycpu 43842 3003273
jbwiebe 43305 2805433 jbwiebe 43305 2805433
Antihistamine 41788 2761312 Antihistamine 41788 2761312
mhunt 41735 2691355 mhunt 41735 2691355
olafm 41277 3284344
homyur 39893 2850481 homyur 39893 2850481
gri 39871 2515779 gri 39871 2515779
armo9494 39064 2832326 MarcusTullius 38303 2251097
oryx 38867 2976992 Garf 37741 2999686
kdave 37424 2557406
SC 37299 2731694 SC 37299 2731694
Garf 37213 2986270
tolkki963 37059 2154330
csnodgrass 36207 2688994 csnodgrass 36207 2688994
jmdana 36157 2210661 jmdana 36157 2210661
strelock 34716 2074055 strelock 34716 2074055
DMBK 34010 2482916
EthanOConnor 33370 2090311 EthanOConnor 33370 2090311
slakovv 32915 2021889 slakovv 32915 2021889
gopeto 30993 2028106 gopeto 31669 2060958
manapbk 30987 1810399 manapbk 30987 1810399
Prcuvu 30377 2170122 Prcuvu 30377 2170122
anst 30301 2190091 anst 30301 2190091
jkiiski 30136 1904470 jkiiski 30136 1904470
spcc 30135 1903728
hyperbolic.tom 29840 2017394 hyperbolic.tom 29840 2017394
xwziegtm 29763 2347412
chuckstablers 29659 2093438 chuckstablers 29659 2093438
Pyafue 29650 1902349 Pyafue 29650 1902349
ncfish1 29105 1704011 belzedar94 28846 1811530
belzedar94 27935 1789106
OuaisBla 27636 1578800 OuaisBla 27636 1578800
chriswk 26902 1868317 chriswk 26902 1868317
achambord 26582 1767323 achambord 26582 1767323
Patrick_G 26276 1801617 Patrick_G 26276 1801617
yorkman 26193 1992080 yorkman 26193 1992080
Ulysses 25289 1674274
SFTUser 25182 1675689 SFTUser 25182 1675689
nabildanial 24942 1519409 nabildanial 24942 1519409
Sharaf_DG 24765 1786697 Sharaf_DG 24765 1786697
rodneyc 24275 1410450 rodneyc 24376 1416402
agg177 23890 1395014 agg177 23890 1395014
Ente 23747 1674582
Karpovbot 23629 1313186
JanErik 23408 1703875 JanErik 23408 1703875
Isidor 23388 1680691 Isidor 23388 1680691
Norabor 23339 1602636 Norabor 23371 1603244
Ente 23270 1651432 cisco2015 22934 1763773
cisco2015 22897 1762669
MarcusTullius 22688 1274821
Zirie 22542 1472937 Zirie 22542 1472937
team-oh 22272 1636708 team-oh 22272 1636708
Roady 22220 1465606
MazeOfGalious 21978 1629593 MazeOfGalious 21978 1629593
sg4032 21947 1643265 sg4032 21947 1643353
ianh2105 21725 1632562 ianh2105 21725 1632562
xor12 21628 1680365 xor12 21628 1680365
dex 21612 1467203 dex 21612 1467203
nesoneg 21494 1463031 nesoneg 21494 1463031
Roady 21323 1433822 user213718 21454 1404128
AndreasKrug 21227 1577833
sphinx 21211 1384728 sphinx 21211 1384728
user213718 21196 1397710
spcc 21065 1311338
jjoshua2 21001 1423089 jjoshua2 21001 1423089
horst.prack 20878 1465656 horst.prack 20878 1465656
jsys14 20729 1221010
0xB00B1ES 20590 1208666 0xB00B1ES 20590 1208666
j3corre 20405 941444 j3corre 20405 941444
kdave 20364 1389254
Adrian.Schmidt123 20316 1281436 Adrian.Schmidt123 20316 1281436
Ulysses 20217 1351500 bonsi 20022 1300682
markkulix 19976 1115258
wei 19973 1745989 wei 19973 1745989
dapper 19754 1167758
Zake9298 19745 1458416
fishtester 19617 1257388
rstoesser 19569 1293588 rstoesser 19569 1293588
eudhan 19274 1283717 eudhan 19274 1283717
fishtester 18995 1238686
vulcan 18871 1729392 vulcan 18871 1729392
Jopo12321 18803 1036284
jundery 18445 1115855 jundery 18445 1115855
iisiraider 18247 1101015
ville 17883 1384026 ville 17883 1384026
5t0ckf15hTr4in3r 17809 1105858
chris 17698 1487385 chris 17698 1487385
dju 17697 994333
purplefishies 17595 1092533 purplefishies 17595 1092533
dju 17353 978595 iisiraider 17275 1049015
Wencey 17125 805964
DragonLord 17014 1162790 DragonLord 17014 1162790
thirdlife 16996 447356 Karby 16457 1010138
Goatminola 16278 1145026
IgorLeMasson 16064 1147232 IgorLeMasson 16064 1147232
Gaster319 16056 1109070
redstone59 15953 1161664
scuzzi 15757 968735
ako027ako 15671 1173203 ako027ako 15671 1173203
AndreasKrug 15550 1194497
Nikolay.IT 15154 1068349 Nikolay.IT 15154 1068349
Andrew Grant 15114 895539 Andrew Grant 15114 895539
scuzzi 14928 953313 Naven94 15054 834762
OssumOpossum 14857 1007129 OssumOpossum 14857 1007129
Karby 14808 867120 qoo_charly_cai 14490 847865
jsys14 14652 855642
enedene 14476 905279 enedene 14476 905279
bpfliegel 14298 884523 szupaw 14252 929130
bpfliegel 14233 882523
mpx86 14019 759568 mpx86 14019 759568
jpulman 13982 870599 jpulman 13982 870599
crocogoat 13803 1117422 crocogoat 13803 1117422
joster 13794 950160
Nesa92 13786 1114691 Nesa92 13786 1114691
joster 13710 946160
mbeier 13650 1044928 mbeier 13650 1044928
Hjax 13535 915487 Hjax 13535 915487
Dark_wizzie 13422 1007152 Dark_wizzie 13422 1007152
Jopo12321 13367 678852
Rudolphous 13244 883140 Rudolphous 13244 883140
Machariel 13010 863104 Machariel 13010 863104
infinigon 12991 943216
pirt 12925 985437
Skiff84 12923 649994
mabichito 12903 749391 mabichito 12903 749391
thijsk 12886 722107 thijsk 12886 722107
AdrianSA 12860 804972 AdrianSA 12860 804972
infinigon 12807 937332
Flopzee 12698 894821 Flopzee 12698 894821
fatmurphy 12547 853210 fatmurphy 12547 853210
woutboat 12419 836696
SapphireBrand 12416 969604 SapphireBrand 12416 969604
Oakwen 12406 840961
deflectooor 12386 579392
modolief 12386 896470 modolief 12386 896470
Farseer 12249 694108 Farseer 12249 694108
pgontarz 12151 848794 pgontarz 12151 848794
pirt 12008 923149
stocky 11954 699440 stocky 11954 699440
mschmidt 11941 803401 mschmidt 11941 803401
dbernier 11609 818636 MooTheCow 11871 773654
Jackfish 11867 773550
dbernier 11705 821780
whelanh 11557 245188
Maxim 11543 836024 Maxim 11543 836024
Nullvalue 11534 731410
icewulf 11528 650470
FormazChar 11523 861599
infinity 11470 727027 infinity 11470 727027
aga 11409 695071 aga 11412 695127
torbjo 11395 729145 torbjo 11395 729145
Thomas A. Anderson 11372 732094 Thomas A. Anderson 11372 732094
savage84 11358 670860 savage84 11358 670860
FormazChar 11349 850327 ali-al-zhrani 11272 781310
d64 11263 789184 d64 11263 789184
MooTheCow 11237 720174 Bourbaki 11108 709144
snicolet 11106 869170 snicolet 11106 869170
ali-al-zhrani 11098 768494 Alb11747 10855 696920
whelanh 11067 235676
Jackfish 10978 720078
deflectooor 10886 520116
basepi 10637 744851 basepi 10637 744851
Cubox 10621 826448 Cubox 10621 826448
Karmatron 10616 674818
michaelrpg 10509 739239 michaelrpg 10509 739239
OIVAS7572 10420 995586 OIVAS7572 10420 995586
Garruk 10348 704905
dzjp 10343 732529 dzjp 10343 732529
Garruk 10334 704065
ols 10259 570669 ols 10259 570669
lbraesch 10252 647825
qoo_charly_cai 10212 620407
Naven94 10069 503192
+81 -40
View File
@@ -116,7 +116,7 @@ ifeq ($(ARCH), $(filter $(ARCH), \
x86-64-vnni512 x86-64-vnni256 x86-64-avx512 x86-64-avxvnni x86-64-bmi2 \ 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-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 \ x86-64 x86-32-sse41-popcnt x86-32-sse2 x86-32 ppc-64 ppc-32 e2k \
armv7 armv7-neon armv8 apple-silicon general-64 general-32)) armv7 armv7-neon armv8 apple-silicon general-64 general-32 riscv64))
SUPPORTED_ARCH=true SUPPORTED_ARCH=true
else else
SUPPORTED_ARCH=false SUPPORTED_ARCH=false
@@ -338,16 +338,26 @@ ifeq ($(findstring e2k,$(ARCH)),e2k)
popcnt = yes popcnt = yes
endif endif
ifeq ($(ARCH),riscv64)
arch = riscv64
endif endif
endif
### ========================================================================== ### ==========================================================================
### Section 3. Low-level Configuration ### Section 3. Low-level Configuration
### ========================================================================== ### ==========================================================================
### 3.1 Selecting compiler (default = gcc) ### 3.1 Selecting compiler (default = gcc)
CXXFLAGS += -Wall -Wcast-qual -fno-exceptions -std=c++17 $(EXTRACXXFLAGS) ifeq ($(MAKELEVEL),0)
DEPENDFLAGS += -std=c++17 export ENV_CXXFLAGS := $(CXXFLAGS)
LDFLAGS += $(EXTRALDFLAGS) export ENV_DEPENDFLAGS := $(DEPENDFLAGS)
export ENV_LDFLAGS := $(LDFLAGS)
endif
CXXFLAGS = $(ENV_CXXFLAGS) -Wall -Wcast-qual -fno-exceptions -std=c++17 $(EXTRACXXFLAGS)
DEPENDFLAGS = $(ENV_DEPENDFLAGS) -std=c++17
LDFLAGS = $(ENV_LDFLAGS) $(EXTRALDFLAGS)
ifeq ($(COMP),) ifeq ($(COMP),)
COMP=gcc COMP=gcc
@@ -358,11 +368,14 @@ ifeq ($(COMP),gcc)
CXX=g++ CXX=g++
CXXFLAGS += -pedantic -Wextra -Wshadow CXXFLAGS += -pedantic -Wextra -Wshadow
ifeq ($(arch),$(filter $(arch),armv7 armv8)) ifeq ($(arch),$(filter $(arch),armv7 armv8 riscv64))
ifeq ($(OS),Android) ifeq ($(OS),Android)
CXXFLAGS += -m$(bits) CXXFLAGS += -m$(bits)
LDFLAGS += -m$(bits) LDFLAGS += -m$(bits)
endif endif
ifeq ($(ARCH),riscv64)
CXXFLAGS += -latomic
endif
else else
CXXFLAGS += -m$(bits) CXXFLAGS += -m$(bits)
LDFLAGS += -m$(bits) LDFLAGS += -m$(bits)
@@ -423,11 +436,14 @@ ifeq ($(COMP),clang)
endif endif
endif endif
ifeq ($(arch),$(filter $(arch),armv7 armv8)) ifeq ($(arch),$(filter $(arch),armv7 armv8 riscv64))
ifeq ($(OS),Android) ifeq ($(OS),Android)
CXXFLAGS += -m$(bits) CXXFLAGS += -m$(bits)
LDFLAGS += -m$(bits) LDFLAGS += -m$(bits)
endif endif
ifeq ($(ARCH),riscv64)
CXXFLAGS += -latomic
endif
else else
CXXFLAGS += -m$(bits) CXXFLAGS += -m$(bits)
LDFLAGS += -m$(bits) LDFLAGS += -m$(bits)
@@ -542,17 +558,17 @@ ifeq ($(optimize),yes)
endif endif
endif endif
ifeq ($(KERNEL),Darwin) ifeq ($(KERNEL),Darwin)
ifeq ($(comp),$(filter $(comp),clang icc)) ifeq ($(comp),$(filter $(comp),clang icc))
CXXFLAGS += -mdynamic-no-pic CXXFLAGS += -mdynamic-no-pic
endif endif
ifeq ($(comp),gcc) ifeq ($(comp),gcc)
ifneq ($(arch),arm64) ifneq ($(arch),arm64)
CXXFLAGS += -mdynamic-no-pic CXXFLAGS += -mdynamic-no-pic
endif endif
endif endif
endif endif
ifeq ($(comp),clang) ifeq ($(comp),clang)
CXXFLAGS += -fexperimental-new-pass-manager CXXFLAGS += -fexperimental-new-pass-manager
@@ -587,7 +603,7 @@ endif
ifeq ($(avx2),yes) ifeq ($(avx2),yes)
CXXFLAGS += -DUSE_AVX2 CXXFLAGS += -DUSE_AVX2
ifeq ($(comp),$(filter $(comp),gcc clang mingw)) ifeq ($(comp),$(filter $(comp),gcc clang mingw))
CXXFLAGS += -mavx2 CXXFLAGS += -mavx2 -mbmi
endif endif
endif endif
@@ -666,13 +682,25 @@ ifeq ($(pext),yes)
endif endif
endif endif
### 3.7.1 Try to include git commit sha for versioning
GIT_SHA = $(shell git rev-parse --short HEAD 2>/dev/null)
ifneq ($(GIT_SHA), )
CXXFLAGS += -DGIT_SHA=\"$(GIT_SHA)\"
endif
### 3.7.2 Try to include git commit date for versioning
GIT_DATE = $(shell git show -s --date=format:'%Y%m%d' --format=%cd HEAD 2>/dev/null)
ifneq ($(GIT_DATE), )
CXXFLAGS += -DGIT_DATE=\"$(GIT_DATE)\"
endif
### 3.8 Link Time Optimization ### 3.8 Link Time Optimization
### This is a mix of compile and link time options because the lto link phase ### This is a mix of compile and link time options because the lto link phase
### needs access to the optimization flags. ### needs access to the optimization flags.
ifeq ($(optimize),yes) ifeq ($(optimize),yes)
ifeq ($(debug), no) ifeq ($(debug), no)
ifeq ($(comp),clang) ifeq ($(comp),clang)
CXXFLAGS += -flto CXXFLAGS += -flto=full
ifeq ($(target_windows),yes) ifeq ($(target_windows),yes)
CXXFLAGS += -fuse-ld=lld CXXFLAGS += -fuse-ld=lld
endif endif
@@ -682,21 +710,19 @@ ifeq ($(debug), no)
# GCC on some systems. # GCC on some systems.
else ifeq ($(comp),gcc) else ifeq ($(comp),gcc)
ifeq ($(gccisclang),) ifeq ($(gccisclang),)
CXXFLAGS += -flto CXXFLAGS += -flto -flto-partition=one
LDFLAGS += $(CXXFLAGS) -flto=jobserver LDFLAGS += $(CXXFLAGS) -flto=jobserver
else else
CXXFLAGS += -flto CXXFLAGS += -flto=full
LDFLAGS += $(CXXFLAGS) LDFLAGS += $(CXXFLAGS)
endif endif
# To use LTO and static linking on Windows, # To use LTO and static linking on Windows,
# the tool chain requires gcc version 10.1 or later. # the tool chain requires gcc version 10.1 or later.
else ifeq ($(comp),mingw) else ifeq ($(comp),mingw)
ifneq ($(arch),i386) CXXFLAGS += -flto -flto-partition=one
CXXFLAGS += -flto
LDFLAGS += $(CXXFLAGS) -save-temps LDFLAGS += $(CXXFLAGS) -save-temps
endif endif
endif
endif endif
endif endif
@@ -753,6 +779,7 @@ help:
@echo "apple-silicon > Apple silicon ARM64" @echo "apple-silicon > Apple silicon ARM64"
@echo "general-64 > unspecified 64-bit" @echo "general-64 > unspecified 64-bit"
@echo "general-32 > unspecified 32-bit" @echo "general-32 > unspecified 32-bit"
@echo "riscv64 > RISC-V 64-bit"
@echo "" @echo ""
@echo "Supported compilers:" @echo "Supported compilers:"
@echo "" @echo ""
@@ -785,7 +812,7 @@ endif
.PHONY: help build profile-build strip install clean net objclean profileclean \ .PHONY: help build profile-build strip install clean net objclean profileclean \
config-sanity icc-profile-use icc-profile-make gcc-profile-use gcc-profile-make \ config-sanity icc-profile-use icc-profile-make gcc-profile-use gcc-profile-make \
clang-profile-use clang-profile-make clang-profile-use clang-profile-make FORCE
build: net config-sanity build: net config-sanity
$(MAKE) ARCH=$(ARCH) COMP=$(COMP) all $(MAKE) ARCH=$(ARCH) COMP=$(COMP) all
@@ -821,25 +848,35 @@ clean: objclean profileclean
net: net:
$(eval nnuenet := $(shell grep EvalFileDefaultName evaluate.h | grep define | sed 's/.*\(nn-[a-z0-9]\{12\}.nnue\).*/\1/')) $(eval nnuenet := $(shell grep EvalFileDefaultName evaluate.h | grep define | sed 's/.*\(nn-[a-z0-9]\{12\}.nnue\).*/\1/'))
@echo "Default net: $(nnuenet)" @echo "Default net: $(nnuenet)"
$(eval nnuedownloadurl := https://tests.stockfishchess.org/api/nn/$(nnuenet)) $(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 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))
@if test -f "$(nnuenet)"; then \ @if [ "x$(curl_or_wget)" = "x" ]; then \
echo "Already available."; \ echo "Automatic download failed: neither curl nor wget is installed. Install one of these tools or download the net manually"; exit 1; \
else \ fi
if [ "x$(curl_or_wget)" = "x" ]; then \
echo "Automatic download failed: neither curl nor wget is installed. Install one of these tools or download the net manually"; exit 1; \
else \
echo "Downloading $(nnuedownloadurl)"; $(curl_or_wget) $(nnuedownloadurl) > $(nnuenet);\
fi; \
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)) $(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))
@if [ "x$(shasum_command)" != "x" ]; then \ @if [ "x$(shasum_command)" = "x" ]; then \
if [ "$(nnuenet)" != "nn-"`$(shasum_command) $(nnuenet) | cut -c1-12`".nnue" ]; then \
echo "Failed download or $(nnuenet) corrupted, please delete!"; exit 1; \
fi \
else \
echo "shasum / sha256sum not found, skipping net validation"; \ echo "shasum / sha256sum not found, skipping net validation"; \
fi fi
@for nnuedownloadurl in "$(nnuedownloadurl1)" "$(nnuedownloadurl2)"; do \
if test -f "$(nnuenet)"; then \
echo "$(nnuenet) available."; \
else \
if [ "x$(curl_or_wget)" != "x" ]; then \
echo "Downloading $${nnuedownloadurl}"; $(curl_or_wget) $${nnuedownloadurl} > $(nnuenet);\
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); \
else \
echo "Network validated"; break; \
fi; \
fi; \
done
@if ! test -f "$(nnuenet)"; then \
echo "Failed to download $(nnuenet)."; \
fi
# clean binaries and objects # clean binaries and objects
objclean: objclean:
@@ -902,7 +939,7 @@ config-sanity: net
@test "$(SUPPORTED_ARCH)" = "true" @test "$(SUPPORTED_ARCH)" = "true"
@test "$(arch)" = "any" || test "$(arch)" = "x86_64" || test "$(arch)" = "i386" || \ @test "$(arch)" = "any" || test "$(arch)" = "x86_64" || test "$(arch)" = "i386" || \
test "$(arch)" = "ppc64" || test "$(arch)" = "ppc" || test "$(arch)" = "e2k" || \ test "$(arch)" = "ppc64" || test "$(arch)" = "ppc" || test "$(arch)" = "e2k" || \
test "$(arch)" = "armv7" || test "$(arch)" = "armv8" || test "$(arch)" = "arm64" test "$(arch)" = "armv7" || test "$(arch)" = "armv8" || test "$(arch)" = "arm64" || test "$(arch)" = "riscv64"
@test "$(bits)" = "32" || test "$(bits)" = "64" @test "$(bits)" = "32" || test "$(bits)" = "64"
@test "$(prefetch)" = "yes" || test "$(prefetch)" = "no" @test "$(prefetch)" = "yes" || test "$(prefetch)" = "no"
@test "$(popcnt)" = "yes" || test "$(popcnt)" = "no" @test "$(popcnt)" = "yes" || test "$(popcnt)" = "no"
@@ -923,6 +960,10 @@ config-sanity: net
$(EXE): $(OBJS) $(EXE): $(OBJS)
+$(CXX) -o $@ $(OBJS) $(LDFLAGS) +$(CXX) -o $@ $(OBJS) $(LDFLAGS)
# Force recompilation to ensure version info is up-to-date
misc.o: FORCE
FORCE:
clang-profile-make: clang-profile-make:
$(MAKE) ARCH=$(ARCH) COMP=$(COMP) \ $(MAKE) ARCH=$(ARCH) COMP=$(COMP) \
EXTRACXXFLAGS='-fprofile-instr-generate ' \ EXTRACXXFLAGS='-fprofile-instr-generate ' \
+33 -59
View File
@@ -159,7 +159,7 @@ namespace Trace {
Score scores[TERM_NB][COLOR_NB]; Score scores[TERM_NB][COLOR_NB];
double to_cp(Value v) { return double(v) / PawnValueEg; } double to_cp(Value v) { return double(v) / UCI::NormalizeToPawnValue; }
void add(int idx, Color c, Score s) { void add(int idx, Color c, Score s) {
scores[idx][c] = s; scores[idx][c] = s;
@@ -981,7 +981,7 @@ namespace {
// Initialize score by reading the incrementally updated scores included in // Initialize score by reading the incrementally updated scores included in
// the position object (material + piece square tables) and the material // the position object (material + piece square tables) and the material
// imbalance. Score is computed internally from the white point of view. // imbalance. Score is computed internally from the white point of view.
Score score = pos.psq_score() + me->imbalance() + pos.this_thread()->trend; Score score = pos.psq_score() + me->imbalance();
// Probe the pawn hash table // Probe the pawn hash table
pe = Pawns::probe(pos); pe = Pawns::probe(pos);
@@ -1042,74 +1042,46 @@ make_v:
return v; return v;
} }
/// Fisher Random Chess: correction for cornered bishops, to fix chess960 play with NNUE
Value fix_FRC(const Position& pos) {
constexpr Bitboard Corners = 1ULL << SQ_A1 | 1ULL << SQ_H1 | 1ULL << SQ_A8 | 1ULL << SQ_H8;
if (!(pos.pieces(BISHOP) & Corners))
return VALUE_ZERO;
int correction = 0;
if ( pos.piece_on(SQ_A1) == W_BISHOP
&& pos.piece_on(SQ_B2) == W_PAWN)
correction -= CorneredBishop;
if ( pos.piece_on(SQ_H1) == W_BISHOP
&& pos.piece_on(SQ_G2) == W_PAWN)
correction -= CorneredBishop;
if ( pos.piece_on(SQ_A8) == B_BISHOP
&& pos.piece_on(SQ_B7) == B_PAWN)
correction += CorneredBishop;
if ( pos.piece_on(SQ_H8) == B_BISHOP
&& pos.piece_on(SQ_G7) == B_PAWN)
correction += CorneredBishop;
return pos.side_to_move() == WHITE ? Value(3 * correction)
: -Value(3 * correction);
}
} // namespace Eval } // namespace Eval
/// evaluate() is the evaluator for the outer world. It returns a static /// evaluate() is the evaluator for the outer world. It returns a static
/// evaluation of the position from the point of view of the side to move. /// evaluation of the position from the point of view of the side to move.
Value Eval::evaluate(const Position& pos) { Value Eval::evaluate(const Position& pos, int* complexity) {
Value v; Value v;
bool useClassical = false; Value psq = pos.psq_eg_stm();
// Deciding between classical and NNUE eval (~10 Elo): for high PSQ imbalance we use classical, // We use the much less accurate but faster Classical eval when the NNUE
// but we switch to NNUE during long shuffling or with high material on the board. // option is set to false. Otherwise we use the NNUE eval unless the
if ( !useNNUE // PSQ advantage is decisive and several pieces remain. (~3 Elo)
|| ((pos.this_thread()->depth > 9 || pos.count<ALL_PIECES>() > 7) && bool useClassical = !useNNUE || (pos.count<ALL_PIECES>() > 7 && abs(psq) > 1760);
abs(eg_value(pos.psq_score())) * 5 > (856 + pos.non_pawn_material() / 64) * (10 + pos.rule50_count())))
if (useClassical)
v = Evaluation<NO_TRACE>(pos).value();
else
{ {
v = Evaluation<NO_TRACE>(pos).value(); // classical int nnueComplexity;
useClassical = abs(v) >= 297; int scale = 1064 + 106 * pos.non_pawn_material() / 5120;
}
// If result of a classical evaluation is much lower than threshold fall back to NNUE Color stm = pos.side_to_move();
if (useNNUE && !useClassical) Value optimism = pos.this_thread()->optimism[stm];
{
Value nnue = NNUE::evaluate(pos, true); // NNUE
int scale = 1036 + 22 * pos.non_pawn_material() / 1024;
Color stm = pos.side_to_move();
Value optimism = pos.this_thread()->optimism[stm];
Value psq = (stm == WHITE ? 1 : -1) * eg_value(pos.psq_score());
int complexity = 35 * abs(nnue - psq) / 256;
optimism = optimism * (44 + complexity) / 31; Value nnue = NNUE::evaluate(pos, true, &nnueComplexity);
v = (nnue + optimism) * scale / 1024 - optimism;
if (pos.is_chess960()) // Blend nnue complexity with (semi)classical complexity
v += fix_FRC(pos); nnueComplexity = ( 416 * nnueComplexity
+ 424 * abs(psq - nnue)
+ (optimism > 0 ? int(optimism) * int(psq - nnue) : 0)
) / 1024;
// Return hybrid NNUE complexity to caller
if (complexity)
*complexity = nnueComplexity;
optimism = optimism * (269 + nnueComplexity) / 256;
v = (nnue * scale + optimism * (scale - 754)) / 1024;
} }
// Damp down the evaluation linearly when shuffling // Damp down the evaluation linearly when shuffling
@@ -1118,6 +1090,10 @@ Value Eval::evaluate(const Position& pos) {
// Guarantee evaluation does not hit the tablebase range // Guarantee evaluation does not hit the tablebase range
v = std::clamp(v, VALUE_TB_LOSS_IN_MAX_PLY + 1, VALUE_TB_WIN_IN_MAX_PLY - 1); v = std::clamp(v, VALUE_TB_LOSS_IN_MAX_PLY + 1, VALUE_TB_WIN_IN_MAX_PLY - 1);
// When not using NNUE, return classical complexity to caller
if (complexity && (!useNNUE || useClassical))
*complexity = abs(v - psq);
return v; return v;
} }
@@ -1139,8 +1115,6 @@ std::string Eval::trace(Position& pos) {
std::memset(scores, 0, sizeof(scores)); std::memset(scores, 0, sizeof(scores));
// Reset any global variable used in eval // Reset any global variable used in eval
pos.this_thread()->depth = 0;
pos.this_thread()->trend = SCORE_ZERO;
pos.this_thread()->bestValue = VALUE_ZERO; pos.this_thread()->bestValue = VALUE_ZERO;
pos.this_thread()->optimism[WHITE] = VALUE_ZERO; pos.this_thread()->optimism[WHITE] = VALUE_ZERO;
pos.this_thread()->optimism[BLACK] = VALUE_ZERO; pos.this_thread()->optimism[BLACK] = VALUE_ZERO;
+3 -3
View File
@@ -31,7 +31,7 @@ class Position;
namespace Eval { namespace Eval {
std::string trace(Position& pos); std::string trace(Position& pos);
Value evaluate(const Position& pos); Value evaluate(const Position& pos, int* complexity = nullptr);
extern bool useNNUE; extern bool useNNUE;
extern std::string currentEvalFileName; extern std::string currentEvalFileName;
@@ -39,12 +39,12 @@ namespace Eval {
// The default net name MUST follow the format nn-[SHA256 first 12 digits].nnue // The default net name MUST follow the format nn-[SHA256 first 12 digits].nnue
// for the build process (profile-build and fishtest) to work. Do not change the // for the build process (profile-build and fishtest) to work. Do not change the
// name of the macro, as it is used in the Makefile. // name of the macro, as it is used in the Makefile.
#define EvalFileDefaultName "nn-6877cd24400e.nnue" #define EvalFileDefaultName "nn-ad9b42354671.nnue"
namespace NNUE { namespace NNUE {
std::string trace(Position& pos); std::string trace(Position& pos);
Value evaluate(const Position& pos, bool adjusted = false); Value evaluate(const Position& pos, bool adjusted = false, int* complexity = nullptr);
void init(); void init();
void verify(); void verify();
+34 -19
View File
@@ -67,9 +67,8 @@ namespace Stockfish {
namespace { namespace {
/// Version number. If Version is left empty, then compile date in the format /// Version number or dev.
/// DD-MM-YY and show in engine_info. const string version = "15.1";
const string Version = "15";
/// Our fancy logging facility. The trick here is to replace cin.rdbuf() and /// 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 /// cout.rdbuf() with two Tie objects that tie cin and cout to a file stream. We
@@ -138,23 +137,41 @@ public:
} // namespace } // namespace
/// engine_info() returns the full name of the current Stockfish version. This /// engine_info() returns the full name of the current Stockfish version.
/// will be either "Stockfish <Tag> DD-MM-YY" (where DD-MM-YY is the date when /// For local dev compiles we try to append the commit sha and commit date
/// the program was compiled) or "Stockfish <Version>", depending on whether /// from git if that fails only the local compilation date is set and "nogit" is specified:
/// Version is empty. /// Stockfish dev-YYYYMMDD-SHA
/// or
/// Stockfish dev-YYYYMMDD-nogit
///
/// For releases (non dev builds) we only include the version number:
/// Stockfish version
string engine_info(bool to_uci) { string engine_info(bool to_uci) {
stringstream ss;
ss << "Stockfish " << version << setfill('0');
const string months("Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec"); if (version == "dev")
string month, day, year;
stringstream ss, date(__DATE__); // From compiler, format is "Sep 21 2008"
ss << "Stockfish " << Version << setfill('0');
if (Version.empty())
{ {
ss << "-";
#ifdef GIT_DATE
ss << GIT_DATE;
#else
const string months("Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec");
string month, day, year;
stringstream date(__DATE__); // From compiler, format is "Sep 21 2008"
date >> month >> day >> year; date >> month >> day >> year;
ss << setw(2) << day << setw(2) << (1 + months.find(month) / 4) << year.substr(2); ss << year << setw(2) << setfill('0') << (1 + months.find(month) / 4) << setw(2) << setfill('0') << day;
#endif
ss << "-";
#ifdef GIT_SHA
ss << GIT_SHA;
#else
ss << "nogit";
#endif
} }
ss << (to_uci ? "\nid author ": " by ") ss << (to_uci ? "\nid author ": " by ")
@@ -378,10 +395,9 @@ void std_aligned_free(void* ptr) {
#if defined(_WIN32) #if defined(_WIN32)
static void* aligned_large_pages_alloc_windows(size_t allocSize) { static void* aligned_large_pages_alloc_windows([[maybe_unused]] size_t allocSize) {
#if !defined(_WIN64) #if !defined(_WIN64)
(void)allocSize; // suppress unused-parameter compiler warning
return nullptr; return nullptr;
#else #else
@@ -626,8 +642,7 @@ string argv0; // path+name of the executable binary, as given by argv
string binaryDirectory; // path of the executable directory string binaryDirectory; // path of the executable directory
string workingDirectory; // path of the working directory string workingDirectory; // path of the working directory
void init(int argc, char* argv[]) { void init([[maybe_unused]] int argc, char* argv[]) {
(void)argc;
string pathSeparator; string pathSeparator;
// extract the path+name of the executable binary // extract the path+name of the executable binary
-40
View File
@@ -116,56 +116,16 @@ class ValueList {
public: public:
std::size_t size() const { return size_; } std::size_t size() const { return size_; }
void resize(std::size_t newSize) { size_ = newSize; }
void push_back(const T& value) { values_[size_++] = value; } void push_back(const T& value) { values_[size_++] = value; }
T& operator[](std::size_t index) { return values_[index]; }
T* begin() { return values_; }
T* end() { return values_ + size_; }
const T& operator[](std::size_t index) const { return values_[index]; }
const T* begin() const { return values_; } const T* begin() const { return values_; }
const T* end() const { return values_ + size_; } const T* end() const { return values_ + size_; }
void swap(ValueList& other) {
const std::size_t maxSize = std::max(size_, other.size_);
for (std::size_t i = 0; i < maxSize; ++i) {
std::swap(values_[i], other.values_[i]);
}
std::swap(size_, other.size_);
}
private: private:
T values_[MaxSize]; T values_[MaxSize];
std::size_t size_ = 0; std::size_t size_ = 0;
}; };
/// sigmoid(t, x0, y0, C, P, Q) implements a sigmoid-like function using only integers,
/// with the following properties:
///
/// - sigmoid is centered in (x0, y0)
/// - sigmoid has amplitude [-P/Q , P/Q] instead of [-1 , +1]
/// - limit is (y0 - P/Q) when t tends to -infinity
/// - limit is (y0 + P/Q) when t tends to +infinity
/// - the slope can be adjusted using C > 0, smaller C giving a steeper sigmoid
/// - the slope of the sigmoid when t = x0 is P/(Q*C)
/// - sigmoid is increasing with t when P > 0 and Q > 0
/// - to get a decreasing sigmoid, change sign of P
/// - mean value of the sigmoid is y0
///
/// Use <https://www.desmos.com/calculator/jhh83sqq92> to draw the sigmoid
inline int64_t sigmoid(int64_t t, int64_t x0,
int64_t y0,
int64_t C,
int64_t P,
int64_t Q)
{
assert(C > 0);
assert(Q != 0);
return y0 + P * (t-x0) / (Q * (std::abs(t-x0) + C)) ;
}
/// xorshift64star Pseudo-Random Number Generator /// xorshift64star Pseudo-Random Number Generator
/// This class is based on original code written and dedicated /// This class is based on original code written and dedicated
/// to the public domain by Sebastiano Vigna (2014). /// to the public domain by Sebastiano Vigna (2014).
+18 -28
View File
@@ -69,6 +69,7 @@ MovePicker::MovePicker(const Position& p, Move ttm, Depth d, const ButterflyHist
stage = (pos.checkers() ? EVASION_TT : MAIN_TT) + stage = (pos.checkers() ? EVASION_TT : MAIN_TT) +
!(ttm && pos.pseudo_legal(ttm)); !(ttm && pos.pseudo_legal(ttm));
threatenedPieces = 0;
} }
/// MovePicker constructor for quiescence search /// MovePicker constructor for quiescence search
@@ -82,14 +83,13 @@ MovePicker::MovePicker(const Position& p, Move ttm, Depth d, const ButterflyHist
stage = (pos.checkers() ? EVASION_TT : QSEARCH_TT) + stage = (pos.checkers() ? EVASION_TT : QSEARCH_TT) +
!( ttm !( ttm
&& (pos.checkers() || depth > DEPTH_QS_RECAPTURES || to_sq(ttm) == recaptureSquare)
&& pos.pseudo_legal(ttm)); && pos.pseudo_legal(ttm));
} }
/// MovePicker constructor for ProbCut: we generate captures with SEE greater /// MovePicker constructor for ProbCut: we generate captures with SEE greater
/// than or equal to the given threshold. /// than or equal to the given threshold.
MovePicker::MovePicker(const Position& p, Move ttm, Value th, Depth d, const CapturePieceToHistory* cph) MovePicker::MovePicker(const Position& p, Move ttm, Value th, const CapturePieceToHistory* cph)
: pos(p), captureHistory(cph), ttMove(ttm), threshold(th), depth(d) : pos(p), captureHistory(cph), ttMove(ttm), threshold(th)
{ {
assert(!pos.checkers()); assert(!pos.checkers());
@@ -106,29 +106,19 @@ void MovePicker::score() {
static_assert(Type == CAPTURES || Type == QUIETS || Type == EVASIONS, "Wrong type"); static_assert(Type == CAPTURES || Type == QUIETS || Type == EVASIONS, "Wrong type");
Bitboard threatened, threatenedByPawn, threatenedByMinor, threatenedByRook; [[maybe_unused]] Bitboard threatenedByPawn, threatenedByMinor, threatenedByRook;
if constexpr (Type == QUIETS) if constexpr (Type == QUIETS)
{ {
Color us = pos.side_to_move(); Color us = pos.side_to_move();
// squares threatened by pawns
threatenedByPawn = pos.attacks_by<PAWN>(~us); threatenedByPawn = pos.attacks_by<PAWN>(~us);
// squares threatened by minors or pawns
threatenedByMinor = pos.attacks_by<KNIGHT>(~us) | pos.attacks_by<BISHOP>(~us) | threatenedByPawn; threatenedByMinor = pos.attacks_by<KNIGHT>(~us) | pos.attacks_by<BISHOP>(~us) | threatenedByPawn;
// squares threatened by rooks, minors or pawns
threatenedByRook = pos.attacks_by<ROOK>(~us) | threatenedByMinor; threatenedByRook = pos.attacks_by<ROOK>(~us) | threatenedByMinor;
// pieces threatened by pieces of lesser material value // Pieces threatened by pieces of lesser material value
threatened = (pos.pieces(us, QUEEN) & threatenedByRook) threatenedPieces = (pos.pieces(us, QUEEN) & threatenedByRook)
| (pos.pieces(us, ROOK) & threatenedByMinor) | (pos.pieces(us, ROOK) & threatenedByMinor)
| (pos.pieces(us, KNIGHT, BISHOP) & threatenedByPawn); | (pos.pieces(us, KNIGHT, BISHOP) & threatenedByPawn);
}
else
{
// Silence unused variable warnings
(void) threatened;
(void) threatenedByPawn;
(void) threatenedByMinor;
(void) threatenedByRook;
} }
for (auto& m : *this) for (auto& m : *this)
@@ -137,27 +127,27 @@ void MovePicker::score() {
+ (*captureHistory)[pos.moved_piece(m)][to_sq(m)][type_of(pos.piece_on(to_sq(m)))]; + (*captureHistory)[pos.moved_piece(m)][to_sq(m)][type_of(pos.piece_on(to_sq(m)))];
else if constexpr (Type == QUIETS) else if constexpr (Type == QUIETS)
m.value = (*mainHistory)[pos.side_to_move()][from_to(m)] m.value = 2 * (*mainHistory)[pos.side_to_move()][from_to(m)]
+ 2 * (*continuationHistory[0])[pos.moved_piece(m)][to_sq(m)] + 2 * (*continuationHistory[0])[pos.moved_piece(m)][to_sq(m)]
+ (*continuationHistory[1])[pos.moved_piece(m)][to_sq(m)] + (*continuationHistory[1])[pos.moved_piece(m)][to_sq(m)]
+ (*continuationHistory[3])[pos.moved_piece(m)][to_sq(m)] + (*continuationHistory[3])[pos.moved_piece(m)][to_sq(m)]
+ (*continuationHistory[5])[pos.moved_piece(m)][to_sq(m)] + (*continuationHistory[5])[pos.moved_piece(m)][to_sq(m)]
+ (threatened & from_sq(m) ? + (threatenedPieces & from_sq(m) ?
(type_of(pos.moved_piece(m)) == QUEEN && !(to_sq(m) & threatenedByRook) ? 50000 (type_of(pos.moved_piece(m)) == QUEEN && !(to_sq(m) & threatenedByRook) ? 50000
: type_of(pos.moved_piece(m)) == ROOK && !(to_sq(m) & threatenedByMinor) ? 25000 : type_of(pos.moved_piece(m)) == ROOK && !(to_sq(m) & threatenedByMinor) ? 25000
: !(to_sq(m) & threatenedByPawn) ? 15000 : !(to_sq(m) & threatenedByPawn) ? 15000
: 0) : 0)
: 0); : 0)
+ bool(pos.check_squares(type_of(pos.moved_piece(m))) & to_sq(m)) * 16384;
else // Type == EVASIONS else // Type == EVASIONS
{ {
if (pos.capture(m)) if (pos.capture(m))
m.value = PieceValue[MG][pos.piece_on(to_sq(m))] m.value = PieceValue[MG][pos.piece_on(to_sq(m))]
- Value(type_of(pos.moved_piece(m))); - Value(type_of(pos.moved_piece(m)))
+ (1 << 28);
else else
m.value = (*mainHistory)[pos.side_to_move()][from_to(m)] m.value = (*mainHistory)[pos.side_to_move()][from_to(m)]
+ 2 * (*continuationHistory[0])[pos.moved_piece(m)][to_sq(m)] + (*continuationHistory[0])[pos.moved_piece(m)][to_sq(m)];
- (1 << 28);
} }
} }
@@ -201,7 +191,7 @@ top:
endMoves = generate<CAPTURES>(pos, cur); endMoves = generate<CAPTURES>(pos, cur);
score<CAPTURES>(); score<CAPTURES>();
partial_insertion_sort(cur, endMoves, -3000 * depth); partial_insertion_sort(cur, endMoves, std::numeric_limits<int>::min());
++stage; ++stage;
goto top; goto top;
+6 -2
View File
@@ -86,7 +86,8 @@ enum StatsType { NoCaptures, Captures };
/// unsuccessful during the current search, and is used for reduction and move /// unsuccessful during the current search, and is used for reduction and move
/// ordering decisions. It uses 2 tables (one for each color) indexed by /// 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 /// the move's from and to squares, see www.chessprogramming.org/Butterfly_Boards
typedef Stats<int16_t, 14365, COLOR_NB, int(SQUARE_NB) * int(SQUARE_NB)> ButterflyHistory; /// (~11 elo)
typedef Stats<int16_t, 7183, COLOR_NB, int(SQUARE_NB) * int(SQUARE_NB)> ButterflyHistory;
/// CounterMoveHistory stores counter moves indexed by [piece][to] of the previous /// CounterMoveHistory stores counter moves indexed by [piece][to] of the previous
/// move, see www.chessprogramming.org/Countermove_Heuristic /// move, see www.chessprogramming.org/Countermove_Heuristic
@@ -101,6 +102,7 @@ typedef Stats<int16_t, 29952, PIECE_NB, SQUARE_NB> PieceToHistory;
/// ContinuationHistory is the combined history of a given pair of moves, usually /// 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 /// the current one given a previous one. The nested history table is based on
/// PieceToHistory instead of ButterflyBoards. /// PieceToHistory instead of ButterflyBoards.
/// (~63 elo)
typedef Stats<PieceToHistory, NOT_USED, PIECE_NB, SQUARE_NB> ContinuationHistory; typedef Stats<PieceToHistory, NOT_USED, PIECE_NB, SQUARE_NB> ContinuationHistory;
@@ -126,9 +128,11 @@ public:
const CapturePieceToHistory*, const CapturePieceToHistory*,
const PieceToHistory**, const PieceToHistory**,
Square); Square);
MovePicker(const Position&, Move, Value, Depth, const CapturePieceToHistory*); MovePicker(const Position&, Move, Value, const CapturePieceToHistory*);
Move next_move(bool skipQuiets = false); Move next_move(bool skipQuiets = false);
Bitboard threatenedPieces;
private: private:
template<PickType T, typename Pred> Move select(Pred); template<PickType T, typename Pred> Move select(Pred);
template<GenType> void score(); template<GenType> void score();
+8 -5
View File
@@ -137,13 +137,13 @@ namespace Stockfish::Eval::NNUE {
} }
// Evaluation function. Perform differential calculation. // Evaluation function. Perform differential calculation.
Value evaluate(const Position& pos, bool adjusted) { Value evaluate(const Position& pos, bool adjusted, int* complexity) {
// We manually align the arrays on the stack because with gcc < 9.3 // We manually align the arrays on the stack because with gcc < 9.3
// overaligning stack variables with alignas() doesn't work correctly. // overaligning stack variables with alignas() doesn't work correctly.
constexpr uint64_t alignment = CacheLineSize; constexpr uint64_t alignment = CacheLineSize;
int delta = 10 - pos.non_pawn_material() / 1515; int delta = 24 - pos.non_pawn_material() / 9560;
#if defined(ALIGNAS_ON_STACK_VARIABLES_BROKEN) #if defined(ALIGNAS_ON_STACK_VARIABLES_BROKEN)
TransformedFeatureType transformedFeaturesUnaligned[ TransformedFeatureType transformedFeaturesUnaligned[
@@ -161,9 +161,12 @@ namespace Stockfish::Eval::NNUE {
const auto psqt = featureTransformer->transform(pos, transformedFeatures, bucket); const auto psqt = featureTransformer->transform(pos, transformedFeatures, bucket);
const auto positional = network[bucket]->propagate(transformedFeatures); const auto positional = network[bucket]->propagate(transformedFeatures);
if (complexity)
*complexity = abs(psqt - positional) / OutputScale;
// Give more value to positional evaluation when adjusted flag is set // Give more value to positional evaluation when adjusted flag is set
if (adjusted) if (adjusted)
return static_cast<Value>(((128 - delta) * psqt + (128 + delta) * positional) / 128 / OutputScale); return static_cast<Value>(((1024 - delta) * psqt + (1024 + delta) * positional) / (1024 * OutputScale));
else else
return static_cast<Value>((psqt + positional) / OutputScale); return static_cast<Value>((psqt + positional) / OutputScale);
} }
@@ -217,7 +220,7 @@ namespace Stockfish::Eval::NNUE {
buffer[0] = (v < 0 ? '-' : v > 0 ? '+' : ' '); buffer[0] = (v < 0 ? '-' : v > 0 ? '+' : ' ');
int cp = std::abs(100 * v / PawnValueEg); int cp = std::abs(100 * v / UCI::NormalizeToPawnValue);
if (cp >= 10000) if (cp >= 10000)
{ {
buffer[1] = '0' + cp / 10000; cp %= 10000; buffer[1] = '0' + cp / 10000; cp %= 10000;
@@ -248,7 +251,7 @@ namespace Stockfish::Eval::NNUE {
buffer[0] = (v < 0 ? '-' : v > 0 ? '+' : ' '); buffer[0] = (v < 0 ? '-' : v > 0 ? '+' : ' ');
double cp = 1.0 * std::abs(int(v)) / PawnValueEg; double cp = 1.0 * std::abs(int(v)) / UCI::NormalizeToPawnValue;
sprintf(&buffer[1], "%6.2f", cp); sprintf(&buffer[1], "%6.2f", cp);
} }
+16 -15
View File
@@ -24,50 +24,51 @@
namespace Stockfish::Eval::NNUE::Features { namespace Stockfish::Eval::NNUE::Features {
// Orient a square according to perspective (rotates by 180 for black)
inline Square HalfKAv2_hm::orient(Color perspective, Square s, Square ksq) {
return Square(int(s) ^ (bool(perspective) * SQ_A8) ^ ((file_of(ksq) < FILE_E) * SQ_H1));
}
// Index of a feature for a given king position and another piece on some square // Index of a feature for a given king position and another piece on some square
inline IndexType HalfKAv2_hm::make_index(Color perspective, Square s, Piece pc, Square ksq) { template<Color Perspective>
Square o_ksq = orient(perspective, ksq, ksq); inline IndexType HalfKAv2_hm::make_index(Square s, Piece pc, Square ksq) {
return IndexType(orient(perspective, s, ksq) + PieceSquareIndex[perspective][pc] + PS_NB * KingBuckets[o_ksq]); return IndexType((int(s) ^ OrientTBL[Perspective][ksq]) + PieceSquareIndex[Perspective][pc] + KingBuckets[Perspective][ksq]);
} }
// Get a list of indices for active features // Get a list of indices for active features
template<Color Perspective>
void HalfKAv2_hm::append_active_indices( void HalfKAv2_hm::append_active_indices(
const Position& pos, const Position& pos,
Color perspective,
IndexList& active IndexList& active
) { ) {
Square ksq = pos.square<KING>(perspective); Square ksq = pos.square<KING>(Perspective);
Bitboard bb = pos.pieces(); Bitboard bb = pos.pieces();
while (bb) while (bb)
{ {
Square s = pop_lsb(bb); Square s = pop_lsb(bb);
active.push_back(make_index(perspective, s, pos.piece_on(s), ksq)); active.push_back(make_index<Perspective>(s, pos.piece_on(s), ksq));
} }
} }
// Explicit template instantiations
template void HalfKAv2_hm::append_active_indices<WHITE>(const Position& pos, IndexList& active);
template void HalfKAv2_hm::append_active_indices<BLACK>(const Position& pos, IndexList& active);
// append_changed_indices() : get a list of indices for recently changed features // append_changed_indices() : get a list of indices for recently changed features
template<Color Perspective>
void HalfKAv2_hm::append_changed_indices( void HalfKAv2_hm::append_changed_indices(
Square ksq, Square ksq,
const DirtyPiece& dp, const DirtyPiece& dp,
Color perspective,
IndexList& removed, IndexList& removed,
IndexList& added IndexList& added
) { ) {
for (int i = 0; i < dp.dirty_num; ++i) { for (int i = 0; i < dp.dirty_num; ++i) {
if (dp.from[i] != SQ_NONE) if (dp.from[i] != SQ_NONE)
removed.push_back(make_index(perspective, dp.from[i], dp.piece[i], ksq)); removed.push_back(make_index<Perspective>(dp.from[i], dp.piece[i], ksq));
if (dp.to[i] != SQ_NONE) if (dp.to[i] != SQ_NONE)
added.push_back(make_index(perspective, dp.to[i], dp.piece[i], ksq)); added.push_back(make_index<Perspective>(dp.to[i], dp.piece[i], ksq));
} }
} }
// Explicit template instantiations
template void HalfKAv2_hm::append_changed_indices<WHITE>(Square ksq, const DirtyPiece& dp, IndexList& removed, IndexList& added);
template void HalfKAv2_hm::append_changed_indices<BLACK>(Square ksq, const DirtyPiece& dp, IndexList& removed, IndexList& added);
int HalfKAv2_hm::update_cost(const StateInfo* st) { int HalfKAv2_hm::update_cost(const StateInfo* st) {
return st->dirtyPiece.dirty_num; return st->dirtyPiece.dirty_num;
} }
+45 -17
View File
@@ -49,8 +49,8 @@ namespace Stockfish::Eval::NNUE::Features {
PS_B_ROOK = 7 * SQUARE_NB, PS_B_ROOK = 7 * SQUARE_NB,
PS_W_QUEEN = 8 * SQUARE_NB, PS_W_QUEEN = 8 * SQUARE_NB,
PS_B_QUEEN = 9 * SQUARE_NB, PS_B_QUEEN = 9 * SQUARE_NB,
PS_KING = 10 * SQUARE_NB, PS_KING = 10 * SQUARE_NB,
PS_NB = 11 * SQUARE_NB PS_NB = 11 * SQUARE_NB
}; };
static constexpr IndexType PieceSquareIndex[COLOR_NB][PIECE_NB] = { static constexpr IndexType PieceSquareIndex[COLOR_NB][PIECE_NB] = {
@@ -62,11 +62,9 @@ namespace Stockfish::Eval::NNUE::Features {
PS_NONE, PS_W_PAWN, PS_W_KNIGHT, PS_W_BISHOP, PS_W_ROOK, PS_W_QUEEN, PS_KING, PS_NONE } PS_NONE, PS_W_PAWN, PS_W_KNIGHT, PS_W_BISHOP, PS_W_ROOK, PS_W_QUEEN, PS_KING, PS_NONE }
}; };
// Orient a square according to perspective (rotates by 180 for black)
static Square orient(Color perspective, Square s, Square ksq);
// Index of a feature for a given king position and another piece on some square // Index of a feature for a given king position and another piece on some square
static IndexType make_index(Color perspective, Square s, Piece pc, Square ksq); template<Color Perspective>
static IndexType make_index(Square s, Piece pc, Square ksq);
public: public:
// Feature name // Feature name
@@ -79,15 +77,45 @@ namespace Stockfish::Eval::NNUE::Features {
static constexpr IndexType Dimensions = static constexpr IndexType Dimensions =
static_cast<IndexType>(SQUARE_NB) * static_cast<IndexType>(PS_NB) / 2; static_cast<IndexType>(SQUARE_NB) * static_cast<IndexType>(PS_NB) / 2;
static constexpr int KingBuckets[64] = { #define B(v) (v * PS_NB)
-1, -1, -1, -1, 31, 30, 29, 28, static constexpr int KingBuckets[COLOR_NB][SQUARE_NB] = {
-1, -1, -1, -1, 27, 26, 25, 24, { B(28), B(29), B(30), B(31), B(31), B(30), B(29), B(28),
-1, -1, -1, -1, 23, 22, 21, 20, B(24), B(25), B(26), B(27), B(27), B(26), B(25), B(24),
-1, -1, -1, -1, 19, 18, 17, 16, B(20), B(21), B(22), B(23), B(23), B(22), B(21), B(20),
-1, -1, -1, -1, 15, 14, 13, 12, B(16), B(17), B(18), B(19), B(19), B(18), B(17), B(16),
-1, -1, -1, -1, 11, 10, 9, 8, B(12), B(13), B(14), B(15), B(15), B(14), B(13), B(12),
-1, -1, -1, -1, 7, 6, 5, 4, B( 8), B( 9), B(10), B(11), B(11), B(10), B( 9), B( 8),
-1, -1, -1, -1, 3, 2, 1, 0 B( 4), B( 5), B( 6), B( 7), B( 7), B( 6), B( 5), B( 4),
B( 0), B( 1), B( 2), B( 3), B( 3), B( 2), B( 1), B( 0) },
{ B( 0), B( 1), B( 2), B( 3), B( 3), B( 2), B( 1), B( 0),
B( 4), B( 5), B( 6), B( 7), B( 7), B( 6), B( 5), B( 4),
B( 8), B( 9), B(10), B(11), B(11), B(10), B( 9), B( 8),
B(12), B(13), B(14), B(15), B(15), B(14), B(13), B(12),
B(16), B(17), B(18), B(19), B(19), B(18), B(17), B(16),
B(20), B(21), B(22), B(23), B(23), B(22), B(21), B(20),
B(24), B(25), B(26), B(27), B(27), B(26), B(25), B(24),
B(28), B(29), B(30), B(31), B(31), B(30), B(29), B(28) }
};
#undef B
// Orient a square according to perspective (rotates by 180 for black)
static constexpr int OrientTBL[COLOR_NB][SQUARE_NB] = {
{ SQ_H1, SQ_H1, SQ_H1, SQ_H1, SQ_A1, SQ_A1, SQ_A1, SQ_A1,
SQ_H1, SQ_H1, SQ_H1, SQ_H1, SQ_A1, SQ_A1, SQ_A1, SQ_A1,
SQ_H1, SQ_H1, SQ_H1, SQ_H1, SQ_A1, SQ_A1, SQ_A1, SQ_A1,
SQ_H1, SQ_H1, SQ_H1, SQ_H1, SQ_A1, SQ_A1, SQ_A1, SQ_A1,
SQ_H1, SQ_H1, SQ_H1, SQ_H1, SQ_A1, SQ_A1, SQ_A1, SQ_A1,
SQ_H1, SQ_H1, SQ_H1, SQ_H1, SQ_A1, SQ_A1, SQ_A1, SQ_A1,
SQ_H1, SQ_H1, SQ_H1, SQ_H1, SQ_A1, SQ_A1, SQ_A1, SQ_A1,
SQ_H1, SQ_H1, SQ_H1, SQ_H1, SQ_A1, SQ_A1, SQ_A1, SQ_A1 },
{ SQ_H8, SQ_H8, SQ_H8, SQ_H8, SQ_A8, SQ_A8, SQ_A8, SQ_A8,
SQ_H8, SQ_H8, SQ_H8, SQ_H8, SQ_A8, SQ_A8, SQ_A8, SQ_A8,
SQ_H8, SQ_H8, SQ_H8, SQ_H8, SQ_A8, SQ_A8, SQ_A8, SQ_A8,
SQ_H8, SQ_H8, SQ_H8, SQ_H8, SQ_A8, SQ_A8, SQ_A8, SQ_A8,
SQ_H8, SQ_H8, SQ_H8, SQ_H8, SQ_A8, SQ_A8, SQ_A8, SQ_A8,
SQ_H8, SQ_H8, SQ_H8, SQ_H8, SQ_A8, SQ_A8, SQ_A8, SQ_A8,
SQ_H8, SQ_H8, SQ_H8, SQ_H8, SQ_A8, SQ_A8, SQ_A8, SQ_A8,
SQ_H8, SQ_H8, SQ_H8, SQ_H8, SQ_A8, SQ_A8, SQ_A8, SQ_A8 }
}; };
// Maximum number of simultaneously active features. // Maximum number of simultaneously active features.
@@ -95,16 +123,16 @@ namespace Stockfish::Eval::NNUE::Features {
using IndexList = ValueList<IndexType, MaxActiveDimensions>; using IndexList = ValueList<IndexType, MaxActiveDimensions>;
// Get a list of indices for active features // Get a list of indices for active features
template<Color Perspective>
static void append_active_indices( static void append_active_indices(
const Position& pos, const Position& pos,
Color perspective,
IndexList& active); IndexList& active);
// Get a list of indices for recently changed features // Get a list of indices for recently changed features
template<Color Perspective>
static void append_changed_indices( static void append_changed_indices(
Square ksq, Square ksq,
const DirtyPiece& dp, const DirtyPiece& dp,
Color perspective,
IndexList& removed, IndexList& removed,
IndexList& added IndexList& added
); );
+11 -5
View File
@@ -25,7 +25,7 @@
#include <algorithm> #include <algorithm>
#include <type_traits> #include <type_traits>
#include "../nnue_common.h" #include "../nnue_common.h"
#include "../../simd.h" #include "simd.h"
/* /*
This file contains the definition for a fully connected layer (aka affine transform). This file contains the definition for a fully connected layer (aka affine transform).
@@ -151,9 +151,15 @@ namespace Stockfish::Eval::NNUE::Layers {
template <IndexType InDims, IndexType OutDims, typename Enabled = void> template <IndexType InDims, IndexType OutDims, typename Enabled = void>
class AffineTransform; class AffineTransform;
#if defined (USE_AVX512)
constexpr IndexType LargeInputSize = 2 * 64;
#else
constexpr IndexType LargeInputSize = std::numeric_limits<IndexType>::max();
#endif
// A specialization for large inputs. // A specialization for large inputs.
template <IndexType InDims, IndexType OutDims> template <IndexType InDims, IndexType OutDims>
class AffineTransform<InDims, OutDims, std::enable_if_t<(ceil_to_multiple<IndexType>(InDims, MaxSimdWidth) >= 2*64)>> { class AffineTransform<InDims, OutDims, std::enable_if_t<(ceil_to_multiple<IndexType>(InDims, MaxSimdWidth) >= LargeInputSize)>> {
public: public:
// Input/output type // Input/output type
using InputType = std::uint8_t; using InputType = std::uint8_t;
@@ -170,7 +176,7 @@ namespace Stockfish::Eval::NNUE::Layers {
using OutputBuffer = OutputType[PaddedOutputDimensions]; using OutputBuffer = OutputType[PaddedOutputDimensions];
static_assert(PaddedInputDimensions >= 128, "Something went wrong. This specialization should not have been chosen."); static_assert(PaddedInputDimensions >= LargeInputSize, "Something went wrong. This specialization should not have been chosen.");
#if defined (USE_AVX512) #if defined (USE_AVX512)
static constexpr const IndexType InputSimdWidth = 64; static constexpr const IndexType InputSimdWidth = 64;
@@ -369,7 +375,7 @@ namespace Stockfish::Eval::NNUE::Layers {
}; };
template <IndexType InDims, IndexType OutDims> template <IndexType InDims, IndexType OutDims>
class AffineTransform<InDims, OutDims, std::enable_if_t<(ceil_to_multiple<IndexType>(InDims, MaxSimdWidth) < 2*64)>> { class AffineTransform<InDims, OutDims, std::enable_if_t<(ceil_to_multiple<IndexType>(InDims, MaxSimdWidth) < LargeInputSize)>> {
public: public:
// Input/output type // Input/output type
// Input/output type // Input/output type
@@ -387,7 +393,7 @@ namespace Stockfish::Eval::NNUE::Layers {
using OutputBuffer = OutputType[PaddedOutputDimensions]; using OutputBuffer = OutputType[PaddedOutputDimensions];
static_assert(PaddedInputDimensions < 128, "Something went wrong. This specialization should not have been chosen."); static_assert(PaddedInputDimensions < LargeInputSize, "Something went wrong. This specialization should not have been chosen.");
#if defined (USE_SSSE3) #if defined (USE_SSSE3)
static constexpr const IndexType OutputSimdWidth = SimdWidth / 4; static constexpr const IndexType OutputSimdWidth = SimdWidth / 4;
+120
View File
@@ -0,0 +1,120 @@
/*
Stockfish, a UCI chess playing engine derived from Glaurung 2.1
Copyright (C) 2004-2022 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/>.
*/
// Definition of layer ClippedReLU of NNUE evaluation function
#ifndef NNUE_LAYERS_SQR_CLIPPED_RELU_H_INCLUDED
#define NNUE_LAYERS_SQR_CLIPPED_RELU_H_INCLUDED
#include "../nnue_common.h"
namespace Stockfish::Eval::NNUE::Layers {
// Clipped ReLU
template <IndexType InDims>
class SqrClippedReLU {
public:
// Input/output type
using InputType = std::int32_t;
using OutputType = std::uint8_t;
// Number of input/output dimensions
static constexpr IndexType InputDimensions = InDims;
static constexpr IndexType OutputDimensions = InputDimensions;
static constexpr IndexType PaddedOutputDimensions =
ceil_to_multiple<IndexType>(OutputDimensions, 32);
using OutputBuffer = OutputType[PaddedOutputDimensions];
// Hash value embedded in the evaluation file
static constexpr std::uint32_t get_hash_value(std::uint32_t prevHash) {
std::uint32_t hashValue = 0x538D24C7u;
hashValue += prevHash;
return hashValue;
}
// Read network parameters
bool read_parameters(std::istream&) {
return true;
}
// Write network parameters
bool write_parameters(std::ostream&) const {
return true;
}
// Forward propagation
const OutputType* propagate(
const InputType* input, OutputType* output) const {
#if defined(USE_SSE2)
constexpr IndexType NumChunks = InputDimensions / 16;
#ifdef USE_SSE41
const __m128i Zero = _mm_setzero_si128();
#else
const __m128i k0x80s = _mm_set1_epi8(-128);
#endif
static_assert(WeightScaleBits == 6);
const auto in = reinterpret_cast<const __m128i*>(input);
const auto out = reinterpret_cast<__m128i*>(output);
for (IndexType i = 0; i < NumChunks; ++i) {
__m128i words0 = _mm_packs_epi32(
_mm_load_si128(&in[i * 4 + 0]),
_mm_load_si128(&in[i * 4 + 1]));
__m128i words1 = _mm_packs_epi32(
_mm_load_si128(&in[i * 4 + 2]),
_mm_load_si128(&in[i * 4 + 3]));
// Not sure if
words0 = _mm_srli_epi16(_mm_mulhi_epi16(words0, words0), 3);
words1 = _mm_srli_epi16(_mm_mulhi_epi16(words1, words1), 3);
const __m128i packedbytes = _mm_packs_epi16(words0, words1);
_mm_store_si128(&out[i],
#ifdef USE_SSE41
_mm_max_epi8(packedbytes, Zero)
#else
_mm_subs_epi8(_mm_adds_epi8(packedbytes, k0x80s), k0x80s)
#endif
);
}
constexpr IndexType Start = NumChunks * 16;
#else
constexpr IndexType Start = 0;
#endif
for (IndexType i = Start; i < InputDimensions; ++i) {
output[i] = static_cast<OutputType>(
// realy should be /127 but we need to make it fast
// needs to be accounted for in the trainer
std::max(0ll, std::min(127ll, (((long long)input[i] * input[i]) >> (2 * WeightScaleBits)) / 128)));
}
return output;
}
};
} // namespace Stockfish::Eval::NNUE::Layers
#endif // NNUE_LAYERS_SQR_CLIPPED_RELU_H_INCLUDED
+7 -2
View File
@@ -29,6 +29,7 @@
#include "layers/affine_transform.h" #include "layers/affine_transform.h"
#include "layers/clipped_relu.h" #include "layers/clipped_relu.h"
#include "layers/sqr_clipped_relu.h"
#include "../misc.h" #include "../misc.h"
@@ -48,8 +49,9 @@ struct Network
static constexpr int FC_1_OUTPUTS = 32; static constexpr int FC_1_OUTPUTS = 32;
Layers::AffineTransform<TransformedFeatureDimensions, FC_0_OUTPUTS + 1> fc_0; Layers::AffineTransform<TransformedFeatureDimensions, FC_0_OUTPUTS + 1> fc_0;
Layers::SqrClippedReLU<FC_0_OUTPUTS + 1> ac_sqr_0;
Layers::ClippedReLU<FC_0_OUTPUTS + 1> ac_0; Layers::ClippedReLU<FC_0_OUTPUTS + 1> ac_0;
Layers::AffineTransform<FC_0_OUTPUTS, FC_1_OUTPUTS> fc_1; Layers::AffineTransform<FC_0_OUTPUTS * 2, FC_1_OUTPUTS> fc_1;
Layers::ClippedReLU<FC_1_OUTPUTS> ac_1; Layers::ClippedReLU<FC_1_OUTPUTS> ac_1;
Layers::AffineTransform<FC_1_OUTPUTS, 1> fc_2; Layers::AffineTransform<FC_1_OUTPUTS, 1> fc_2;
@@ -93,6 +95,7 @@ struct Network
struct alignas(CacheLineSize) Buffer struct alignas(CacheLineSize) Buffer
{ {
alignas(CacheLineSize) decltype(fc_0)::OutputBuffer fc_0_out; alignas(CacheLineSize) decltype(fc_0)::OutputBuffer fc_0_out;
alignas(CacheLineSize) decltype(ac_sqr_0)::OutputType ac_sqr_0_out[ceil_to_multiple<IndexType>(FC_0_OUTPUTS * 2, 32)];
alignas(CacheLineSize) decltype(ac_0)::OutputBuffer ac_0_out; alignas(CacheLineSize) decltype(ac_0)::OutputBuffer ac_0_out;
alignas(CacheLineSize) decltype(fc_1)::OutputBuffer fc_1_out; alignas(CacheLineSize) decltype(fc_1)::OutputBuffer fc_1_out;
alignas(CacheLineSize) decltype(ac_1)::OutputBuffer ac_1_out; alignas(CacheLineSize) decltype(ac_1)::OutputBuffer ac_1_out;
@@ -114,8 +117,10 @@ struct Network
#endif #endif
fc_0.propagate(transformedFeatures, buffer.fc_0_out); fc_0.propagate(transformedFeatures, buffer.fc_0_out);
ac_sqr_0.propagate(buffer.fc_0_out, buffer.ac_sqr_0_out);
ac_0.propagate(buffer.fc_0_out, buffer.ac_0_out); ac_0.propagate(buffer.fc_0_out, buffer.ac_0_out);
fc_1.propagate(buffer.ac_0_out, buffer.fc_1_out); std::memcpy(buffer.ac_sqr_0_out + FC_0_OUTPUTS, buffer.ac_0_out, FC_0_OUTPUTS * sizeof(decltype(ac_0)::OutputType));
fc_1.propagate(buffer.ac_sqr_0_out, buffer.fc_1_out);
ac_1.propagate(buffer.fc_1_out, buffer.ac_1_out); ac_1.propagate(buffer.fc_1_out, buffer.ac_1_out);
fc_2.propagate(buffer.ac_1_out, buffer.fc_2_out); fc_2.propagate(buffer.ac_1_out, buffer.fc_2_out);
+42 -41
View File
@@ -120,12 +120,12 @@ namespace Stockfish::Eval::NNUE {
#define vec_zero() _mm_setzero_si64() #define vec_zero() _mm_setzero_si64()
#define vec_set_16(a) _mm_set1_pi16(a) #define vec_set_16(a) _mm_set1_pi16(a)
inline vec_t vec_max_16(vec_t a,vec_t b){ inline vec_t vec_max_16(vec_t a,vec_t b){
vec_t comparison = _mm_cmpgt_pi16(a,b); vec_t comparison = _mm_cmpgt_pi16(a,b);
return _mm_or_si64(_mm_and_si64(comparison, a), _mm_andnot_si64(comparison, b)); return _mm_or_si64(_mm_and_si64(comparison, a), _mm_andnot_si64(comparison, b));
} }
inline vec_t vec_min_16(vec_t a,vec_t b){ inline vec_t vec_min_16(vec_t a,vec_t b){
vec_t comparison = _mm_cmpgt_pi16(a,b); vec_t comparison = _mm_cmpgt_pi16(a,b);
return _mm_or_si64(_mm_and_si64(comparison, b), _mm_andnot_si64(comparison, a)); return _mm_or_si64(_mm_and_si64(comparison, b), _mm_andnot_si64(comparison, a));
} }
#define vec_msb_pack_16(a,b) _mm_packs_pi16(_mm_srli_pi16(a,7),_mm_srli_pi16(b,7)) #define vec_msb_pack_16(a,b) _mm_packs_pi16(_mm_srli_pi16(a,7),_mm_srli_pi16(b,7))
#define vec_load_psqt(a) (*(a)) #define vec_load_psqt(a) (*(a))
@@ -150,10 +150,10 @@ namespace Stockfish::Eval::NNUE {
#define vec_max_16(a,b) vmaxq_s16(a,b) #define vec_max_16(a,b) vmaxq_s16(a,b)
#define vec_min_16(a,b) vminq_s16(a,b) #define vec_min_16(a,b) vminq_s16(a,b)
inline vec_t vec_msb_pack_16(vec_t a, vec_t b){ inline vec_t vec_msb_pack_16(vec_t a, vec_t b){
const int8x8_t shifta = vshrn_n_s16(a, 7); const int8x8_t shifta = vshrn_n_s16(a, 7);
const int8x8_t shiftb = vshrn_n_s16(b, 7); const int8x8_t shiftb = vshrn_n_s16(b, 7);
const int8x16_t compacted = vcombine_s8(shifta,shiftb); const int8x16_t compacted = vcombine_s8(shifta,shiftb);
return *reinterpret_cast<const vec_t*> (&compacted); return *reinterpret_cast<const vec_t*> (&compacted);
} }
#define vec_load_psqt(a) (*(a)) #define vec_load_psqt(a) (*(a))
#define vec_store_psqt(a,b) *(a)=(b) #define vec_store_psqt(a,b) *(a)=(b)
@@ -271,8 +271,8 @@ namespace Stockfish::Eval::NNUE {
// Convert input features // Convert input features
std::int32_t transform(const Position& pos, OutputType* output, int bucket) const { std::int32_t transform(const Position& pos, OutputType* output, int bucket) const {
update_accumulator(pos, WHITE); update_accumulator<WHITE>(pos);
update_accumulator(pos, BLACK); update_accumulator<BLACK>(pos);
const Color perspectives[2] = {pos.side_to_move(), ~pos.side_to_move()}; const Color perspectives[2] = {pos.side_to_move(), ~pos.side_to_move()};
const auto& accumulation = pos.state()->accumulator.accumulation; const auto& accumulation = pos.state()->accumulator.accumulation;
@@ -290,7 +290,7 @@ namespace Stockfish::Eval::NNUE {
#if defined(VECTOR) #if defined(VECTOR)
constexpr IndexType OutputChunkSize = MaxChunkSize; constexpr IndexType OutputChunkSize = MaxChunkSize;
static_assert((HalfDimensions / 2) % OutputChunkSize == 0); static_assert((HalfDimensions / 2) % OutputChunkSize == 0);
constexpr IndexType NumOutputChunks = HalfDimensions / 2 / OutputChunkSize; constexpr IndexType NumOutputChunks = HalfDimensions / 2 / OutputChunkSize;
@@ -338,7 +338,8 @@ namespace Stockfish::Eval::NNUE {
private: private:
void update_accumulator(const Position& pos, const Color perspective) const { template<Color Perspective>
void update_accumulator(const Position& pos) const {
// The size must be enough to contain the largest possible update. // The size must be enough to contain the largest possible update.
// That might depend on the feature set and generally relies on the // That might depend on the feature set and generally relies on the
@@ -356,18 +357,18 @@ namespace Stockfish::Eval::NNUE {
// of the estimated gain in terms of features to be added/subtracted. // of the estimated gain in terms of features to be added/subtracted.
StateInfo *st = pos.state(), *next = nullptr; StateInfo *st = pos.state(), *next = nullptr;
int gain = FeatureSet::refresh_cost(pos); int gain = FeatureSet::refresh_cost(pos);
while (st->previous && !st->accumulator.computed[perspective]) while (st->previous && !st->accumulator.computed[Perspective])
{ {
// This governs when a full feature refresh is needed and how many // This governs when a full feature refresh is needed and how many
// updates are better than just one full refresh. // updates are better than just one full refresh.
if ( FeatureSet::requires_refresh(st, perspective) if ( FeatureSet::requires_refresh(st, Perspective)
|| (gain -= FeatureSet::update_cost(st) + 1) < 0) || (gain -= FeatureSet::update_cost(st) + 1) < 0)
break; break;
next = st; next = st;
st = st->previous; st = st->previous;
} }
if (st->accumulator.computed[perspective]) if (st->accumulator.computed[Perspective])
{ {
if (next == nullptr) if (next == nullptr)
return; return;
@@ -376,17 +377,17 @@ namespace Stockfish::Eval::NNUE {
// accumulator. Then, we update the current accumulator (pos.state()). // accumulator. Then, we update the current accumulator (pos.state()).
// Gather all features to be updated. // Gather all features to be updated.
const Square ksq = pos.square<KING>(perspective); const Square ksq = pos.square<KING>(Perspective);
FeatureSet::IndexList removed[2], added[2]; FeatureSet::IndexList removed[2], added[2];
FeatureSet::append_changed_indices( FeatureSet::append_changed_indices<Perspective>(
ksq, next->dirtyPiece, perspective, removed[0], added[0]); ksq, next->dirtyPiece, removed[0], added[0]);
for (StateInfo *st2 = pos.state(); st2 != next; st2 = st2->previous) for (StateInfo *st2 = pos.state(); st2 != next; st2 = st2->previous)
FeatureSet::append_changed_indices( FeatureSet::append_changed_indices<Perspective>(
ksq, st2->dirtyPiece, perspective, removed[1], added[1]); ksq, st2->dirtyPiece, removed[1], added[1]);
// Mark the accumulators as computed. // Mark the accumulators as computed.
next->accumulator.computed[perspective] = true; next->accumulator.computed[Perspective] = true;
pos.state()->accumulator.computed[perspective] = true; pos.state()->accumulator.computed[Perspective] = true;
// Now update the accumulators listed in states_to_update[], where the last element is a sentinel. // Now update the accumulators listed in states_to_update[], where the last element is a sentinel.
StateInfo *states_to_update[3] = StateInfo *states_to_update[3] =
@@ -396,7 +397,7 @@ namespace Stockfish::Eval::NNUE {
{ {
// Load accumulator // Load accumulator
auto accTile = reinterpret_cast<vec_t*>( auto accTile = reinterpret_cast<vec_t*>(
&st->accumulator.accumulation[perspective][j * TileHeight]); &st->accumulator.accumulation[Perspective][j * TileHeight]);
for (IndexType k = 0; k < NumRegs; ++k) for (IndexType k = 0; k < NumRegs; ++k)
acc[k] = vec_load(&accTile[k]); acc[k] = vec_load(&accTile[k]);
@@ -422,7 +423,7 @@ namespace Stockfish::Eval::NNUE {
// Store accumulator // Store accumulator
accTile = reinterpret_cast<vec_t*>( accTile = reinterpret_cast<vec_t*>(
&states_to_update[i]->accumulator.accumulation[perspective][j * TileHeight]); &states_to_update[i]->accumulator.accumulation[Perspective][j * TileHeight]);
for (IndexType k = 0; k < NumRegs; ++k) for (IndexType k = 0; k < NumRegs; ++k)
vec_store(&accTile[k], acc[k]); vec_store(&accTile[k], acc[k]);
} }
@@ -432,7 +433,7 @@ namespace Stockfish::Eval::NNUE {
{ {
// Load accumulator // Load accumulator
auto accTilePsqt = reinterpret_cast<psqt_vec_t*>( auto accTilePsqt = reinterpret_cast<psqt_vec_t*>(
&st->accumulator.psqtAccumulation[perspective][j * PsqtTileHeight]); &st->accumulator.psqtAccumulation[Perspective][j * PsqtTileHeight]);
for (std::size_t k = 0; k < NumPsqtRegs; ++k) for (std::size_t k = 0; k < NumPsqtRegs; ++k)
psqt[k] = vec_load_psqt(&accTilePsqt[k]); psqt[k] = vec_load_psqt(&accTilePsqt[k]);
@@ -458,7 +459,7 @@ namespace Stockfish::Eval::NNUE {
// Store accumulator // Store accumulator
accTilePsqt = reinterpret_cast<psqt_vec_t*>( accTilePsqt = reinterpret_cast<psqt_vec_t*>(
&states_to_update[i]->accumulator.psqtAccumulation[perspective][j * PsqtTileHeight]); &states_to_update[i]->accumulator.psqtAccumulation[Perspective][j * PsqtTileHeight]);
for (std::size_t k = 0; k < NumPsqtRegs; ++k) for (std::size_t k = 0; k < NumPsqtRegs; ++k)
vec_store_psqt(&accTilePsqt[k], psqt[k]); vec_store_psqt(&accTilePsqt[k], psqt[k]);
} }
@@ -467,12 +468,12 @@ namespace Stockfish::Eval::NNUE {
#else #else
for (IndexType i = 0; states_to_update[i]; ++i) for (IndexType i = 0; states_to_update[i]; ++i)
{ {
std::memcpy(states_to_update[i]->accumulator.accumulation[perspective], std::memcpy(states_to_update[i]->accumulator.accumulation[Perspective],
st->accumulator.accumulation[perspective], st->accumulator.accumulation[Perspective],
HalfDimensions * sizeof(BiasType)); HalfDimensions * sizeof(BiasType));
for (std::size_t k = 0; k < PSQTBuckets; ++k) for (std::size_t k = 0; k < PSQTBuckets; ++k)
states_to_update[i]->accumulator.psqtAccumulation[perspective][k] = st->accumulator.psqtAccumulation[perspective][k]; states_to_update[i]->accumulator.psqtAccumulation[Perspective][k] = st->accumulator.psqtAccumulation[Perspective][k];
st = states_to_update[i]; st = states_to_update[i];
@@ -482,10 +483,10 @@ namespace Stockfish::Eval::NNUE {
const IndexType offset = HalfDimensions * index; const IndexType offset = HalfDimensions * index;
for (IndexType j = 0; j < HalfDimensions; ++j) for (IndexType j = 0; j < HalfDimensions; ++j)
st->accumulator.accumulation[perspective][j] -= weights[offset + j]; st->accumulator.accumulation[Perspective][j] -= weights[offset + j];
for (std::size_t k = 0; k < PSQTBuckets; ++k) for (std::size_t k = 0; k < PSQTBuckets; ++k)
st->accumulator.psqtAccumulation[perspective][k] -= psqtWeights[index * PSQTBuckets + k]; st->accumulator.psqtAccumulation[Perspective][k] -= psqtWeights[index * PSQTBuckets + k];
} }
// Difference calculation for the activated features // Difference calculation for the activated features
@@ -494,10 +495,10 @@ namespace Stockfish::Eval::NNUE {
const IndexType offset = HalfDimensions * index; const IndexType offset = HalfDimensions * index;
for (IndexType j = 0; j < HalfDimensions; ++j) for (IndexType j = 0; j < HalfDimensions; ++j)
st->accumulator.accumulation[perspective][j] += weights[offset + j]; st->accumulator.accumulation[Perspective][j] += weights[offset + j];
for (std::size_t k = 0; k < PSQTBuckets; ++k) for (std::size_t k = 0; k < PSQTBuckets; ++k)
st->accumulator.psqtAccumulation[perspective][k] += psqtWeights[index * PSQTBuckets + k]; st->accumulator.psqtAccumulation[Perspective][k] += psqtWeights[index * PSQTBuckets + k];
} }
} }
#endif #endif
@@ -506,9 +507,9 @@ namespace Stockfish::Eval::NNUE {
{ {
// Refresh the accumulator // Refresh the accumulator
auto& accumulator = pos.state()->accumulator; auto& accumulator = pos.state()->accumulator;
accumulator.computed[perspective] = true; accumulator.computed[Perspective] = true;
FeatureSet::IndexList active; FeatureSet::IndexList active;
FeatureSet::append_active_indices(pos, perspective, active); FeatureSet::append_active_indices<Perspective>(pos, active);
#ifdef VECTOR #ifdef VECTOR
for (IndexType j = 0; j < HalfDimensions / TileHeight; ++j) for (IndexType j = 0; j < HalfDimensions / TileHeight; ++j)
@@ -528,7 +529,7 @@ namespace Stockfish::Eval::NNUE {
} }
auto accTile = reinterpret_cast<vec_t*>( auto accTile = reinterpret_cast<vec_t*>(
&accumulator.accumulation[perspective][j * TileHeight]); &accumulator.accumulation[Perspective][j * TileHeight]);
for (unsigned k = 0; k < NumRegs; k++) for (unsigned k = 0; k < NumRegs; k++)
vec_store(&accTile[k], acc[k]); vec_store(&accTile[k], acc[k]);
} }
@@ -548,27 +549,27 @@ namespace Stockfish::Eval::NNUE {
} }
auto accTilePsqt = reinterpret_cast<psqt_vec_t*>( auto accTilePsqt = reinterpret_cast<psqt_vec_t*>(
&accumulator.psqtAccumulation[perspective][j * PsqtTileHeight]); &accumulator.psqtAccumulation[Perspective][j * PsqtTileHeight]);
for (std::size_t k = 0; k < NumPsqtRegs; ++k) for (std::size_t k = 0; k < NumPsqtRegs; ++k)
vec_store_psqt(&accTilePsqt[k], psqt[k]); vec_store_psqt(&accTilePsqt[k], psqt[k]);
} }
#else #else
std::memcpy(accumulator.accumulation[perspective], biases, std::memcpy(accumulator.accumulation[Perspective], biases,
HalfDimensions * sizeof(BiasType)); HalfDimensions * sizeof(BiasType));
for (std::size_t k = 0; k < PSQTBuckets; ++k) for (std::size_t k = 0; k < PSQTBuckets; ++k)
accumulator.psqtAccumulation[perspective][k] = 0; accumulator.psqtAccumulation[Perspective][k] = 0;
for (const auto index : active) for (const auto index : active)
{ {
const IndexType offset = HalfDimensions * index; const IndexType offset = HalfDimensions * index;
for (IndexType j = 0; j < HalfDimensions; ++j) for (IndexType j = 0; j < HalfDimensions; ++j)
accumulator.accumulation[perspective][j] += weights[offset + j]; accumulator.accumulation[Perspective][j] += weights[offset + j];
for (std::size_t k = 0; k < PSQTBuckets; ++k) for (std::size_t k = 0; k < PSQTBuckets; ++k)
accumulator.psqtAccumulation[perspective][k] += psqtWeights[index * PSQTBuckets + k]; accumulator.psqtAccumulation[Perspective][k] += psqtWeights[index * PSQTBuckets + k];
} }
#endif #endif
} }
+9 -4
View File
@@ -129,7 +129,7 @@ void Position::init() {
// Prepare the cuckoo tables // Prepare the cuckoo tables
std::memset(cuckoo, 0, sizeof(cuckoo)); std::memset(cuckoo, 0, sizeof(cuckoo));
std::memset(cuckooMove, 0, sizeof(cuckooMove)); std::memset(cuckooMove, 0, sizeof(cuckooMove));
int count = 0; [[maybe_unused]] int count = 0;
for (Piece pc : Pieces) for (Piece pc : Pieces)
for (Square s1 = SQ_A1; s1 <= SQ_H8; ++s1) for (Square s1 = SQ_A1; s1 <= SQ_H8; ++s1)
for (Square s2 = Square(s1 + 1); s2 <= SQ_H8; ++s2) for (Square s2 = Square(s1 + 1); s2 <= SQ_H8; ++s2)
@@ -1054,7 +1054,10 @@ Key Position::key_after(Move m) const {
if (captured) if (captured)
k ^= Zobrist::psq[captured][to]; k ^= Zobrist::psq[captured][to];
return k ^ Zobrist::psq[pc][to] ^ Zobrist::psq[pc][from]; k ^= Zobrist::psq[pc][to] ^ Zobrist::psq[pc][from];
return (captured || type_of(pc) == PAWN)
? k : adjust_key50<true>(k);
} }
@@ -1099,10 +1102,12 @@ bool Position::see_ge(Move m, Value threshold) const {
// Don't allow pinned pieces to attack as long as there are // Don't allow pinned pieces to attack as long as there are
// pinners on their original square. // pinners on their original square.
if (pinners(~stm) & occupied) if (pinners(~stm) & occupied)
{
stmAttackers &= ~blockers_for_king(stm); stmAttackers &= ~blockers_for_king(stm);
if (!stmAttackers) if (!stmAttackers)
break; break;
}
res ^= 1; res ^= 1;
+15 -2
View File
@@ -161,6 +161,7 @@ public:
bool has_repeated() const; bool has_repeated() const;
int rule50_count() const; int rule50_count() const;
Score psq_score() const; Score psq_score() const;
Value psq_eg_stm() const;
Value non_pawn_material(Color c) const; Value non_pawn_material(Color c) const;
Value non_pawn_material() const; Value non_pawn_material() const;
@@ -184,6 +185,8 @@ private:
void move_piece(Square from, Square to); void move_piece(Square from, Square to);
template<bool Do> 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);
template<bool AfterMove>
Key adjust_key50(Key k) const;
// Data members // Data members
Piece board[SQUARE_NB]; Piece board[SQUARE_NB];
@@ -326,8 +329,14 @@ inline int Position::pawns_on_same_color_squares(Color c, Square s) const {
} }
inline Key Position::key() const { inline Key Position::key() const {
return st->rule50 < 14 ? st->key return adjust_key50<false>(st->key);
: st->key ^ make_key((st->rule50 - 14) / 8); }
template<bool AfterMove>
inline Key Position::adjust_key50(Key k) const
{
return st->rule50 < 14 - AfterMove
? k : k ^ make_key((st->rule50 - (14 - AfterMove)) / 8);
} }
inline Key Position::pawn_key() const { inline Key Position::pawn_key() const {
@@ -342,6 +351,10 @@ inline Score Position::psq_score() const {
return psq; return psq;
} }
inline Value Position::psq_eg_stm() const {
return (sideToMove == WHITE ? 1 : -1) * eg_value(psq);
}
inline Value Position::non_pawn_material(Color c) const { inline Value Position::non_pawn_material(Color c) const {
return st->nonPawnMaterial[c]; return st->nonPawnMaterial[c];
} }
+165 -176
View File
@@ -63,7 +63,7 @@ namespace {
// Futility margin // Futility margin
Value futility_margin(Depth d, bool improving) { Value futility_margin(Depth d, bool improving) {
return Value(168 * (d - improving)); return Value(165 * (d - improving));
} }
// Reductions lookup table, initialized at startup // Reductions lookup table, initialized at startup
@@ -71,21 +71,22 @@ namespace {
Depth reduction(bool i, Depth d, int mn, Value delta, Value rootDelta) { Depth reduction(bool i, Depth d, int mn, Value delta, Value rootDelta) {
int r = Reductions[d] * Reductions[mn]; int r = Reductions[d] * Reductions[mn];
return (r + 1463 - int(delta) * 1024 / int(rootDelta)) / 1024 + (!i && r > 1010); return (r + 1642 - int(delta) * 1024 / int(rootDelta)) / 1024 + (!i && r > 916);
} }
constexpr int futility_move_count(bool improving, Depth depth) { constexpr int futility_move_count(bool improving, Depth depth) {
return (3 + depth * depth) / (2 - improving); return improving ? (3 + depth * depth)
: (3 + depth * depth) / 2;
} }
// History and stats update bonus, based on depth // History and stats update bonus, based on depth
int stat_bonus(Depth d) { int stat_bonus(Depth d) {
return std::min((9 * d + 270) * d - 311 , 2145); return std::min((12 * d + 282) * d - 349 , 1594);
} }
// Add a small random component to draw evaluations to avoid 3-fold blindness // Add a small random component to draw evaluations to avoid 3-fold blindness
Value value_draw(Thread* thisThread) { Value value_draw(const Thread* thisThread) {
return VALUE_DRAW + Value(2 * (thisThread->nodes & 1) - 1); return VALUE_DRAW - 1 + Value(thisThread->nodes & 0x2);
} }
// Skill structure is used to implement strength limit. If we have an uci_elo then // Skill structure is used to implement strength limit. If we have an uci_elo then
@@ -115,7 +116,7 @@ namespace {
Value value_to_tt(Value v, int ply); Value value_to_tt(Value v, int ply);
Value value_from_tt(Value v, int ply, int r50c); Value value_from_tt(Value v, int ply, int r50c);
void update_pv(Move* pv, Move move, Move* childPv); void update_pv(Move* pv, Move move, const Move* childPv);
void update_continuation_histories(Stack* ss, Piece pc, Square to, int bonus); void update_continuation_histories(Stack* ss, Piece pc, Square to, int bonus);
void update_quiet_stats(const Position& pos, Stack* ss, Move move, int bonus); void update_quiet_stats(const Position& pos, Stack* ss, Move move, int bonus);
void update_all_stats(const Position& pos, Stack* ss, Move bestMove, Value bestValue, Value beta, Square prevSq, void update_all_stats(const Position& pos, Stack* ss, Move bestMove, Value bestValue, Value beta, Square prevSq,
@@ -157,7 +158,7 @@ namespace {
void Search::init() { void Search::init() {
for (int i = 1; i < MAX_MOVES; ++i) for (int i = 1; i < MAX_MOVES; ++i)
Reductions[i] = int((20.81 + std::log(Threads.size()) / 2) * std::log(i)); Reductions[i] = int((20.26 + std::log(Threads.size()) / 2) * std::log(i));
} }
@@ -238,9 +239,12 @@ void MainThread::search() {
bestPreviousScore = bestThread->rootMoves[0].score; bestPreviousScore = bestThread->rootMoves[0].score;
bestPreviousAverageScore = bestThread->rootMoves[0].averageScore; bestPreviousAverageScore = bestThread->rootMoves[0].averageScore;
for (Thread* th : Threads)
th->previousDepth = bestThread->completedDepth;
// Send again PV info if we have a new best thread // Send again PV info if we have a new best thread
if (bestThread != this) if (bestThread != this)
sync_cout << UCI::pv(bestThread->rootPos, bestThread->completedDepth, -VALUE_INFINITE, VALUE_INFINITE) << sync_endl; sync_cout << UCI::pv(bestThread->rootPos, bestThread->completedDepth) << sync_endl;
sync_cout << "bestmove " << UCI::move(bestThread->rootMoves[0].pv[0], rootPos.is_chess960()); sync_cout << "bestmove " << UCI::move(bestThread->rootMoves[0].pv[0], rootPos.is_chess960());
@@ -303,11 +307,9 @@ void Thread::search() {
multiPV = std::min(multiPV, rootMoves.size()); multiPV = std::min(multiPV, rootMoves.size());
complexityAverage.set(202, 1); complexityAverage.set(155, 1);
trend = SCORE_ZERO; optimism[us] = optimism[~us] = VALUE_ZERO;
optimism[ us] = Value(39);
optimism[~us] = -optimism[us];
int searchAgainCounter = 0; int searchAgainCounter = 0;
@@ -349,16 +351,12 @@ void Thread::search() {
if (rootDepth >= 4) if (rootDepth >= 4)
{ {
Value prev = rootMoves[pvIdx].averageScore; Value prev = rootMoves[pvIdx].averageScore;
delta = Value(16) + int(prev) * prev / 19178; delta = Value(10) + int(prev) * prev / 15620;
alpha = std::max(prev - delta,-VALUE_INFINITE); alpha = std::max(prev - delta,-VALUE_INFINITE);
beta = std::min(prev + delta, VALUE_INFINITE); beta = std::min(prev + delta, VALUE_INFINITE);
// Adjust trend and optimism based on root move's previousScore // Adjust optimism based on root move's previousScore
int tr = sigmoid(prev, 3, 8, 90, 125, 1); int opt = 118 * prev / (std::abs(prev) + 169);
trend = (us == WHITE ? make_score(tr, tr / 2)
: -make_score(tr, tr / 2));
int opt = sigmoid(prev, 8, 17, 144, 13966, 183);
optimism[ us] = Value(opt); optimism[ us] = Value(opt);
optimism[~us] = -optimism[us]; optimism[~us] = -optimism[us];
} }
@@ -369,7 +367,9 @@ void Thread::search() {
int failedHighCnt = 0; int failedHighCnt = 0;
while (true) while (true)
{ {
Depth adjustedDepth = std::max(1, rootDepth - failedHighCnt - searchAgainCounter); // Adjust the effective depth searched, but ensuring at least one effective increment for every
// four searchAgain steps (see issue #2717).
Depth adjustedDepth = std::max(1, rootDepth - failedHighCnt - 3 * (searchAgainCounter + 1) / 4);
bestValue = Stockfish::search<Root>(rootPos, ss, alpha, beta, adjustedDepth, false); bestValue = Stockfish::search<Root>(rootPos, ss, alpha, beta, adjustedDepth, false);
// Bring the best move to the front. It is critical that sorting // Bring the best move to the front. It is critical that sorting
@@ -392,7 +392,7 @@ void Thread::search() {
&& multiPV == 1 && multiPV == 1
&& (bestValue <= alpha || bestValue >= beta) && (bestValue <= alpha || bestValue >= beta)
&& Time.elapsed() > 3000) && Time.elapsed() > 3000)
sync_cout << UCI::pv(rootPos, rootDepth, alpha, beta) << sync_endl; sync_cout << UCI::pv(rootPos, rootDepth) << sync_endl;
// In case of failing low/high increase aspiration window and // In case of failing low/high increase aspiration window and
// re-search, otherwise exit the loop. // re-search, otherwise exit the loop.
@@ -423,7 +423,7 @@ void Thread::search() {
if ( mainThread if ( mainThread
&& (Threads.stop || pvIdx + 1 == multiPV || Time.elapsed() > 3000)) && (Threads.stop || pvIdx + 1 == multiPV || Time.elapsed() > 3000))
sync_cout << UCI::pv(rootPos, rootDepth, alpha, beta) << sync_endl; sync_cout << UCI::pv(rootPos, rootDepth) << sync_endl;
} }
if (!Threads.stop) if (!Threads.stop)
@@ -459,17 +459,16 @@ void Thread::search() {
&& !Threads.stop && !Threads.stop
&& !mainThread->stopOnPonderhit) && !mainThread->stopOnPonderhit)
{ {
double fallingEval = (69 + 12 * (mainThread->bestPreviousAverageScore - bestValue) double fallingEval = (71 + 12 * (mainThread->bestPreviousAverageScore - bestValue)
+ 6 * (mainThread->iterValue[iterIdx] - bestValue)) / 781.4; + 6 * (mainThread->iterValue[iterIdx] - bestValue)) / 656.7;
fallingEval = std::clamp(fallingEval, 0.5, 1.5); fallingEval = std::clamp(fallingEval, 0.5, 1.5);
// If the bestMove is stable over several iterations, reduce time accordingly // If the bestMove is stable over several iterations, reduce time accordingly
timeReduction = lastBestMoveDepth + 10 < completedDepth ? 1.63 : 0.73; timeReduction = lastBestMoveDepth + 9 < completedDepth ? 1.37 : 0.65;
double reduction = (1.56 + mainThread->previousTimeReduction) / (2.20 * timeReduction); double reduction = (1.4 + mainThread->previousTimeReduction) / (2.15 * timeReduction);
double bestMoveInstability = 1.073 + std::max(1.0, 2.25 - 9.9 / rootDepth) double bestMoveInstability = 1 + 1.7 * totBestMoveChanges / Threads.size();
* totBestMoveChanges / Threads.size();
int complexity = mainThread->complexityAverage.value(); int complexity = mainThread->complexityAverage.value();
double complexPosition = std::clamp(1.0 + (complexity - 326) / 1618.1, 0.5, 1.5); double complexPosition = std::min(1.0 + (complexity - 261) / 1738.7, 1.5);
double totalTime = Time.optimum() * fallingEval * reduction * bestMoveInstability * complexPosition; double totalTime = Time.optimum() * fallingEval * reduction * bestMoveInstability * complexPosition;
@@ -490,7 +489,7 @@ void Thread::search() {
} }
else if ( Threads.increaseDepth else if ( Threads.increaseDepth
&& !mainThread->ponder && !mainThread->ponder
&& Time.elapsed() > totalTime * 0.43) && Time.elapsed() > totalTime * 0.53)
Threads.increaseDepth = false; Threads.increaseDepth = false;
else else
Threads.increaseDepth = true; Threads.increaseDepth = true;
@@ -553,18 +552,17 @@ namespace {
Move ttMove, move, excludedMove, bestMove; Move ttMove, move, excludedMove, bestMove;
Depth extension, newDepth; Depth extension, newDepth;
Value bestValue, value, ttValue, eval, maxValue, probCutBeta; Value bestValue, value, ttValue, eval, maxValue, probCutBeta;
bool givesCheck, improving, didLMR, priorCapture; bool givesCheck, improving, priorCapture, singularQuietLMR;
bool capture, doFullDepthSearch, moveCountPruning, ttCapture; bool capture, moveCountPruning, ttCapture;
Piece movedPiece; Piece movedPiece;
int moveCount, captureCount, quietCount, bestMoveCount, improvement, complexity; int moveCount, captureCount, quietCount, improvement, complexity;
// Step 1. Initialize node // Step 1. Initialize node
Thread* thisThread = pos.this_thread(); Thread* thisThread = pos.this_thread();
thisThread->depth = depth;
ss->inCheck = pos.checkers(); ss->inCheck = pos.checkers();
priorCapture = pos.captured_piece(); priorCapture = pos.captured_piece();
Color us = pos.side_to_move(); Color us = pos.side_to_move();
moveCount = bestMoveCount = captureCount = quietCount = ss->moveCount = 0; moveCount = captureCount = quietCount = ss->moveCount = 0;
bestValue = -VALUE_INFINITE; bestValue = -VALUE_INFINITE;
maxValue = VALUE_INFINITE; maxValue = VALUE_INFINITE;
@@ -604,8 +602,8 @@ namespace {
(ss+1)->ttPv = false; (ss+1)->ttPv = false;
(ss+1)->excludedMove = bestMove = MOVE_NONE; (ss+1)->excludedMove = bestMove = MOVE_NONE;
(ss+2)->killers[0] = (ss+2)->killers[1] = MOVE_NONE; (ss+2)->killers[0] = (ss+2)->killers[1] = MOVE_NONE;
(ss+2)->cutoffCnt = 0;
ss->doubleExtensions = (ss-1)->doubleExtensions; ss->doubleExtensions = (ss-1)->doubleExtensions;
ss->depth = depth;
Square prevSq = to_sq((ss-1)->currentMove); Square prevSq = to_sq((ss-1)->currentMove);
// Initialize statScore to zero for the grandchildren of the current position. // Initialize statScore to zero for the grandchildren of the current position.
@@ -632,10 +630,9 @@ namespace {
// At non-PV nodes we check for an early TT cutoff // At non-PV nodes we check for an early TT cutoff
if ( !PvNode if ( !PvNode
&& ss->ttHit && ss->ttHit
&& tte->depth() > depth - (thisThread->id() % 2 == 1) && tte->depth() > depth - (tte->bound() == BOUND_EXACT)
&& ttValue != VALUE_NONE // Possible in case of TT access race && ttValue != VALUE_NONE // Possible in case of TT access race
&& (ttValue >= beta ? (tte->bound() & BOUND_LOWER) && (tte->bound() & (ttValue >= beta ? BOUND_LOWER : BOUND_UPPER)))
: (tte->bound() & BOUND_UPPER)))
{ {
// If ttMove is quiet, update move sorting heuristics on TT hit (~1 Elo) // If ttMove is quiet, update move sorting heuristics on TT hit (~1 Elo)
if (ttMove) if (ttMove)
@@ -734,11 +731,9 @@ namespace {
// Never assume anything about values stored in TT // Never assume anything about values stored in TT
ss->staticEval = eval = tte->eval(); ss->staticEval = eval = tte->eval();
if (eval == VALUE_NONE) if (eval == VALUE_NONE)
ss->staticEval = eval = evaluate(pos); ss->staticEval = eval = evaluate(pos, &complexity);
else // Fall back to (semi)classical complexity for TT hits, the NNUE complexity is lost
// Randomize draw evaluation complexity = abs(ss->staticEval - pos.psq_eg_stm());
if (eval == VALUE_DRAW)
eval = value_draw(thisThread);
// ttValue can be used as a better position evaluation (~4 Elo) // ttValue can be used as a better position evaluation (~4 Elo)
if ( ttValue != VALUE_NONE if ( ttValue != VALUE_NONE
@@ -747,17 +742,19 @@ namespace {
} }
else else
{ {
ss->staticEval = eval = evaluate(pos); ss->staticEval = eval = evaluate(pos, &complexity);
// Save static evaluation into transposition table // Save static evaluation into transposition table
if (!excludedMove) if (!excludedMove)
tte->save(posKey, VALUE_NONE, ss->ttPv, BOUND_NONE, DEPTH_NONE, MOVE_NONE, eval); tte->save(posKey, VALUE_NONE, ss->ttPv, BOUND_NONE, DEPTH_NONE, MOVE_NONE, eval);
} }
thisThread->complexityAverage.update(complexity);
// Use static evaluation difference to improve quiet move ordering (~3 Elo) // Use static evaluation difference to improve quiet move ordering (~3 Elo)
if (is_ok((ss-1)->currentMove) && !(ss-1)->inCheck && !priorCapture) if (is_ok((ss-1)->currentMove) && !(ss-1)->inCheck && !priorCapture)
{ {
int bonus = std::clamp(-16 * int((ss-1)->staticEval + ss->staticEval), -2000, 2000); int bonus = std::clamp(-19 * int((ss-1)->staticEval + ss->staticEval), -1914, 1914);
thisThread->mainHistory[~us][from_to((ss-1)->currentMove)] << bonus; thisThread->mainHistory[~us][from_to((ss-1)->currentMove)] << bonus;
} }
@@ -767,19 +764,13 @@ namespace {
// margin and the improving flag are used in various pruning heuristics. // margin and the improving flag are used in various pruning heuristics.
improvement = (ss-2)->staticEval != VALUE_NONE ? ss->staticEval - (ss-2)->staticEval improvement = (ss-2)->staticEval != VALUE_NONE ? ss->staticEval - (ss-2)->staticEval
: (ss-4)->staticEval != VALUE_NONE ? ss->staticEval - (ss-4)->staticEval : (ss-4)->staticEval != VALUE_NONE ? ss->staticEval - (ss-4)->staticEval
: 175; : 168;
improving = improvement > 0; improving = improvement > 0;
complexity = abs(ss->staticEval - (us == WHITE ? eg_value(pos.psq_score()) : -eg_value(pos.psq_score())));
thisThread->complexityAverage.update(complexity);
// Step 7. Razoring. // Step 7. Razoring.
// If eval is really low check with qsearch if it can exceed alpha, if it can't, // If eval is really low check with qsearch if it can exceed alpha, if it can't,
// return a fail low. // return a fail low.
if ( !PvNode if (eval < alpha - 369 - 254 * depth * depth)
&& depth <= 7
&& eval < alpha - 348 - 258 * depth * depth)
{ {
value = qsearch<NonPV>(pos, ss, alpha - 1, alpha); value = qsearch<NonPV>(pos, ss, alpha - 1, alpha);
if (value < alpha) if (value < alpha)
@@ -790,18 +781,18 @@ namespace {
// The depth condition is important for mate finding. // The depth condition is important for mate finding.
if ( !ss->ttPv if ( !ss->ttPv
&& depth < 8 && depth < 8
&& eval - futility_margin(depth, improving) - (ss-1)->statScore / 256 >= beta && eval - futility_margin(depth, improving) - (ss-1)->statScore / 303 >= beta
&& eval >= beta && eval >= beta
&& eval < 26305) // larger than VALUE_KNOWN_WIN, but smaller than TB wins. && eval < 28031) // larger than VALUE_KNOWN_WIN, but smaller than TB wins
return eval; return eval;
// Step 9. Null move search with verification search (~22 Elo) // Step 9. Null move search with verification search (~22 Elo)
if ( !PvNode if ( !PvNode
&& (ss-1)->currentMove != MOVE_NULL && (ss-1)->currentMove != MOVE_NULL
&& (ss-1)->statScore < 14695 && (ss-1)->statScore < 17139
&& eval >= beta && eval >= beta
&& eval >= ss->staticEval && eval >= ss->staticEval
&& ss->staticEval >= beta - 15 * depth - improvement / 15 + 198 + complexity / 28 && ss->staticEval >= beta - 20 * depth - improvement / 13 + 233 + complexity / 25
&& !excludedMove && !excludedMove
&& pos.non_pawn_material(us) && pos.non_pawn_material(us)
&& (ss->ply >= thisThread->nmpMinPly || us != thisThread->nmpColor)) && (ss->ply >= thisThread->nmpMinPly || us != thisThread->nmpColor))
@@ -809,7 +800,7 @@ namespace {
assert(eval - beta >= 0); assert(eval - beta >= 0);
// Null move dynamic reduction based on depth, eval and complexity of position // Null move dynamic reduction based on depth, eval and complexity of position
Depth R = std::min(int(eval - beta) / 147, 5) + depth / 3 + 4 - (complexity > 753); Depth R = std::min(int(eval - beta) / 168, 7) + depth / 3 + 4 - (complexity > 861);
ss->currentMove = MOVE_NULL; ss->currentMove = MOVE_NULL;
ss->continuationHistory = &thisThread->continuationHistory[0][0][NO_PIECE][0]; ss->continuationHistory = &thisThread->continuationHistory[0][0][NO_PIECE][0];
@@ -845,7 +836,7 @@ namespace {
} }
} }
probCutBeta = beta + 179 - 46 * improving; probCutBeta = beta + 191 - 54 * improving;
// Step 10. ProbCut (~4 Elo) // Step 10. ProbCut (~4 Elo)
// If we have a good enough capture and a reduced search returns a value // If we have a good enough capture and a reduced search returns a value
@@ -864,21 +855,16 @@ namespace {
{ {
assert(probCutBeta < VALUE_INFINITE); assert(probCutBeta < VALUE_INFINITE);
MovePicker mp(pos, ttMove, probCutBeta - ss->staticEval, depth - 3, &captureHistory); MovePicker mp(pos, ttMove, probCutBeta - ss->staticEval, &captureHistory);
bool ttPv = ss->ttPv;
bool captureOrPromotion;
ss->ttPv = false;
while ((move = mp.next_move()) != MOVE_NONE) while ((move = mp.next_move()) != MOVE_NONE)
if (move != excludedMove && pos.legal(move)) if (move != excludedMove && pos.legal(move))
{ {
assert(pos.capture(move) || promotion_type(move) == QUEEN); assert(pos.capture(move) || promotion_type(move) == QUEEN);
captureOrPromotion = true;
ss->currentMove = move; ss->currentMove = move;
ss->continuationHistory = &thisThread->continuationHistory[ss->inCheck] ss->continuationHistory = &thisThread->continuationHistory[ss->inCheck]
[captureOrPromotion] [true]
[pos.moved_piece(move)] [pos.moved_piece(move)]
[to_sq(move)]; [to_sq(move)];
@@ -895,34 +881,31 @@ namespace {
if (value >= probCutBeta) if (value >= probCutBeta)
{ {
// if transposition table doesn't have equal or more deep info write probCut data into it // Save ProbCut data into transposition table
if ( !(ss->ttHit tte->save(posKey, value_to_tt(value, ss->ply), ss->ttPv, BOUND_LOWER, depth - 3, move, ss->staticEval);
&& tte->depth() >= depth - 3
&& ttValue != VALUE_NONE))
tte->save(posKey, value_to_tt(value, ss->ply), ttPv,
BOUND_LOWER,
depth - 3, move, ss->staticEval);
return value; return value;
} }
} }
ss->ttPv = ttPv;
} }
// Step 11. If the position is not in TT, decrease depth by 2 or 1 depending on node type (~3 Elo) // Step 11. If the position is not in TT, decrease depth by 3.
if ( PvNode // Use qsearch if depth is equal or below zero (~4 Elo)
&& depth >= 3 if ( PvNode
&& !ttMove)
depth -= 3;
if (depth <= 0)
return qsearch<PV>(pos, ss, alpha, beta);
if ( cutNode
&& depth >= 9
&& !ttMove) && !ttMove)
depth -= 2; depth -= 2;
if ( cutNode
&& depth >= 8
&& !ttMove)
depth--;
moves_loop: // When in check, search starts here moves_loop: // When in check, search starts here
// Step 12. A small Probcut idea, when we are in check (~0 Elo) // Step 12. A small Probcut idea, when we are in check (~0 Elo)
probCutBeta = beta + 481; probCutBeta = beta + 417;
if ( ss->inCheck if ( ss->inCheck
&& !PvNode && !PvNode
&& depth >= 2 && depth >= 2
@@ -949,7 +932,7 @@ moves_loop: // When in check, search starts here
ss->killers); ss->killers);
value = bestValue; value = bestValue;
moveCountPruning = false; moveCountPruning = singularQuietLMR = false;
// Indicate PvNodes that will probably fail low if the node was searched // Indicate PvNodes that will probably fail low if the node was searched
// at a depth equal or greater than the current depth, and the result of this search was a fail low. // at a depth equal or greater than the current depth, and the result of this search was a fail low.
@@ -1013,17 +996,16 @@ moves_loop: // When in check, search starts here
|| givesCheck) || givesCheck)
{ {
// Futility pruning for captures (~0 Elo) // Futility pruning for captures (~0 Elo)
if ( !pos.empty(to_sq(move)) if ( !givesCheck
&& !givesCheck
&& !PvNode && !PvNode
&& lmrDepth < 6 && lmrDepth < 7
&& !ss->inCheck && !ss->inCheck
&& ss->staticEval + 281 + 179 * lmrDepth + PieceValue[EG][pos.piece_on(to_sq(move))] && ss->staticEval + 180 + 201 * lmrDepth + PieceValue[EG][pos.piece_on(to_sq(move))]
+ captureHistory[movedPiece][to_sq(move)][type_of(pos.piece_on(to_sq(move)))] / 6 < alpha) + captureHistory[movedPiece][to_sq(move)][type_of(pos.piece_on(to_sq(move)))] / 6 < alpha)
continue; continue;
// SEE based pruning (~9 Elo) // SEE based pruning (~9 Elo)
if (!pos.see_ge(move, Value(-203) * depth)) if (!pos.see_ge(move, Value(-222) * depth))
continue; continue;
} }
else else
@@ -1037,16 +1019,16 @@ moves_loop: // When in check, search starts here
&& history < -3875 * (depth - 1)) && history < -3875 * (depth - 1))
continue; continue;
history += thisThread->mainHistory[us][from_to(move)]; history += 2 * thisThread->mainHistory[us][from_to(move)];
// Futility pruning: parent node (~9 Elo) // Futility pruning: parent node (~9 Elo)
if ( !ss->inCheck if ( !ss->inCheck
&& lmrDepth < 11 && lmrDepth < 13
&& ss->staticEval + 122 + 138 * lmrDepth + history / 60 <= alpha) && ss->staticEval + 106 + 145 * lmrDepth + history / 52 <= alpha)
continue; continue;
// Prune moves with negative SEE (~3 Elo) // Prune moves with negative SEE (~3 Elo)
if (!pos.see_ge(move, Value(-25 * lmrDepth * lmrDepth - 20 * lmrDepth))) if (!pos.see_ge(move, Value(-24 * lmrDepth * lmrDepth - 15 * lmrDepth)))
continue; continue;
} }
} }
@@ -1061,7 +1043,7 @@ moves_loop: // When in check, search starts here
// a reduced search on all the other moves but the ttMove and if the // a reduced search on all the other moves but the ttMove and if the
// result is lower than ttValue minus a margin, then we will extend the ttMove. // result is lower than ttValue minus a margin, then we will extend the ttMove.
if ( !rootNode if ( !rootNode
&& depth >= 4 + 2 * (PvNode && tte->is_pv()) && depth >= 4 - (thisThread->previousDepth > 24) + 2 * (PvNode && tte->is_pv())
&& move == ttMove && move == ttMove
&& !excludedMove // Avoid recursive singular search && !excludedMove // Avoid recursive singular search
/* && ttValue != VALUE_NONE Already implicit in the next condition */ /* && ttValue != VALUE_NONE Already implicit in the next condition */
@@ -1069,7 +1051,7 @@ moves_loop: // When in check, search starts here
&& (tte->bound() & BOUND_LOWER) && (tte->bound() & BOUND_LOWER)
&& tte->depth() >= depth - 3) && tte->depth() >= depth - 3)
{ {
Value singularBeta = ttValue - 3 * depth; Value singularBeta = ttValue - (3 + (ss->ttPv && !PvNode)) * depth;
Depth singularDepth = (depth - 1) / 2; Depth singularDepth = (depth - 1) / 2;
ss->excludedMove = move; ss->excludedMove = move;
@@ -1079,11 +1061,12 @@ moves_loop: // When in check, search starts here
if (value < singularBeta) if (value < singularBeta)
{ {
extension = 1; extension = 1;
singularQuietLMR = !ttCapture;
// Avoid search explosion by limiting the number of double extensions // Avoid search explosion by limiting the number of double extensions
if ( !PvNode if ( !PvNode
&& value < singularBeta - 26 && value < singularBeta - 25
&& ss->doubleExtensions <= 8) && ss->doubleExtensions <= 9)
extension = 2; extension = 2;
} }
@@ -1098,19 +1081,23 @@ moves_loop: // When in check, search starts here
// If the eval of ttMove is greater than beta, we reduce it (negative extension) // If the eval of ttMove is greater than beta, we reduce it (negative extension)
else if (ttValue >= beta) else if (ttValue >= beta)
extension = -2; extension = -2;
// If the eval of ttMove is less than alpha and value, we reduce it (negative extension)
else if (ttValue <= alpha && ttValue <= value)
extension = -1;
} }
// Check extensions (~1 Elo) // Check extensions (~1 Elo)
else if ( givesCheck else if ( givesCheck
&& depth > 9 && depth > 9
&& abs(ss->staticEval) > 71) && abs(ss->staticEval) > 82)
extension = 1; extension = 1;
// Quiet ttMove extensions (~0 Elo) // Quiet ttMove extensions (~0 Elo)
else if ( PvNode else if ( PvNode
&& move == ttMove && move == ttMove
&& move == ss->killers[0] && move == ss->killers[0]
&& (*contHist[0])[movedPiece][to_sq(move)] >= 5491) && (*contHist[0])[movedPiece][to_sq(move)] >= 5177)
extension = 1; extension = 1;
} }
@@ -1131,8 +1118,6 @@ moves_loop: // When in check, search starts here
// Step 16. Make the move // Step 16. Make the move
pos.do_move(move, st, givesCheck); pos.do_move(move, st, givesCheck);
bool doDeeperSearch = false;
// Step 17. Late moves reduction / extension (LMR, ~98 Elo) // Step 17. Late moves reduction / extension (LMR, ~98 Elo)
// We use various heuristics for the sons of a node after the first son has // We use various heuristics for the sons of a node after the first son has
// been searched. In general we would like to reduce them, but there are many // been searched. In general we would like to reduce them, but there are many
@@ -1145,11 +1130,6 @@ moves_loop: // When in check, search starts here
{ {
Depth r = reduction(improving, depth, moveCount, delta, thisThread->rootDelta); Depth r = reduction(improving, depth, moveCount, delta, thisThread->rootDelta);
// Decrease reduction at some PvNodes (~2 Elo)
if ( PvNode
&& bestMoveCount <= 3)
r--;
// Decrease reduction if position is or has been on the PV // Decrease reduction if position is or has been on the PV
// and node is not likely to fail low. (~3 Elo) // and node is not likely to fail low. (~3 Elo)
if ( ss->ttPv if ( ss->ttPv
@@ -1161,63 +1141,59 @@ moves_loop: // When in check, search starts here
r--; r--;
// Increase reduction for cut nodes (~3 Elo) // Increase reduction for cut nodes (~3 Elo)
if (cutNode && move != ss->killers[0]) if (cutNode)
r += 2; r += 2;
// Increase reduction if ttMove is a capture (~3 Elo) // Increase reduction if ttMove is a capture (~3 Elo)
if (ttCapture) if (ttCapture)
r++; r++;
// Decrease reduction at PvNodes if bestvalue // Decrease reduction for PvNodes based on depth
// is vastly different from static evaluation if (PvNode)
if (PvNode && !ss->inCheck && abs(ss->staticEval - bestValue) > 250) r -= 1 + 11 / (3 + depth);
// Decrease reduction if ttMove has been singularly extended (~1 Elo)
if (singularQuietLMR)
r--; r--;
// Increase depth based reduction if PvNode // Decrease reduction if we move a threatened piece (~1 Elo)
if (PvNode) if ( depth > 9
r -= 15 / ( 3 + depth ); && (mp.threatenedPieces & from_sq(move)))
r--;
ss->statScore = thisThread->mainHistory[us][from_to(move)] // Increase reduction if next ply has a lot of fail high
if ((ss+1)->cutoffCnt > 3)
r++;
ss->statScore = 2 * thisThread->mainHistory[us][from_to(move)]
+ (*contHist[0])[movedPiece][to_sq(move)] + (*contHist[0])[movedPiece][to_sq(move)]
+ (*contHist[1])[movedPiece][to_sq(move)] + (*contHist[1])[movedPiece][to_sq(move)]
+ (*contHist[3])[movedPiece][to_sq(move)] + (*contHist[3])[movedPiece][to_sq(move)]
- 4334; - 4433;
// Decrease/increase reduction for moves with a good/bad history (~30 Elo) // Decrease/increase reduction for moves with a good/bad history (~30 Elo)
r -= ss->statScore / 15914; r -= ss->statScore / (13628 + 4000 * (depth > 7 && depth < 19));
// In general we want to cap the LMR depth search at newDepth. But if reductions // In general we want to cap the LMR depth search at newDepth, but when
// are really negative and movecount is low, we allow this move to be searched // reduction is negative, we allow this move a limited search extension
// deeper than the first move (this may lead to hidden double extensions). // beyond the first move depth. This may lead to hidden double extensions.
int deeper = r >= -1 ? 0 Depth d = std::clamp(newDepth - r, 1, newDepth + 1);
: moveCount <= 4 ? 2
: PvNode && depth > 4 ? 1
: cutNode && moveCount <= 8 ? 1
: 0;
Depth d = std::clamp(newDepth - r, 1, newDepth + deeper);
value = -search<NonPV>(pos, ss+1, -(alpha+1), -alpha, d, true); value = -search<NonPV>(pos, ss+1, -(alpha+1), -alpha, d, true);
// If the son is reduced and fails high it will be re-searched at full depth // Do full depth search when reduced LMR search fails high
doFullDepthSearch = value > alpha && d < newDepth; if (value > alpha && d < newDepth)
doDeeperSearch = value > (alpha + 78 + 11 * (newDepth - d));
didLMR = true;
}
else
{
doFullDepthSearch = !PvNode || moveCount > 1;
didLMR = false;
}
// Step 18. Full depth search when LMR is skipped or fails high
if (doFullDepthSearch)
{
value = -search<NonPV>(pos, ss+1, -(alpha+1), -alpha, newDepth + doDeeperSearch, !cutNode);
// If the move passed LMR update its stats
if (didLMR)
{ {
// Adjust full depth search based on LMR results - if result
// was good enough search deeper, if it was bad enough search shallower
const bool doDeeperSearch = value > (alpha + 64 + 11 * (newDepth - d));
const bool doShallowerSearch = value < bestValue + newDepth;
newDepth += doDeeperSearch - doShallowerSearch;
if (newDepth > d)
value = -search<NonPV>(pos, ss+1, -(alpha+1), -alpha, newDepth, !cutNode);
int bonus = value > alpha ? stat_bonus(newDepth) int bonus = value > alpha ? stat_bonus(newDepth)
: -stat_bonus(newDepth); : -stat_bonus(newDepth);
@@ -1228,6 +1204,12 @@ moves_loop: // When in check, search starts here
} }
} }
// Step 18. Full depth search when LMR is skipped
else if (!PvNode || moveCount > 1)
{
value = -search<NonPV>(pos, ss+1, -(alpha+1), -alpha, newDepth, !cutNode);
}
// For PV nodes only, do a full PV search on the first move or after a fail // For PV nodes only, do a full PV search on the first move or after a fail
// high (in the latter case search only if value < beta), otherwise let the // high (in the latter case search only if value < beta), otherwise let the
// parent node fail low with value <= alpha and try another move. // parent node fail low with value <= alpha and try another move.
@@ -1264,6 +1246,8 @@ moves_loop: // When in check, search starts here
{ {
rm.score = value; rm.score = value;
rm.selDepth = thisThread->selDepth; rm.selDepth = thisThread->selDepth;
rm.scoreLowerbound = value >= beta;
rm.scoreUpperbound = value <= alpha;
rm.pv.resize(1); rm.pv.resize(1);
assert((ss+1)->pv); assert((ss+1)->pv);
@@ -1299,16 +1283,26 @@ moves_loop: // When in check, search starts here
if (PvNode && value < beta) // Update alpha! Always alpha < beta if (PvNode && value < beta) // Update alpha! Always alpha < beta
{ {
alpha = value; alpha = value;
bestMoveCount++;
// Reduce other moves if we have found at least one score improvement
if ( depth > 1
&& depth < 6
&& beta < VALUE_KNOWN_WIN
&& alpha > -VALUE_KNOWN_WIN)
depth -= 1;
assert(depth > 0);
} }
else else
{ {
ss->cutoffCnt++;
assert(value >= beta); // Fail high assert(value >= beta); // Fail high
break; break;
} }
} }
} }
// If the move is worse than some previously searched move, remember it to update its stats later // If the move is worse than some previously searched move, remember it to update its stats later
if (move != bestMove) if (move != bestMove)
{ {
@@ -1346,14 +1340,14 @@ moves_loop: // When in check, search starts here
quietsSearched, quietCount, capturesSearched, captureCount, depth); quietsSearched, quietCount, capturesSearched, captureCount, depth);
// Bonus for prior countermove that caused the fail low // Bonus for prior countermove that caused the fail low
else if ( (depth >= 4 || PvNode) else if ( (depth >= 5 || PvNode)
&& !priorCapture) && !priorCapture)
{ {
//Assign extra bonus if current node is PvNode or cutNode //Assign extra bonus if current node is PvNode or cutNode
//or fail low was really bad //or fail low was really bad
bool extraBonus = PvNode bool extraBonus = PvNode
|| cutNode || cutNode
|| bestValue < alpha - 70 * depth; || bestValue < alpha - 62 * depth;
update_continuation_histories(ss-1, pos.piece_on(prevSq), prevSq, stat_bonus(depth) * (1 + extraBonus)); update_continuation_histories(ss-1, pos.piece_on(prevSq), prevSq, stat_bonus(depth) * (1 + extraBonus));
} }
@@ -1381,6 +1375,7 @@ moves_loop: // When in check, search starts here
// qsearch() is the quiescence search function, which is called by the main search // qsearch() is the quiescence search function, which is called by the main search
// function with zero depth, or recursively with further decreasing depth per call. // function with zero depth, or recursively with further decreasing depth per call.
// (~155 elo)
template <NodeType nodeType> template <NodeType nodeType>
Value qsearch(Position& pos, Stack* ss, Value alpha, Value beta, Depth depth) { Value qsearch(Position& pos, Stack* ss, Value alpha, Value beta, Depth depth) {
@@ -1437,8 +1432,7 @@ moves_loop: // When in check, search starts here
&& ss->ttHit && ss->ttHit
&& tte->depth() >= ttDepth && tte->depth() >= ttDepth
&& ttValue != VALUE_NONE // Only in case of TT access race && ttValue != VALUE_NONE // Only in case of TT access race
&& (ttValue >= beta ? (tte->bound() & BOUND_LOWER) && (tte->bound() & (ttValue >= beta ? BOUND_LOWER : BOUND_UPPER)))
: (tte->bound() & BOUND_UPPER)))
return ttValue; return ttValue;
// Evaluate the position statically // Evaluate the position statically
@@ -1480,7 +1474,7 @@ moves_loop: // When in check, search starts here
if (PvNode && bestValue > alpha) if (PvNode && bestValue > alpha)
alpha = bestValue; alpha = bestValue;
futilityBase = bestValue + 118; futilityBase = bestValue + 153;
} }
const PieceToHistory* contHist[] = { (ss-1)->continuationHistory, (ss-2)->continuationHistory, const PieceToHistory* contHist[] = { (ss-1)->continuationHistory, (ss-2)->continuationHistory,
@@ -1554,18 +1548,17 @@ moves_loop: // When in check, search starts here
[to_sq(move)]; [to_sq(move)];
// Continuation history based pruning (~2 Elo) // Continuation history based pruning (~2 Elo)
if ( !capture if ( !capture
&& bestValue > VALUE_TB_LOSS_IN_MAX_PLY && bestValue > VALUE_TB_LOSS_IN_MAX_PLY
&& (*contHist[0])[pos.moved_piece(move)][to_sq(move)] < CounterMovePruneThreshold && (*contHist[0])[pos.moved_piece(move)][to_sq(move)] < 0
&& (*contHist[1])[pos.moved_piece(move)][to_sq(move)] < CounterMovePruneThreshold) && (*contHist[1])[pos.moved_piece(move)][to_sq(move)] < 0)
continue; continue;
// movecount pruning for quiet check evasions // We prune after 2nd quiet check evasion where being 'in check' is implicitly checked through the counter
if ( bestValue > VALUE_TB_LOSS_IN_MAX_PLY // and being a 'quiet' apart from being a tt move is assumed after an increment because captures are pushed ahead.
&& quietCheckEvasions > 1 if ( bestValue > VALUE_TB_LOSS_IN_MAX_PLY
&& !capture && quietCheckEvasions > 1)
&& ss->inCheck) break;
continue;
quietCheckEvasions += !capture && ss->inCheck; quietCheckEvasions += !capture && ss->inCheck;
@@ -1662,7 +1655,7 @@ moves_loop: // When in check, search starts here
// update_pv() adds current move and appends child pv[] // update_pv() adds current move and appends child pv[]
void update_pv(Move* pv, Move move, Move* childPv) { void update_pv(Move* pv, Move move, const Move* childPv) {
for (*pv++ = move; childPv && *childPv != MOVE_NONE; ) for (*pv++ = move; childPv && *childPv != MOVE_NONE; )
*pv++ = *childPv++; *pv++ = *childPv++;
@@ -1675,19 +1668,18 @@ moves_loop: // When in check, search starts here
void update_all_stats(const Position& pos, Stack* ss, Move bestMove, Value bestValue, Value beta, Square prevSq, void update_all_stats(const Position& pos, Stack* ss, Move bestMove, Value bestValue, Value beta, Square prevSq,
Move* quietsSearched, int quietCount, Move* capturesSearched, int captureCount, Depth depth) { Move* quietsSearched, int quietCount, Move* capturesSearched, int captureCount, Depth depth) {
int bonus1, bonus2;
Color us = pos.side_to_move(); Color us = pos.side_to_move();
Thread* thisThread = pos.this_thread(); Thread* thisThread = pos.this_thread();
CapturePieceToHistory& captureHistory = thisThread->captureHistory; CapturePieceToHistory& captureHistory = thisThread->captureHistory;
Piece moved_piece = pos.moved_piece(bestMove); Piece moved_piece = pos.moved_piece(bestMove);
PieceType captured = type_of(pos.piece_on(to_sq(bestMove))); PieceType captured = type_of(pos.piece_on(to_sq(bestMove)));
int bonus1 = stat_bonus(depth + 1);
bonus1 = stat_bonus(depth + 1);
bonus2 = bestValue > beta + PawnValueMg ? bonus1 // larger bonus
: stat_bonus(depth); // smaller bonus
if (!pos.capture(bestMove)) if (!pos.capture(bestMove))
{ {
int bonus2 = bestValue > beta + 137 ? bonus1 // larger bonus
: stat_bonus(depth); // smaller bonus
// Increase stats for the best move in case it was a quiet move // Increase stats for the best move in case it was a quiet move
update_quiet_stats(pos, ss, bestMove, bonus2); update_quiet_stats(pos, ss, bestMove, bonus2);
@@ -1830,7 +1822,7 @@ void MainThread::check_time() {
/// UCI::pv() formats PV information according to the UCI protocol. UCI requires /// UCI::pv() formats PV information according to the UCI protocol. UCI requires
/// that all (if any) unsearched PV lines are sent using a previous search score. /// that all (if any) unsearched PV lines are sent using a previous search score.
string UCI::pv(const Position& pos, Depth depth, Value alpha, Value beta) { string UCI::pv(const Position& pos, Depth depth) {
std::stringstream ss; std::stringstream ss;
TimePoint elapsed = Time.elapsed() + 1; TimePoint elapsed = Time.elapsed() + 1;
@@ -1868,16 +1860,13 @@ string UCI::pv(const Position& pos, Depth depth, Value alpha, Value beta) {
if (Options["UCI_ShowWDL"]) if (Options["UCI_ShowWDL"])
ss << UCI::wdl(v, pos.game_ply()); ss << UCI::wdl(v, pos.game_ply());
if (!tb && i == pvIdx) if (i == pvIdx && !tb && updated) // tablebase- and previous-scores are exact
ss << (v >= beta ? " lowerbound" : v <= alpha ? " upperbound" : ""); ss << (rootMoves[i].scoreLowerbound ? " lowerbound" : (rootMoves[i].scoreUpperbound ? " upperbound" : ""));
ss << " nodes " << nodesSearched ss << " nodes " << nodesSearched
<< " nps " << nodesSearched * 1000 / elapsed; << " nps " << nodesSearched * 1000 / elapsed
<< " hashfull " << TT.hashfull()
if (elapsed > 1000) // Earlier makes little sense << " tbhits " << tbHits
ss << " hashfull " << TT.hashfull();
ss << " tbhits " << tbHits
<< " time " << elapsed << " time " << elapsed
<< " pv"; << " pv";
+3 -4
View File
@@ -31,9 +31,6 @@ class Position;
namespace Search { namespace Search {
/// Threshold used for countermoves based pruning
constexpr int CounterMovePruneThreshold = 0;
/// Stack struct keeps track of the information we need to remember from nodes /// Stack struct keeps track of the information we need to remember from nodes
/// shallower and deeper in the tree during the search. Each search thread has /// shallower and deeper in the tree during the search. Each search thread has
@@ -47,13 +44,13 @@ struct Stack {
Move excludedMove; Move excludedMove;
Move killers[2]; Move killers[2];
Value staticEval; Value staticEval;
Depth depth;
int statScore; int statScore;
int moveCount; int moveCount;
bool inCheck; bool inCheck;
bool ttPv; bool ttPv;
bool ttHit; bool ttHit;
int doubleExtensions; int doubleExtensions;
int cutoffCnt;
}; };
@@ -74,6 +71,8 @@ struct RootMove {
Value score = -VALUE_INFINITE; Value score = -VALUE_INFINITE;
Value previousScore = -VALUE_INFINITE; Value previousScore = -VALUE_INFINITE;
Value averageScore = -VALUE_INFINITE; Value averageScore = -VALUE_INFINITE;
bool scoreLowerbound = false;
bool scoreUpperbound = false;
int selDepth = 0; int selDepth = 0;
int tbRank = 0; int tbRank = 0;
Value tbScore; Value tbScore;
+8 -7
View File
@@ -59,6 +59,7 @@ namespace Stockfish {
namespace { namespace {
constexpr int TBPIECES = 7; // Max number of supported pieces constexpr int TBPIECES = 7; // Max number of supported pieces
constexpr int MAX_DTZ = 1 << 18; // Max DTZ supported, large enough to deal with the syzygy TB limit.
enum { BigEndian, LittleEndian }; enum { BigEndian, LittleEndian };
enum TBType { WDL, DTZ }; // Used as template parameter enum TBType { WDL, DTZ }; // Used as template parameter
@@ -1290,7 +1291,7 @@ void Tablebases::init(const std::string& paths) {
for (auto s : diagonal) for (auto s : diagonal)
MapA1D1D4[s] = code++; MapA1D1D4[s] = code++;
// MapKK[] encodes all the 461 possible legal positions of two kings where // MapKK[] encodes all the 462 possible legal positions of two kings where
// the first is in the a1-d1-d4 triangle. If the first king is on the a1-d4 // the first is in the a1-d1-d4 triangle. If the first king is on the a1-d4
// diagonal, the other one shall not to be above the a1-h8 diagonal. // diagonal, the other one shall not to be above the a1-h8 diagonal.
std::vector<std::pair<int, Square>> bothOnDiagonal; std::vector<std::pair<int, Square>> bothOnDiagonal;
@@ -1522,7 +1523,7 @@ bool Tablebases::root_probe(Position& pos, Search::RootMoves& rootMoves) {
// Check whether a position was repeated since the last zeroing move. // Check whether a position was repeated since the last zeroing move.
bool rep = pos.has_repeated(); bool rep = pos.has_repeated();
int dtz, bound = Options["Syzygy50MoveRule"] ? 900 : 1; int dtz, bound = Options["Syzygy50MoveRule"] ? (MAX_DTZ - 100) : 1;
// Probe and rank each move // Probe and rank each move
for (auto& m : rootMoves) for (auto& m : rootMoves)
@@ -1565,8 +1566,8 @@ bool Tablebases::root_probe(Position& pos, Search::RootMoves& rootMoves) {
// Better moves are ranked higher. Certain wins are ranked equally. // Better moves are ranked higher. Certain wins are ranked equally.
// Losing moves are ranked equally unless a 50-move draw is in sight. // Losing moves are ranked equally unless a 50-move draw is in sight.
int r = dtz > 0 ? (dtz + cnt50 <= 99 && !rep ? 1000 : 1000 - (dtz + cnt50)) int r = dtz > 0 ? (dtz + cnt50 <= 99 && !rep ? MAX_DTZ : MAX_DTZ - (dtz + cnt50))
: dtz < 0 ? (-dtz * 2 + cnt50 < 100 ? -1000 : -1000 + (-dtz + cnt50)) : dtz < 0 ? (-dtz * 2 + cnt50 < 100 ? -MAX_DTZ : -MAX_DTZ + (-dtz + cnt50))
: 0; : 0;
m.tbRank = r; m.tbRank = r;
@@ -1574,9 +1575,9 @@ bool Tablebases::root_probe(Position& pos, Search::RootMoves& rootMoves) {
// 1 cp to cursed wins and let it grow to 49 cp as the positions gets // 1 cp to cursed wins and let it grow to 49 cp as the positions gets
// closer to a real win. // closer to a real win.
m.tbScore = r >= bound ? VALUE_MATE - MAX_PLY - 1 m.tbScore = r >= bound ? VALUE_MATE - MAX_PLY - 1
: r > 0 ? Value((std::max( 3, r - 800) * int(PawnValueEg)) / 200) : r > 0 ? Value((std::max( 3, r - (MAX_DTZ - 200)) * int(PawnValueEg)) / 200)
: r == 0 ? VALUE_DRAW : r == 0 ? VALUE_DRAW
: r > -bound ? Value((std::min(-3, r + 800) * int(PawnValueEg)) / 200) : r > -bound ? Value((std::min(-3, r + (MAX_DTZ - 200)) * int(PawnValueEg)) / 200)
: -VALUE_MATE + MAX_PLY + 1; : -VALUE_MATE + MAX_PLY + 1;
} }
@@ -1590,7 +1591,7 @@ bool Tablebases::root_probe(Position& pos, Search::RootMoves& rootMoves) {
// A return value false indicates that not all probes were successful. // A return value false indicates that not all probes were successful.
bool Tablebases::root_probe_wdl(Position& pos, Search::RootMoves& rootMoves) { bool Tablebases::root_probe_wdl(Position& pos, Search::RootMoves& rootMoves) {
static const int WDL_to_rank[] = { -1000, -899, 0, 899, 1000 }; static const int WDL_to_rank[] = { -MAX_DTZ, -MAX_DTZ + 101, 0, MAX_DTZ - 101, MAX_DTZ };
ProbeState result; ProbeState result;
StateInfo st; StateInfo st;
-2
View File
@@ -31,8 +31,6 @@ enum WDLScore {
WDLDraw = 0, // Draw WDLDraw = 0, // Draw
WDLCursedWin = 1, // Win, but draw under 50-move rule WDLCursedWin = 1, // Win, but draw under 50-move rule
WDLWin = 2, // Win WDLWin = 2, // Win
WDLScoreNone = -1000
}; };
// Possible states after a probing operation // Possible states after a probing operation
+13 -11
View File
@@ -60,15 +60,13 @@ void Thread::clear() {
counterMoves.fill(MOVE_NONE); counterMoves.fill(MOVE_NONE);
mainHistory.fill(0); mainHistory.fill(0);
captureHistory.fill(0); captureHistory.fill(0);
previousDepth = 0;
for (bool inCheck : { false, true }) for (bool inCheck : { false, true })
for (StatsType c : { NoCaptures, Captures }) for (StatsType c : { NoCaptures, Captures })
{
for (auto& to : continuationHistory[inCheck][c]) for (auto& to : continuationHistory[inCheck][c])
for (auto& h : to) for (auto& h : to)
h->fill(-71); h->fill(-71);
continuationHistory[inCheck][c][NO_PIECE][0]->fill(Search::CounterMovePruneThreshold - 1);
}
} }
@@ -223,11 +221,14 @@ Thread* ThreadPool::get_best_thread() const {
minScore = std::min(minScore, th->rootMoves[0].score); minScore = std::min(minScore, th->rootMoves[0].score);
// Vote according to score and depth, and select the best thread // Vote according to score and depth, and select the best thread
for (Thread* th : *this) auto thread_value = [minScore](Thread* th) {
{ return (th->rootMoves[0].score - minScore + 14) * int(th->completedDepth);
votes[th->rootMoves[0].pv[0]] += };
(th->rootMoves[0].score - minScore + 14) * int(th->completedDepth);
for (Thread* th : *this)
votes[th->rootMoves[0].pv[0]] += thread_value(th);
for (Thread* th : *this)
if (abs(bestThread->rootMoves[0].score) >= VALUE_TB_WIN_IN_MAX_PLY) if (abs(bestThread->rootMoves[0].score) >= VALUE_TB_WIN_IN_MAX_PLY)
{ {
// Make sure we pick the shortest mate / TB conversion or stave off mate the longest // Make sure we pick the shortest mate / TB conversion or stave off mate the longest
@@ -236,9 +237,10 @@ Thread* ThreadPool::get_best_thread() const {
} }
else if ( th->rootMoves[0].score >= VALUE_TB_WIN_IN_MAX_PLY else if ( th->rootMoves[0].score >= VALUE_TB_WIN_IN_MAX_PLY
|| ( th->rootMoves[0].score > VALUE_TB_LOSS_IN_MAX_PLY || ( th->rootMoves[0].score > VALUE_TB_LOSS_IN_MAX_PLY
&& votes[th->rootMoves[0].pv[0]] > votes[bestThread->rootMoves[0].pv[0]])) && ( votes[th->rootMoves[0].pv[0]] > votes[bestThread->rootMoves[0].pv[0]]
|| ( votes[th->rootMoves[0].pv[0]] == votes[bestThread->rootMoves[0].pv[0]]
&& thread_value(th) > thread_value(bestThread)))))
bestThread = th; bestThread = th;
}
return bestThread; return bestThread;
} }
+1 -2
View File
@@ -69,13 +69,12 @@ public:
Position rootPos; Position rootPos;
StateInfo rootState; StateInfo rootState;
Search::RootMoves rootMoves; Search::RootMoves rootMoves;
Depth rootDepth, completedDepth, depth; Depth rootDepth, completedDepth, previousDepth;
Value rootDelta; Value rootDelta;
CounterMoveHistory counterMoves; CounterMoveHistory counterMoves;
ButterflyHistory mainHistory; ButterflyHistory mainHistory;
CapturePieceToHistory captureHistory; CapturePieceToHistory captureHistory;
ContinuationHistory continuationHistory[2][2]; ContinuationHistory continuationHistory[2][2];
Score trend;
}; };
+1 -1
View File
@@ -80,7 +80,7 @@ void TimeManagement::init(Search::LimitsType& limits, Color us, int ply) {
// game time for the current move, so also cap to 20% of available game time. // game time for the current move, so also cap to 20% of available game time.
if (limits.movestogo == 0) if (limits.movestogo == 0)
{ {
optScale = std::min(0.0084 + std::pow(ply + 3.0, 0.5) * 0.0042, optScale = std::min(0.0120 + std::pow(ply + 3.0, 0.45) * 0.0039,
0.2 * limits.time[us] / double(timeLeft)) 0.2 * limits.time[us] / double(timeLeft))
* optExtra; * optExtra;
maxScale = std::min(7.0, 4.0 + ply / 12.0); maxScale = std::min(7.0, 4.0 + ply / 12.0);
+1 -1
View File
@@ -450,7 +450,7 @@ constexpr Square to_sq(Move m) {
} }
constexpr int from_to(Move m) { constexpr int from_to(Move m) {
return m & 0xFFF; return m & 0xFFF;
} }
constexpr MoveType type_of(Move m) { constexpr MoveType type_of(Move m) {
+73 -63
View File
@@ -40,14 +40,14 @@ extern vector<string> setup_bench(const Position&, istream&);
namespace { namespace {
// FEN string of the initial position, normal chess // FEN string for the initial position in standard chess
const char* StartFEN = "rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq - 0 1"; const char* StartFEN = "rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq - 0 1";
// position() is called when engine receives the "position" UCI command. // position() is called when the engine receives the "position" UCI command.
// The function sets up the position described in the given FEN string ("fen") // It sets up the position that is described in the given FEN string ("fen") or
// or the starting position ("startpos") and then makes the moves given in the // the initial position ("startpos") and then makes the moves given in the following
// following move list ("moves"). // move list ("moves").
void position(Position& pos, istringstream& is, StateListPtr& states) { void position(Position& pos, istringstream& is, StateListPtr& states) {
@@ -59,7 +59,7 @@ namespace {
if (token == "startpos") if (token == "startpos")
{ {
fen = StartFEN; fen = StartFEN;
is >> token; // Consume "moves" token if any is >> token; // Consume the "moves" token, if any
} }
else if (token == "fen") else if (token == "fen")
while (is >> token && token != "moves") while (is >> token && token != "moves")
@@ -67,10 +67,10 @@ namespace {
else else
return; return;
states = StateListPtr(new std::deque<StateInfo>(1)); // Drop old and create a new one states = StateListPtr(new std::deque<StateInfo>(1)); // Drop the old state and create a new one
pos.set(fen, Options["UCI_Chess960"], &states->back(), Threads.main()); pos.set(fen, Options["UCI_Chess960"], &states->back(), Threads.main());
// Parse move list (if any) // Parse the move list, if any
while (is >> token && (m = UCI::to_move(pos, token)) != MOVE_NONE) while (is >> token && (m = UCI::to_move(pos, token)) != MOVE_NONE)
{ {
states->emplace_back(); states->emplace_back();
@@ -78,8 +78,8 @@ namespace {
} }
} }
// trace_eval() prints the evaluation for the current position, consistent with the UCI // trace_eval() prints the evaluation of the current position, consistent with
// options set so far. // the UCI options set so far.
void trace_eval(Position& pos) { void trace_eval(Position& pos) {
@@ -93,20 +93,20 @@ namespace {
} }
// setoption() is called when engine receives the "setoption" UCI command. The // setoption() is called when the engine receives the "setoption" UCI command.
// function updates the UCI option ("name") to the given value ("value"). // The function updates the UCI option ("name") to the given value ("value").
void setoption(istringstream& is) { void setoption(istringstream& is) {
string token, name, value; string token, name, value;
is >> token; // Consume "name" token is >> token; // Consume the "name" token
// Read option name (can contain spaces) // Read the option name (can contain spaces)
while (is >> token && token != "value") while (is >> token && token != "value")
name += (name.empty() ? "" : " ") + token; name += (name.empty() ? "" : " ") + token;
// Read option value (can contain spaces) // Read the option value (can contain spaces)
while (is >> token) while (is >> token)
value += (value.empty() ? "" : " ") + token; value += (value.empty() ? "" : " ") + token;
@@ -117,9 +117,9 @@ namespace {
} }
// go() is called when engine receives the "go" UCI command. The function sets // go() is called when the engine receives the "go" UCI command. The function
// the thinking time and other parameters from the input string, then starts // sets the thinking time and other parameters from the input string, then starts
// the search. // with a search.
void go(Position& pos, istringstream& is, StateListPtr& states) { void go(Position& pos, istringstream& is, StateListPtr& states) {
@@ -127,7 +127,7 @@ namespace {
string token; string token;
bool ponderMode = false; bool ponderMode = false;
limits.startTime = now(); // As early as possible! limits.startTime = now(); // The search starts as early as possible
while (is >> token) while (is >> token)
if (token == "searchmoves") // Needs to be the last command on the line if (token == "searchmoves") // Needs to be the last command on the line
@@ -151,9 +151,9 @@ namespace {
} }
// bench() is called when engine receives the "bench" command. Firstly // bench() is called when the engine receives the "bench" command.
// a list of UCI commands is setup according to bench parameters, then // Firstly, a list of UCI commands is set up according to the bench
// it is run one by one printing a summary at the end. // parameters, then it is run one by one, printing a summary at the end.
void bench(Position& pos, istream& args, StateListPtr& states) { void bench(Position& pos, istream& args, StateListPtr& states) {
@@ -184,12 +184,12 @@ namespace {
} }
else if (token == "setoption") setoption(is); else if (token == "setoption") setoption(is);
else if (token == "position") position(pos, is, states); else if (token == "position") position(pos, is, states);
else if (token == "ucinewgame") { Search::clear(); elapsed = now(); } // Search::clear() may take some while else if (token == "ucinewgame") { Search::clear(); elapsed = now(); } // Search::clear() may take a while
} }
elapsed = now() - elapsed + 1; // Ensure positivity to avoid a 'divide by zero' elapsed = now() - elapsed + 1; // Ensure positivity to avoid a 'divide by zero'
dbg_print(); // Just before exiting dbg_print();
cerr << "\n===========================" cerr << "\n==========================="
<< "\nTotal time (ms) : " << elapsed << "\nTotal time (ms) : " << elapsed
@@ -197,36 +197,40 @@ namespace {
<< "\nNodes/second : " << 1000 * nodes / elapsed << endl; << "\nNodes/second : " << 1000 * nodes / elapsed << endl;
} }
// The win rate model returns the probability (per mille) of winning given an eval // The win rate model returns the probability of winning (in per mille units) given an
// and a game-ply. The model fits rather accurately the LTC fishtest statistics. // eval and a game ply. It fits the LTC fishtest statistics rather accurately.
int win_rate_model(Value v, int ply) { int win_rate_model(Value v, int ply) {
// The model captures only up to 240 plies, so limit input (and rescale) // The model only captures up to 240 plies, so limit the input and then rescale
double m = std::min(240, ply) / 64.0; double m = std::min(240, ply) / 64.0;
// Coefficients of a 3rd order polynomial fit based on fishtest data // The coefficients of a third-order polynomial fit is based on the fishtest data
// for two parameters needed to transform eval to the argument of a // for two parameters that need to transform eval to the argument of a logistic
// logistic function. // function.
double as[] = {-1.17202460e-01, 5.94729104e-01, 1.12065546e+01, 1.22606222e+02}; constexpr double as[] = { -0.58270499, 2.68512549, 15.24638015, 344.49745382};
double bs[] = {-1.79066759, 11.30759193, -17.43677612, 36.47147479}; constexpr double bs[] = { -2.65734562, 15.96509799, -20.69040836, 73.61029937 };
// Enforce that NormalizeToPawnValue corresponds to a 50% win rate at ply 64
static_assert(UCI::NormalizeToPawnValue == int(as[0] + as[1] + as[2] + as[3]));
double a = (((as[0] * m + as[1]) * m + as[2]) * m) + as[3]; 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]; double b = (((bs[0] * m + bs[1]) * m + bs[2]) * m) + bs[3];
// Transform eval to centipawns with limited range // Transform the eval to centipawns with limited range
double x = std::clamp(double(100 * v) / PawnValueEg, -2000.0, 2000.0); double x = std::clamp(double(v), -4000.0, 4000.0);
// Return win rate in per mille (rounded to nearest) // Return the win rate in per mille units rounded to the nearest value
return int(0.5 + 1000 / (1 + std::exp((a - x) / b))); return int(0.5 + 1000 / (1 + std::exp((a - x) / b)));
} }
} // namespace } // namespace
/// UCI::loop() waits for a command from stdin, parses it and calls the appropriate /// UCI::loop() waits for a command from the stdin, parses it and then calls the appropriate
/// function. Also intercepts EOF from stdin to ensure gracefully exiting if the /// function. It also intercepts an end-of-file (EOF) indication from the stdin to ensure a
/// GUI dies unexpectedly. When called with some command line arguments, e.g. to /// graceful exit if the GUI dies unexpectedly. When called with some command-line arguments,
/// run 'bench', once the command is executed the function returns immediately. /// like running 'bench', the function returns immediately after the command is executed.
/// In addition to the UCI ones, also some additional debug commands are supported. /// In addition to the UCI ones, some additional debug commands are also supported.
void UCI::loop(int argc, char* argv[]) { void UCI::loop(int argc, char* argv[]) {
@@ -240,24 +244,24 @@ void UCI::loop(int argc, char* argv[]) {
cmd += std::string(argv[i]) + " "; cmd += std::string(argv[i]) + " ";
do { do {
if (argc == 1 && !getline(cin, cmd)) // Block here waiting for input or EOF if (argc == 1 && !getline(cin, cmd)) // Wait for an input or an end-of-file (EOF) indication
cmd = "quit"; cmd = "quit";
istringstream is(cmd); istringstream is(cmd);
token.clear(); // Avoid a stale if getline() returns empty or blank line token.clear(); // Avoid a stale if getline() returns nothing or a blank line
is >> skipws >> token; is >> skipws >> token;
if ( token == "quit" if ( token == "quit"
|| token == "stop") || token == "stop")
Threads.stop = true; Threads.stop = true;
// The GUI sends 'ponderhit' to tell us the user has played the expected move. // The GUI sends 'ponderhit' to tell that the user has played the expected move.
// So 'ponderhit' will be sent if we were told to ponder on the same move the // So, 'ponderhit' is sent if pondering was done on the same move that the user
// user has played. We should continue searching but switch from pondering to // has played. The search should continue, but should also switch from pondering
// normal search. // to the normal search.
else if (token == "ponderhit") else if (token == "ponderhit")
Threads.main()->ponder = false; // Switch to normal search Threads.main()->ponder = false; // Switch to the normal search
else if (token == "uci") else if (token == "uci")
sync_cout << "id name " << engine_info(true) sync_cout << "id name " << engine_info(true)
@@ -270,8 +274,8 @@ void UCI::loop(int argc, char* argv[]) {
else if (token == "ucinewgame") Search::clear(); else if (token == "ucinewgame") Search::clear();
else if (token == "isready") sync_cout << "readyok" << sync_endl; else if (token == "isready") sync_cout << "readyok" << sync_endl;
// Additional custom non-UCI commands, mainly for debugging. // Add custom non-UCI commands, mainly for debugging purposes.
// Do not use these commands during a search! // These commands must not be used during a search!
else if (token == "flip") pos.flip(); else if (token == "flip") pos.flip();
else if (token == "bench") bench(pos, is, states); else if (token == "bench") bench(pos, is, states);
else if (token == "d") sync_cout << pos << sync_endl; else if (token == "d") sync_cout << pos << sync_endl;
@@ -285,19 +289,25 @@ void UCI::loop(int argc, char* argv[]) {
filename = f; filename = f;
Eval::NNUE::save_eval(filename); Eval::NNUE::save_eval(filename);
} }
else if (token == "--help" || token == "help" || token == "--license" || token == "license")
sync_cout << "\nStockfish is a powerful chess engine for playing and analyzing."
"\nIt is released as free software licensed under the GNU GPLv3 License."
"\nStockfish is normally used with a graphical user interface (GUI) and implements"
"\nthe Universal Chess Interface (UCI) protocol to communicate with a GUI, an API, etc."
"\nFor any further information, visit https://github.com/official-stockfish/Stockfish#readme"
"\nor read the corresponding README.md and Copying.txt files distributed along with this program.\n" << sync_endl;
else if (!token.empty() && token[0] != '#') else if (!token.empty() && token[0] != '#')
sync_cout << "Unknown command: " << cmd << sync_endl; sync_cout << "Unknown command: '" << cmd << "'. Type help for more information." << sync_endl;
} while (token != "quit" && argc == 1); // Command line args are one-shot } while (token != "quit" && argc == 1); // The command-line arguments are one-shot
} }
/// UCI::value() converts a Value to a string suitable for use with the UCI /// UCI::value() converts a Value to a string by adhering to the UCI protocol specification:
/// protocol specification:
/// ///
/// cp <x> The score from the engine's point of view in centipawns. /// cp <x> The score from the engine's point of view in centipawns.
/// mate <y> Mate in y moves, not plies. If the engine is getting mated /// mate <y> Mate in 'y' moves (not plies). If the engine is getting mated,
/// use negative values for y. /// uses negative values for 'y'.
string UCI::value(Value v) { string UCI::value(Value v) {
@@ -306,7 +316,7 @@ string UCI::value(Value v) {
stringstream ss; stringstream ss;
if (abs(v) < VALUE_MATE_IN_MAX_PLY) if (abs(v) < VALUE_MATE_IN_MAX_PLY)
ss << "cp " << v * 100 / PawnValueEg; ss << "cp " << v * 100 / NormalizeToPawnValue;
else else
ss << "mate " << (v > 0 ? VALUE_MATE - v + 1 : -VALUE_MATE - v) / 2; ss << "mate " << (v > 0 ? VALUE_MATE - v + 1 : -VALUE_MATE - v) / 2;
@@ -314,8 +324,8 @@ string UCI::value(Value v) {
} }
/// UCI::wdl() report WDL statistics given an evaluation and a game ply, based on /// UCI::wdl() reports the win-draw-loss (WDL) statistics given an evaluation
/// data gathered for fishtest LTC games. /// and a game ply based on the data gathered for fishtest LTC games.
string UCI::wdl(Value v, int ply) { string UCI::wdl(Value v, int ply) {
@@ -338,9 +348,9 @@ std::string UCI::square(Square s) {
/// UCI::move() converts a Move to a string in coordinate notation (g1f3, a7a8q). /// UCI::move() converts a Move to a string in coordinate notation (g1f3, a7a8q).
/// The only special case is castling, where we print in the e1g1 notation in /// The only special case is castling where the e1g1 notation is printed in
/// normal chess mode, and in e1h1 notation in chess960 mode. Internally all /// standard chess mode and in e1h1 notation it is printed in Chess960 mode.
/// castling moves are always encoded as 'king captures rook'. /// Internally, all castling moves are always encoded as 'king captures rook'.
string UCI::move(Move m, bool chess960) { string UCI::move(Move m, bool chess960) {
@@ -370,8 +380,8 @@ string UCI::move(Move m, bool chess960) {
Move UCI::to_move(const Position& pos, string& str) { Move UCI::to_move(const Position& pos, string& str) {
if (str.length() == 5) // Junior could send promotion piece in uppercase if (str.length() == 5)
str[4] = char(tolower(str[4])); str[4] = char(tolower(str[4])); // The promotion piece character must be lowercased
for (const auto& m : MoveList<LEGAL>(pos)) for (const auto& m : MoveList<LEGAL>(pos))
if (str == UCI::move(m, pos.is_chess960())) if (str == UCI::move(m, pos.is_chess960()))
+11 -4
View File
@@ -30,17 +30,24 @@ class Position;
namespace UCI { namespace UCI {
// Normalizes the internal value as reported by evaluate or search
// to the UCI centipawn result used in output. This value is derived from
// the win_rate_model() such that Stockfish outputs an advantage of
// "100 centipawns" for a position if the engine has a 50% probability to win
// from this position in selfplay at fishtest LTC time control.
const int NormalizeToPawnValue = 361;
class Option; class Option;
/// Custom comparator because UCI options should be case insensitive /// Define a custom comparator, because the UCI options should be case-insensitive
struct CaseInsensitiveLess { struct CaseInsensitiveLess {
bool operator() (const std::string&, const std::string&) const; bool operator() (const std::string&, const std::string&) const;
}; };
/// Our options container is actually a std::map /// The options container is defined as a std::map
typedef std::map<std::string, Option, CaseInsensitiveLess> OptionsMap; typedef std::map<std::string, Option, CaseInsensitiveLess> OptionsMap;
/// Option class implements an option as defined by UCI protocol /// The Option class implements each option as specified by the UCI protocol
class Option { class Option {
typedef void (*OnChange)(const Option&); typedef void (*OnChange)(const Option&);
@@ -72,7 +79,7 @@ void loop(int argc, char* argv[]);
std::string value(Value v); std::string value(Value v);
std::string square(Square s); std::string square(Square s);
std::string move(Move m, bool chess960); std::string move(Move m, bool chess960);
std::string pv(const Position& pos, Depth depth, Value alpha, Value beta); std::string pv(const Position& pos, Depth depth);
std::string wdl(Value v, int ply); std::string wdl(Value v, int ply);
Move to_move(const Position& pos, std::string& str); Move to_move(const Position& pos, std::string& str);
+1 -1
View File
@@ -61,7 +61,7 @@ void init(OptionsMap& o) {
constexpr int MaxHashMB = Is64Bit ? 33554432 : 2048; constexpr int MaxHashMB = Is64Bit ? 33554432 : 2048;
o["Debug Log File"] << Option("", on_logger); o["Debug Log File"] << Option("", on_logger);
o["Threads"] << Option(1, 1, 512, on_threads); o["Threads"] << Option(1, 1, 1024, on_threads);
o["Hash"] << Option(16, 1, MaxHashMB, on_hash_size); o["Hash"] << Option(16, 1, MaxHashMB, on_hash_size);
o["Clear Hash"] << Option(on_clear_hash); o["Clear Hash"] << Option(on_clear_hash);
o["Ponder"] << Option(false); o["Ponder"] << Option(false);