Compare commits

...

791 Commits

Author SHA1 Message Date
opelly27 f65a195ca4 Update evaluate.h 2025-02-19 10:18:39 -08:00
FauziAkram fa6c30af81 FutilityValue formula tweak
Passed STC:
LLR: 2.95 (-2.94,2.94) <0.00,2.00>
Total: 29600 W: 7979 L: 7662 D: 13959
Ptnml(0-2): 138, 3446, 7324, 3745, 147
https://tests.stockfishchess.org/tests/view/67ac7dff52879dfd14d7e7da

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

Tested vs #5851.

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

i.e. prevents and helps debug this case

```cpp
int x1 = 5;

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

No functional change

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

Discussed in more detail here #5766

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

Tested against #5764.

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

The implementation approach was suggested by Disservin.

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

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

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

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

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

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

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

No functional change

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

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

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

```
make config-sanity:

    patch: 6.199s
    master: 12.738s

make help:

    patch: 3.1s
    master: 11.49s

make -j build:

    patch: 36s
    master: 43.25s

make -j build:

    master ubuntu: 10s
```

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

Passed STC:

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

Passed LTC:

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

No functional change

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

No functional change
2024-09-09 17:21:14 +02:00
Joost VandeVondele e0bfc4b69b Stockfish 17
Official release version of Stockfish 17

Bench: 1484730

---

Stockfish 17

Today we have the pleasure to announce a new major release of Stockfish. As
always, you can freely download it at https://stockfishchess.org/download and
use it in the GUI of your choice.

Don’t forget to join our Discord server[1] to get in touch with the community
of developers and users of the project!

*Quality of chess play*

In tests against Stockfish 16, this release brings an Elo gain of up to 46
points[2] and wins up to 4.5 times more game pairs[3] than it loses. In
practice, high-quality moves are now found in less time, with a user upgrading
from Stockfish 14 being able to analyze games at least 6 times[4] faster with
Stockfish 17 while maintaining roughly the same quality.

During this development period, Stockfish won its 9th consecutive first place
in the main league of the Top Chess Engine Championship (TCEC)[5], and the 24th
consecutive first place in the main events (bullet, blitz, and rapid) of the
Computer Chess Championship (CCC)[6].

*Update highlights*

*Improved engine lines*

This release introduces principal variations (PVs) that are more informative
for mate and decisive table base (TB) scores. In both cases, the PV will
contain all moves up to checkmate. For mate scores, the PV shown is the best
variation known to the engine at that point, while for table base wins, it
follows, based on the TB, a sequence of moves that preserves the game outcome
to checkmate.

*NUMA performance optimization*

For high-end computers with multiple CPUs (typically a dual-socket architecture
with 100+ cores), this release automatically improves performance with a
`NumaPolicy` setting that optimizes non-uniform memory access (NUMA).  Although
typical consumer hardware will not benefit, speedups of up to 2.8x[7] have been
measured.

*Shoutouts*

*ChessDB*

During the past 1.5 years, hundreds of cores have been continuously running
Stockfish to grow a database of analyzed positions. This chess cloud
database[8] now contains well over 45 billion positions, providing excellent
coverage of all openings and commonly played lines. This database is already
integrated into GUIs such as En Croissant[9] and Nibbler[10], which access it
through the public API.

*Leela Chess Zero*

Generally considered to be the strongest GPU engine, it continues to provide
open data which is essential for training our NNUE networks. They released
version 0.31.1[11] of their engine a few weeks ago, check it out!

*Website redesign*

Our website has undergone a redesign in recent months, most notably in our home
page[12], now featuring a darker color scheme and a more modern aesthetic,
while still maintaining its core identity. We hope you'll like it as much as we
do!

*Thank you*

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

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

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

The Stockfish team

[1] https://discord.gg/GWDRS3kU6R
[2] https://tests.stockfishchess.org/tests/view/66d738ba9de3e7f9b33d159a
[3] https://tests.stockfishchess.org/tests/view/66d738f39de3e7f9b33d15a0
[4] https://github.com/official-stockfish/Stockfish/wiki/Useful-data#equivalent-time-odds-and-normalized-game-pair-elo
[5] https://en.wikipedia.org/wiki/Stockfish_(chess)#Top_Chess_Engine_Championship
[6] https://en.wikipedia.org/wiki/Stockfish_(chess)#Chess.com_Computer_Chess_Championship
[7] https://github.com/official-stockfish/Stockfish/pull/5285
[8] https://chessdb.cn/queryc_en/
[9] https://encroissant.org/
[10] https://github.com/rooklift/nibbler
[11] https://github.com/LeelaChessZero/lc0/releases/tag/v0.31.1
[12] https://stockfishchess.org/
[13] https://github.com/official-stockfish/Stockfish/stargazers
[14] https://github.com/official-stockfish/fishtest/wiki/Running-the-worker
[15] https://github.com/official-stockfish/Stockfish
[16] https://github.com/official-stockfish/fishtest
[17] https://github.com/official-stockfish/nnue-pytorch
[18] https://github.com/official-stockfish/stockfish-web
2024-09-06 16:53:45 +02:00
Joost VandeVondele 38e0cc7b90 Update Top CPU Contributors
to the status as of Aug 31st 2024.

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

No functional change
2024-09-03 17:53:23 +02:00
Robert Nurnberg @ elitebook 2054add23c Update the WDL model
updates the internal WDL model, using data from 2.6M games played by the revisions since 9fb5832.

https://github.com/official-stockfish/Stockfish/pull/5565

No functional change
2024-09-03 17:53:23 +02:00
Joost VandeVondele ab00c24c7e Fix some of the tests
due to https://github.com/official-stockfish/Stockfish/issues/5185 some CI tests are skipped.
This patch fixes a few tests that need updating.

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

No functional change
2024-09-03 17:48:58 +02:00
FauziAkram 451044202a Simpler formula for ss->cutoffCnt update
closes https://github.com/official-stockfish/Stockfish/pull/5548

No functional change
2024-08-28 09:35:21 +02:00
Taras Vuk 54def6f7eb rename !(PvNode || cutNode) to allNode
Passed STC:
LLR: 2.94 (-2.94,2.94) <-1.75,0.25>
Total: 108992 W: 28178 L: 28039 D: 52775
Ptnml(0-2): 356, 12428, 28762, 12621, 329
https://tests.stockfishchess.org/tests/view/66c73a51bf8c9d8780fda532

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

No functional change
2024-08-28 09:34:09 +02:00
Tomasz Sobczyk a0597b1281 Forcibly split NUMA nodes on Windows
split by processor groups due to Window's thread scheduler issues.

fixes #5551
closes https://github.com/official-stockfish/Stockfish/pull/5552

No functional change
2024-08-28 08:52:24 +02:00
Taras Vuk 9fb58328e3 Tweak late move extensions
Allow late move extensions only for PV and cut nodes.

Passed STC:
LLR: 2.95 (-2.94,2.94) <0.00,2.00>
Total: 44512 W: 11688 L: 11355 D: 21469
Ptnml(0-2): 167, 5180, 11229, 5513, 167
https://tests.stockfishchess.org/tests/view/66c0509d4ff211be9d4ef10e

Passed LTC:
LLR: 2.94 (-2.94,2.94) <0.50,2.50>
Total: 152970 W: 39026 L: 38466 D: 75478
Ptnml(0-2): 102, 16792, 42164, 17298, 129
https://tests.stockfishchess.org/tests/view/66c0994d21503a509c13b2b6

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

bench: 1484730
2024-08-20 21:37:25 +02:00
Shawn Xu d275bf9643 Introduce Fail Low History Bonus
When a node fails low, give TT move a small bonus 1/4 of normal value.

Passed STC:
LLR: 2.95 (-2.94,2.94) <0.00,2.00>
Total: 92384 W: 24094 L: 23691 D: 44599
Ptnml(0-2): 323, 10852, 23465, 11203, 349
https://tests.stockfishchess.org/tests/view/66be80794ff211be9d4eed68

Passed LTC:
LLR: 2.94 (-2.94,2.94) <0.50,2.50>
Total: 114660 W: 29260 L: 28778 D: 56622
Ptnml(0-2): 97, 12506, 31653, 12966, 108
https://tests.stockfishchess.org/tests/view/66bf63ee4ff211be9d4eeef0

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

bench 1463003
2024-08-20 21:34:19 +02:00
Nonlinear2 6cf7f300ac Simplify stand pat adjustement
Remove && !PvNode condition for stand pat adjustement in quiescence search.

Passed non-regression STC:
LLR: 2.94 (-2.94,2.94) <-1.75,0.25>
Total: 108544 W: 28228 L: 28085 D: 52231
Ptnml(0-2): 389, 12902, 27554, 13031, 396
https://tests.stockfishchess.org/tests/view/66bb402e4ff211be9d4ee688

Passed non-regression LTC:
LLR: 2.94 (-2.94,2.94) <-1.75,0.25>
Total: 193014 W: 48796 L: 48751 D: 95467
Ptnml(0-2): 188, 21481, 53116, 21542, 180
https://tests.stockfishchess.org/tests/view/66bc78774ff211be9d4ee88f

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

Bench 1787360
2024-08-20 21:31:33 +02:00
Shawn Xu 87814d2fb8 Simplify doShallowerSearch
Passed Non-regression STC:
LLR: 2.94 (-2.94,2.94) <-1.75,0.25>
Total: 242336 W: 62657 L: 62663 D: 117016
Ptnml(0-2): 941, 28949, 61418, 28895, 965
https://tests.stockfishchess.org/tests/view/66bc13c34ff211be9d4ee794

Passed Non-regression LTC:
LLR: 2.94 (-2.94,2.94) <-1.75,0.25>
Total: 128100 W: 32503 L: 32390 D: 63207
Ptnml(0-2): 106, 14319, 35113, 14380, 132
https://tests.stockfishchess.org/tests/view/66bdbb304ff211be9d4eec5d

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

bench 1586246
2024-08-20 21:27:58 +02:00
Shawn Xu 175021721c Simplify bestMove promotion
Passed Non-regression STC:
LLR: 2.95 (-2.94,2.94) <-1.75,0.25>
Total: 216768 W: 56240 L: 56217 D: 104311
Ptnml(0-2): 794, 24900, 56956, 24957, 777
https://tests.stockfishchess.org/tests/view/66bc11324ff211be9d4ee78b

Passed Non-regression LTC:
LLR: 2.94 (-2.94,2.94) <-1.75,0.25>
Total: 44970 W: 11391 L: 11199 D: 22380
Ptnml(0-2): 44, 4596, 13002, 4810, 33
https://tests.stockfishchess.org/tests/view/66bdbb1b4ff211be9d4eec5a

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

bench: 1613043
2024-08-20 21:24:04 +02:00
Linmiao Xu 5d81071953 Update default main net to nn-1111cefa1111.nnue
Created from 2 distinct spsa tunes of the latest main net (nn-31337bea577c.nnue)
and applying the params to the prior main net (nn-e8bac1c07a5a.nnue). This
effectively reverts the modifications to output weights and biases in
https://github.com/official-stockfish/Stockfish/pull/5509

SPSA:
A: 6000, alpha: 0.602, gamma: 0.101

1st - 437 feature transformer biases where values are < 25
54k / 120k games at 180+1.8
https://tests.stockfishchess.org/tests/view/66af98ac4ff211be9d4edad0
nn-808259761cca.nnue

2nd - 208 L2 weights where values are zero
112k / 120k games at 180+1.8
https://tests.stockfishchess.org/tests/view/66b0c3074ff211be9d4edbe5
nn-a56cb8c3d477.nnue

When creating the above 2 nets (nn-808259761cca.nnue, nn-a56cb8c3d477.nnue),
spsa params were unintentionally applied to nn-e8bac1c07a5a.nnue rather
than nn-31337bea577c.nnue due to an issue in a script that creates nets
by applying spsa results to base nets.

Since they both passed STC and were neutral or slightly positive at LTC,
they were combined to see if the elo from each set of params was additive.

The 2 nets can be merged on top of nn-e8bac1c07a5a.nnue with:
https://github.com/linrock/nnue-tools/blob/90942d3/spsa/combine_nnue.py
```
python3 combine_nnue.py \
  nn-e8bac1c07a5a.nnue \
  nn-808259761cca.nnue \
  nn-a56cb8c3d477.nnue
```

Merging yields nn-87caa003fc6a.nnue which was renamed to nn-1111cefa1111.nnue
with an updated nnue-namer around 10x faster than before by:
- using a prefix trie for efficient prefix matches
- modifying 4 non-functional bytes near the end of the file instead of 2
https://github.com/linrock/nnue-namer

Thanks to @MinetaS for pointing out in #nnue-dev what the non-functional bytes are:
  L3 is 32, 4 bytes for biases, 32 bytes for weights. (fc_2)
  So -38 and -37 are technically -2 and -1 of fc_1 (type AffineTransform<30, 32>)
  And since InputDimension is padded to 32 there are total 32 of 2 adjacent bytes padding.
  So yes, it's non-functional whatever values are there.
  It's possible to tweak bytes at -38 - 32 * N and -37 - 32 * N given N = 0 ... 31

The net renamed with the new method passed non-regression STC vs. the original net:
https://tests.stockfishchess.org/tests/view/66c0f0a821503a509c13b332

To print the spsa params with nnue-pytorch:
```
import features
from serialize import NNUEReader

feature_set = features.get_feature_set_from_name("HalfKAv2_hm")

with open("nn-31337bea577c.nnue", "rb") as f:
    model = NNUEReader(f, feature_set).model

c_end = 16
for i,ft_bias in enumerate(model.input.bias.data[:3072]):
    value = int(ft_bias * 254)
    if abs(value) < 25:
        print(f"ftB[{i}],{value},-1024,1024,{c_end},0.0020")

c_end = 6
for i in range(8):
    for j in range(32):
        for k in range(30):
            value = int(model.layer_stacks.l2.weight.data[32 * i + j, k] * 64)
            if value == 0:
                print(f"twoW[{i}][{j}][{k}],{value},-127,127,{c_end},0.0020")
```

New params found with the same method as:
https://github.com/official-stockfish/Stockfish/pull/5459

Passed STC:
https://tests.stockfishchess.org/tests/view/66b4d4464ff211be9d4edf6e
LLR: 2.94 (-2.94,2.94) <0.00,2.00>
Total: 136416 W: 35753 L: 35283 D: 65380
Ptnml(0-2): 510, 16159, 34416, 16597, 526

Passed LTC:
https://tests.stockfishchess.org/tests/view/66b76e814ff211be9d4ee1cc
LLR: 2.95 (-2.94,2.94) <0.50,2.50>
Total: 159336 W: 40753 L: 40178 D: 78405
Ptnml(0-2): 126, 17497, 43864, 18038, 143

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

bench 1613043
2024-08-20 20:59:36 +02:00
FauziAkram 4995792a6c Simplify cutnode reduction formula
Passed STC:
LLR: 2.94 (-2.94,2.94) <-1.75,0.25>
Total: 137994 W: 34705 L: 34603 D: 68686
Ptnml(0-2): 124, 15371, 37903, 15477, 122
https://tests.stockfishchess.org/tests/view/66aeb74b4ff211be9d4eda10

Passed LTC:
LLR: 2.93 (-2.94,2.94) <-1.75,0.25>
Total: 131456 W: 34148 L: 34031 D: 63277
Ptnml(0-2): 506, 15571, 33465, 15672, 514
https://tests.stockfishchess.org/tests/view/66ae258b4ff211be9d4ed95d

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

Bench: 1261995
2024-08-20 20:57:07 +02:00
Shawn Xu a75717ede1 Simplify Post-LMR Continuation History Updates
Passed Non-regression STC:
LLR: 2.94 (-2.94,2.94) <-1.75,0.25>
Total: 55520 W: 14625 L: 14420 D: 26475
Ptnml(0-2): 247, 6522, 14007, 6747, 237
https://tests.stockfishchess.org/tests/view/66ad40874ff211be9d4ed8f7

Passed Non-regression LTC:
LLR: 2.94 (-2.94,2.94) <-1.75,0.25>
Total: 216168 W: 54561 L: 54540 D: 107067
Ptnml(0-2): 196, 24212, 59244, 24239, 193
https://tests.stockfishchess.org/tests/view/66aeac954ff211be9d4eda03

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

bench 1418263
2024-08-20 20:51:39 +02:00
Shawn Xu bc80ece6c7 Improve Comments for Pairwise Multiplication Optimization
closes https://github.com/official-stockfish/Stockfish/pull/5524

no functional change
2024-08-20 20:47:46 +02:00
Disservin d626af5c3a Fix failing CI for MacOS 13 GCC 11
closes https://github.com/official-stockfish/Stockfish/pull/5540

No functional change
2024-08-20 20:44:55 +02:00
Shawn Xu ae9e55cf53 Simplify Cutnode Reduction
Passed Non-regression STC:
LR: 2.96 (-2.94,2.94) <-1.75,0.25>
Total: 143968 W: 37439 L: 37333 D: 69196
Ptnml(0-2): 521, 17228, 36456, 17182, 597
https://tests.stockfishchess.org/tests/view/66a73f9f4ff211be9d4ed27f

Passed Non-regression LTC:
LLR: 2.94 (-2.94,2.94) <-1.75,0.25>
Total: 198954 W: 50384 L: 50345 D: 98225
Ptnml(0-2): 201, 22360, 54347, 22337, 232
https://tests.stockfishchess.org/tests/view/66a906e94ff211be9d4ed423

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

bench 1277466
2024-08-03 09:42:54 +02:00
MinetaS b976f0a101 Move DotProd code into optimized affine layer
This patch moves the DotProd code into the propagation function which
has sequential access optimization. To prove the speedup, the comparison
is done without the sparse layer. With the sparse layer the effect is
marginal (GCC 0.3%, LLVM/Clang 0.1%).

For both tests, binary is compiled with GCC 14.1. Each test had 50 runs.

Sparse layer included:
```
speedup        = +0.0030
P(speedup > 0) =  1.0000
```

Sparse layer excluded:
```
speedup        = +0.0561
P(speedup > 0) =  1.0000
```

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

No functional change
2024-08-03 09:42:03 +02:00
Tomasz Sobczyk 8e560c4fd3 Replicate network weights only to used NUMA nodes
On a system with multiple NUMA nodes, this patch avoids unneeded replicated
(e.g. 8x for a single threaded run), reducting memory use in that case.

Lazy initialization forced before search.

Passed STC:
https://tests.stockfishchess.org/tests/view/66a28c524ff211be9d4ecdd4
LLR: 2.96 (-2.94,2.94) <-1.75,0.25>
Total: 691776 W: 179429 L: 179927 D: 332420
Ptnml(0-2): 2573, 79370, 182547, 78778, 2620

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

No functional change
2024-08-03 09:41:37 +02:00
Shawn Xu 2343f71f3f Remove Killers
The removal of killers on line 1774 resulted in a substantial decrease
in pre-LMR history average, so a negative history fill is applied to
counter it.

Passed Non-regression STC (vs #5513):
LLR: 2.95 (-2.94,2.94) <-1.75,0.25>
Total: 21984 W: 5886 L: 5645 D: 10453
Ptnml(0-2): 80, 2492, 5628, 2691, 101
https://tests.stockfishchess.org/tests/view/66a095894ff211be9d4ecb9d

Passed Non-regression LTC (vs #5513):
LLR: 2.94 (-2.94,2.94) <-1.75,0.25>
Total: 95430 W: 24141 L: 23995 D: 47294
Ptnml(0-2): 97, 10537, 26298, 10689, 94
https://tests.stockfishchess.org/tests/view/66a11c8d4ff211be9d4ecbf8

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

Bench: 1660869
2024-07-28 22:22:50 +02:00
Stéphane Nicolet af802da65b Clean up comments for movepicker
Remove references to checks in MovePicker comments. Follow-up for
https://github.com/official-stockfish/Stockfish/pull/5498

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

No functional change
2024-07-28 22:21:03 +02:00
Michael Chaly 607c3e404f Remove unneeded depth tracking in qsearch
Since simplification of quiet checks in qsearch this depth isn't used by
any function at all apart movepicker, which also doesn't use passed
qsearch depth in any way, so can be removed. No functional change.

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

No functional change
2024-07-28 22:18:33 +02:00
Shawn Xu 85893ac1cd Simplify Away Killer Condition in Cutnode LMR
Passed Non-regression STC:
LLR: 2.93 (-2.94,2.94) <-1.75,0.25>
Total: 42944 W: 11240 L: 11024 D: 20680
Ptnml(0-2): 159, 5056, 10825, 5274, 158
https://tests.stockfishchess.org/tests/view/669c13384ff211be9d4ec69f

Passed Non-regression LTC:
LLR: 2.96 (-2.94,2.94) <-1.75,0.25>
Total: 163548 W: 41366 L: 41289 D: 80893
Ptnml(0-2): 109, 18246, 45007, 18283, 129
https://tests.stockfishchess.org/tests/view/669cb1254ff211be9d4ec73a

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

Bench: 1178570
2024-07-28 22:13:47 +02:00
Linmiao Xu b55217fd02 Update default main net to nn-31337bea577c.nnue
Created by updating output weights (256) and biases (8)
of the previous main net with values found with spsa around
101k / 120k games at 140+1.4.

264 spsa params: output weights and biases in nn-e8bac1c07a5a.nnue
A: 6000, alpha: 0.602, gamma: 0.101
weights: [-127, 127], c_end = 6
biases: [-8192, 8192], c_end = 64

Among the 264 params, 189 weights and all 8 biases were changed.

Changes in the weights:
- mean: -0.111 +/- 3.57
- range: [-8, 8]

Found with the same method as:
https://github.com/official-stockfish/Stockfish/pull/5459

Due to the original name (nn-ea8c9128c325.nnue) being too similar
to the previous main net (nn-e8bac1c07a5a.nnue) and creating confusion,
it was renamed by making non-functional changes to the .nnue file
the same way as past nets with:
https://github.com/linrock/nnue-namer

To verify that bench is the same and view the modified non-functional bytes:
```
echo -e "setoption name EvalFile value nn-ea8c9128c325.nnue\nbench" | ./stockfish
echo -e "setoption name EvalFile value nn-31337bea577c.nnue\nbench" | ./stockfish

cmp -l nn-ea8c9128c325.nnue nn-31337bea577c.nnue

diff <(xxd nn-ea8c9128c325.nnue) <(xxd nn-31337bea577c.nnue)
```

Passed STC:
https://tests.stockfishchess.org/tests/view/669564154ff211be9d4ec080
LLR: 2.93 (-2.94,2.94) <0.00,2.00>
Total: 57280 W: 15139 L: 14789 D: 27352
Ptnml(0-2): 209, 6685, 14522, 6995, 229

Passed LTC:
https://tests.stockfishchess.org/tests/view/669694204ff211be9d4ec1b4
LLR: 2.94 (-2.94,2.94) <0.50,2.50>
Total: 63030 W: 16093 L: 15720 D: 31217
Ptnml(0-2): 47, 6766, 17516, 7139, 47

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

bench 1371485
2024-07-23 19:34:27 +02:00
Michael Chaly 836154acb5 Introduce pre-qsearch ttmove extensions at pv nodes
The idea is that we are about to dive into qsearch (next search depth is <= 0)
but since we have the move in transposition table we should extend that move
and evaluate it with more precise search - because branch seems important.

Passed STC:
https://tests.stockfishchess.org/tests/view/6699d2564ff211be9d4ec488
LLR: 2.93 (-2.94,2.94) <0.00,2.00>
Total: 83104 W: 21789 L: 21401 D: 39914
Ptnml(0-2): 293, 9748, 21128, 10044, 339

Passed LTC:
https://tests.stockfishchess.org/tests/view/669b3f1a4ff211be9d4ec602
LLR: 2.94 (-2.94,2.94) <0.50,2.50>
Total: 136098 W: 34636 L: 34111 D: 67351
Ptnml(0-2): 105, 14882, 37550, 15407, 105

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

bench 1526129
2024-07-23 19:24:00 +02:00
Shawn Xu 985b9fd7b0 Remove Killer Heuristic In Move Ordering
Passed Non-regression STC:
LLR: 2.96 (-2.94,2.94) <-1.75,0.25>
Total: 80480 W: 20979 L: 20802 D: 38699
Ptnml(0-2): 279, 9610, 20337, 9683, 331
https://tests.stockfishchess.org/tests/view/669c12c14ff211be9d4ec69b

Passed Non-regression LTC:
LLR: 2.94 (-2.94,2.94) <-1.75,0.25>
Total: 77988 W: 19788 L: 19624 D: 38576
Ptnml(0-2): 66, 8605, 21481, 8783, 59
https://tests.stockfishchess.org/tests/view/669d628a4ff211be9d4ec7a8

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

bench 1367740
2024-07-23 19:24:00 +02:00
Linmiao Xu 1e2f051103 Replace simple eval with psqt in re-eval condition
As a result, re-eval depends only on smallnet outputs
so an extra call to simple eval can be removed.

Passed non-regression STC:
https://tests.stockfishchess.org/tests/view/669743054ff211be9d4ec232
LLR: 2.94 (-2.94,2.94) <-1.75,0.25>
Total: 214912 W: 55801 L: 55777 D: 103334
Ptnml(0-2): 746, 24597, 56760, 24593, 760

https://github.com/official-stockfish/Stockfish/pull/5501

Bench: 1440277
2024-07-23 19:24:00 +02:00
Shahin M. Shahin bb4b01e306 Fix TB guard
even if beta is below TB range, once we return probcutBeta with beta + 390 we
can return wrong TB value, and guard against ttData.value being `VALUE_NONE`

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

bench: 1440277
2024-07-23 19:24:00 +02:00
FauziAkram 986173264f Adding LowestElo and HighestElo constants
These values represent the lowest Elo rating in the skill level calculation,
and the highest one, but it's not clear from the code where these values come
from other than the comment.  This should improve code readability and
maintainability. It makes the purpose of the values clear and allows for easy
modification if the Elo range for skill level calculation changes in the
future.  Moved the Skill struct definition from search.cpp to search.h header
file to define the Search::Skill struct, making it accessible from other files.

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

No functional change
2024-07-23 19:23:57 +02:00
FauziAkram a2ba3e3362 Bonus Simplification
This tune removes completely a recently added term.

Passed STC:
LLR: 2.93 (-2.94,2.94) <0.00,2.00>
Total: 61376 W: 16046 L: 15693 D: 29637
Ptnml(0-2): 207, 7132, 15665, 7469, 215
https://tests.stockfishchess.org/tests/view/669512b94ff211be9d4ebffb

Passed LTC:
LLR: 2.94 (-2.94,2.94) <0.50,2.50>
Total: 100662 W: 25474 L: 25020 D: 50168
Ptnml(0-2): 64, 11092, 27581, 11514, 80
https://tests.stockfishchess.org/tests/view/66955f194ff211be9d4ec06a

Passed LTC#2:
LLR: 2.96 (-2.94,2.94) <-1.75,0.25>
Total: 28056 W: 7128 L: 6909 D: 14019
Ptnml(0-2): 18, 3084, 7620, 3273, 33
https://tests.stockfishchess.org/tests/view/669a541a4ff211be9d4ec52b

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

bench: 1619438
2024-07-23 18:01:14 +02:00
Dubslow 703f17975b Remove QS_CHECKS movepick stage
Passed STC: https://tests.stockfishchess.org/tests/view/669597cf4ff211be9d4ec147
LLR: 2.94 (-2.94,2.94) <-1.75,0.25>
Total: 199072 W: 52100 L: 52058 D: 94914
Ptnml(0-2): 829, 23679, 50406, 23865, 757

Passed LTC: https://tests.stockfishchess.org/tests/view/66988f5f4ff211be9d4ec33e
LLR: 2.94 (-2.94,2.94) <-1.75,0.25>
Total: 119778 W: 30420 L: 30299 D: 59059
Ptnml(0-2): 106, 13293, 32957, 13440, 93

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

Bench 1499842
2024-07-23 17:56:52 +02:00
Joost VandeVondele e57fba7fc9 Fix TB PV extension and MultiPV
in the case of MultiPV, the first move of the Nth multiPV could actually turn a
winning position in a losing one, so don't attempt to correct it. Instead,
always perform the first move without correction.

Fixes #5505

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

No functional change
2024-07-23 17:51:30 +02:00
Joost VandeVondele 1fb4dc2e0f Enable syzygy in the matetrack action
now checks correctness of PV lines with TB score.

uses 3-4-5 man table bases, downloaded from lichess,
which are cached with the appropriate action.

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

No functional change
2024-07-23 17:49:07 +02:00
Michael Chaly a8401e803d Adjust bonus to move that caused a fail low
This is an elo gainer and simultaneously a minor logical fix to bonuses that caused a fail low.
It increases maximum of statscore based subtraction - but disallows negative bonuses.

Passed STC:
https://tests.stockfishchess.org/tests/view/66955e6f4ff211be9d4ec063
LLR: 2.94 (-2.94,2.94) <0.00,2.00>
Total: 44640 W: 11805 L: 11472 D: 21363
Ptnml(0-2): 166, 5178, 11335, 5439, 202

Passed LTC:
https://tests.stockfishchess.org/tests/view/66963fde4ff211be9d4ec190
LLR: 2.95 (-2.94,2.94) <0.50,2.50>
Total: 72288 W: 18478 L: 18082 D: 35728
Ptnml(0-2): 50, 7919, 19825, 8285, 65

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

Bench: 1477054
2024-07-19 08:41:38 +02:00
Linmiao Xu c2837769e0 Avoid calculating nnue complexity twice
Passed non-regression STC:
https://tests.stockfishchess.org/tests/view/6697459d4ff211be9d4ec236
LLR: 2.96 (-2.94,2.94) <-1.75,0.25>
Total: 146848 W: 38289 L: 38189 D: 70370
Ptnml(0-2): 503, 16665, 39046, 16649, 561

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

No functional change
2024-07-19 08:40:23 +02:00
Shahin M. Shahin c8d8e362fc Try nullmoves only on cutnodes
since master only tries nullmoves on cutNodes already with 99.0224% of the
cases running bench, We can try null moves at 100% of cutNodes and achieve such
simplification, by making passing false already equivalent to passing !cutNode

This is a more correct form of PR #5482

Passed non-regression STC:
https://tests.stockfishchess.org/tests/view/66941c044ff211be9d4ebf5f
LLR: 2.93 (-2.94,2.94) <-1.75,0.25>
Total: 153216 W: 39856 L: 39764 D: 73596
Ptnml(0-2): 590, 18174, 38979, 18284, 581

Passed non-regression LTC:
https://tests.stockfishchess.org/tests/view/6694e5cd4ff211be9d4ebfdf
LLR: 2.94 (-2.94,2.94) <-1.75,0.25>
Total: 67842 W: 17178 L: 17004 D: 33660
Ptnml(0-2): 52, 7437, 18759, 7631, 42

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

bench: 1345400

Co-Authored-By: FauziAkram <11150271+fauziakram@users.noreply.github.com>
2024-07-19 08:38:13 +02:00
Dubslow 27042fe949 Linearize corrHist
Passed STC: https://tests.stockfishchess.org/tests/view/66919cdec6827afcdcee146f
LLR: 2.95 (-2.94,2.94) <-1.75,0.25>
Total: 130656 W: 33579 L: 33461 D: 63616
Ptnml(0-2): 394, 15548, 33318, 15682, 386

Passed VVLTC: https://tests.stockfishchess.org/tests/view/6691acb2c6827afcdcee1645
LLR: 2.94 (-2.94,2.94) <-1.75,0.25>
Total: 160314 W: 40925 L: 40854 D: 78535
Ptnml(0-2): 12, 14754, 50551, 14831, 9

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

bench 1380295
2024-07-19 08:36:25 +02:00
yl25946 7bb45d05fa Replace ternary with std::min
equivalent and more readable.

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

No functional change
2024-07-19 08:34:02 +02:00
Guenther Demetz c755bc1a73 Simplify improving condition
if we were in check at our previous move we look back until we weren't
in check and take the staticEval of that position as reference.

Passed STC:
https://tests.stockfishchess.org/tests/view/668ba7b65034141ae5996665
LLR: 2.93 (-2.94,2.94) <-1.75,0.25>
Total: 74784 W: 19454 L: 19274 D: 36056
Ptnml(0-2): 260, 8874, 18952, 9038, 268

Passted LTC:
https://tests.stockfishchess.org/tests/view/668cb2db5034141ae599678b
LLR: 2.94 (-2.94,2.94) <-1.75,0.25>
Total: 241488 W: 61166 L: 61171 D: 119151
Ptnml(0-2): 190, 27154, 66062, 27147, 191

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

bench: 1368313
2024-07-19 08:32:16 +02:00
Linmiao Xu e443b2459e Separate eval params for smallnet and main net
Values found with spsa around 80% of 120k games at 60+0.6:
https://tests.stockfishchess.org/tests/view/669205dac6827afcdcee3ea4

Passed STC:
https://tests.stockfishchess.org/tests/view/6692928b4ff211be9d4e98a9
LLR: 2.96 (-2.94,2.94) <0.00,2.00>
Total: 313696 W: 81107 L: 80382 D: 152207
Ptnml(0-2): 934, 36942, 80363, 37683, 926

Passed LTC:
https://tests.stockfishchess.org/tests/view/6692aab54ff211be9d4e9915
LLR: 2.94 (-2.94,2.94) <0.50,2.50>
Total: 228420 W: 57903 L: 57190 D: 113327
Ptnml(0-2): 131, 25003, 63243, 25688, 145

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

bench 1319322
2024-07-15 13:38:14 +02:00
Michael Chaly de2bf1a186 Remove quiet history pruning depth limit
This patch removes lmrDepth limit for quiet moves history based pruning.

Previously removal of this type of depth limits was considered bad because it
was performing bad for matetrack - but with this pruning heuristic this
shouldn't be that bad because it's "naturally" depth limited by history
threshold and should be completely disabled at depth >= 15 or so.  Also this
heuristic in previous years was known to scale non-linearly - bigger lmrDepth
thresholds were better at longer time controls and removing it completely
probably should scale pretty well.

Passed STC:
https://tests.stockfishchess.org/tests/view/6692b89b4ff211be9d4eab21
LLR: 2.93 (-2.94,2.94) <-1.75,0.25>
Total: 114464 W: 29675 L: 29545 D: 55244
Ptnml(0-2): 372, 12516, 31329, 12640, 375

Passed LTC:
https://tests.stockfishchess.org/tests/view/6692c4554ff211be9d4eab3d
LLR: 2.94 (-2.94,2.94) <-1.75,0.25>
Total: 67746 W: 17182 L: 17014 D: 33550
Ptnml(0-2): 28, 6993, 19652, 7183, 17

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

Bench: 1250388
2024-07-15 13:35:06 +02:00
MinetaS 2b37b151dd Use ValueList to represent searched moves array
This PR replaces a pair of array and size with existing ValueList class.
Removes two local variables in search and two parameters of
update_all_stats.

Passed non-regression STC:
LLR: 2.93 (-2.94,2.94) <-1.75,0.25>
Total: 227040 W: 58472 L: 58463 D: 110105
Ptnml(0-2): 495, 23572, 65427, 23481, 545
https://tests.stockfishchess.org/tests/view/669299204ff211be9d4e98dc

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

No functional change
2024-07-15 13:30:47 +02:00
FauziAkram 7395d56832 bonus calculation for prior countermoves
Introduce a new term to the bonus calculation for prior countermoves

Passed STC:
LLR: 2.93 (-2.94,2.94) <0.00,2.00>
Total: 140896 W: 36545 L: 36079 D: 68272
Ptnml(0-2): 383, 16505, 36217, 16949, 394
https://tests.stockfishchess.org/tests/view/6691c73cc6827afcdcee1816

Passed LTC:
LLR: 2.94 (-2.94,2.94) <0.50,2.50>
Total: 126660 W: 32089 L: 31587 D: 62984
Ptnml(0-2): 63, 13774, 35154, 14276, 63
https://tests.stockfishchess.org/tests/view/6691cdc4c6827afcdcee1930

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

bench: 1250388
2024-07-15 13:27:42 +02:00
Linmiao Xu 558abdbe8a Set best value to futility value after pruned quiet move
Passed non-regression STC:
https://tests.stockfishchess.org/tests/view/6691592f5034141ae599c68d
LLR: 2.93 (-2.94,2.94) <-1.75,0.25>
Total: 278496 W: 71818 L: 71865 D: 134813
Ptnml(0-2): 865, 33311, 70978, 33194, 900

Passed non-regression LTC:
https://tests.stockfishchess.org/tests/view/66918fca5034141ae599e761
LLR: 2.95 (-2.94,2.94) <-1.75,0.25>
Total: 202986 W: 51048 L: 51013 D: 100925
Ptnml(0-2): 107, 22552, 56133, 22601, 100

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

bench 1715206
2024-07-15 13:24:14 +02:00
Michael Chaly 930915de90 Decrease delta
Decrease delta in aspiration windows - both initial value and quadratic
function of previous best value.

Passed STC:
https://tests.stockfishchess.org/tests/view/6691a52ec6827afcdcee1569
LLR: 2.93 (-2.94,2.94) <0.00,2.00>
Total: 55456 W: 14449 L: 14107 D: 26900
Ptnml(0-2): 174, 6416, 14193, 6784, 161

Passed LTC:
https://tests.stockfishchess.org/tests/view/6691aac1c6827afcdcee1625
LLR: 2.94 (-2.94,2.94) <0.50,2.50>
Total: 107940 W: 27530 L: 27065 D: 53345
Ptnml(0-2): 52, 11787, 29840, 12226, 65

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

bench 1547707
2024-07-15 13:22:31 +02:00
MinetaS 563d268519 Simplify futility_move_count
This patch reverts changes from #4032 which was introduced as a speedup.
Modern compilers no longer use DIV/IDIV instructions, potentially making
the explicit branch perform worse. Since evaluations spend significantly
more time now, the impact of the speedup in search diminishes with old
compilers as well.

GCC 14.1.0 profile-build, x86-64-vnni512
```
.text:000000014010FEA9                 mov     ecx, [rsp+3FB8h+var_3F5C]
...
.text:000000014010FEBD                 mov     r10d, ecx
.text:000000014010FEC0                 imul    r10d, ecx
.text:000000014010FEC4                 mov     ecx, dword ptr [rsp+3FB8h+var_3F44+4]
.text:000000014010FEC8                 add     r10d, 3
.text:000000014010FECC                 mov     r11d, r10d
.text:000000014010FECF                 sar     r11d, 1
.text:000000014010FED2                 cmp     [rsp+3FB8h+var_3EE7], 0
.text:000000014010FEDA                 cmovnz  r11d, r10d
```

LLVM 18.1.18 profile-build, x86-64-vnni512
```
.text:0000000140001EDC                 mov     [rsp+40h+arg_E0], r13
.text:0000000140001EE4                 movsxd  rcx, r13d
.text:0000000140001EE7                 mov     rax, rcx
.text:0000000140001EEA                 mov     [rsp+40h+arg_B8], rcx
.text:0000000140001EF2                 imul    eax, eax
.text:0000000140001EF5                 add     eax, 3
.text:0000000140001EF8                 mov     ecx, [rsp+40h+arg_8C]
.text:0000000140001EFF                 shrx    eax, eax, ecx
.text:0000000140001F04                 mov     [rsp+40h+arg_190], rax
```

Passed non-regression STC:
LLR: 2.96 (-2.94,2.94) <-1.75,0.25>
Total: 109504 W: 28420 L: 28280 D: 52804
Ptnml(0-2): 355, 12326, 29273, 12420, 378
https://tests.stockfishchess.org/tests/view/6690dc095034141ae599c5fe

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

No functional change
2024-07-15 13:19:46 +02:00
Shawn Xu 024eb6f453 Unify Movepick Initializer
Passed Non-regression STC:
LLR: 2.94 (-2.94,2.94) <-1.75,0.25>
Total: 168704 W: 43524 L: 43455 D: 81725
Ptnml(0-2): 414, 17173, 49076, 17308, 381
https://tests.stockfishchess.org/tests/view/66904b7b5034141ae599a197

Passed Non-regression LTC:
LLR: 2.95 (-2.94,2.94) <-1.75,0.25>
Total: 120294 W: 30473 L: 30364 D: 59457
Ptnml(0-2): 40, 10974, 38032, 11039, 62
https://tests.stockfishchess.org/tests/view/66905b235034141ae599a223

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

bench 1459677
2024-07-15 13:18:37 +02:00
Shawn Xu 3df09c04d7 Simplify Away Refutation Stage
Simplify away killer stage to a constant bonus given to the killer move during
quiet move scoring.

Passed Non-regression STC (Against then-pending PR #5472):
LLR: 2.93 (-2.94,2.94) <-1.75,0.25>
Total: 106176 W: 27685 L: 27539 D: 50952
Ptnml(0-2): 410, 12765, 26637, 12821, 455
https://tests.stockfishchess.org/tests/view/668dd0835034141ae5999e8f

Passed Non-regression LTC:
LLR: 2.95 (-2.94,2.94) <-1.75,0.25>
Total: 92472 W: 23426 L: 23276 D: 45770
Ptnml(0-2): 55, 10376, 25215, 10544, 46
https://tests.stockfishchess.org/tests/view/669019e45034141ae5999fd2

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

Bench 1459677
2024-07-15 13:15:35 +02:00
Andyson007 42aae5fe8b Fixed non UCI compliance
print `<empty>` and accept `<empty>` for UCI string options,
accepting empty strings as well. Internally use empty strings (`""`).

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

No functional change
2024-07-15 13:14:57 +02:00
yl25946 8d1e41458e removed second killer move
STC with movepicker rewrite:

LLR: 2.93 (-2.94,2.94) <-1.75,0.25>
Total: 46656 W: 12208 L: 11995 D: 22453
Ptnml(0-2): 203, 5461, 11777, 5694, 193
https://tests.stockfishchess.org/tests/view/668d98a15034141ae5999e68

Earlier version passed STC:
LLR: 2.94 (-2.94,2.94) <0.00,2.00>
Total: 468896 W: 120999 L: 120054 D: 227843
Ptnml(0-2): 1207, 55209, 120639, 56218, 1175
https://tests.stockfishchess.org/tests/view/668b17d2cf91c430fca58630

Earlier version passed LTC:
LLR: 2.94 (-2.94,2.94) <-1.75,0.25>
Total: 550524 W: 139553 L: 139877 D: 271094
Ptnml(0-2): 333, 61646, 151616, 61346, 321
https://tests.stockfishchess.org/tests/view/668b2e04cf91c430fca586b1

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

bench 1234309

Co-authored-by: rn5f107s2 <clemens.lerchl@gmail.com>
2024-07-11 07:29:49 +02:00
Joost VandeVondele 6135a0e2f8 Provide more info on found TB files
now uses the following format:

`info string Found 510 WDL and 510 DTZ tablebase files (up to 6-man).`

this clarifies exactly what has been found, as the difference matters,
e.g. for the PV extension of TB scores.

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

No functional change
2024-07-11 07:29:44 +02:00
Stéphane Nicolet 7e72b37e4c Clean up comments in code
- Capitalize comments
- Reformat multi-lines comments to equalize the widths of the lines
- Try to keep the width of comments around 85 characters
- Remove periods at the end of single-line comments

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

No functional change
2024-07-11 07:29:33 +02:00
Disservin 98a7bb4436 CI give correct permissions for the clang-format action
closes https://github.com/official-stockfish/Stockfish/pull/5470

No functional change
2024-07-11 07:21:04 +02:00
yl25946 362a77a345 Move Loop Consistency in Probcut
In probcut move loop, everything is enclosed within a large if statement. I've
changed it to guard clauses to stay consistent with other move loops.

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

No functional change
2024-07-09 18:54:12 +02:00
Linmiao Xu b209f14b1e Update default main net to nn-e8bac1c07a5a.nnue
Created by modifying L2 weights from the previous main net (nn-74f1d263ae9a.nnue)
with params found by spsa around 9k / 120k games at 120+1.2.

370 spsa params - L2 weights in nn-74f1d263ae9a.nnue where |val| >= 50
A: 6000, alpha: 0.602, gamma: 0.101
weights: [-127, 127], c_end = 6

To print the spsa params with nnue-pytorch:
```
import features
from serialize import NNUEReader

feature_set = features.get_feature_set_from_name("HalfKAv2_hm")
with open("nn-74f1d263ae9a.nnue", "rb") as f:
    model = NNUEReader(f, feature_set).model

c_end = 6
for i in range(8):
    for j in range(32):
        for k in range(30):
            value = int(model.layer_stacks.l2.weight[32 * i + j, k] * 64)
            if abs(value) >= 50:
                print(f"twoW[{i}][{j}][{k}],{value},-127,127,{c_end},0.0020")
```

Among the 370 params, 229 weights were changed.
  avg change: 0.0961 ± 1.67
  range: [-4, 3]

The number of weights changed, grouped by layer stack index,
shows more weights were modified in the lower piece count buckets:
[54, 52, 29, 23, 22, 18, 14, 17]

Found with the same method described in:
https://github.com/official-stockfish/Stockfish/pull/5459

Passed STC:
https://tests.stockfishchess.org/tests/view/668aec9a58083e5fd88239e7
LLR: 3.00 (-2.94,2.94) <0.00,2.00>
Total: 52384 W: 13569 L: 13226 D: 25589
Ptnml(0-2): 127, 6141, 13335, 6440, 149

Passed LTC:
https://tests.stockfishchess.org/tests/view/668af50658083e5fd8823a0b
LLR: 2.94 (-2.94,2.94) <0.50,2.50>
Total: 46974 W: 12006 L: 11668 D: 23300
Ptnml(0-2): 25, 4992, 13121, 5318, 31

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

bench 1300471
2024-07-09 18:49:28 +02:00
Shawn Xu 4880ed4ad1 Simplify Probcut Malus
Passed Non-regression STC:
LLR: 2.94 (-2.94,2.94) <-1.75,0.25>
Total: 74880 W: 19261 L: 19083 D: 36536
Ptnml(0-2): 202, 8861, 19120, 9071, 186
https://tests.stockfishchess.org/tests/view/668a0966eca84f4d25864cba

Passed Non-regression LTC:
LLR: 2.94 (-2.94,2.94) <-1.75,0.25>
Total: 263916 W: 66690 L: 66718 D: 130508
Ptnml(0-2): 125, 29348, 73040, 29320, 125
https://tests.stockfishchess.org/tests/view/668a17e3eca84f4d25864e91

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

bench 1331408
2024-07-09 18:44:39 +02:00
Stéphane Nicolet acd0a933ad Fix compilation on Apple
Always use the posix function posix_memalign() as aligned memory
allocator on Apple computers. This should allow to compile Stockfish
out of the box on all versions of Mac OS X.

Patch tested on the following systems (apart from the CI) :
  • Mac OS 10.9.6 (arch x86-64-sse41-popcnt) with gcc-10
  • Mac OS 10.13.6 (arch x86-64-bmi2) with gcc-10, gcc-14 and clang-11
  • Mac OS 14.1.1 (arch apple-silicon) with clang-15

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

No functional change
2024-07-09 18:42:21 +02:00
Michael Chaly eac2d080a3 Further simplify stat bonuses
Based on recent simplification by linrock Since it completely removed any
special bonuses based on values difference and made it flat stat_bonus(depth +
1) I got an idea that we might as well remove all (depth + 1) bonuses and make
them usual depth bonuses.  Also removes weird negative bonus for depth 1 as a
side effect.

Passed STC:
https://tests.stockfishchess.org/tests/view/6689d817eca84f4d25863746
LLR: 2.94 (-2.94,2.94) <-1.75,0.25>
Total: 18080 W: 4789 L: 4552 D: 8739
Ptnml(0-2): 46, 1987, 4727, 2244, 36

Passed LTC:
https://tests.stockfishchess.org/tests/view/6689daa4eca84f4d258639d7
LLR: 2.95 (-2.94,2.94) <-1.75,0.25>
Total: 109062 W: 27548 L: 27417 D: 54097
Ptnml(0-2): 58, 11983, 30293, 12164, 33

Passed direct LTC vs linrock patch:
https://tests.stockfishchess.org/tests/view/668a46f8eca84f4d25866fe9
LLR: 2.95 (-2.94,2.94) <-1.75,0.25>
Total: 100002 W: 25351 L: 25209 D: 49442
Ptnml(0-2): 54, 11119, 27529, 11229, 70

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

Bench 1175744
2024-07-09 18:41:36 +02:00
Joost VandeVondele 5d3517c601 Fix output for GUI
Fritz 19 can hang with the current way to provide output,
i.e. too much output in a short time for a mate / depth 245 found quickly.

fallout from 25361e514b

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

No functional change
2024-07-09 18:36:46 +02:00
Linmiao Xu 5752529cab Update default main net to nn-74f1d263ae9a.nnue
Created by setting output weights (256) and biases (8) of the previous main net
nn-ddcfb9224cdb.nnue to values found around 12k / 120k spsa games at 120+1.2

This used modified fishtest dev workers to construct .nnue files from
spsa params, then load them with EvalFile when running tests:
https://github.com/linrock/fishtest/tree/spsa-file-modified-nnue/worker

Inspired by researching loading spsa params from files:
https://github.com/official-stockfish/fishtest/pull/1926

Scripts for modifying nnue files and preparing params:
https://github.com/linrock/nnue-pytorch/tree/no-gpu-modify-nnue

spsa params:
  weights: [-127, 127], c_end = 6
  biases: [-8192, 8192], c_end = 64

Example of reading output weights and biases from the previous main net using
nnue-pytorch and printing spsa params in a format compatible with fishtest:

```
import features
from serialize import NNUEReader

feature_set = features.get_feature_set_from_name("HalfKAv2_hm")
with open("nn-ddcfb9224cdb.nnue", "rb") as f:
    model = NNUEReader(f, feature_set).model

c_end_weights = 6
c_end_biases = 64

for i in range(8):
    for j in range(32):
        value = round(int(model.layer_stacks.output.weight[i, j] * 600 * 16) / 127)
        print(f"oW[{i}][{j}],{value},-127,127,{c_end_weights},0.0020")

for i in range(8):
    value = int(model.layer_stacks.output.bias[i] * 600 * 16)
    print(f"oB[{i}],{value},-8192,8192,{c_end_biases},0.0020")
```

For more info on spsa tuning params in nets:
https://github.com/official-stockfish/Stockfish/pull/5149
https://github.com/official-stockfish/Stockfish/pull/5254

Passed STC:
https://tests.stockfishchess.org/tests/view/66894d64e59d990b103f8a37
LLR: 2.94 (-2.94,2.94) <0.00,2.00>
Total: 32000 W: 8443 L: 8137 D: 15420
Ptnml(0-2): 80, 3627, 8309, 3875, 109

Passed LTC:
https://tests.stockfishchess.org/tests/view/6689668ce59d990b103f8b8b
LLR: 2.94 (-2.94,2.94) <0.50,2.50>
Total: 172176 W: 43822 L: 43225 D: 85129
Ptnml(0-2): 97, 18821, 47633, 19462, 75

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

bench 1120091
2024-07-09 18:35:23 +02:00
MinetaS cdb0b96e07 Clean up refutations array in MovePicker
This is a follow-up cleanup to a45c2bc34a.

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

No functional change
2024-07-09 18:34:00 +02:00
Linmiao Xu 4e9fded5a6 Larger bonus when updating quiet stats
Also removes unused arguments to update_all_stats to
fix compiler warnings about unused parameters.

Passed non-regression STC:
https://tests.stockfishchess.org/tests/view/6689a79a0fdd852d63cf52e9
LLR: 2.94 (-2.94,2.94) <-1.75,0.25>
Total: 26496 W: 6901 L: 6669 D: 12926
Ptnml(0-2): 62, 3094, 6715, 3304, 73

Passed non-regression LTC:
https://tests.stockfishchess.org/tests/view/6689a9960fdd852d63cf532d
LLR: 2.94 (-2.94,2.94) <-1.75,0.25>
Total: 41214 W: 10373 L: 10173 D: 20668
Ptnml(0-2): 11, 4491, 11412, 4673, 20

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

bench 1169958
2024-07-09 18:31:02 +02:00
Michael Chaly 75c8cb2c2f Adjust usage of previous statscore in bonus assignments
This patch adjusts usage of previous statscore for bonus assginments - allowing
it for any statscores and clamping it to wider range.

Passed STC:
https://tests.stockfishchess.org/tests/view/66892e76e59d990b103f6a91
LLR: 2.94 (-2.94,2.94) <0.00,2.00>
Total: 431520 W: 111767 L: 110872 D: 208881
Ptnml(0-2): 1180, 51165, 110133, 52144, 1138

Passed LTC:
https://tests.stockfishchess.org/tests/view/66897176e59d990b103f9605
LLR: 2.94 (-2.94,2.94) <0.50,2.50>
Total: 143184 W: 36463 L: 35929 D: 70792
Ptnml(0-2): 55, 15540, 39863, 16084, 50

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

bench 1330556
2024-07-09 18:29:09 +02:00
Linmiao Xu bb9b65408f Simplify improving deduction in futility margin
Passed non-regression STC:
https://tests.stockfishchess.org/tests/view/668981d4df142e108ffc9bb4
LLR: 2.94 (-2.94,2.94) <-1.75,0.25>
Total: 312672 W: 80280 L: 80363 D: 152029
Ptnml(0-2): 729, 37198, 80529, 37187, 693

Passed non-regression LTC:
https://tests.stockfishchess.org/tests/view/668988c6df142e108ffca042
LLR: 2.95 (-2.94,2.94) <-1.75,0.25>
Total: 126042 W: 31971 L: 31857 D: 62214
Ptnml(0-2): 50, 13988, 34832, 14100, 51

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

bench 1100483
2024-07-09 18:28:06 +02:00
Shawn Xu 2d3ef434b4 Tweak LMR at Root
Passed STC:
LLR: 2.93 (-2.94,2.94) <0.00,2.00>
Total: 328192 W: 84751 L: 84014 D: 159427
Ptnml(0-2): 758, 38802, 84253, 39511, 772
https://tests.stockfishchess.org/tests/view/6689203959cb3228a4759a49

Passed LTC:
LLR: 2.95 (-2.94,2.94) <0.50,2.50>
Total: 56748 W: 14494 L: 14136 D: 28118
Ptnml(0-2): 19, 6089, 15803, 6441, 22
https://tests.stockfishchess.org/tests/view/66892d76e59d990b103f6626

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

Bench 1253593
2024-07-09 18:26:35 +02:00
Shawn Xu b79ac764ff Simplify in-check condition for Probcut-in-check
dont let your memes be dreams !?

Passed Non-regression STC:
LLR: 2.95 (-2.94,2.94) <-1.75,0.25>
Total: 512000 W: 132193 L: 132497 D: 247310
Ptnml(0-2): 1600, 61170, 130704, 60986, 1540
https://tests.stockfishchess.org/tests/view/66838911c4f539faa03268a2

Passed Non-regression LTC:
LLR: 2.95 (-2.94,2.94) <-1.75,0.25>
Total: 380268 W: 95894 L: 96042 D: 188332
Ptnml(0-2): 193, 42861, 104180, 42701, 199
https://tests.stockfishchess.org/tests/view/6688d0550c9d7c1ab33ed5a8

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

Bench: 1130282
2024-07-09 18:24:40 +02:00
Shawn Xu b1f522930d Simplify Away Move Count Pruning Adjustment
Using Singular Search Result

Passed Non-regression STC:
LLR: 3.01 (-2.94,2.94) <-1.75,0.25>
Total: 62688 W: 16319 L: 16121 D: 30248
Ptnml(0-2): 196, 7317, 16104, 7547, 180
https://tests.stockfishchess.org/tests/view/66879bf51b527f04dd477ff9

Passed Non-regression LTC:
LLR: 2.96 (-2.94,2.94) <-1.75,0.25>
Total: 116502 W: 29504 L: 29379 D: 57619
Ptnml(0-2): 66, 12881, 32226, 13018, 60
https://tests.stockfishchess.org/tests/view/6688629e0c9d7c1ab33ed030

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

bench 1207930
2024-07-09 18:20:26 +02:00
Muzhen Gaming 4d6e1225bd Simplify ttPv reduction formula
This is a revert of 2046c92.
This patch is based on the fact that the ttPv reduction has proven non-linear scaling (as documented in the code, along with testing guidelines); however, the original patch had (erroneously) not been tested at VLTC or longer.

Simplification STC: https://tests.stockfishchess.org/tests/view/6689266e59cb3228a4759b28
LLR: 2.95 (-2.94,2.94) <-1.75,0.25>
Total: 100320 W: 25913 L: 25763 D: 48644
Ptnml(0-2): 270, 11842, 25750, 12064, 234

Simplification LTC: https://tests.stockfishchess.org/tests/view/66893103e59d990b103f6ab3
LLR: 2.94 (-2.94,2.94) <-1.75,0.25>
Total: 57078 W: 14466 L: 14282 D: 28330
Ptnml(0-2): 34, 6214, 15851, 6414, 26

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

Bench: 1124658
2024-07-06 18:00:09 +02:00
Muzhen Gaming 55cb235d47 Simplify internal iterative reductions
This is a revert of cc992e5.
This patch is based on consistent observations that decreasing depth more in IIR generally has a bad scaling behaviour (good at STC, bad at longer time controls).

Simplification STC: https://tests.stockfishchess.org/tests/view/6689266659cb3228a4759b26
LLR: 2.93 (-2.94,2.94) <-1.75,0.25>
Total: 96992 W: 24977 L: 24824 D: 47191
Ptnml(0-2): 251, 11497, 24851, 11642, 255

Simplification LTC: https://tests.stockfishchess.org/tests/view/668930ffe59d990b103f6ab1
LLR: 2.95 (-2.94,2.94) <-1.75,0.25>
Total: 35808 W: 9185 L: 8980 D: 17643
Ptnml(0-2): 25, 3776, 10101, 3973, 29

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

Bench: 1097766
2024-07-06 17:58:23 +02:00
Shawn Xu 24ab46c511 Non-functional Fixes & Updates
Fixes a missing default slot for dbg_extremes of, removes a extra newline, and
updates SE elo estimate from
https://tests.stockfishchess.org/tests/view/664ebd1e928b1fb18de4e4b7 while we
are at it.

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

No functional change
2024-07-06 17:56:31 +02:00
FauziAkram ec8288fe0d Simplify away eval in TM
Passed STC:
LLR: 2.93 (-2.94,2.94) <-1.75,0.25>
Total: 40160 W: 10523 L: 10309 D: 19328
Ptnml(0-2): 129, 4543, 10524, 4753, 131
https://tests.stockfishchess.org/tests/view/6685ab8b99271ae49479dbe9

Passed LTC:
LLR: 2.95 (-2.94,2.94) <-1.75,0.25>
Total: 195672 W: 49681 L: 49639 D: 96352
Ptnml(0-2): 112, 20976, 55597, 21060, 91
https://tests.stockfishchess.org/tests/view/6686f27a7092ade1206f7889

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

No functional change
2024-07-06 17:54:22 +02:00
Shawn Xu a45c2bc34a Simplify Away Countermove Heuristic
Passed Non-regression STC:
LLR: 2.93 (-2.94,2.94) <-1.75,0.25>
Total: 977824 W: 252072 L: 252888 D: 472864
Ptnml(0-2): 2518, 117120, 250560, 116088, 2626
https://tests.stockfishchess.org/tests/view/6683452d95b0d1e881e81541

Passed Non-regression LTC:
LLR: 2.95 (-2.94,2.94) <-1.75,0.25>
Total: 81048 W: 20630 L: 20470 D: 39948
Ptnml(0-2): 36, 8915, 22464, 9071, 38
https://tests.stockfishchess.org/tests/view/66886b7b0c9d7c1ab33ed281

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

bench 1276784
2024-07-06 17:48:11 +02:00
Muzhen Gaming daa9e217ab VVLTC search tune
Passed VVLTC 1st sprt: https://tests.stockfishchess.org/tests/view/6688af640c9d7c1ab33ed327
LLR: 2.94 (-2.94,2.94) <0.00,2.00>
Total: 16050 W: 4200 L: 3959 D: 7891
Ptnml(0-2): 0, 1383, 5018, 1624, 0

Passed VVLTC 2nd sprt: https://tests.stockfishchess.org/tests/view/6688e8900c9d7c1ab33efd60
LLR: 2.95 (-2.94,2.94) <0.50,2.50>
Total: 44044 W: 11303 L: 10999 D: 21742
Ptnml(0-2): 1, 3973, 13772, 4273, 3

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

Bench: 992058
2024-07-06 17:45:58 +02:00
Stéphane Nicolet d212e663bb Introduction evaluation grain of 16 (and randomize)
This patch uses an evaluation grain of 16 in order to get more cutoffs in
the alpha-beta algorithm. For a discussion of the efficiency of alpha-beta
related to changes in the number of discrete values of terminal nodes, see
for instance section 9.1.2 of Judea Pearl's classical book "Heuristics" :

https://mat.uab.cat/~alseda/MasterOpt/Judea_Pearl-Heuristics_Intelligent_Search_Strategies_for_Computer_Problem_Solving.pdf

Moreover, we add a small (-1, +1) random component after the quantification
to help the search exploration a little bit. This is similar in spirit to
the (-1, +1) random component already present in the function draw_value()
to make Stockfish more robust in draw evaluations.

passed STC:
LLR: 2.95 (-2.94,2.94) <0.00,2.00>
Total: 220960 W: 57249 L: 56668 D: 107043
Ptnml(0-2): 499, 26017, 56882, 26568, 514
https://tests.stockfishchess.org/tests/view/668907fb7edfb6f233f999f8

passed LTC :
LLR: 2.94 (-2.94,2.94) <0.50,2.50>
Total: 48966 W: 12574 L: 12233 D: 24159
Ptnml(0-2): 14, 5233, 13654, 5562, 20
https://tests.stockfishchess.org/tests/view/6689105659cb3228a47598bf

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

bench: 1336007
2024-07-06 17:43:39 +02:00
Joost VandeVondele c40dd26cbc CI give creditials for the clang-format action
following up from earlier changes

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

No functional change
2024-07-06 17:42:23 +02:00
Joost VandeVondele 2cbc20e846 Correct and extend PV lines with decisive TB score
Currently (after #5407), SF has the property that any PV line with a decisive
TB score contains the corresponding TB position, with a score that correctly
identifies the depth at which TB are entered. The PV line that follows might
not preserve the game outcome, but can easily be verified and extended based on
TB information. This patch provides this functionality, simply extending the PV
lines on output, this doesn't affect search.

Indeed, if DTZ tables are available, search based PV lines that correspond to
decisive TB scores are verified to preserve game outcome, truncating the line
as needed. Subsequently, such PV lines are extended with a game outcome
preserving line until mate, as a possible continuation.  These lines are not
optimal mating lines, but are similar to what a user could produce on a website
like https://syzygy-tables.info/ clicking always the top ranked move, i.e.
minimizing or maximizing DTZ (with a simple tie-breaker for moves that have
identical DTZ), and are thus an just an illustration of how to game can be won.

A similar approach is already in established in
https://github.com/joergoster/Stockfish/tree/matefish2

This also contributes to addressing #5175 where SF can give an incorrect TB
win/loss for positions in TB with a movecounter that doesn't reflect optimal
play. While the full solution requires either TB generated differently, or a
search when ranking rootmoves, current SF will eventually find a draw in these
cases, in practice quite quickly, e.g.
`1kq5/q2r4/5K2/8/8/8/8/7Q w - - 96 1`
`8/8/6k1/3B4/3K4/4N3/8/8 w - - 54 106`

Gives the same results as master on an extended set of test positions from
https://github.com/mcostalba/Stockfish/commit/9173d29c414ddb8f4bec74e4db3ccbe664c66bf9
with the exception of the above mentioned fen where this commit improves.

With https://github.com/vondele/matetrack using 6men TB, all generated PVs verify:
```
Using ../Stockfish/src/stockfish.syzygyExtend on matetrack.epd with --nodes 1000000 --syzygyPath /chess/syzygy/3-4-5-6/WDL:/chess/syzygy/3-4-5-6/DTZ
Engine ID:     Stockfish dev-20240704-ff227954
Total FENs:    6555
Found mates:   3299
Best mates:    2582
Found TB wins: 568
```

As repeated DTZ probing could be slow a procedure (100ms+ on HDD, a few ms on
SSD), the extension is only done as long as the time taken is less than half
the `Move Overhead` parameter. For tournaments where these lines might be of
interest to the user, a suitable `Move Overhead` might be needed (e.g. TCEC has
1000ms already).

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

No functional change
2024-07-05 15:43:49 +02:00
Linmiao Xu 3c379e55d9 Update 7 stat bonus/malus params
Values found around 119k / 120k spsa games at 60+0.6:
https://tests.stockfishchess.org/tests/view/6683112a192114e61f92f87a

Passed STC:
https://tests.stockfishchess.org/tests/view/66838148c4f539faa0326897
LLR: 2.95 (-2.94,2.94) <0.00,2.00>
Total: 40928 W: 10835 L: 10508 D: 19585
Ptnml(0-2): 139, 4802, 10254, 5131, 138

Passed LTC:
https://tests.stockfishchess.org/tests/view/668448a87a1863935cee42c6
LLR: 2.96 (-2.94,2.94) <0.50,2.50>
Total: 29208 W: 7559 L: 7253 D: 14396
Ptnml(0-2): 17, 3118, 8019, 3442, 8

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

bench 1138753
2024-07-05 15:43:49 +02:00
Joost VandeVondele 25361e514b Output from a fix depth onward, instead of 3s.
To avoid output that depends on timing, output currmove and similar only from depth > 30
onward.  Current choice of 3s makes the output of the same search depending on
the system load, and doesn't always start at move 1. Depth 30 is nowadays
reached in a few seconds on most systems.

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

No functional change
2024-07-05 15:43:42 +02:00
Disservin 74a8fc0604 Use explicit action permissions in CI
Necessary modifications according to changes in the GitHub Action settings.

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

Follow up from the report by Yaron Avital (yaronav) earlier.

No functional change
2024-07-05 15:35:13 +02:00
Joost VandeVondele ee6fc7e38b CI: limit artifact uploads
do not upload some unneeded intermediate directories,
disable running authenticated git commands with the checkout action.

Thanks to Yaron A for the report.

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

No functional change
2024-07-03 13:45:14 +02:00
Shawn Xu b9ff5bb93b Implement dbg_extremes_of
An alternative to #5431, implements one function `dbg_extremes_of` to keep track
of min and max.

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

No functional change
2024-07-03 13:44:01 +02:00
Joost VandeVondele ad0f1fecda Move info strings once more
Follow up from #5404 ... current location leads to troubles with Aquarium GUI

Fixes #5430

Now prints the information on threads and available processors at the beginning
of search, where info about the networks is already printed (and is known to
work)

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

No functional change.
2024-07-03 13:39:31 +02:00
Shahin M. Shahin 6b7822119f Limit has_game_cycle() to only upcoming repetition
use the original algorithm according to the paper
http://web.archive.org/web/20201107002606/https://marcelk.net/2013-04-06/paper/upcoming-rep-v2.pdf,
which detects accurately if a position has an upcoming repetition. The 'no
progress' part of has_game_cycle has been removed, the function has been
renamed to upcoming_repetition to reflect this.

As a result of this fix, to the best of our knowledge, all PVs for completed
iterations that yield a mate or decisive table base score now end in mate or
contain a TB position, respectively.

passed non-regression STC:
https://tests.stockfishchess.org/tests/view/6679fa1d0c2db3fa2dcecbf2
LLR: 2.96 (-2.94,2.94) <-1.75,0.25>
Total: 63584 W: 16666 L: 16472 D: 30446
Ptnml(0-2): 186, 7552, 16146, 7698, 210

Passed non-regression LTC:
https://tests.stockfishchess.org/tests/view/667ac965e439ed1c7a9ca042
LLR: 2.94 (-2.94,2.94) <-1.75,0.25>
Total: 464574 W: 117493 L: 117729 D: 229352
Ptnml(0-2): 311, 52468, 126974, 52214, 320

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

bench: 1209805
2024-07-03 13:35:49 +02:00
Shawn Xu 69ad4667fb Do Capture History Updates In Probcut
This patch introduces history updates to probcut. Standard depth - 3 bonus and
maluses are given to the capture that caused fail high and previously searched
captures, respectively. Similar to #5243, a negative history fill is applied to
compensate for an increase in capture history average, thus improving the
scaling of this patch.

Passed STC:
LLR: 2.95 (-2.94,2.94) <0.00,2.00>
Total: 84832 W: 21941 L: 21556 D: 41335
Ptnml(0-2): 226, 9927, 21688, 10386, 189
https://tests.stockfishchess.org/tests/view/6682fab9389b9ee542b1d029

Passed LTC:
LLR: 2.94 (-2.94,2.94) <0.50,2.50>
Total: 104298 W: 26469 L: 26011 D: 51818
Ptnml(0-2): 43, 11458, 28677, 11940, 31
https://tests.stockfishchess.org/tests/view/6682ff06389b9ee542b1d0a0

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

bench 1281351
2024-07-03 13:18:00 +02:00
Dubslow 6138a0fd0e Probcut in check no matter if pv or capture
Passed STC: https://tests.stockfishchess.org/tests/view/6681e9c8c1657e386d294cef
LLR: 2.93 (-2.94,2.94) <-1.75,0.25>
Total: 217824 W: 56149 L: 56129 D: 105546
Ptnml(0-2): 587, 25926, 55848, 25982, 569

Passed LTC: https://tests.stockfishchess.org/tests/view/6681fcb8c1657e386d294db1
LLR: 2.94 (-2.94,2.94) <-1.75,0.25>
Total: 357552 W: 90546 L: 90671 D: 176335
Ptnml(0-2): 207, 40064, 98362, 39933, 210

Each half of this also passed STC+LTC separately

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

bench 1227870
2024-07-01 20:07:03 +02:00
Linmiao Xu 843b6f7c98 Update some params for pruning at shallow depth
Values found around 82k / 120k spsa games at 60+0.6:
https://tests.stockfishchess.org/tests/view/6681aca4481148df247298bd

Passed STC:
https://tests.stockfishchess.org/tests/view/6681c795c1657e386d2948fa
LLR: 2.93 (-2.94,2.94) <0.00,2.00>
Total: 145216 W: 37595 L: 37122 D: 70499
Ptnml(0-2): 375, 17122, 37185, 17507, 419

Passed LTC:
https://tests.stockfishchess.org/tests/view/6681d4eec1657e386d2949e0
LLR: 2.95 (-2.94,2.94) <0.50,2.50>
Total: 154062 W: 39117 L: 38557 D: 76388
Ptnml(0-2): 67, 16874, 42608, 17396, 86

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

bench 996419
2024-07-01 20:04:13 +02:00
Linmiao Xu f6842a145c Simplify worsening deduction in futility margin
Passed non-regression STC:
https://tests.stockfishchess.org/tests/view/66817d46442423e547141226
LLR: 2.94 (-2.94,2.94) <-1.75,0.25>
Total: 345408 W: 89146 L: 89266 D: 166996
Ptnml(0-2): 954, 41317, 88286, 41189, 958

Passed non-regression LTC:
https://tests.stockfishchess.org/tests/view/66818dbe1e90a146232d1f62
LLR: 2.95 (-2.94,2.94) <-1.75,0.25>
Total: 173214 W: 43821 L: 43755 D: 85638
Ptnml(0-2): 108, 19407, 47492, 19511, 89

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

bench 981017
2024-07-01 20:02:38 +02:00
FauziAkram 5deb262393 Simplify rm.averageScore calculation
Passed STC:
LLR: 2.94 (-2.94,2.94) <-1.75,0.25>
Total: 485056 W: 125222 L: 125497 D: 234337
Ptnml(0-2): 1384, 58197, 123614, 57976, 1357
https://tests.stockfishchess.org/tests/view/6681816d442423e54714133f

Passed LTC:
LLR: 2.94 (-2.94,2.94) <-1.75,0.25>
Total: 56622 W: 14301 L: 14115 D: 28206
Ptnml(0-2): 31, 6259, 15538, 6459, 24
https://tests.stockfishchess.org/tests/view/6681a9a5596d543edc677490

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

bench: 1171203
2024-07-01 20:01:05 +02:00
Shahin M. Shahin 38c5fc33e4 Increase reduction based on correct expectation
If the current node is not a cutNode then it means that the child is one in LMR
and the cutoff count is expected, so more reduction when the cutoffs are
expected

Passed STC:
https://tests.stockfishchess.org/tests/view/66815e791c5b344a34ca7090
LLR: 2.93 (-2.94,2.94) <0.00,2.00>
Total: 64416 W: 16876 L: 16519 D: 31021
Ptnml(0-2): 150, 7670, 16264, 7921, 203

Passed LTC:
https://tests.stockfishchess.org/tests/view/668162f61c5b344a34ca725c
LLR: 2.94 (-2.94,2.94) <0.50,2.50>
Total: 78186 W: 19905 L: 19499 D: 38782
Ptnml(0-2): 55, 8561, 21437, 9003, 37

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

bench: 1161531
2024-07-01 19:58:13 +02:00
Michael Chaly 7b49f9dd70 Tweak multicut
This patch is an original patch by author of Altair
(https://github.com/Alex2262/AltairChessEngine) chess engine.

It allows to produce more aggressive multicut compared to master by changing
condition it needs to fulfil and also returns bigger value.  Also has applied
matetrack fix on top.

Passed STC:
https://tests.stockfishchess.org/tests/view/667223ab602682471b0650e2
LLR: 2.95 (-2.94,2.94) <0.00,2.00>
Total: 50048 W: 13200 L: 12860 D: 23988
Ptnml(0-2): 181, 5822, 12679, 6160, 182

Passed LTC:
https://tests.stockfishchess.org/tests/view/6672f777602682471b06515d
LLR: 2.97 (-2.94,2.94) <0.50,2.50>
Total: 706380 W: 179707 L: 177981 D: 348692
Ptnml(0-2): 656, 79250, 191665, 80950, 669

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

bench 1148966
2024-07-01 19:56:38 +02:00
Daniel Monroe 91ec31dac4 Grade countermove bonus for low statscores
Passed STC:
LLR: 2.96 (-2.94,2.94) <0.00,2.00>
Total: 338592 W: 88396 L: 87627 D: 162569
Ptnml(0-2): 1161, 40201, 85788, 41000, 1146
https://tests.stockfishchess.org/tests/view/6679d40c0c2db3fa2dcecbcc

Passed LTC:
LLR: 2.95 (-2.94,2.94) <0.50,2.50>
Total: 83526 W: 21429 L: 21010 D: 41087
Ptnml(0-2): 54, 9173, 22913, 9546, 77
https://tests.stockfishchess.org/tests/view/667c5f2980450dba965911fc

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

bench: 1489815
2024-07-01 19:53:45 +02:00
mstembera 90eca83e7f Simplify away a useless TTEntry::read()
Not needed when we don hit an entry.

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

No functional change
2024-07-01 19:50:32 +02:00
Taras Vuk 22a502ac74 Skip futility pruning if beta is below TB loss value
Passed STC:
LLR: 2.95 (-2.94,2.94) <-1.75,0.25>
Total: 77024 W: 20122 L: 19946 D: 36956
Ptnml(0-2): 278, 8754, 20277, 8920, 283
https://tests.stockfishchess.org/tests/view/66752d59602682471b0652f3

Passed LTC:
LLR: 2.95 (-2.94,2.94) <-1.75,0.25>
Total: 93114 W: 23623 L: 23477 D: 46014
Ptnml(0-2): 77, 9839, 26566, 10011, 64
https://tests.stockfishchess.org/tests/view/6676b3e1602682471b065395

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

bench: 1003441
2024-07-01 19:48:06 +02:00
Joost VandeVondele 66e6274d32 Fix typos in comments
closes https://github.com/official-stockfish/Stockfish/pull/5409

No functional change
2024-07-01 19:44:17 +02:00
FauziAkram b2a12917e2 Remove redundant inline
constexpr implies inline anyway

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

No functional change
2024-07-01 19:40:04 +02:00
Joost VandeVondele 5fbfd06171 Move info output afer uciok
fixes #5393 : an incompatibility with an older GUI (Chesspartner)
fixes #5396 : an incompatibility with an older GUI (Fritz9)

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

No functional change
2024-07-01 19:37:25 +02:00
FauziAkram cc992e5e4a Internal iterative reductions: decrease depth more
For PV nodes without a ttMove, we decrease depth.
But in this patch, additionally, if the current position is found in the TT, and the stored depth in the TT is greater than or equal to
the current search depth, we decrease the search depth even further.

Passed STC:
LLR: 2.96 (-2.94,2.94) <0.00,2.00>
Total: 84384 W: 22154 L: 21761 D: 40469
Ptnml(0-2): 292, 9972, 21315, 10277, 336
https://tests.stockfishchess.org/tests/view/666b0a4d602682471b064db6

Passed LTC:
LLR: 2.95 (-2.94,2.94) <0.50,2.50>
Total: 92106 W: 23471 L: 23032 D: 45603
Ptnml(0-2): 79, 10155, 25154, 10578, 87
https://tests.stockfishchess.org/tests/view/666c423d602682471b064e56

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

bench: 1038234
2024-06-23 11:46:41 +02:00
Shawn Xu d5c130569b Simplify Bonus Formula In History Adjustment
Inspired by a discord message [1] from Vizvezdenec, this patch simplifies the
bonus adjustment bonus = bonus > 0 ? 2 * bonus : bonus / 2 to a constant
addition, maintaining bonus average at around 0 in regular bench. As cj5716
pointed in discord [2], the constant bonus can also be considered as factoring
tempo when calculating bonus, yielding a better value of the move.

[1] https://discord.com/channels/435943710472011776/882956631514689597/1243877089443188776
[2] https://discord.com/channels/435943710472011776/813919248455827515/1252277437249622077

Passed Non-regression STC:
LLR: 2.94 (-2.94,2.94) <-1.75,0.25>
Total: 29984 W: 7908 L: 7677 D: 14399
Ptnml(0-2): 95, 3502, 7594, 3679, 122
https://tests.stockfishchess.org/tests/view/666f7210602682471b064fa2

Passed Non-regression LTC:
LLR: 2.94 (-2.94,2.94) <-1.75,0.25>
Total: 170136 W: 43214 L: 43145 D: 83777
Ptnml(0-2): 158, 19185, 46311, 19258, 156
https://tests.stockfishchess.org/tests/view/666fb32e602682471b064fb5

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

bench 1438375
2024-06-23 11:41:48 +02:00
evqsx 8806a58ebf Simplify static exchange evaluation pruning formula
Passed STC: https://tests.stockfishchess.org/tests/view/666bda31602682471b064e1f
LLR: 2.94 (-2.94,2.94) <-1.75,0.25>
Total: 141696 W: 36932 L: 36826 D: 67938
Ptnml(0-2): 510, 16880, 35989, 16932, 537

Passed LTC: https://tests.stockfishchess.org/tests/view/666e6b67602682471b064f4b
LLR: 2.94 (-2.94,2.94) <-1.75,0.25>
Total: 159504 W: 40552 L: 40471 D: 78481
Ptnml(0-2): 130, 18160, 43103, 18217, 142

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

bench: 1084115
2024-06-23 11:37:32 +02:00
Joost VandeVondele 5514690f8e CI/CD: play games
this action plays games under fast-chess with a `debug=yes` compiled binary.

It checks for triggered asserts in the code, or generally for engine disconnects.

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

No functional change
2024-06-23 11:35:50 +02:00
xoto10 2678606e8d Consider wider range of moves near leaves.
try to avoid missing good moves for opponent or engine, by updating bestMove
also when value == bestValue (i.e. value == alpha) under certain conditions.
In particular require this is at higher depth in the tree, leaving the logic
near the root unchanged, and only apply randomly. Avoid doing this near mate
scores, leaving mate PVs intact.

Passed SMP STC 6+0.06 th7 :
LLR: 2.94 (-2.94,2.94) <0.00,2.00>
Total: 42040 W: 10930 L: 10624 D: 20486
Ptnml(0-2): 28, 4682, 11289, 4998, 23
https://tests.stockfishchess.org/tests/view/66608b00c340c8eed7757d1d

Passed SMP LTC 24+0.24 th7 :
LLR: 2.94 (-2.94,2.94) <0.50,2.50>
Total: 73692 W: 18978 L: 18600 D: 36114
Ptnml(0-2): 9, 7421, 21614, 7787, 15
https://tests.stockfishchess.org/tests/view/666095e8c340c8eed7757d49

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

Bench 1205168
2024-06-23 11:29:02 +02:00
FauziAkram 2046c92ad4 Tweak the reduction formula
Tweak the reduction formula if position is or has been on the PV
Taking inspiration from an old Viren test.

Passed STC:
LLR: 2.94 (-2.94,2.94) <0.00,2.00>
Total: 78528 W: 20607 L: 20225 D: 37696
Ptnml(0-2): 262, 9297, 19785, 9637, 283
https://tests.stockfishchess.org/tests/view/666339c70ff7cb4868d1fe24

Passed LTC:
LLR: 2.94 (-2.94,2.94) <0.50,2.50>
Total: 138630 W: 35666 L: 35132 D: 67832
Ptnml(0-2): 118, 15345, 37835, 15919, 98
https://tests.stockfishchess.org/tests/view/66645dec0612cd151f9e77b0

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

Bench: 1134281
2024-06-15 12:13:59 +02:00
Dubslow ff10f4ac65 Fix readability of TTEntry occupancy check
Passed STC:
https://tests.stockfishchess.org/tests/view/66695b6a602682471b064cfc
LLR: 2.93 (-2.94,2.94) <-1.75,0.25>
Total: 107520 W: 28138 L: 27998 D: 51384
Ptnml(0-2): 373, 12257, 28358, 12401, 371

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

No functional change
2024-06-15 12:10:49 +02:00
Joost VandeVondele b01fdb596a Fix upperbound/lowerbound output in multithreaded case
In case a stop is received during multithreaded searches, the PV of the best
thread might be printed without the correct upperbound/lowerbound indicators.
This was due to the pvIdx variable being incremented after receiving the stop.

passed STC:
https://tests.stockfishchess.org/tests/view/666985da602682471b064d08
 LLR: 2.93 (-2.94,2.94) <-1.75,0.25>
Total: 196576 W: 51039 L: 50996 D: 94541
Ptnml(0-2): 760, 22545, 51603, 22652, 728

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

Bench: 1160467
2024-06-15 12:08:29 +02:00
Joost VandeVondele 44cddbd962 Add matetrack to CI
verifies that all mate PVs printed for finished iterations (i.e. no lower or upper bounds),
are complete, i.e. of the expected length and ending in mate, and do not contain drawing
or illegal moves.

based on a set of 2000 positions and the code in https://github.com/vondele/matetrack

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

No functional change
2024-06-15 12:06:45 +02:00
Tomasz Sobczyk 7c0607d2d3 Fix printing of empty info strings.
Handle printing of `info string` in a single place.

Fixes #5386

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

No functional change
2024-06-15 12:04:16 +02:00
Joost VandeVondele 3d92950859 Limit depth after extensions to avoid asserts.
currently extensions can cause depth to exceed MAX_PLY.

This triggers the assert near line 542 in search when running a binary compiled with `debug=yes` on a testcase like:
```
position fen 7K/P1p1p1p1/2P1P1Pk/6pP/3p2P1/1P6/3P4/8 w - - 0 1
go nodes 1000000
```

passed STC
https://tests.stockfishchess.org/tests/view/6668a56a602682471b064c8d
LLR: 2.93 (-2.94,2.94) <-1.75,0.25>
Total: 143936 W: 37338 L: 37238 D: 69360
Ptnml(0-2): 514, 16335, 38149, 16477, 493

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

Bench: 1160467
2024-06-15 12:02:56 +02:00
Linmiao Xu 025da6a0d1 Give positional output more weight in nnue eval
This effectively reverts the removal of delta in:
https://github.com/official-stockfish/Stockfish/pull/5373

Passed STC:
https://tests.stockfishchess.org/tests/view/6664d41922234461cef58e6b
LLR: 2.95 (-2.94,2.94) <0.00,2.00>
Total: 56448 W: 14849 L: 14500 D: 27099
Ptnml(0-2): 227, 6481, 14457, 6834, 225

Passed LTC:
https://tests.stockfishchess.org/tests/view/666587a1996b40829f4ee007
LLR: 2.94 (-2.94,2.94) <0.50,2.50>
Total: 91686 W: 23402 L: 22963 D: 45321
Ptnml(0-2): 78, 10205, 24840, 10640, 80

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

bench 1160467
2024-06-12 09:17:04 +02:00
Disservin 7013a22b74 Move options into the engine
Move the engine options into the engine class, also avoid duplicated
initializations after startup.  UCIEngine needs to register an add_listener to
listen to all option changes and print these.  Also avoid a double
initialization of the TT, which was the case with the old state.

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

No functional change
2024-06-12 09:17:04 +02:00
Dubslow c8213ba0d0 Simplify TT interface and avoid changing TT info
This commit builds on the work and ideas of #5345, #5348, and #5364.

Place as much as possible of the TT implementation in tt.cpp, rather than in the
header.  Some commentary is added to better document the public interface.

Fix the search read-TT races, or at least contain them to within TT methods only.

Passed SMP STC: https://tests.stockfishchess.org/tests/view/666134ab91e372763104b443
LLR: 2.94 (-2.94,2.94) <-1.75,0.25>
Total: 512552 W: 132387 L: 132676 D: 247489
Ptnml(0-2): 469, 58429, 138771, 58136, 471

The unmerged version has bench identical to the other PR (see also #5348) and
therefore those same-functionality tests:

SMP LTC: https://tests.stockfishchess.org/tests/view/665c7021fd45fb0f907c214a
SMP LTC: https://tests.stockfishchess.org/tests/view/665d28a7fd45fb0f907c5495

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

bench 1205675
2024-06-12 09:17:04 +02:00
Joost VandeVondele 7e890fd048 Keep mate PVs intact.
do not return a cutoff value in razoring if that value is in the mate/tb range.

passed STC:
https://tests.stockfishchess.org/tests/view/666381880ff7cb4868d1fe58
LLR: 2.93 (-2.94,2.94) <-1.75,0.25>
Total: 130848 W: 34046 L: 33931 D: 62871
Ptnml(0-2): 429, 14968, 34524, 15065, 438

passed LTC:
https://tests.stockfishchess.org/tests/view/66643f120612cd151f9e7788
LLR: 2.94 (-2.94,2.94) <-1.75,0.25>
Total: 39702 W: 10157 L: 9959 D: 19586
Ptnml(0-2): 20, 4108, 11402, 4296, 25

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

Bench: 1174094
2024-06-12 09:03:32 +02:00
cj5716 e271059e08 Make repeated bench runs identical
fixes https://github.com/official-stockfish/Stockfish/issues/5376
closes https://github.com/official-stockfish/Stockfish/pull/5377

No functional changes
2024-06-08 23:40:22 +02:00
evqsx 4151c06b74 Remove the correction history bonus in null move search
Passed STC:
https://tests.stockfishchess.org/tests/view/666168e191e372763104c664
LLR: 2.94 (-2.94,2.94) <-1.75,0.25>
Total: 94848 W: 24708 L: 24550 D: 45590
Ptnml(0-2): 289, 11355, 24033, 11403, 344

Passed LTC:
https://tests.stockfishchess.org/tests/view/6661e73591e372763104c751
LLR: 2.94 (-2.94,2.94) <-1.75,0.25>
Total: 70452 W: 17849 L: 17679 D: 34924
Ptnml(0-2): 27, 7707, 19596, 7861, 35

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

Bench: 1174094
2024-06-08 23:39:46 +02:00
Dubslow 1c67b46caf Linearize corrHist
Passed STC: https://tests.stockfishchess.org/tests/view/6661fff88dd8f31ed3c5d819
LLR: 2.93 (-2.94,2.94) <-1.75,0.25>
Total: 17504 W: 4651 L: 4406 D: 8447
Ptnml(0-2): 71, 1975, 4384, 2282, 40

Passed LTC: https://tests.stockfishchess.org/tests/view/666205b48dd8f31ed3c61296
LLR: 2.94 (-2.94,2.94) <-1.75,0.25>
Total: 24522 W: 6313 L: 6094 D: 12115
Ptnml(0-2): 14, 2643, 6726, 2866, 12

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

Bench: 1237729
2024-06-08 23:35:00 +02:00
Dubslow 7d4ffa175c Remove delta from evaluation
Passed STC: https://tests.stockfishchess.org/tests/view/6660e49c6489614cdad14e29
LLR: 2.94 (-2.94,2.94) <-1.75,0.25>
Total: 188768 W: 48907 L: 48854 D: 91007
Ptnml(0-2): 584, 22571, 48005, 22656, 568

Passed LTC: https://tests.stockfishchess.org/tests/view/6660ff9791e372763104b38c
LLR: 2.95 (-2.94,2.94) <-1.75,0.25>
Total: 310680 W: 78651 L: 78727 D: 153302
Ptnml(0-2): 180, 34818, 85433, 34716, 193

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

Bench: 1214575
2024-06-08 23:34:03 +02:00
Tomasz Sobczyk f55239b2f3 NumaPolicy fixes and robustness improvements
1. Fix GetProcessGroupAffinity still not getting properly aligned memory
   sometimes.
2. Fix a very theoretically possible heap corruption if
   GetActiveProcessorGroupCount changes between calls.
3. Fully determine affinity on Windows 11 and Windows Server 2022. It
   should only ever be indeterminate in case of an error.
4. Separate isDeterminate for old and new API, as they are &'d together
   we still can end up with a subset of processors even if one API is
   indeterminate.
5. likely_used_old_api() that is based on actual affinity that's been
   detected
6. IMPORTANT: Gather affinities at startup, so that we only later use
   the affinites set at startup. Not only does this prevent us from our
   own calls interfering with detection but it also means subsequent
   setoption NumaPolicy calls should behave as expected.
7. Fix ERROR_INSUFFICIENT_BUFFER from GetThreadSelectedCpuSetMasks being
   treated like an error.

Should resolve
https://github.com/vondele/Stockfish/commit/02ff76630b358e5f958793cc93df0009d2da65a5#commitcomment-142790025

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

Bench: 1231853
2024-06-08 23:32:27 +02:00
FauziAkram e2be0aaf67 Tweak pruning formula
Tweak pruning formula, including a constant. I started from an old
yellow patch, if I'm not mistaken by Viz (Unfortunately I lost the link)
where he tried something similar.
I worked on it, trying different variations, until I came up with a good
configuration to pass.

Passed STC:
LLR: 2.93 (-2.94,2.94) <0.00,2.00>
Total: 213120 W: 55351 L: 54778 D: 102991
Ptnml(0-2): 572, 25209, 54437, 25758, 584
https://tests.stockfishchess.org/tests/view/6660c9a7c340c8eed7758195

Passed LTC:
LLR: 2.94 (-2.94,2.94) <0.50,2.50>
Total: 315324 W: 80176 L: 79284 D: 155864
Ptnml(0-2): 155, 34711, 87030, 35619, 147
https://tests.stockfishchess.org/tests/view/6660d7bb6489614cdad13d66

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

Bench: 1231853
2024-06-08 23:28:07 +02:00
rn5f107s2 5dda4037c7 Simplify razor changes
Remove razoring changes from
https://github.com/official-stockfish/Stockfish/pull/5360

The mentioned patch introduced the usage of futility_margin into
razoring alongside a tune to futility_margin. It seems the elo gained in
this patch comes from the tune of futility_margin and not the
introduction of futility_margin to razoring, so simplify it away here.

Passed Non-regression STC:
https://tests.stockfishchess.org/tests/view/66606581c340c8eed7757bc8
LLR: 2.93 (-2.94,2.94) <-1.75,0.25>
Total: 169056 W: 43922 L: 43848 D: 81286
Ptnml(0-2): 438, 20288, 43034, 20298, 470

Passed Non-regression LTC:
https://tests.stockfishchess.org/tests/view/66607764c340c8eed7757c58
LLR: 2.94 (-2.94,2.94) <-1.75,0.25>
Total: 157134 W: 39805 L: 39723 D: 77606
Ptnml(0-2): 74, 17444, 43461, 17502, 86

Passed rebased Non-regression LTC:
https://tests.stockfishchess.org/tests/view/6660c696c340c8eed77580c0
LLR: 2.94 (-2.94,2.94) <-1.75,0.25>
Total: 135984 W: 34427 L: 34324 D: 67233
Ptnml(0-2): 67, 15063, 37615, 15194, 53

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

Bench: 1150518
2024-06-08 23:10:59 +02:00
Disservin 66ed4312f2 Workaround the clang-format inconsistencies
closes https://github.com/official-stockfish/Stockfish/pull/5378

No functional change
2024-06-08 23:09:02 +02:00
R-Goc e6c83beed1 Change PGO type for clang
Change type of PGO in clang to IR which is recommended by LLVM/clang and
could result in a speedup.
https://github.com/llvm/llvm-project/issues/45668

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

No functional change
2024-06-08 23:05:56 +02:00
cj5716 5688b188cc Simplify evaluation constants
Passed STC (<0, 2> by accident):
LLR: 2.95 (-2.94,2.94) <0.00,2.00>
Total: 346016 W: 89529 L: 88756 D: 167731
Ptnml(0-2): 1012, 41074, 88027, 41919, 976
https://tests.stockfishchess.org/tests/view/6659d6ecf426908fcc6b6929

Passed LTC:
LLR: 2.96 (-2.94,2.94) <-1.75,0.25>
Total: 89862 W: 22887 L: 22734 D: 44241
Ptnml(0-2): 45, 9999, 24694, 10144, 49
https://tests.stockfishchess.org/tests/view/665a6ebb062b2c3cf814fde8

Passed LTC (Rebased):
LLR: 2.94 (-2.94,2.94) <-1.75,0.25>
Total: 325500 W: 82734 L: 82826 D: 159940
Ptnml(0-2): 193, 36409, 89665, 36263, 220
https://tests.stockfishchess.org/tests/view/665bd39f44e8416a9cdc1909

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

Bench 961982
2024-06-05 21:49:29 +02:00
Disservin fb18caae7a Update clang-format to version 18
clang-format-18 is available in ubuntu noble(24.04), if you are on
a version lower than that you can use the update script from llvm.
https://apt.llvm.org/

Windows users should be able to download and use clang-format from
their release builds https://github.com/llvm/llvm-project/releases
or get the latest from msys2
https://packages.msys2.org/package/mingw-w64-x86_64-clang.

macOS users can resort to "brew install clang-format".

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

No functional change
2024-06-05 21:41:43 +02:00
Viren6 36eb9bc783 Use futility margin in razoring margin
Uses futilityMargin * depth to set the razoring margin. This retains the
quadratic depth scaling to preserve mate finding capabilities. This patch is
nice because it increases the elo sensitivity of the futility margin
heuristics.

Passed STC:
https://tests.stockfishchess.org/tests/view/665f9892fd11ae7170b4849c
LLR: 2.93 (-2.94,2.94) <0.00,2.00>
Total: 39392 W: 10348 L: 10030 D: 19014
Ptnml(0-2): 99, 4585, 10009, 4905, 98

Passed LTC:
https://tests.stockfishchess.org/tests/view/665f9d2dfd11ae7170b484a8
LLR: 2.95 (-2.94,2.94) <0.50,2.50>
Total: 107910 W: 27521 L: 27053 D: 53336
Ptnml(0-2): 73, 11835, 29670, 12305, 72

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

bench 1277173
2024-06-05 21:33:46 +02:00
Muzhen Gaming a08fcacb28 VVLTC search tune
Parameters were tuned with 199k games of VVLTC: https://tests.stockfishchess.org/tests/view/665c67e73542f91ad1c54fe2

Passed VVLTC 1st sprt: https://tests.stockfishchess.org/tests/view/665e9c83fd45fb0f907c837c
LLR: 2.95 (-2.94,2.94) <0.00,2.00>
Total: 83494 W: 21546 L: 21219 D: 40729
Ptnml(0-2): 6, 7707, 25993, 8036, 5

Passed VVLTC 2nd sprt: https://tests.stockfishchess.org/tests/view/665f650bfd45fb0f907cb360
LLR: 2.94 (-2.94,2.94) <0.50,2.50>
Total: 151056 W: 38796 L: 38295 D: 73965
Ptnml(0-2): 5, 13742, 47536, 14237, 8

https://github.com/official-stockfish/Stockfish/pull/5359

Bench: 1154524
2024-06-05 21:10:55 +02:00
mstembera 21ba32af6d Remove m512_hadd128x16_interleave()
This functionality is no longer used anywhere.

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

No functional change
2024-06-05 21:07:07 +02:00
Tomasz Sobczyk 02ff76630b Add NumaPolicy "hardware" option that bypasses current processor affinity.
Can be used in case a GUI (e.g. ChessBase 17 see #5307) sets affinity to a
single processor group, but the user would like to use the full capabilities of
the hardware.  Improves affinity handling on Windows in case of multiple
available APIs and existing affinities.

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

No functional change
2024-06-05 21:01:45 +02:00
Gahtan Nahdi daaccd9fc9 Simplify smallnet threshold
remove pawncount

Passed STC non-reg:
https://tests.stockfishchess.org/tests/view/665e4548fd45fb0f907c80d5
LLR: 2.94 (-2.94,2.94) <-1.75,0.25>
Total: 60896 W: 15710 L: 15518 D: 29668
Ptnml(0-2): 149, 7145, 15660, 7353, 141

Passed LTC non-reg:
https://tests.stockfishchess.org/tests/view/665e4c52fd45fb0f907c815f
LLR: 2.94 (-2.94,2.94) <-1.75,0.25>
Total: 58068 W: 14773 L: 14590 D: 28705
Ptnml(0-2): 16, 6368, 16090, 6537, 23

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

Bench: 1343156
2024-06-05 20:59:56 +02:00
Disservin 4f53560d24 Accumulate nodes over all bench positions not just the last
closes https://github.com/official-stockfish/Stockfish/pull/5352

No functional change
2024-06-04 08:26:35 +02:00
Disservin 7f09d06b83 Properly initialize the TT in a multithreaded way again 2024-06-04 07:53:25 +02:00
Disservin ba06671aa9 Normalize some variable names and reuse existing logic
closes https://github.com/official-stockfish/Stockfish/pull/5346

No functional change
2024-06-03 23:28:23 +02:00
Dubslow 86b564055d Remove delta, adjusted, complexity from nnue code
...rather they're the consumer's concern whether to tweak the result or not.

Passed STC:
https://tests.stockfishchess.org/tests/view/665cea9ffd45fb0f907c53bd
LLR: 2.93 (-2.94,2.94) <-1.75,0.25>
Total: 69696 W: 18101 L: 17918 D: 33677
Ptnml(0-2): 195, 8171, 17929, 8362, 191

Passed LTC:
https://tests.stockfishchess.org/tests/view/665cf761fd45fb0f907c5406
LLR: 2.96 (-2.94,2.94) <-1.75,0.25>
Total: 63720 W: 16344 L: 16165 D: 31211
Ptnml(0-2): 32, 6990, 17625, 7193, 20

Non functional except for rounding issues of OutputScale changing bench.

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

Bench: 1378596
2024-06-03 23:27:58 +02:00
Dubslow 397f47a7a1 Adjust lowest depth constants to the natural place
Passed STC:
https://tests.stockfishchess.org/tests/view/665ce3f8fd45fb0f907c537f
LLR: 2.93 (-2.94,2.94) <-1.75,0.25>
Total: 282784 W: 73032 L: 73082 D: 136670
Ptnml(0-2): 680, 31845, 76364, 31851, 652

Recently when I overhauled these comments, Disservin asked why these
were so much lower: they're a relic from when we had a third QS stage at
-5. Now we don't, so fix these to the obvious place.

I was fairly sure it was nonfunctional but ran the nonreg to be double
sure.

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

Bench: 1057383
2024-06-03 23:20:02 +02:00
Gahtan Nahdi fe298953f8 Simplify smallnet threshold
Turns the quadratic threshold to a linear one

STC non-reg:
https://tests.stockfishchess.org/tests/view/665ba0b744e8416a9cdc188d
LLR: 2.95 (-2.94,2.94) <-1.75,0.25>
Total: 330432 W: 85351 L: 85454 D: 159627
Ptnml(0-2): 888, 39643, 84283, 39488, 914

LTC non-reg:
https://tests.stockfishchess.org/tests/view/665cd60ffd45fb0f907c4306
LLR: 2.95 (-2.94,2.94) <-1.75,0.25>
Total: 139146 W: 35194 L: 35093 D: 68859
Ptnml(0-2): 58, 15523, 38313, 15618, 61

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

Bench: 1057383
2024-06-03 23:18:36 +02:00
FauziAkram 924a843594 Simplify recapture extension
Simplifying the extension formula by removing the move == ttMove
condition.

Passed STC:
LLR: 2.93 (-2.94,2.94) <-1.75,0.25>
Total: 47328 W: 12324 L: 12117 D: 22887
Ptnml(0-2): 134, 5532, 12097, 5795, 106
https://tests.stockfishchess.org/tests/view/665ca5e6fd45fb0f907c41be

Passed LTC:
LLR: 2.95 (-2.94,2.94) <-1.75,0.25>
Total: 72126 W: 18378 L: 18209 D: 35539
Ptnml(0-2): 36, 7841, 20130, 8030, 26
https://tests.stockfishchess.org/tests/view/665cb276fd45fb0f907c41f9

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

Bench: 1399468
2024-06-03 23:17:09 +02:00
FauziAkram 3d6756769c Simplify continuation histories
Functional simplification.

Simplify continuation histories, therefore increasing the effect of
stats updates and movepicker bonuses for continuation history 3 plies
deep.

Passed STC:
LLR: 2.93 (-2.94,2.94) <-1.75,0.25>
Total: 229184 W: 59087 L: 59080 D: 111017
Ptnml(0-2): 554, 27248, 59002, 27213, 575
https://tests.stockfishchess.org/tests/view/665c7a09fd45fb0f907c223b

Passed LTC:
LLR: 2.95 (-2.94,2.94) <-1.75,0.25>
Total: 44532 W: 11419 L: 11223 D: 21890
Ptnml(0-2): 18, 4787, 12457, 4989, 15
https://tests.stockfishchess.org/tests/view/665c8842fd45fb0f907c23ec

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

Bench: 1326444
2024-06-03 23:12:13 +02:00
Disservin 00a28ae325 Add helpers for managing aligned memory
Previously, we had two type aliases, LargePagePtr and AlignedPtr, which
required manually initializing the aligned memory for the pointer.

The new helpers:

- make_unique_aligned
- make_unique_large_page

are now available for allocating aligned memory (with large pages). They
behave similarly to std::make_unique, ensuring objects allocated with
these functions follow RAII.

The old approach had issues with initializing non-trivial types or
arrays of objects. The evaluation function of the network is now a
unique pointer to an array instead of an array of unique pointers.

Memory related functions have been moved into memory.h

Passed High Hash Pressure Test Non-Regression STC:
https://tests.stockfishchess.org/tests/view/665b2b36586058766677cfd2
LLR: 2.93 (-2.94,2.94) <-1.75,0.25>
Total: 476992 W: 122426 L: 122677 D: 231889
Ptnml(0-2): 1145, 51027, 134419, 50744, 1161

Failed Normal Non-Regression STC:
https://tests.stockfishchess.org/tests/view/665b2997586058766677cfc8
LLR: -2.94 (-2.94,2.94) <-1.75,0.25>
Total: 877312 W: 225233 L: 226395 D: 425684
Ptnml(0-2): 2110, 94642, 246239, 93630, 2035

Probably a fluke since there shouldn't be a real slowndown and it has also
passed the high hash pressure test.

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

No functional change
2024-06-03 23:11:59 +02:00
Tomasz Sobczyk a2a7edf4c8 Fix GetProcessGroupAffinity call
`GetProcessGroupAffinity` appears to require 4 byte alignment for `GroupArray` memory.

See https://stackoverflow.com/q/78567676 for further information

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

No functional change
2024-06-03 08:54:24 +02:00
Joost VandeVondele 8aaae0367c Revert "Adjust return bonus from tt cutoffs at fail highs"
This reverts commit 783dfc2eb2.

could lead to a division by zero for:

ttValue = (ttValue * tte->depth() + beta) / (tte->depth() + 1)

as other threads can overwrite the tte with a QS depth of -1.

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

Bench: 1280020
2024-06-02 09:23:28 +02:00
Linmiao Xu c17d73c554 Simplify statScore divisor into a constant
Passed non-regression STC:
https://tests.stockfishchess.org/tests/view/665b392ff4a1fd0c208ea864
LLR: 2.93 (-2.94,2.94) <-1.75,0.25>
Total: 114752 W: 29628 L: 29495 D: 55629
Ptnml(0-2): 293, 13694, 29269, 13827, 293

Passed non-regression LTC:
https://tests.stockfishchess.org/tests/view/665b588c11645bd3d3fac467
LLR: 2.95 (-2.94,2.94) <-1.75,0.25>
Total: 65322 W: 16549 L: 16373 D: 32400
Ptnml(0-2): 30, 7146, 18133, 7322, 30

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

bench 1241443
2024-06-01 20:17:38 +02:00
xoto10 b009c43254 Simplify tm, removing faster 1st move and 1.13 extraTime.
Passed STC 10+0.1 :
LLR: 2.93 (-2.94,2.94) <-1.75,0.25>
Total: 349760 W: 90112 L: 90231 D: 169417
Ptnml(0-2): 784, 37970, 97496, 37841, 789
https://tests.stockfishchess.org/tests/view/665aeee00223e235f05b7d21

Passed LTC 60+0.6 :
LLR: 2.95 (-2.94,2.94) <-1.75,0.25>
Total: 140082 W: 35463 L: 35370 D: 69249
Ptnml(0-2): 59, 13492, 42851, 13575, 64
https://tests.stockfishchess.org/tests/view/665b15e78da109e362924e5a

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

No functional change
2024-06-01 20:12:36 +02:00
MinetaS 180cab4438 Simplify 50 move rule dampening
Refactor the logic of 50 move rule dampening by removing a constant.

Passed non-regression STC:
LLR: 2.93 (-2.94,2.94) <-1.75,0.25>
Total: 35232 W: 9214 L: 8992 D: 17026
Ptnml(0-2): 114, 4081, 8999, 4313, 109
https://tests.stockfishchess.org/tests/view/665a329013d08af3c1725610

Passed non-regression LTC:
LLR: 2.94 (-2.94,2.94) <-1.75,0.25>
Total: 38406 W: 9732 L: 9530 D: 19144
Ptnml(0-2): 14, 4132, 10708, 4336, 13
https://tests.stockfishchess.org/tests/view/665a370913d08af3c1725651

https://github.com/official-stockfish/Stockfish/pull/5327

Bench: 1059739
2024-06-01 20:09:47 +02:00
FauziAkram ec1cda1d81 Simplify histories movepick formula
Passed STC:
LLR: 2.93 (-2.94,2.94) <-1.75,0.25>
Total: 81440 W: 21100 L: 20929 D: 39411
Ptnml(0-2): 248, 9659, 20718, 9864, 231
https://tests.stockfishchess.org/tests/view/6659a8b7ea624d64ea5f3208

Passed LTC:
LLR: 2.94 (-2.94,2.94) <-1.75,0.25>
Total: 85758 W: 21763 L: 21607 D: 42388
Ptnml(0-2): 34, 9606, 23463, 9722, 54
https://tests.stockfishchess.org/tests/view/6659d7bff426908fcc6b692c

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

bench: 1280472
2024-06-01 20:08:08 +02:00
Joost VandeVondele b0870cf528 Avoid changing bestvalue
in the case the ttValue contains mate scores, do not return them as bestValue, since they are not proven.

passed STC
https://tests.stockfishchess.org/tests/view/665b1ea5586058766677cfa3
LLR: 2.93 (-2.94,2.94) <-1.75,0.25>
Total: 58912 W: 15319 L: 15130 D: 28463
Ptnml(0-2): 141, 6562, 15854, 6765, 134

passed LTC:
https://tests.stockfishchess.org/tests/view/665b2712586058766677cfc4
LLR: 2.94 (-2.94,2.94) <-1.75,0.25>
Total: 141666 W: 35976 L: 35879 D: 69811
Ptnml(0-2): 61, 15513, 39584, 15618, 57

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

Bench: 1336115
2024-06-01 20:04:30 +02:00
Michael Chaly 783dfc2eb2 Adjust return bonus from tt cutoffs at fail highs
This is reintroduction of the recently simplified logic - if positive tt cutoff
occurs return not a tt value but smth between it and beta.  Difference is that
instead of static linear combination there we use basically the same formula as
we do in the main search - with the only difference being using tt depth
instead of depth, which makes a lot of sense.

Passed STC:
https://tests.stockfishchess.org/tests/view/665b3a34f4a1fd0c208ea870
LLR: 2.95 (-2.94,2.94) <0.00,2.00>
Total: 54944 W: 14239 L: 13896 D: 26809
Ptnml(0-2): 151, 6407, 14008, 6760, 146

Passed LTC:
https://tests.stockfishchess.org/tests/view/665b520011645bd3d3fac341
LLR: 2.94 (-2.94,2.94) <0.50,2.50>
Total: 90540 W: 23070 L: 22640 D: 44830
Ptnml(0-2): 39, 9903, 24965, 10315, 48

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

bench 1381237
2024-06-01 20:02:09 +02:00
Linmiao Xu cb4a623119 Update default smallnet to nn-37f18f62d772.nnue
Created by training L1-128 from scratch with:
- skipping based on simple eval in the trainer, for compatibility with
  regular binpacks without requiring pre-filtering all binpacks
- minimum simple eval of 950, lower than 1000 previously
- usage of some hse-v1 binpacks with minimum simple eval 1000
- addition of hse-v6 binpacks with minimum simple eval 500
- permuting the FT with 10k positions from fishpack32.binpack
- torch.compile to speed up smallnet training

Training is significantly slower when using non-pre-filtered binpacks due to
the increased skipping required.

This net was reached at epoch 339.

```
experiment-name: 128--S1-hse-1k-T80-v6-unfilt-less-sf--se-gt950-no-wld-skip

training-dataset:
  /data/:
    - dfrc99-16tb7p.v2.min.binpack

  /data/hse-v1/:
    - leela96-filt-v2.min.high-simple-eval-1k.min-v2.binpack

    - test60-novdec2021-12tb7p-filter-v6-dd.min-mar2023.unmin.high-simple-eval-1k.min-v2.binpack

    - test77-nov2021-2tb7p.no-db.min.high-simple-eval-1k.min-v2.binpack
    - test77-dec2021-16tb7p.no-db.min.high-simple-eval-1k.min-v2.binpack
    - test77-jan2022-2tb7p.high-simple-eval-1k.min-v2.binpack

    - test78-jantomay2022-16tb7p-filter-v6-dd.min-mar2023.unmin.high-simple-eval-1k.min-v2.binpack
    - test78-juntosep2022-16tb7p-filter-v6-dd.min-mar2023.unmin.high-simple-eval-1k.min-v2.binpack

    - test79-apr2022-16tb7p.min.high-simple-eval-1k.min-v2.binpack
    - test79-may2022-16tb7p-filter-v6-dd.min-mar2023.unmin.high-simple-eval-1k.min-v2.binpack

    - test80-apr2022-16tb7p.min.high-simple-eval-1k.min-v2.binpack
    - test80-may2022-16tb7p.high-simple-eval-1k.min-v2.binpack
    - test80-jun2022-16tb7p-filter-v6-dd.min-mar2023.unmin.high-simple-eval-1k.min-v2.binpack
    - test80-jul2022-16tb7p.v6-dd.min.high-simple-eval-1k.min-v2.binpack
    - test80-sep2022-16tb7p-filter-v6-dd.min-mar2023.unmin.high-simple-eval-1k.min-v2.binpack
    - test80-nov2022-16tb7p-v6-dd.min.high-simple-eval-1k.min-v2.binpack

  /data/S11-mar2024/:
    - test80-2022-08-aug-16tb7p.v6-dd.min.binpack
    - test80-2022-10-oct-16tb7p.v6-dd.binpack
    - test80-2022-12-dec-16tb7p.min.binpack

    - test80-2023-01-jan-16tb7p.v6-sk20.min.binpack
    - test80-2023-02-feb-16tb7p.v6-sk20.min.binpack
    - test80-2023-03-mar-2tb7p.v6-sk16.min.binpack
    - test80-2023-04-apr-2tb7p.v6-sk16.min.binpack
    - test80-2023-05-may-2tb7p.v6.min.binpack
    - test80-2023-06-jun-2tb7p.binpack.min-v2.binpack
    - test80-2023-07-jul-2tb7p.binpack.min-v2.binpack
    - test80-2023-08-aug-2tb7p.v6.min.binpack
    - test80-2023-09-sep-2tb7p.binpack.hse-v6.binpack
    - test80-2023-10-oct-2tb7p.binpack.hse-v6.binpack
    - test80-2023-11-nov-2tb7p.binpack.hse-v6.binpack
    - test80-2023-12-dec-2tb7p.binpack.hse-v6.binpack

    - test80-2024-01-jan-2tb7p.binpack.hse-v6.binpack
    - test80-2024-02-feb-2tb7p.binpack.hse-v6.binpack
    - test80-2024-03-mar-2tb7p.binpack

wld-fen-skipping: False

nnue-pytorch-branch: linrock/nnue-pytorch/128-skipSimpleEval-lt950-torch-compile
engine-test-branch: linrock/Stockfish/L1-128-nolazy
engine-base-branch: linrock/Stockfish/L1-128
start-from-engine-test-net: False

num-epochs: 500
start-lambda: 1.0
end-lambda: 1.0
```

Training data can be found at:
https://robotmoon.com/nnue-training-data/

Passed STC:
https://tests.stockfishchess.org/tests/view/66549c16a86388d5e27daff5
LLR: 2.93 (-2.94,2.94) <0.00,2.00>
Total: 196608 W: 51254 L: 50697 D: 94657
Ptnml(0-2): 722, 23244, 49796, 23839, 703

Passed LTC:
https://tests.stockfishchess.org/tests/view/6658d1aa6b0e318cefa90122
LLR: 2.96 (-2.94,2.94) <0.50,2.50>
Total: 122538 W: 31332 L: 30835 D: 60371
Ptnml(0-2): 69, 13407, 33811, 13922, 60

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

bench
2024-06-01 19:59:07 +02:00
rn5f107s2 b34a690cd4 MCP more after a bad singular search
The idea is, that if we have the information that the singular search failed low and therefore produced an upperbound score, we can use the score from singularsearch as approximate upperbound as to what bestValue our non ttMoves will produce. If this value is well below alpha, we assume that all non-ttMoves will score below alpha and therfore can skip more moves.
This patch also sets up variables for future patches wanting to use teh singular search result outside of singular extensions, in singularBound and singularValue, meaning further patches using this search result to affect various pruning techniques can be tried.

Passed STC:
https://tests.stockfishchess.org/tests/view/6658d13e6b0e318cefa90120
LLR: 2.94 (-2.94,2.94) <0.00,2.00>
Total: 85632 W: 22112 L: 21725 D: 41795
Ptnml(0-2): 243, 10010, 21947, 10349, 267

Passed LTC:
https://tests.stockfishchess.org/tests/view/6658dd356b0e318cefa9016a
LLR: 2.94 (-2.94,2.94) <0.50,2.50>
Total: 243978 W: 62014 L: 61272 D: 120692
Ptnml(0-2): 128, 26598, 67791, 27348, 124

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

bench 1397172
2024-06-01 19:58:20 +02:00
Linmiao Xu 0ef809ac71 Quadratic smallnet threshold with re-evaluation
The threshold now decreases more quickly as pawn count decreases,
using the smallnet more compared to before.

Combo of two eval patches:
https://tests.stockfishchess.org/tests/view/66576c5f6b0e318cefa8d26e
https://tests.stockfishchess.org/tests/view/664ced40830eb9f886616a77

Passed STC:
https://tests.stockfishchess.org/tests/view/66588c136b0e318cefa8ff21
LLR: 2.94 (-2.94,2.94) <0.00,2.00>
Total: 112608 W: 29336 L: 28908 D: 54364
Ptnml(0-2): 344, 13223, 28718, 13699, 320

Passed LTC:
https://tests.stockfishchess.org/tests/view/6658c8786b0e318cefa900f5
LLR: 2.96 (-2.94,2.94) <0.50,2.50>
Total: 108288 W: 27493 L: 27026 D: 53769
Ptnml(0-2): 54, 11821, 29930, 12282, 57

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

bench 1728074
2024-06-01 19:56:05 +02:00
FauziAkram de1ae4949d Tweak first picked move (ttMove) reduction rule
Tweak first picked move (ttMove) reduction rule:

Instead of always resetting the reduction to 0, we now only do so if the current reduction is less than 2.
If the current reduction is 2 or more, we decrease it by 2 instead.

Passed STC:
LLR: 2.93 (-2.94,2.94) <0.00,2.00>
Total: 109504 W: 28340 L: 27919 D: 53245
Ptnml(0-2): 305, 12848, 28028, 13263, 308
https://tests.stockfishchess.org/tests/view/6658c2fa6b0e318cefa900c2

Passed LTC:
LLR: 2.96 (-2.94,2.94) <0.50,2.50>
Total: 130410 W: 33248 L: 32738 D: 64424
Ptnml(0-2): 53, 14139, 36328, 14615, 70
https://tests.stockfishchess.org/tests/view/6658dd8a6b0e318cefa90173

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

bench: 1224588
2024-06-01 19:53:13 +02:00
Joost VandeVondele 54e74919d4 Fix cross from Linux to Windows
specifies Windows 7 required

https://learn.microsoft.com/en-us/cpp/porting/modifying-winver-and-win32-winnt?view=msvc-170

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

No functional change
2024-05-30 23:07:25 +02:00
Tomasz Sobczyk c8375c2fbd On linux use sysfs instead of lscpu
Use sysfs (https://www.kernel.org/doc/Documentation/ABI/stable/sysfs-devices-node)
to determine processor to NUMA node mapping.

Avoids problems on some machines with high core count where lscpu was showing high cpu utilization.

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

No functional change
2024-05-30 23:05:25 +02:00
Tomasz Sobczyk 86694b5914 Replace std::from_chars with std::stoull
the former was not widely supported, requiring newer compiler versions.

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

No functional change
2024-05-30 23:05:21 +02:00
Tomasz Sobczyk f1bb4164bf Fix process' processor affinity determination on Windows.
Specialize and privatize NumaConfig::get_process_affinity.
Only enable NUMA capability for 64-bit Windows.

Following #5307 and some more testing it was determined that the way affinity
was being determined on Windows was incorrect, based on incorrect assumptions
about GetNumaProcessorNodeEx.

This patch fixes the issue by attempting to retrieve the actual process'
processor affinity using Windows API. However one issue persists that is not
addressable due to limitations of Windows, and will have to be considered a
limitation. If affinities were set using SetThreadAffinityMask instead of
SetThreadSelectedCpuSetMasks and GetProcessGroupAffinity returns more than 1
group it is NOT POSSIBLE to determine the affinity programmatically on Windows.
In such case the implementation assumes no affinites are set and will consider
all processors available for execution.

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

No functional change
2024-05-30 23:05:16 +02:00
Disservin 596fb4842b NUMA: Fix concurrency counting for windows systems
If there is more than 1 processor group, std::thread::hardware_concurrency should not be used.

fixes #5307

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

No functional change
2024-05-30 23:05:01 +02:00
FauziAkram 02eae52833 Simplifying the malus for putting piece en prise formula
Simplifying the malus for putting piece en prise
formula by merging the minor pieces and pawns
(removing the pawn exclusion from the formula).

Passed STC:
https://tests.stockfishchess.org/tests/view/66578d9c6b0e318cefa8d441
LLR: 2.99 (-2.94,2.94) <-1.75,0.25>
Total: 314272 W: 80705 L: 80786 D: 152781
Ptnml(0-2): 873, 37577, 80366, 37398, 922

Passed LTC (before rebasing):
https://tests.stockfishchess.org/tests/view/6657b5ee6b0e318cefa8d6ab
LLR: 2.95 (-2.94,2.94) <-1.75,0.25>
Total: 117000 W: 29447 L: 29324 D: 58229
Ptnml(0-2): 47, 12877, 32535, 12988, 53

Passed LTC (also after rebasing):
https://tests.stockfishchess.org/tests/view/6658803d6b0e318cefa8fd99
LLR: 2.96 (-2.94,2.94) <-1.75,0.25>
Total: 244992 W: 61807 L: 61814 D: 121371
Ptnml(0-2): 125, 27420, 67414, 27411, 126

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

Bench: 1484840
2024-05-30 23:00:22 +02:00
Michael Chaly b280d2f065 Allow tt cutoffs for shallower depths in certain conditions
Current master allows tt cutoffs only when depth
from tt is strictly greater than current node
depth. This patch also allows them when it's equal
and if tt value is lower or equal to beta.

Passed STC:
https://tests.stockfishchess.org/tests/view/66578e2e6b0e318cefa8d447
LLR: 2.93 (-2.94,2.94) <0.00,2.00>
Total: 26592 W: 6944 L: 6645 D: 13003
Ptnml(0-2): 67, 3039, 6795, 3318, 77

Passed LTC:
https://tests.stockfishchess.org/tests/view/6657f46b6b0e318cefa8d7e9
LLR: 2.96 (-2.94,2.94) <0.50,2.50>
Total: 142572 W: 36315 L: 35776 D: 70481
Ptnml(0-2): 70, 15666, 39288, 16179, 83

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

Bench: 1368486
2024-05-30 22:54:23 +02:00
FauziAkram d1a71fdaa7 Functional simplification in the transposition table
Passed STC:
LLR: 2.98 (-2.94,2.94) <-1.75,0.25>
Total: 154848 W: 39838 L: 39750 D: 75260
Ptnml(0-2): 404, 16214, 44087, 16328, 391
https://tests.stockfishchess.org/tests/view/664892b088b8c6a2bbe430fc

Passed LTC:
LLR: 2.94 (-2.94,2.94) <-1.75,0.25>
Total: 68172 W: 17296 L: 17137 D: 33739
Ptnml(0-2): 23, 6349, 21185, 6504, 25
https://tests.stockfishchess.org/tests/view/6648aabfa0781149e383e526

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

Bench: 1623228
2024-05-30 22:53:20 +02:00
Viren6 a77a895c3b Add extension condition to cutoffCnt
Decrease cutoffCnt increment by 1 if extension is 2 or greater.

Passed STC:
https://tests.stockfishchess.org/tests/view/66577a696b0e318cefa8d34d
LLR: 2.94 (-2.94,2.94) <0.00,2.00>
Total: 99200 W: 25703 L: 25297 D: 48200
Ptnml(0-2): 253, 11660, 25390, 12022, 275

Passed LTC:
https://tests.stockfishchess.org/tests/view/665787ab6b0e318cefa8d411
LLR: 2.94 (-2.94,2.94) <0.50,2.50>
Total: 124530 W: 31659 L: 31161 D: 61710
Ptnml(0-2): 58, 13578, 34489, 14088, 52

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

bench 1623228
2024-05-30 14:34:24 +02:00
Robert Nurnberg @ elitebook a4ea183e78 Tweak and update the WDL model
This PR updates the internal WDL model, using data from 2.5M games played by SF-dev (3c62ad7).
Note that the normalizing constant has increased from 329 to 368.

Changes to the fitting procedure:

* the value for --materialMin was increased from 10 to 17: including data with less material leads to less accuracy for larger material count values
* the data was filtered to only include single thread LTC games at 60+0.6
* the data was filtered to only include games from master against patches that are (approximatively) within 5 nElo of master

For more information and plots of the model see PR#5309

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

No functional change
2024-05-30 14:29:31 +02:00
Linmiao Xu 35aff79843 Update default main net to nn-ddcfb9224cdb.nnue
Created by further tuning the spsa-tuned main net `nn-c721dfca8cd3.nnue`
with the same methods described in https://github.com/official-stockfish/Stockfish/pull/5254

This net was reached at 61k / 120k spsa games at 70+0.7 th 7:
https://tests.stockfishchess.org/tests/view/665639d0a86388d5e27dd259

Passed STC:
https://tests.stockfishchess.org/tests/view/6657d44e6b0e318cefa8d771
LLR: 2.95 (-2.94,2.94) <0.00,2.00>
Total: 114688 W: 29775 L: 29344 D: 55569
Ptnml(0-2): 274, 13633, 29149, 13964, 324

Passed LTC:
https://tests.stockfishchess.org/tests/view/6657e1e46b0e318cefa8d7a6
LLR: 2.94 (-2.94,2.94) <0.50,2.50>
Total: 88152 W: 22412 L: 21988 D: 43752
Ptnml(0-2): 56, 9560, 24409, 10006, 45

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

Bench: 1434678
2024-05-30 14:28:07 +02:00
FauziAkram 0ea6337ccf Remove Queen threatenedByMinor
Remove Queen threatenedByMinor from movepick

Passed STC:
LLR: 2.93 (-2.94,2.94) <-1.75,0.25>
Total: 54432 W: 14053 L: 13855 D: 26524
Ptnml(0-2): 124, 6347, 14090, 6517, 138
https://tests.stockfishchess.org/tests/view/66578d036b0e318cefa8d43d

Passed LTC:
LLR: 2.94 (-2.94,2.94) <-1.75,0.25>
Total: 198168 W: 49979 L: 49940 D: 98249
Ptnml(0-2): 84, 21824, 55236, 21849, 91
https://tests.stockfishchess.org/tests/view/66579cf86b0e318cefa8d5b1

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

bench: 1342438
2024-05-30 14:21:28 +02:00
Linmiao Xu 5ab3fe6db8 Simplify blending eval with nnue complexity
Passed non-regression STC:
https://tests.stockfishchess.org/tests/view/66567377a86388d5e27dd89c
LLR: 2.95 (-2.94,2.94) <-1.75,0.25>
Total: 144000 W: 37443 L: 37338 D: 69219
Ptnml(0-2): 587, 17260, 36208, 17351, 594

Passed non-regression LTC:
https://tests.stockfishchess.org/tests/view/66567f29a86388d5e27dd924
LLR: 2.94 (-2.94,2.94) <-1.75,0.25>
Total: 112326 W: 28550 L: 28421 D: 55355
Ptnml(0-2): 66, 12732, 30434, 12869, 62

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

bench 1554486
2024-05-30 14:18:39 +02:00
Shawn Xu 4a2291ed33 Simplify Away Quadruple Extension
Passed non-regression VVLTC:
LLR: 2.95 (-2.94,2.94) <-1.75,0.25>
Total: 90792 W: 23155 L: 23018 D: 44619
Ptnml(0-2): 6, 8406, 28432, 8549, 3
https://tests.stockfishchess.org/tests/view/664ffa4ca86388d5e27d8e7a

Passed non-regression VLTC:
LLR: 2.94 (-2.94,2.94) <-1.75,0.25>
Total: 288136 W: 72608 L: 72659 D: 142869
Ptnml(0-2): 38, 30258, 83525, 30211, 36
https://tests.stockfishchess.org/tests/view/66551609a86388d5e27db9ae

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

bench 1501735
2024-05-30 14:16:17 +02:00
xoto10 3c62ad7e07 Add compensation factor to adjust extra time according to time control
As stockfish nets and search evolve, the existing time control appears
to give too little time at STC, roughly correct at LTC, and too little
at VLTC+.

This change adds an adjustment to the optExtra calculation. This
adjustment is easy to retune and refine, so it should be easier to keep
up-to-date than the more complex calculations used for optConstant and
optScale.

Passed STC 10+0.1:
LLR: 2.93 (-2.94,2.94) <0.00,2.00>
Total: 169568 W: 43803 L: 43295 D: 82470
Ptnml(0-2): 485, 19679, 44055, 19973, 592
https://tests.stockfishchess.org/tests/view/66531865a86388d5e27da9fa

Yellow LTC 60+0.6:
LLR: -2.94 (-2.94,2.94) <0.50,2.50>
Total: 209970 W: 53087 L: 52914 D: 103969
Ptnml(0-2): 91, 19652, 65314, 19849, 79
https://tests.stockfishchess.org/tests/view/6653e38ba86388d5e27daaa0

Passed VLTC 180+1.8 :
LLR: 2.94 (-2.94,2.94) <0.50,2.50>
Total: 85618 W: 21735 L: 21342 D: 42541
Ptnml(0-2): 15, 8267, 25848, 8668, 11
https://tests.stockfishchess.org/tests/view/6655131da86388d5e27db95f

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

Bench: 1212167
2024-05-29 19:04:57 +02:00
Shawn Xu ae7eef51fd Simplify Fail Low Bonus Formula
Tested against PR #5299

Passed Non-regression STC:
LLR: 2.94 (-2.94,2.94) <-1.75,0.25>
Total: 76352 W: 19797 L: 19619 D: 36936
Ptnml(0-2): 236, 9017, 19509, 9161, 253
https://tests.stockfishchess.org/tests/view/66564f60a86388d5e27dd307

Passed Non-regression LTC:
LLR: 2.94 (-2.94,2.94) <-1.75,0.25>
Total: 114624 W: 28946 L: 28821 D: 56857
Ptnml(0-2): 59, 12675, 31714, 12810, 54
https://tests.stockfishchess.org/tests/view/6656543da86388d5e27dd329

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

Bench: 1212167
2024-05-29 19:01:50 +02:00
mstembera a2f4e988aa Fix MSVC NUMA compile issues
closes https://github.com/official-stockfish/Stockfish/pull/5298

No functional change
2024-05-29 19:00:37 +02:00
Shawn Xu c14297a483 Tune Fail Low Bonus
Fractional bonus idea is from @Ergodice on
[discord](https://discord.com/channels/435943710472011776/735707599353151579/1244039134499180614).
Values are tuned for 149k games at LTC.

SPSA tune:
https://tests.stockfishchess.org/tests/view/6652d5d5a86388d5e27da9d6

Failed STC:
LLR: -2.95 (-2.94,2.94) <0.00,2.00>
Total: 67424 W: 17364 L: 17528 D: 32532
Ptnml(0-2): 238, 8043, 17299, 7909, 223
https://tests.stockfishchess.org/tests/view/66551e1ba86388d5e27db9f9

Passed LTC:
LLR: 2.94 (-2.94,2.94) <0.00,2.00>
Total: 146910 W: 37141 L: 36695 D: 73074
Ptnml(0-2): 84, 16201, 40441, 16643, 86
https://tests.stockfishchess.org/tests/view/66559949a86388d5e27dcc5d

Passed VLTC:
LLR: 2.95 (-2.94,2.94) <0.50,2.50>
Total: 27248 W: 6924 L: 6633 D: 13691
Ptnml(0-2): 5, 2744, 7835, 3035, 5
https://tests.stockfishchess.org/tests/view/66563f4da86388d5e27dd27a

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

Bench: 1390709
2024-05-29 18:58:38 +02:00
Stéphane Nicolet c7b80f6c8a Merge pawn count terms using their average
This simplification patch merges the pawn count terms in the eval
formula with the material term, updating the offset constant for
the nnue part of the formula from 34000 to 34300 because the average
pawn count in middlegame positions evaluated during search is around 8.

STC:
LLR: 2.94 (-2.94,2.94) <-1.75,0.25>
Total: 138240 W: 35834 L: 35723 D: 66683
Ptnml(0-2): 527, 16587, 34817, 16626, 563
https://tests.stockfishchess.org/tests/view/6653f474a86388d5e27daaac

LTC:
LLR: 2.94 (-2.94,2.94) <-1.75,0.25>
Total: 454272 W: 114787 L: 115012 D: 224473
Ptnml(0-2): 246, 51168, 124553, 50903, 266
https://tests.stockfishchess.org/tests/view/6654f256a86388d5e27db131

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

Bench: 1279635
2024-05-29 18:57:32 +02:00
FauziAkram 41acbcae1a Simplifying malus for putting piece en prise formula
Patch author: @ehsanrashid

Passed STC:
LLR: 2.93 (-2.94,2.94) <-1.75,0.25>
Total: 116192 W: 30229 L: 30094 D: 55869
Ptnml(0-2): 451, 13880, 29351, 13911, 503
https://tests.stockfishchess.org/tests/view/66510a40a86388d5e27da936

Passed LTC:
LLR: 2.94 (-2.94,2.94) <-1.75,0.25>
Total: 441312 W: 111009 L: 111220 D: 219083
Ptnml(0-2): 217, 49390, 121659, 49167, 223
https://tests.stockfishchess.org/tests/view/66530696a86388d5e27da9e3

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

Bench: 1987574
2024-05-29 18:55:30 +02:00
Tomasz Sobczyk a169c78b6d Improve performance on NUMA systems
Allow for NUMA memory replication for NNUE weights.  Bind threads to ensure execution on a specific NUMA node.

This patch introduces NUMA memory replication, currently only utilized for the NNUE weights. Along with it comes all machinery required to identify NUMA nodes and bind threads to specific processors/nodes. It also comes with small changes to Thread and ThreadPool to allow easier execution of custom functions on the designated thread. Old thread binding (WinProcGroup) machinery is removed because it's incompatible with this patch. Small changes to unrelated parts of the code were made to ensure correctness, like some classes being made unmovable, raw pointers replaced with unique_ptr. etc.

Windows 7 and Windows 10 is partially supported. Windows 11 is fully supported. Linux is fully supported, with explicit exclusion of Android. No additional dependencies.

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

A new UCI option `NumaPolicy` is introduced. It can take the following values:
```
system - gathers NUMA node information from the system (lscpu or windows api), for each threads binds it to a single NUMA node
none - assumes there is 1 NUMA node, never binds threads
auto - this is the default value, depends on the number of set threads and NUMA nodes, will only enable binding on multinode systems and when the number of threads reaches a threshold (dependent on node size and count)
[[custom]] -
  // ':'-separated numa nodes
  // ','-separated cpu indices
  // supports "first-last" range syntax for cpu indices,
  for example '0-15,32-47:16-31,48-63'
```

Setting `NumaPolicy` forces recreation of the threads in the ThreadPool, which in turn forces the recreation of the TT.

The threads are distributed among NUMA nodes in a round-robin fashion based on fill percentage (i.e. it will strive to fill all NUMA nodes evenly). Threads are bound to NUMA nodes, not specific processors, because that's our only requirement and the OS can schedule them better.

Special care is made that maximum memory usage on systems that do not require memory replication stays as previously, that is, unnecessary copies are avoided.

On linux the process' processor affinity is respected. This means that if you for example use taskset to restrict Stockfish to a single NUMA node then the `system` and `auto` settings will only see a single NUMA node (more precisely, the processors included in the current affinity mask) and act accordingly.

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

We can't ensure that a memory allocation takes place on a given NUMA node without using libnuma on linux, or using appropriate custom allocators on windows (https://learn.microsoft.com/en-us/windows/win32/memory/allocating-memory-from-a-numa-node), so to avoid complications the current implementation relies on first-touch policy. Due to this we also rely on the memory allocator to give us a new chunk of untouched memory from the system. This appears to work reliably on linux, but results may vary.

MacOS is not supported, because AFAIK it's not affected, and implementation would be problematic anyway.

Windows is supported since Windows 7 (https://learn.microsoft.com/en-us/windows/win32/api/processtopologyapi/nf-processtopologyapi-setthreadgroupaffinity). Until Windows 11/Server 2022 NUMA nodes are split such that they cannot span processor groups. This is because before Windows 11/Server 2022 it's not possible to set thread affinity spanning processor groups. The splitting is done manually in some cases (required after Windows 10 Build 20348). Since Windows 11/Server 2022 we can set affinites spanning processor group so this splitting is not done, so the behaviour is pretty much like on linux.

Linux is supported, **without** libnuma requirement. `lscpu` is expected.

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

Passed 60+1 @ 256t 16000MB hash: https://tests.stockfishchess.org/tests/view/6654e443a86388d5e27db0d8
```
LLR: 2.95 (-2.94,2.94) <0.00,10.00>
Total: 278 W: 110 L: 29 D: 139
Ptnml(0-2): 0, 1, 56, 82, 0
```

Passed SMP STC: https://tests.stockfishchess.org/tests/view/6654fc74a86388d5e27db1cd
```
LLR: 2.95 (-2.94,2.94) <-1.75,0.25>
Total: 67152 W: 17354 L: 17177 D: 32621
Ptnml(0-2): 64, 7428, 18408, 7619, 57
```

Passed STC: https://tests.stockfishchess.org/tests/view/6654fb27a86388d5e27db15c
```
LLR: 2.94 (-2.94,2.94) <-1.75,0.25>
Total: 131648 W: 34155 L: 34045 D: 63448
Ptnml(0-2): 426, 13878, 37096, 14008, 416
```

fixes #5253
closes https://github.com/official-stockfish/Stockfish/pull/5285

No functional change
2024-05-28 18:34:15 +02:00
Disservin b0287dcb1c apply const to prefetch parameter
closes https://github.com/official-stockfish/Stockfish/pull/5296

No functional change
2024-05-28 18:31:06 +02:00
FauziAkram d0b9411b82 Tweak return value in futility pruning
Tweak the return value formula in futility pruning.

Passed STC:
LLR: 2.93 (-2.94,2.94) <0.00,2.00>
Total: 60544 W: 15791 L: 15440 D: 29313
Ptnml(0-2): 193, 7024, 15520, 7309, 226
https://tests.stockfishchess.org/tests/view/6654ef22a86388d5e27db122

Passed LTC:
LLR: 2.96 (-2.94,2.94) <0.50,2.50>
Total: 126426 W: 32317 L: 31812 D: 62297
Ptnml(0-2): 55, 13871, 34869, 14350, 68
https://tests.stockfishchess.org/tests/view/66550644a86388d5e27db649

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

bench: 1856147
2024-05-28 18:30:24 +02:00
Shawn Xu 5e98a4e43d Simplify Away TT Cutoff Return Value Adjustments
Passed Non-regression STC:
LLR: 2.93 (-2.94,2.94) <-1.75,0.25>
Total: 198432 W: 51161 L: 51119 D: 96152
Ptnml(0-2): 772, 23670, 50273, 23746, 755
https://tests.stockfishchess.org/tests/view/66517b9ea86388d5e27da966

Passed Non-regression LTC:
LLR: 2.95 (-2.94,2.94) <-1.75,0.25>
Total: 234150 W: 59200 L: 59197 D: 115753
Ptnml(0-2): 126, 26200, 64404, 26235, 110
https://tests.stockfishchess.org/tests/view/6653a84da86388d5e27daa63

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

bench 1555200
2024-05-28 18:26:42 +02:00
Shahin M. Shahin 8e1f273c7d Remove rootDelta branch
This makes rootDelta logic easier to understand, recalculating the value
where it belongs so removes an unnecessary branch.

Passed non-regression STC:
https://tests.stockfishchess.org/tests/view/664fc147a86388d5e27d8d8e
LLR: 2.94 (-2.94,2.94) <-1.75,0.25>
Total: 206016 W: 53120 L: 53089 D: 99807
Ptnml(0-2): 591, 20928, 59888, 21061, 540

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

No functional change
2024-05-26 20:32:41 +02:00
Linmiao Xu 8bc3fd3871 Lower smallnet threshold with tuned eval params
The smallnet threshold is now below the training data range
of the current smallnet (simple eval diff > 1k, nn-baff1edelf90.nnue)
when no pawns are on the board.

Params found with spsa at 93k / 120k games at 60+06:
https://tests.stockfishchess.org/tests/view/664fa166a86388d5e27d7d6b

Tuned on top of: https://github.com/official-stockfish/Stockfish/pull/5287

Passed STC:
https://tests.stockfishchess.org/tests/view/664fc8b7a86388d5e27d8dac
LLR: 2.96 (-2.94,2.94) <0.00,2.00>
Total: 64672 W: 16731 L: 16371 D: 31570
Ptnml(0-2): 239, 7463, 16517, 7933, 184

Passed LTC:
https://tests.stockfishchess.org/tests/view/664fd5f9a86388d5e27d8dfe
LLR: 2.94 (-2.94,2.94) <0.50,2.50>
Total: 210648 W: 53489 L: 52813 D: 104346
Ptnml(0-2): 102, 23129, 58164, 23849, 80

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

Bench: 1717838
2024-05-26 20:32:30 +02:00
Stéphane Nicolet 4d876275cf Simplify material weights in evaluation
This patch uses the same material weights for the nnue
amplification term and the optimism term in evaluate().

STC:
LLR: 2.99 (-2.94,2.94) <-1.75,0.25>
Total: 83360 W: 21489 L: 21313 D: 40558
Ptnml(0-2): 303, 9934, 21056, 10058, 329
https://tests.stockfishchess.org/tests/view/664eee69928b1fb18de500d9

LTC:
LLR: 2.94 (-2.94,2.94) <-1.75,0.25>
Total: 192648 W: 48675 L: 48630 D: 95343
Ptnml(0-2): 82, 21484, 53161, 21501, 96
https://tests.stockfishchess.org/tests/view/664fa17aa86388d5e27d7d6e

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

Bench: 1495602
2024-05-26 20:24:05 +02:00
Muzhen Gaming 61acbfc7d3 VVLTC search tune
Parameters were tuned in 2 stages:
1. 127k games at VVLTC:
   https://tests.stockfishchess.org/tests/view/6649f8dfb8fa20e74c39f52a.
2. 106k games at VVLTC:
   https://tests.stockfishchess.org/tests/view/664bfb77830eb9f886615a9d.

Passed VVLTC 1st sprt:
https://tests.stockfishchess.org/tests/view/664e8dd9928b1fb18de4e410
LLR: 2.94 (-2.94,2.94) <0.00,2.00>
Total: 20466 W: 5340 L: 5093 D: 10033
Ptnml(0-2): 0, 1796, 6397, 2037, 3

Passed VVLTC 2nd sprt:
https://tests.stockfishchess.org/tests/view/664eb4aa928b1fb18de4e47d
LLR: 2.95 (-2.94,2.94) <0.50,2.50>
Total: 15854 W: 4186 L: 3934 D: 7734
Ptnml(0-2): 1, 1367, 4938, 1621, 0

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

Bench: 1558110
2024-05-23 21:37:46 +02:00
Linmiao Xu 365aa85dce Remove material imbalance param when adjusting optimism
Passed non-regression STC:
https://tests.stockfishchess.org/tests/view/664d033d830eb9f886616aff
LLR: 2.93 (-2.94,2.94) <-1.75,0.25>
Total: 102144 W: 26283 L: 26135 D: 49726
Ptnml(0-2): 292, 12201, 25991, 12243, 345

Passed non-regression LTC:
https://tests.stockfishchess.org/tests/view/664d5c00830eb9f886616cb3
LLR: 2.94 (-2.94,2.94) <-1.75,0.25>
Total: 250032 W: 63022 L: 63036 D: 123974
Ptnml(0-2): 103, 27941, 68970, 27871, 131

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

Bench: 1330940
2024-05-23 21:37:46 +02:00
Muzhen Gaming 72a345873d Revert "Reduce When TTValue is Above Alpha"
The patch regressed significantly at longer time controls. In
particular, the `depth--` behavior was predicted to scale badly based on
data from other variations of the patch.

Passed VVLTC 1st sprt:
https://tests.stockfishchess.org/tests/view/664d45cf830eb9f886616c7d
LLR: 2.95 (-2.94,2.94) <0.00,2.00>
Total: 51292 W: 13242 L: 12954 D: 25096
Ptnml(0-2): 5, 4724, 15896, 5020, 1

Passed VVLTC 2nd sprt:
https://tests.stockfishchess.org/tests/view/664e641a928b1fb18de4e385
LLR: 2.94 (-2.94,2.94) <0.50,2.50>
Total: 41884 W: 10933 L: 10634 D: 20317
Ptnml(0-2): 1, 3759, 13125, 4054, 3

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

Bench: 1503815
2024-05-23 21:37:46 +02:00
cj5716 c6a1e7fd42 Optimise pairwise multiplication
This speedup was first inspired by a comment by @AndyGrant on my recent
PR "If mullo_epi16 would preserve the signedness, then this could be
used to remove 50% of the max operations during the halfkp-pairwise
mat-mul relu deal."

That got me thinking, because although mullo_epi16 did not preserve the
signedness, mulhi_epi16 did, and so we could shift left and then use
mulhi_epi16, instead of shifting right after the mullo.

However, due to some issues with shifting into the sign bit, the FT
weights and biases had to be multiplied by 2 for the optimisation to
work.

Speedup on "Arch=x86-64-bmi2 COMP=clang", courtesy of @Torom
Result of 50 runs
base (...es/stockfish) =     962946  +/- 1202
test (...ise-max-less) =     979696  +/- 1084
diff                   =     +16750  +/- 1794

speedup        = +0.0174
P(speedup > 0) =  1.0000

CPU: 4 x Intel(R) Core(TM) i7-6700K CPU @ 4.00GHz
Hyperthreading: on

Also a speedup on "COMP=gcc", courtesy of Torom once again
Result of 50 runs
base (...tockfish_gcc) =     966033  +/- 1574
test (...max-less_gcc) =     983319  +/- 1513
diff                   =     +17286  +/- 2515

speedup        = +0.0179
P(speedup > 0) =  1.0000

CPU: 4 x Intel(R) Core(TM) i7-6700K CPU @ 4.00GHz
Hyperthreading: on

Passed STC:
LLR: 2.96 (-2.94,2.94) <0.00,2.00>
Total: 67712 W: 17715 L: 17358 D: 32639
Ptnml(0-2): 225, 7472, 18140, 7759, 260
https://tests.stockfishchess.org/tests/view/664c1d75830eb9f886616906

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

No functional change
2024-05-23 21:37:46 +02:00
Shawn Xu c39b98b9e3 Simplify Away History Updates in Multicut
Passed Non-regression STC:
LLR: 2.93 (-2.94,2.94) <-1.75,0.25>
Total: 44896 W: 11600 L: 11388 D: 21908
Ptnml(0-2): 140, 5230, 11532, 5370, 176
https://tests.stockfishchess.org/tests/view/664cee31830eb9f886616a80

Passed Non-regression LTC:
LLR: 2.96 (-2.94,2.94) <-1.75,0.25>
Total: 56832 W: 14421 L: 14234 D: 28177
Ptnml(0-2): 37, 6251, 15643, 6458, 27
https://tests.stockfishchess.org/tests/view/664cfd4e830eb9f886616aa6

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

Bench: 1119412
2024-05-23 21:30:33 +02:00
Linmiao Xu 1dcffa6210 Comment about re-evaluating positions
While the smallNet bool is no longer used as of now,
setting it to false upon re-evaluation represents the
correct eval state.

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

No functional change
2024-05-23 21:30:24 +02:00
Viren6 6db47ed71a Addition of new scaling comments
This patch is intended to prevent patches like 9b90cd8 and the
subsequent reversion e3c9ed7 from happening again. Scaling behaviour of
the reduction adjustments in the non-linear scaling
section have been proven to >8 sigma:

STC: https://tests.stockfishchess.org/tests/view/6647b19f6dcff0d1d6b05d52
Elo: 4.28 ± 0.8 (95%) LOS: 100.0%
Total: 200000 W: 52555 L: 50094 D: 97351
Ptnml(0-2): 573, 22628, 51248, 24867, 684
nElo: 8.35 ± 1.5 (95%) PairsRatio: 1.10

VLTC: https://tests.stockfishchess.org/tests/view/6647b1b06dcff0d1d6b05d54
Elo: -1.48 ± 1.0 (95%) LOS: 0.2%
Total: 100000 W: 25009 L: 25436 D: 49555
Ptnml(0-2): 11, 10716, 28971, 10293, 9
nElo: -3.23 ± 2.2 (95%) PairsRatio: 0.96

The else if condition is moved to the non scaling section based on:
https://tests.stockfishchess.org/tests/view/664567a193ce6da3e93b3232 (It
has no proven scaling)

General comment improvements and removal of a redundant margin condition
have also been included.

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

No functional change
2024-05-23 21:29:36 +02:00
Dubslow ed79745bb9 Improve comments about DEPTH constants
Also "fix" movepicker to allow depths between CHECKS and NO_CHECKS,
which makes them easier to tweak (not that they get tweaked hardly ever)
(This was more beneficial when there was a third stage to DEPTH_QS, but
it's still an improvement now)

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

No functional change
2024-05-23 21:29:11 +02:00
Linmiao Xu c14b69790a Lower smallnet threshold with updated eval divisors
Params found after 30k spsa games at 60+0.6, with initial
values from 64k spsa games at 45+0.45

First spsa with 64k / 120k games at 45+0.45:
https://tests.stockfishchess.org/tests/view/664a561b5fc7b70b8817c663
https://tests.stockfishchess.org/tests/view/664ae88e830eb9f8866146f9

Second spsa with 30k / 120k games at 60+0.6:
https://tests.stockfishchess.org/tests/view/664be227830eb9f886615a36

Values found at 10k games at 60+0.6 also passed STC and LTC:
https://tests.stockfishchess.org/tests/view/664bf4bd830eb9f886615a72
https://tests.stockfishchess.org/tests/view/664c0905830eb9f886615abf

Passed STC:
https://tests.stockfishchess.org/tests/view/664c139e830eb9f886615af2
LLR: 2.94 (-2.94,2.94) <0.00,2.00>
Total: 69408 W: 18216 L: 17842 D: 33350
Ptnml(0-2): 257, 8275, 17401, 8379, 392

Passed LTC:
https://tests.stockfishchess.org/tests/view/664cdaf7830eb9f886616a24
LLR: 2.94 (-2.94,2.94) <0.50,2.50>
Total: 35466 W: 9075 L: 8758 D: 17633
Ptnml(0-2): 27, 3783, 9794, 4104, 25

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

bench 1301287
2024-05-21 22:06:17 +02:00
MinetaS c86ec8ec29 Remove cutoffCnt margin adjustment in razoring
Passed non-regression STC:
LLR: 2.95 (-2.94,2.94) <-1.75,0.25>
Total: 65344 W: 16767 L: 16578 D: 31999
Ptnml(0-2): 198, 7557, 16987, 7718, 212
https://tests.stockfishchess.org/tests/view/664bd895830eb9f886615a26

Passed non-regression LTC:
LLR: 2.96 (-2.94,2.94) <-1.75,0.25>
Total: 35214 W: 8999 L: 8791 D: 17424
Ptnml(0-2): 16, 3804, 9760, 4010, 17
https://tests.stockfishchess.org/tests/view/664bead5830eb9f886615a52

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

Bench: 1296223
2024-05-21 08:46:12 +02:00
FauziAkram 87bad0c38a Refine Evaluation Scaling with Piece-Specific Weights
Refine Evaluation Scaling with Piece-Specific Weights, instead of the simplified npm method.
I took the initial idea from Viren6 , as he worked on it in September of last year.
I worked on it, and tuned it, and now it passed both tests.

Passed STC:
LLR: 2.94 (-2.94,2.94) <0.00,2.00>
Total: 95712 W: 24731 L: 24325 D: 46656
Ptnml(0-2): 363, 11152, 24357, 11684, 300
https://tests.stockfishchess.org/tests/view/664b5493830eb9f886614af3

Passed LTC:
LLR: 2.94 (-2.94,2.94) <0.50,2.50>
Total: 204480 W: 52167 L: 51501 D: 100812
Ptnml(0-2): 114, 22579, 56166, 23289, 92
https://tests.stockfishchess.org/tests/view/664b75dd830eb9f886614b44

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

Bench: 1384337
2024-05-21 08:44:59 +02:00
Shawn Xu f27a9be29c Reduce When TTValue is Above Alpha
Passed STC:
LLR: 2.95 (-2.94,2.94) <0.00,2.00>
Total: 53376 W: 13818 L: 13476 D: 26082
Ptnml(0-2): 156, 6212, 13626, 6522, 172
https://tests.stockfishchess.org/tests/view/664aa261830eb9f8866145e5

Passed LTC:
LLR: 2.94 (-2.94,2.94) <0.50,2.50>
Total: 393444 W: 100096 L: 99042 D: 194306
Ptnml(0-2): 191, 43516, 108248, 44582, 185
https://tests.stockfishchess.org/tests/view/664ab54f830eb9f88661463c

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

Bench: 1024562
2024-05-21 08:40:37 +02:00
Michael Chaly daf9787de1 Rescale pawn history updates
This patch is somewhat of a continuation of recent pawn history gainers.
It makes pawn history updates after search twice smaller. Since on average they make pawn history more negative offset is changed to lower value to remain average value approximately the same.

https://tests.stockfishchess.org/tests/view/664b3af9830eb9f886614aab
Passed STC:
LLR: 2.93 (-2.94,2.94) <0.00,2.00>
Total: 170464 W: 44239 L: 43724 D: 82501
Ptnml(0-2): 523, 20278, 43128, 20767, 536

Passed LTC against pending PR :
https://tests.stockfishchess.org/tests/view/664b8c58830eb9f886614b64
LLR: 2.94 (-2.94,2.94) <0.50,2.50>
Total: 98178 W: 25015 L: 24569 D: 48594
Ptnml(0-2): 48, 10769, 27005, 11223, 44

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

Bench: 1343175
2024-05-21 08:36:32 +02:00
FauziAkram b8ccaf038a Use same shuffling Constant for both nets
Passed STC:
https://tests.stockfishchess.org/tests/view/664a42b15fc7b70b8817aeef
LLR: 2.93 (-2.94,2.94) <-1.75,0.25>
Total: 87840 W: 22759 L: 22594 D: 42487
Ptnml(0-2): 335, 10351, 22324, 10634, 276

Passed LTC:
https://tests.stockfishchess.org/tests/view/664a46995fc7b70b8817af02
LLR: 2.94 (-2.94,2.94) <-1.75,0.25>
Total: 163122 W: 41443 L: 41367 D: 80312
Ptnml(0-2): 105, 18154, 44927, 18310, 65

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

bench: 1190174
2024-05-21 08:27:16 +02:00
Michael Chaly 0c797367a3 Update correction history in case of successful null move pruning
Since null move pruning uses the same position it makes some sense to try to update correction history there in case of fail high.
Update value is 4 times less than normal update.

Passed STC:
https://tests.stockfishchess.org/tests/view/664a011cae57c1758ac5b4dd
LLR: 2.94 (-2.94,2.94) <0.00,2.00>
Total: 419360 W: 108390 L: 107505 D: 203465
Ptnml(0-2): 1416, 49603, 106724, 50554, 1383

Passed LTC:
https://tests.stockfishchess.org/tests/view/664a53d95fc7b70b8817c65b
LLR: 2.94 (-2.94,2.94) <0.50,2.50>
Total: 193518 W: 49076 L: 48434 D: 96008
Ptnml(0-2): 89, 21335, 53263, 21989, 83

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

bench 1301487
2024-05-21 08:17:20 +02:00
Linmiao Xu 4d88a63e60 Re-eval only if smallnet output flips from simple eval
Recent attempts to change the smallnet nnue re-eval
threshold did not show much elo difference:
https://tests.stockfishchess.org/tests/view/664a29bb25a9058c4d21d53c
https://tests.stockfishchess.org/tests/view/664a299925a9058c4d21d53a

Passed non-regression STC:
https://tests.stockfishchess.org/tests/view/664a3ea95fc7b70b8817aee2
LLR: 2.94 (-2.94,2.94) <-1.75,0.25>
Total: 22304 W: 5905 L: 5664 D: 10735
Ptnml(0-2): 67, 2602, 5603, 2783, 97

Passed non-regression LTC:
https://tests.stockfishchess.org/tests/view/664a43d35fc7b70b8817aef4
LLR: 2.96 (-2.94,2.94) <-1.75,0.25>
Total: 37536 W: 9667 L: 9460 D: 18409
Ptnml(0-2): 25, 4090, 10321, 4317, 15

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

bench 1287409
2024-05-21 08:13:25 +02:00
Stefan Geschwentner 81e21a69f0 Simplify the recently introduced ply-based cmh bonus factor.
Replace it with a constant which is an approximation of the limit of the factor.

STC:
LLR: 2.95 (-2.94,2.94) <-1.75,0.25>
Total: 120064 W: 30967 L: 30836 D: 58261
Ptnml(0-2): 421, 14238, 30608, 14319, 446
https://tests.stockfishchess.org/tests/view/6649d146b8fa20e74c39f4ad

LTC:
LLR: 2.95 (-2.94,2.94) <-1.75,0.25>
Total: 53856 W: 13719 L: 13530 D: 26607
Ptnml(0-2): 31, 5879, 14922, 6062, 34
https://tests.stockfishchess.org/tests/view/664a027fae57c1758ac5b4ee

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

Bench: 1355618
2024-05-21 08:11:17 +02:00
Michael Chaly 4a66a7c9ca Do more aggressive pawn history updates
Tweak of recent patch that made pawn history to update for move that caused a fail low - and setting up default value of it to -900.  This patch makes it more aggressive - twice bigger updates and default value -1100.

Passed STC:
https://tests.stockfishchess.org/tests/view/6648c5d4308cceea45533b5d
LLR: 2.94 (-2.94,2.94) <0.00,2.00>
Total: 235200 W: 61090 L: 60476 D: 113634
Ptnml(0-2): 763, 27952, 59651, 28376, 858

Passed LTC:
https://tests.stockfishchess.org/tests/view/664a1008ae57c1758ac5b523
LLR: 2.94 (-2.94,2.94) <0.50,2.50>
Total: 20076 W: 5193 L: 4908 D: 9975
Ptnml(0-2): 7, 2105, 5534, 2380, 12

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

Bench: 1590474
2024-05-21 08:07:22 +02:00
Stefan Geschwentner a3bb7e626d Tweak continuation history bonus dependent on ply.
This patch is based on following tuning https://tests.stockfishchess.org/tests/view/6648b2eb308cceea45533abe by only using the tuned factors for the continuation history.

Passed STC:
LLR: 2.94 (-2.94,2.94) <0.00,2.00>
Total: 99904 W: 25865 L: 25457 D: 48582
Ptnml(0-2): 281, 11705, 25578, 12101, 287
https://tests.stockfishchess.org/tests/view/6648c136308cceea45533af8

Passed LTC:
LLR: 2.96 (-2.94,2.94) <0.50,2.50>
Total: 36402 W: 9362 L: 9039 D: 18001
Ptnml(0-2): 20, 3952, 9951, 4241, 37
https://tests.stockfishchess.org/tests/view/6648ee3cb8fa20e74c39f3fd

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

Bench: 1917762
2024-05-21 08:04:44 +02:00
cj5716 27eb49a221 Simplify ClippedReLU
Removes some max calls

Some speedup stats, courtesy of @AndyGrant (albeit measured in an alternate implementation)
Dev  749240 nps
Base 748495 nps
Gain 0.100%
289936 games

STC:
LLR: 2.94 (-2.94,2.94) <-1.75,0.25>
Total: 203040 W: 52213 L: 52179 D: 98648
Ptnml(0-2): 480, 20722, 59139, 20642, 537
https://tests.stockfishchess.org/tests/view/664805fe6dcff0d1d6b05f2c

closes #5261

No functional change
2024-05-21 07:58:16 +02:00
Viren6 2d32581623 Revert "Simplify Away Quadruple Extensions"
This reverts commit 4edd1a3

The unusual result of (combined) +12.0 +- 3.7 in the 2 VVLTC simplification SPRTs ran was the result of base having only 64MB of hash instead of 512MB (Asymmetric hash).
Vizvezdenec was the one to notice this.

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

bench 1404295

Co-Authored-By: Michael Chaly <26898827+Vizvezdenec@users.noreply.github.com>
2024-05-19 09:37:22 +02:00
Muzhen Gaming 99f1bacfd6 VVLTC search tune
Tuned with 85k games at VVLTC.

VVLTC 1st sprt: https://tests.stockfishchess.org/tests/view/6648b836308cceea45533ad7
LLR: 2.94 (-2.94,2.94) <0.00,2.00>
Total: 14880 W: 3890 L: 3652 D: 7338
Ptnml(0-2): 0, 1255, 4694, 1489, 2

VVLTC 2nd sprt: https://tests.stockfishchess.org/tests/view/6648c34f308cceea45533b4f
LLR: 2.95 (-2.94,2.94) <0.50,2.50>
Total: 24984 W: 6502 L: 6235 D: 12247
Ptnml(0-2): 1, 2178, 7867, 2445, 1

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

Bench: 1198142
2024-05-18 18:09:45 +02:00
Linmiao Xu 2694fce928 Simplify away adjustEval lambda
Now that only the shuffling constant differs between nets,
a lambda for adjusting eval is no longer needed.

Passed non-regression STC:
https://tests.stockfishchess.org/tests/view/664806ca6dcff0d1d6b05f34
LLR: 2.99 (-2.94,2.94) <-1.75,0.25>
Total: 31552 W: 8175 L: 7959 D: 15418
Ptnml(0-2): 76, 3180, 9065, 3362, 93

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

No functional change
2024-05-18 18:08:39 +02:00
Shawn Xu 4edd1a389e Simplify Away Quadruple Extensions
serendipitous gainer

Passed LTC:
LLR: 2.94 (-2.94,2.94) <-1.75,0.25>
Total: 95472 W: 24176 L: 24031 D: 47265
Ptnml(0-2): 52, 10533, 26414, 10692, 45
https://tests.stockfishchess.org/tests/live_elo/6647fa596dcff0d1d6b05efa

Passed VVLTC 70+7 th 7:
LLR: 2.94 (-2.94,2.94) <-1.75,0.25>
Total: 6772 W: 1793 L: 1583 D: 3396
Ptnml(0-2): 0, 502, 2172, 712, 0
https://tests.stockfishchess.org/tests/live_elo/6648277a6dcff0d1d6b05ffb

Passed VVLTC 70+7 th 7 (2x):
https://tests.stockfishchess.org/tests/view/66484c896dcff0d1d6b0619d
LLR: 2.94 (-2.94,2.94) <-1.75,0.25>
Total: 5424 W: 1469 L: 1254 D: 2701
Ptnml(0-2): 0, 394, 1710, 607, 1

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

Bench: 1441794
2024-05-18 09:32:21 +02:00
Linmiao Xu 99dfc63e03 Use one nnue pawn count multiplier
Switch to the value used by the main net.

Passed non-regression STC:
https://tests.stockfishchess.org/tests/view/6647e8096dcff0d1d6b05e96
LLR: 2.93 (-2.94,2.94) <-1.75,0.25>
Total: 51040 W: 13249 L: 13044 D: 24747
Ptnml(0-2): 139, 6029, 13016, 6160, 176

Passed non-regression LTC:
https://tests.stockfishchess.org/tests/view/6647f4a46dcff0d1d6b05eea
LLR: 2.95 (-2.94,2.94) <-1.75,0.25>
Total: 20460 W: 5195 L: 4972 D: 10293
Ptnml(0-2): 8, 2178, 5637, 2397, 10

https://github.com/official-stockfish/Stockfish/pull/5258

bench 1887462
2024-05-18 09:29:26 +02:00
Shawn Xu 285f1d2a66 Tweak NMP Formula
Passed STC:
LLR: 2.99 (-2.94,2.94) <0.00,2.00>
Total: 241728 W: 62440 L: 61811 D: 117477
Ptnml(0-2): 914, 28467, 61458, 29126, 899
https://tests.stockfishchess.org/tests/live_elo/6645992993ce6da3e93b5b99

Passed LTC:
LLR: 2.96 (-2.94,2.94) <0.50,2.50>
Total: 167850 W: 42620 L: 42030 D: 83200
Ptnml(0-2): 82, 18412, 46354, 18988, 89
https://tests.stockfishchess.org/tests/live_elo/6647c5726dcff0d1d6b05dd3

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

Bench: 1636018
2024-05-18 09:26:42 +02:00
FauziAkram f5e15441b8 Early Exit in Bitboards::sliding_attack()
he original code checks for occupancy within the loop condition. By moving this check inside the loop and adding an early exit condition, we can avoid unnecessary iterations if a blocking piece is encountered.

Passed stc:
LLR: 2.95 (-2.94,2.94) <0.00,2.00>
Total: 127200 W: 33129 L: 32700 D: 61371
Ptnml(0-2): 424, 13243, 35826, 13694, 413
https://tests.stockfishchess.org/tests/view/664646006dcff0d1d6b05bca

closes https://github.com/official-stockfish/Stockfish/pull/5256

No functional change
2024-05-18 09:24:23 +02:00
Linmiao Xu d92d1f3180 Move smallnet threshold logic into a function
Now that the smallnet threshold is no longer a constant,
use a function to organize it with other eval code.

Passed non-regression STC:
https://tests.stockfishchess.org/tests/view/66459fa093ce6da3e93b5ba2
LLR: 2.95 (-2.94,2.94) <-1.75,0.25>
Total: 217600 W: 56281 L: 56260 D: 105059
Ptnml(0-2): 756, 23787, 59729, 23736, 792

closes https://github.com/official-stockfish/Stockfish/pull/5255

No functional change
2024-05-18 09:21:00 +02:00
Linmiao Xu 1b7dea3f85 Update default main net to nn-c721dfca8cd3.nnue
Created by first retraining the spsa-tuned main net `nn-ae6a388e4a1a.nnue` with:
- using v6-dd data without bestmove captures removed
- addition of T80 mar2024 data
- increasing loss by 20% when Q is too high
- torch.compile changes for marginal training speed gains

And then SPSA tuning weights of epoch 899 following methods described in:
https://github.com/official-stockfish/Stockfish/pull/5149

This net was reached at 92k out of 120k steps in this 70+0.7 th 7 SPSA tuning run:
https://tests.stockfishchess.org/tests/view/66413b7df9f4e8fc783c9bbb
Thanks to @Viren6 for suggesting usage of:
- c value 4 for the weights
- c value 128 for the biases

Scripts for automating applying fishtest spsa params to exporting tuned .nnue are in:
https://github.com/linrock/nnue-tools/tree/master/spsa

Before spsa tuning, epoch 899 was nn-f85738aefa84.nnue
https://tests.stockfishchess.org/tests/view/663e5c893a2f9702074bc167

After initially training with max-epoch 800, training was resumed with max-epoch 1000.

```
experiment-name: 3072--S11--more-data-v6-dd-t80-mar2024--see-ge0-20p-more-loss-high-q-sk28-l8
nnue-pytorch-branch: linrock/nnue-pytorch/3072-r21-skip-more-wdl-see-ge0-20p-more-loss-high-q-torch-compile-more

start-from-engine-test-net: False
start-from-model: /data/config/apr2024-3072/nn-ae6a388e4a1a.nnue

early-fen-skipping: 28
training-dataset:
  /data/S11-mar2024/:
    - leela96.v2.min.binpack

    - test60-2021-11-12-novdec-12tb7p.v6-dd.min.binpack
    - test78-2022-01-to-05-jantomay-16tb7p.v6-dd.min.binpack

    - test80-2022-06-jun-16tb7p.v6-dd.min.binpack

    - test80-2022-08-aug-16tb7p.v6-dd.min.binpack
    - test80-2022-09-sep-16tb7p.v6-dd.min.binpack

    - test80-2023-01-jan-16tb7p.v6-sk20.min.binpack
    - test80-2023-02-feb-16tb7p.v6-sk20.min.binpack
    - test80-2023-03-mar-2tb7p.v6-sk16.min.binpack
    - test80-2023-04-apr-2tb7p.v6-sk16.min.binpack
    - test80-2023-05-may-2tb7p.v6.min.binpack

    # https://github.com/official-stockfish/Stockfish/pull/4782
    - test80-2023-06-jun-2tb7p.binpack
    - test80-2023-07-jul-2tb7p.binpack

    # https://github.com/official-stockfish/Stockfish/pull/4972
    - test80-2023-08-aug-2tb7p.v6.min.binpack
    - test80-2023-09-sep-2tb7p.binpack
    - test80-2023-10-oct-2tb7p.binpack

    # S9 new data: https://github.com/official-stockfish/Stockfish/pull/5056
    - test80-2023-11-nov-2tb7p.binpack
    - test80-2023-12-dec-2tb7p.binpack

    # S10 new data: https://github.com/official-stockfish/Stockfish/pull/5149
    - test80-2024-01-jan-2tb7p.binpack
    - test80-2024-02-feb-2tb7p.binpack

    # S11 new data
    - test80-2024-03-mar-2tb7p.binpack

  /data/filt-v6-dd/:
    - test77-dec2021-16tb7p-filter-v6-dd.binpack
    - test78-juntosep2022-16tb7p-filter-v6-dd.binpack
    - test79-apr2022-16tb7p-filter-v6-dd.binpack
    - test79-may2022-16tb7p-filter-v6-dd.binpack
    - test80-jul2022-16tb7p-filter-v6-dd.binpack
    - test80-oct2022-16tb7p-filter-v6-dd.binpack
    - test80-nov2022-16tb7p-filter-v6-dd.binpack

num-epochs: 1000

lr: 4.375e-4
gamma: 0.995
start-lambda: 0.8
end-lambda: 0.7
```

Training data can be found at:
https://robotmoon.com/nnue-training-data/

Local elo at 25k nodes per move:
nn-epoch899.nnue : 4.6 +/- 1.4

Passed STC:
https://tests.stockfishchess.org/tests/view/6645454893ce6da3e93b31ae
LLR: 2.95 (-2.94,2.94) <0.00,2.00>
Total: 95232 W: 24598 L: 24194 D: 46440
Ptnml(0-2): 294, 11215, 24180, 11647, 280

Passed LTC:
https://tests.stockfishchess.org/tests/view/6645522d93ce6da3e93b31df
LLR: 2.95 (-2.94,2.94) <0.50,2.50>
Total: 320544 W: 81432 L: 80524 D: 158588
Ptnml(0-2): 164, 35659, 87696, 36611, 142

closes https://github.com/official-stockfish/Stockfish/pull/5254

bench 1995552
2024-05-18 09:19:10 +02:00
Rak Laptudirm e0227a6272 Improve comment
closes https://github.com/official-stockfish/Stockfish/pull/5249

No functional change
2024-05-18 09:18:14 +02:00
Linmiao Xu 47597641dc Lower smallnet threshold linearly as pawn count decreases
Passed STC:
https://tests.stockfishchess.org/tests/view/6644f677324e96f42f89d894
LLR: 2.94 (-2.94,2.94) <0.00,2.00>
Total: 377920 W: 97135 L: 96322 D: 184463
Ptnml(0-2): 1044, 44259, 97588, 44978, 1091

Passed LTC:
https://tests.stockfishchess.org/tests/view/664548af93ce6da3e93b31b3
LLR: 2.94 (-2.94,2.94) <0.50,2.50>
Total: 169056 W: 42901 L: 42312 D: 83843
Ptnml(0-2): 58, 18538, 46753, 19115, 64

closes https://github.com/official-stockfish/Stockfish/pull/5252

Bench: 1991750
2024-05-16 14:19:28 +02:00
Muzhen Gaming e3c9ed77aa Revert "Reduce more when improving and ttvalue is lower than alpha"
The patch regressed significantly at longer time controls.

Passed VLTC:
https://tests.stockfishchess.org/tests/view/6644c7a2bc537f5619453096
LLR: 2.95 (-2.94,2.94) <0.00,2.00>
Total: 43336 W: 11177 L: 10884 D: 21275
Ptnml(0-2): 3, 4432, 12507, 4721, 5

Passed VVLTC:
https://tests.stockfishchess.org/tests/view/66450c974aa4fa9a83b6d0b0
LLR: 2.95 (-2.94,2.94) <0.50,2.50>
Total: 32394 W: 8350 L: 8072 D: 15972
Ptnml(0-2): 2, 2798, 10317, 3080, 0

closes https://github.com/official-stockfish/Stockfish/pull/5251

Bench: 1594188
2024-05-16 14:17:53 +02:00
Linmiao Xu 541406ab91 Use same nnue divisor for both nets
Passed non-regression STC:
https://tests.stockfishchess.org/tests/view/6643ceeabc537f56194506f6
LLR: 2.95 (-2.94,2.94) <-1.75,0.25>
Total: 224800 W: 57910 L: 57896 D: 108994
Ptnml(0-2): 673, 26790, 57519, 26686, 732

Passed non-regression LTC:
https://tests.stockfishchess.org/tests/view/6643ff15bc537f5619451719
LLR: 2.95 (-2.94,2.94) <-1.75,0.25>
Total: 347658 W: 87574 L: 87688 D: 172396
Ptnml(0-2): 207, 39004, 95488, 38956, 174

closes https://github.com/official-stockfish/Stockfish/pull/5250

Bench: 1804704
2024-05-16 14:16:54 +02:00
FauziAkram dcb0233784 Simplifying improving and worsening deduction formulas
Passed STC:
LLR: 2.93 (-2.94,2.94) <-1.75,0.25>
Total: 77696 W: 20052 L: 19878 D: 37766
Ptnml(0-2): 222, 9124, 19994, 9274, 234
https://tests.stockfishchess.org/tests/view/66440032bc537f561945171e

Passed LTC:
LLR: 2.95 (-2.94,2.94) <-1.75,0.25>
Total: 234414 W: 58874 L: 58871 D: 116669
Ptnml(0-2): 96, 26147, 64742, 26102, 120
https://tests.stockfishchess.org/tests/view/6644094cbc537f5619451735

closes https://github.com/official-stockfish/Stockfish/pull/5248

Bench: 1336738
2024-05-15 16:27:03 +02:00
Linmiao Xu 1f3a0fda2e Use same eval divisor for both nets
Passed non-regression STC:
https://tests.stockfishchess.org/tests/view/66428f146577e9d2c8a29cf8
LLR: 2.95 (-2.94,2.94) <-1.75,0.25>
Total: 241024 W: 62173 L: 62177 D: 116674
Ptnml(0-2): 904, 28648, 61407, 28654, 899

Passed non-regression LTC:
https://tests.stockfishchess.org/tests/view/6643ae6f1f32a966da74977b
LLR: 2.95 (-2.94,2.94) <-1.75,0.25>
Total: 193710 W: 48762 L: 48717 D: 96231
Ptnml(0-2): 70, 21599, 53481, 21626, 79

closes https://github.com/official-stockfish/Stockfish/pull/5246

Bench: 1700680
2024-05-15 16:26:00 +02:00
Stefan Geschwentner 9b90cd88f0 Reduce more when improving and ttvalue is lower than alpha
More reduction if position is improving but value from TT doesn't
exceeds alpha but the tt move is excluded.

This idea is based on following LMR condition tuning
https://tests.stockfishchess.org/tests/view/66423a1bf9f4e8fc783cba37
by using only three of the four largest terms P[3], P[18] and P[12].

Passed STC:
LLR: 2.93 (-2.94,2.94) <0.00,2.00>
Total: 27840 W: 7309 L: 7004 D: 13527
Ptnml(0-2): 85, 3219, 7018, 3502, 96
https://tests.stockfishchess.org/tests/view/6643dc1cbc537f56194508ba

Passed LTC:
LLR: 2.95 (-2.94,2.94) <0.50,2.50>
Total: 191280 W: 48656 L: 48020 D: 94604
Ptnml(0-2): 78, 20979, 52903, 21589, 91
https://tests.stockfishchess.org/tests/view/6643e543bc537f5619451683

closes https://github.com/official-stockfish/Stockfish/pull/5245

Bench: 1430835
2024-05-15 16:20:14 +02:00
mstembera 09dba1f080 Call adjustEval with correct parameters after rescore
Set smallNet to false after rescoring so we call adjustEval() w/ correct
parameters.

STC:
https://tests.stockfishchess.org/tests/view/664308687134c82f3f7a4003
LLR: 2.93 (-2.94,2.94) <-1.75,0.25>
Total: 146912 W: 37856 L: 37756 D: 71300
Ptnml(0-2): 566, 17562, 37122, 17618, 588

LTC:
https://tests.stockfishchess.org/tests/view/6643a0821f32a966da7485d6
LLR: 2.94 (-2.94,2.94) <-1.75,0.25>
Total: 390414 W: 98015 L: 98173 D: 194226
Ptnml(0-2): 162, 43555, 107929, 43401, 160

closes https://github.com/official-stockfish/Stockfish/pull/5244

Bench: 1819318
2024-05-15 16:19:04 +02:00
Michael Chaly 9e45644c50 Add extra bonus to pawn history for a move that caused a fail low
Basically the same idea as it is for continuation/main history, but it
has some tweaks.
1) it has * 2 multiplier for bonus instead of full/half bonus - for
   whatever reason this seems to work better;
2) attempts with this type of big bonuses scaled somewhat poorly (or
   were unlucky at longer time controls), but after measuring the fact
   that average value of pawn history in LMR after adding this bonuses
   increased by substantial number (for multiplier 1,5 it increased by
   smth like 400~ from 8192 cap) attempts were made to make default pawn
   history negative to compensate it - and version with multiplier 2 and
   initial fill value -900 passed.

Passed STC:
https://tests.stockfishchess.org/tests/view/66424815f9f4e8fc783cba59
LLR: 2.93 (-2.94,2.94) <0.00,2.00>
Total: 115008 W: 30001 L: 29564 D: 55443
Ptnml(0-2): 432, 13629, 28903, 14150, 390

Passed LTC:
https://tests.stockfishchess.org/tests/view/6642f5437134c82f3f7a3ffa
LLR: 2.94 (-2.94,2.94) <0.50,2.50>
Total: 56448 W: 14432 L: 14067 D: 27949
Ptnml(0-2): 36, 6268, 15254, 6627, 39

Bench: 1857237
2024-05-15 16:15:15 +02:00
FauziAkram fa114266fa Add extra bonus for high-depth condition
Passed STC:
LLR: 2.93 (-2.94,2.94) <0.00,2.00>
Total: 54208 W: 14058 L: 13717 D: 26433
Ptnml(0-2): 166, 6277, 13885, 6602, 174
https://tests.stockfishchess.org/tests/view/664136d8f9f4e8fc783c9b82

Passed LTC:
LLR: 2.96 (-2.94,2.94) <0.50,2.50>
Total: 112548 W: 28492 L: 28018 D: 56038
Ptnml(0-2): 53, 12186, 31318, 12668, 49
https://tests.stockfishchess.org/tests/view/664143fef9f4e8fc783c9bf6

closes https://github.com/official-stockfish/Stockfish/pull/5242

Bench: 1725980
2024-05-15 16:13:43 +02:00
xoto10 2682c2127d Use 5% less time on first move
Stockfish appears to take too much time on the first move of a game and
then not enough on moves 2,3,4... Probably caused by most of the factors
that increase time usually applying on the first move.

Attempts to give more time to the subsequent moves have not worked so
far, but this change to simply reduce first move time by 5% worked.

STC 10+0.1 :
LLR: 2.96 (-2.94,2.94) <0.00,2.00>
Total: 78496 W: 20516 L: 20135 D: 37845
Ptnml(0-2): 340, 8859, 20456, 9266, 327
https://tests.stockfishchess.org/tests/view/663d47bf507ebe1c0e9200ba

LTC 60+0.6 :
LLR: 2.95 (-2.94,2.94) <0.50,2.50>
Total: 94872 W: 24179 L: 23751 D: 46942
Ptnml(0-2): 61, 9743, 27405, 10161, 66
https://tests.stockfishchess.org/tests/view/663e779cbb28828150dd9089

closes https://github.com/official-stockfish/Stockfish/pull/5235

Bench: 1876282
2024-05-15 16:09:30 +02:00
mstembera e608eab8dd Optimize update_accumulator_refresh_cache()
STC https://tests.stockfishchess.org/tests/view/664105df26ac5f9b286d30e6
LLR: 2.94 (-2.94,2.94) <0.00,2.00>
Total: 178528 W: 46235 L: 45750 D: 86543
Ptnml(0-2): 505, 17792, 52142, 18363, 462

Combo of two yellow speedups
https://tests.stockfishchess.org/tests/view/6640abf9d163897c63214f5c
LLR: -2.93 (-2.94,2.94) <0.00,2.00>
Total: 355744 W: 91714 L: 91470 D: 172560
Ptnml(0-2): 913, 36233, 103384, 36381, 961

https://tests.stockfishchess.org/tests/view/6628ce073fe04ce4cefc739c
LLR: -2.93 (-2.94,2.94) <0.00,2.00>
Total: 627040 W: 162001 L: 161339 D: 303700
Ptnml(0-2): 2268, 72379, 163532, 73105, 2236

closes https://github.com/official-stockfish/Stockfish/pull/5239

No functional change
2024-05-13 07:32:32 +02:00
Linmiao Xu 0b08953174 Re-evaluate some small net positions for more accurate evals
Use main net evals when small net evals hint that higher eval
accuracy may be worth the slower eval speeds. With Finny caches,
re-evals with the main net are less expensive than before.

Original idea by mstembera who I've added as co-author to this PR.

Based on reEval tests by mstembera:
https://tests.stockfishchess.org/tests/view/65e69187b6345c1b934866e5
https://tests.stockfishchess.org/tests/view/65e863aa0ec64f0526c3e991

A few variants of this patch also passed LTC:
https://tests.stockfishchess.org/tests/view/663d2108507ebe1c0e91f407
https://tests.stockfishchess.org/tests/view/663e388c3a2f9702074bc152

Passed STC:
https://tests.stockfishchess.org/tests/view/663dadbd1a61d6377f190e2c
LLR: 2.93 (-2.94,2.94) <0.00,2.00>
Total: 92320 W: 23941 L: 23531 D: 44848
Ptnml(0-2): 430, 10993, 22931, 11349, 457

Passed LTC:
https://tests.stockfishchess.org/tests/view/663ef48b2948bf9aa698690c
LLR: 2.94 (-2.94,2.94) <0.50,2.50>
Total: 98934 W: 24907 L: 24457 D: 49570
Ptnml(0-2): 48, 10952, 27027, 11382, 58

closes https://github.com/official-stockfish/Stockfish/pull/5238

bench 1876282

Co-Authored-By: mstembera <5421953+mstembera@users.noreply.github.com>
2024-05-13 07:30:18 +02:00
Linmiao Xu 53f363041c Simplify npm constants when adjusting eval
Passed non-regression STC:
https://tests.stockfishchess.org/tests/view/663d0c4f507ebe1c0e91ec8d
LLR: 2.93 (-2.94,2.94) <-1.75,0.25>
Total: 162784 W: 41987 L: 41906 D: 78891
Ptnml(0-2): 520, 19338, 41591, 19427, 516

Passed non-regression LTC:
https://tests.stockfishchess.org/tests/view/663d20fd507ebe1c0e91f405
LLR: 2.94 (-2.94,2.94) <-1.75,0.25>
Total: 457242 W: 115022 L: 115250 D: 226970
Ptnml(0-2): 271, 51566, 125179, 51330, 275

closes https://github.com/official-stockfish/Stockfish/pull/5237

Bench: 2238216
2024-05-13 07:25:22 +02:00
Michael Chaly d3f081ed8a Adjust standpat return value in qsearch
Instead of returning value itself return value between it and beta for non pv nodes - analogous to what we do after actual search there.

Passed STC:
https://tests.stockfishchess.org/tests/view/663cb1b4c0b75d7f7b98188e
LLR: 2.95 (-2.94,2.94) <0.00,2.00>
Total: 131552 W: 34131 L: 33673 D: 63748
Ptnml(0-2): 420, 15446, 33600, 15876, 434

Passed LTC:
https://tests.stockfishchess.org/tests/view/663cda5dc0b75d7f7b981c6f
LLR: 2.95 (-2.94,2.94) <0.50,2.50>
Total: 282798 W: 71658 L: 70833 D: 140307
Ptnml(0-2): 112, 31187, 77979, 32006, 115

closes https://github.com/official-stockfish/Stockfish/pull/5233

Bench: 1606672
2024-05-13 07:22:11 +02:00
Muzhen Gaming 813c5aa532 VVLTC search tune
Tuned at 111k games of VVLTC.

Passed VVLTC 1st sprt: https://tests.stockfishchess.org/tests/view/664090c6d163897c63214324
LLR: 2.94 (-2.94,2.94) <0.00,2.00>
Total: 83046 W: 21071 L: 20747 D: 41228
Ptnml(0-2): 2, 7574, 26048, 7896, 3

Passed VVLTC 2nd sprt: https://tests.stockfishchess.org/tests/view/6640cb2abaa6260a5688dc17
LLR: 2.95 (-2.94,2.94) <0.50,2.50>
Total: 68630 W: 17620 L: 17270 D: 33740
Ptnml(0-2): 4, 6242, 21471, 6596, 2

closes https://github.com/official-stockfish/Stockfish/pull/5240

Bench: 1752471
2024-05-13 07:20:03 +02:00
Shawn Xu 540545d127 simplify away quietCheckEvasions pruning
simplifies away the pruning of quiet evasion moves in quiescent search.

Passed STC:
LLR: 2.98 (-2.94,2.94) <-1.75,0.25>
Total: 343520 W: 88356 L: 88470 D: 166694
Ptnml(0-2): 1061, 40073, 89706, 39759, 1161
https://tests.stockfishchess.org/tests/view/663c7ddfc0b75d7f7b980f3b

Passed LTC:
LLR: 2.95 (-2.94,2.94) <-1.75,0.25>
Total: 168744 W: 42454 L: 42384 D: 83906
Ptnml(0-2): 75, 18678, 46782, 18776, 61
https://tests.stockfishchess.org/tests/view/663ce34fc0b75d7f7b981ed9

closes https://github.com/official-stockfish/Stockfish/pull/5231

bench 3681552
2024-05-13 07:16:59 +02:00
xu-shawn b8812138e8 Fix usage of abs vs std::abs
closes https://github.com/official-stockfish/Stockfish/pull/5229

no functional change
2024-05-13 07:15:25 +02:00
Shawn Xu c43425b0b1 Simplify Away Negative Extension
This patch simplifies away the negative extension applied when the value returned by the transposition table is assumed to fail low over the value of reduced search.

Passed STC:
LLR: 2.99 (-2.94,2.94) <-1.75,0.25>
Total: 248736 W: 64293 L: 64302 D: 120141
Ptnml(0-2): 925, 29833, 62831, 29884, 895
https://tests.stockfishchess.org/tests/view/663bee3bca93dad645f7f64a

Passed LTC:
LLR: 2.94 (-2.94,2.94) <-1.75,0.25>
Total: 254970 W: 64289 L: 64308 D: 126373
Ptnml(0-2): 110, 28428, 70422, 28421, 104
https://tests.stockfishchess.org/tests/view/663c11f0c0b75d7f7b97d4bb

closes https://github.com/official-stockfish/Stockfish/pull/5226

Bench: 2353057
2024-05-09 09:02:57 +02:00
FauziAkram 574ad14b32 Simplify depth formula based on score improvement
Simplify depth formula based on score improvement.
This idea was first tried by cj5716

Passed STC:
LLR: 2.93 (-2.94,2.94) <-1.75,0.25>
Total: 347104 W: 89683 L: 89804 D: 167617
Ptnml(0-2): 1357, 38824, 93307, 38711, 1353
https://tests.stockfishchess.org/tests/view/66378edf9819650825aa75d0

Passed LTC:
LLR: 2.93 (-2.94,2.94) <-1.75,0.25>
Total: 63000 W: 15851 L: 15694 D: 31455
Ptnml(0-2): 22, 5396, 20499, 5569, 14
https://tests.stockfishchess.org/tests/view/663c04e5c0b75d7f7b97d461

closes https://github.com/official-stockfish/Stockfish/pull/5225

Bench: 2691699

Co-Authored-By: cj5716 <125858804+cj5716@users.noreply.github.com>
2024-05-09 09:00:32 +02:00
Michael Chaly 23439e4096 Remove conthist 3 from moves loop pruning
Followup to previous gainer that made it twice less impactful there - this patch removes it entirely as a simplification.

Passed STC:
https://tests.stockfishchess.org/tests/view/6637aa7e9819650825aa93e0
LLR: 2.93 (-2.94,2.94) <-1.75,0.25>
Total: 26208 W: 6930 L: 6694 D: 12584
Ptnml(0-2): 113, 2997, 6652, 3225, 117

Passed LTC:
https://tests.stockfishchess.org/tests/view/66383cba493aaaf4b7ea90c2
LLR: 2.94 (-2.94,2.94) <-1.75,0.25>
Total: 67866 W: 17294 L: 17118 D: 33454
Ptnml(0-2): 46, 7627, 18415, 7795, 50

closes https://github.com/official-stockfish/Stockfish/pull/5221

Bench: 2691699
2024-05-09 08:56:36 +02:00
Michael Chaly 3b4ddf4ae6 Simplify away conthist 3 from statscore
Following previous elo gainer that gained by making conthist 3 less important in pruning this patch simplifies away this history from calculation of statscore.

Passed STC:
https://tests.stockfishchess.org/tests/view/6637aa7e9819650825aa93e0
LLR: 3.00 (-2.94,2.94) <-1.75,0.25>
Total: 35392 W: 9352 L: 9120 D: 16920
Ptnml(0-2): 141, 4145, 8888, 4385, 137

Passed LTC:
https://tests.stockfishchess.org/tests/view/66383cd8493aaaf4b7ea90c5
LLR: 2.94 (-2.94,2.94) <-1.75,0.25>
Total: 33948 W: 8714 L: 8503 D: 16731
Ptnml(0-2): 39, 3701, 9270, 3938, 26

closes https://github.com/official-stockfish/Stockfish/pull/5220

Bench: 2508571
2024-05-09 08:52:06 +02:00
FauziAkram 9d6dab06a8 simplify moveCountPruning
no (significant) speedup upon renewed testing

Passed stc:
LLR: 2.94 (-2.94,2.94) <-1.75,0.25>
Total: 88992 W: 22779 L: 22633 D: 43580
Ptnml(0-2): 137, 8706, 26681, 8818, 154
https://tests.stockfishchess.org/tests/view/6636c4844b68b70d85800dae

closes https://github.com/official-stockfish/Stockfish/pull/5213

No functional change.
2024-05-09 08:48:29 +02:00
MinetaS 2dbb44e28d Fix nodestime
1. The current time management system utilizes limits.inc and
limits.time, which can represent either milliseconds or node count,
depending on whether the nodestime option is active. There have been
several modifications which brought Elo gain for typical uses (i.e.
real-time matches), however some of these changes overlooked such
distinction. This patch adjusts constants and multiplication/division to
more accurately simulate real TC conditions when nodestime is used.

2. The advance_nodes_time function has a bug that can extend the time
limit when availableNodes reaches exact zero. This patch fixes the bug
by initializing the variable to -1 and make sure it does not go below
zero.

3. elapsed_time function is newly introduced to print PV in the UCI
output based on real time. This makes PV output more consistent with the
behavior of trivial use cases.

closes https://github.com/official-stockfish/Stockfish/pull/5186

No functional changes
2024-05-09 08:42:56 +02:00
rn5f107s2 db147fe258 IIR on cutnodes if there is a ttMove but the ttBound is upper
If there is an upper bound stored in the transposition table, but we still have a ttMove, the upperbound indicates that the last time the ttMove was tried, it failed low. This fail low indicates that the ttMove may not be good, so this patch introduces a depth reduction of one for cutnodes with such ttMoves.

Passed STC:
https://tests.stockfishchess.org/tests/view/663be4d1ca93dad645f7f45f
LLR: 2.93 (-2.94,2.94) <0.00,2.00>
Total: 139424 W: 35900 L: 35433 D: 68091
Ptnml(0-2): 425, 16357, 35743, 16700, 487

Passed LTC:
https://tests.stockfishchess.org/tests/view/663bec95ca93dad645f7f5c8
LLR: 2.94 (-2.94,2.94) <0.50,2.50>
Total: 129690 W: 32902 L: 32390 D: 64398
Ptnml(0-2): 63, 14304, 35610, 14794, 74

closes https://github.com/official-stockfish/Stockfish/pull/5227

bench 2257437
2024-05-09 08:38:04 +02:00
Michael Chaly d1b8d8bab3 Refactor quiet moves pruning in qsearch
Make it formula more in line with what we use in search - current formula is more or less the one we used years ago for search but since then it was remade, this patch remakes qsearch formula to almost exactly the same as we use in search - with sum of conthist 0, 1 and pawn structure history.

Passed STC:
https://tests.stockfishchess.org/tests/view/6639c8421343f0cb16716206
LLR: 2.93 (-2.94,2.94) <0.00,2.00>
Total: 84992 W: 22414 L: 22019 D: 40559
Ptnml(0-2): 358, 9992, 21440, 10309, 397

Passed LTC:
LLR: 2.95 (-2.94,2.94) <0.50,2.50>
Total: 119136 W: 30407 L: 29916 D: 58813
Ptnml(0-2): 46, 13192, 32622, 13641, 67

closes https://github.com/official-stockfish/Stockfish/pull/5224

Bench: 2138659
2024-05-09 08:33:07 +02:00
FauziAkram 3bdfa0fb4a Depth dependent statscore based reductions
Test a modification of Fawzi's PR #5223, against that PR.

parameters locally tuned with nevergrad4sf.

passed STC:
LLR: 2.93 (-2.94,2.94) <0.00,2.00>
Total: 1047424 W: 271478 L: 269649 D: 506297
Ptnml(0-2): 3851, 124543, 265290, 125982, 4046
https://tests.stockfishchess.org/tests/view/663b0889ca93dad645f7c58c

passed LTC:
LLR: 2.96 (-2.94,2.94) <0.50,2.50>
Total: 796236 W: 201712 L: 199825 D: 394699
Ptnml(0-2): 361, 88381, 218778, 90206, 392
https://tests.stockfishchess.org/tests/view/663be6adca93dad645f7f509

https://github.com/official-stockfish/Stockfish/pull/5228

Bench: 3346224
2024-05-09 08:29:33 +02:00
FauziAkram 2d5e248f58 Tweak reduction formula based on depth
The idea came to me by checking for trends from the megafauzi tunes, since the values of the divisor for this specific formula were as follows:
stc: 15990
mtc: 16117
ltc: 14805
vltc: 12719
new vltc passed by Muzhen: 12076

This shows a clear trend related to time control, the higher it is, the lower the optimum value for the divisor seems to be.
So I tried a simple formula, using educated guesses based on some calculations, tests show it works pretty fine, and it can still be further tuned at VLTC in the future to scale even better.

Passed STC:
LLR: 2.94 (-2.94,2.94) <0.00,2.00>
Total: 431360 W: 110791 L: 109898 D: 210671
Ptnml(0-2): 1182, 50846, 110698, 51805, 1149
https://tests.stockfishchess.org/tests/view/663770409819650825aa269f

Passed LTC:
LLR: 2.94 (-2.94,2.94) <0.50,2.50>
Total: 114114 W: 29109 L: 28625 D: 56380
Ptnml(0-2): 105, 12628, 31101, 13124, 99
https://tests.stockfishchess.org/tests/view/66378c099819650825aa73f6

https://github.com/official-stockfish/Stockfish/pull/5223

bench: 2273551
2024-05-09 08:26:35 +02:00
Muzhen Gaming 070e564c38 VVLTC search tune
This patch is the result of two tuning stages:
1. ~32k games at 60+0.6 th8:
   https://tests.stockfishchess.org/tests/view/662d9dea6115ff6764c7f817
2. ~193k games at 80+0.8 th6, based on PR #5211:
   https://tests.stockfishchess.org/tests/view/663587e273559a8aa857ca00.
   Based on extensive VVLTC tuning and testing both before and after
   #5211, it is observed that introduction of new extensions positively
   affected the search tune results.

Passed VVLTC 70+0.7 th7 1st sprt: https://tests.stockfishchess.org/tests/view/6636c6f04b68b70d85801409
LLR: 2.94 (-2.94,2.94) <0.00,2.00>
Total: 18566 W: 4864 L: 4620 D: 9082
Ptnml(0-2): 0, 1608, 5827, 1844, 4

Passed VVLTC 70+0.7 th7 2nd sprt: https://tests.stockfishchess.org/tests/view/6636d4b84b68b70d85802ab7
LLR: 2.94 (-2.94,2.94) <0.50,2.50>
Total: 43142 W: 11141 L: 10838 D: 21163
Ptnml(0-2): 4, 3915, 13427, 4224, 1

Passed VVLTC 70+0.7 3rd sprt: https://tests.stockfishchess.org/tests/view/66376b4f9819650825aa230b
LLR: 2.94 (-2.94,2.94) <0.50,2.50>
Total: 40322 W: 10374 L: 10076 D: 19872
Ptnml(0-2): 1, 3660, 12544, 3952, 4

The first two sprts were run against passed #5211. The third sprt was
run against latest master.

closes https://github.com/official-stockfish/Stockfish/pull/5216

Bench: 2180675
2024-05-05 15:11:53 +02:00
cj5716 61f12a4c38 Simplify accumulator refreshes
Passed Non-Regression STC:
https://tests.stockfishchess.org/tests/view/6631f5d5d01fb9ac9bcdc7d0
LLR: 2.94 (-2.94,2.94) <-1.75,0.25>
Total: 57472 W: 14979 L: 14784 D: 27709
Ptnml(0-2): 185, 6486, 15192, 6695, 178

closes https://github.com/official-stockfish/Stockfish/pull/5207

No functional change
2024-05-05 15:11:37 +02:00
Michael Chaly f161261245 Adjust history usage in moves loop pruning
After experiments with conthist 5 addition failed really bad divions by 2 passed as a gainer.

Passed STC:
https://tests.stockfishchess.org/tests/view/6636d7114b68b70d858035ce
LLR: 2.94 (-2.94,2.94) <0.00,2.00>
Total: 35936 W: 9287 L: 8976 D: 17673
Ptnml(0-2): 81, 4129, 9234, 4446, 78

Passed LTC:
https://tests.stockfishchess.org/tests/view/6636ddb64b68b70d858040a8
LLR: 2.95 (-2.94,2.94) <0.50,2.50>
Total: 82428 W: 21035 L: 20622 D: 40771
Ptnml(0-2): 29, 8985, 22775, 9394, 31

closes https://github.com/official-stockfish/Stockfish/pull/5217

Bench: 2309253
2024-05-05 13:06:22 +02:00
cj5716 6da1590de0 Some history fixes and tidy-up
This adds the functions `update_refutations` and `update_quiet_histories` to better distinguish the two. `update_quiet_stats` now just calls both of these functions.

The functional side of this patch is two-fold:
1. Stop refutations being updated when we carry out multicut
2. Update pawn history every time we update other quiet histories

Yellow STC:
LLR: -2.95 (-2.94,2.94) <0.00,2.00>
Total: 238976 W: 61506 L: 61415 D: 116055
Ptnml(0-2): 846, 28628, 60456, 28705, 853
https://tests.stockfishchess.org/tests/view/66321b5ed01fb9ac9bcdca83

However, it passed in <-1.75, 0.25> bounds:
$ python3 sprt.py --wins 61506 --losses 61415 --draws 116055 --elo0 -1.75 --elo1 0.25
ELO: 0.132 +- 0.998 [-0.865, 1.13]
LLR: 4.15 [-1.75, 0.25] (-2.94, 2.94)
H1 Accepted

Passed LTC:
LLR: 2.94 (-2.94,2.94) <-1.75,0.25>
Total: 399126 W: 100730 L: 100896 D: 197500
Ptnml(0-2): 116, 44328, 110843, 44158, 118
https://tests.stockfishchess.org/tests/view/66357b0473559a8aa857ba6f

closes #5215

Bench 2370967
2024-05-05 13:04:37 +02:00
FauziAkram d712ed38d1 Simplify shuffling and optimism divisors to constants
Shuffling divisor and Optimism divisors passed STC & LTC separately:
shuf STC: https://tests.stockfishchess.org/tests/view/66356316b4e9bdbc7228b995
shuf LTC: https://tests.stockfishchess.org/tests/view/6635815a73559a8aa857c1dc
opt STC: https://tests.stockfishchess.org/tests/view/66356326b4e9bdbc7228b9a0
opt LTC: https://tests.stockfishchess.org/tests/view/663615c673559a8aa8589f8a

And then passed LTC together:
LLR: 2.94 (-2.94,2.94) <-1.75,0.25>
Total: 178278 W: 45039 L: 44979 D: 88260
Ptnml(0-2): 43, 19776, 49460, 19798, 62
https://tests.stockfishchess.org/tests/view/66363f19cdb7cf5da64e22a3

closes https://github.com/official-stockfish/Stockfish/pull/5212

Bench: 2198243
2024-05-05 13:02:42 +02:00
Viren6 741aaf8a38 Introduce Quadruple Extensions
This patch introduces quadruple extensions, with the new condition of not ttPv. It also generalises all margins, so that extensions can still occur if conditions are only partially fulfilled, but with a stricter margin.

Failed STC:
LLR: -2.94 (-2.94,2.94) <0.00,2.00>
Total: 16096 W: 3984 L: 4228 D: 7884
Ptnml(0-2): 72, 2067, 4002, 1847, 60
https://tests.stockfishchess.org/tests/view/66316422d01fb9ac9bcdbdcd

Passed VVLTC 1:
LLR: 2.94 (-2.94,2.94) <0.00,2.00>
Total: 96660 W: 24550 L: 24210 D: 47900
Ptnml(0-2): 5, 8776, 30426, 9120, 3
https://tests.stockfishchess.org/tests/view/66361f2c74fa3f41ef2ee091

Passed VVLTC 2:
LLR: 2.94 (-2.94,2.94) <0.50,2.50>
Total: 80546 W: 20495 L: 20120 D: 39931
Ptnml(0-2): 6, 7477, 24929, 7858, 3
https://tests.stockfishchess.org/tests/view/66350cf739ba8e443112b3fa

closes https://github.com/official-stockfish/Stockfish/pull/5211

bench 2233743
2024-05-05 12:53:58 +02:00
Michael Chaly 351a2e22dd Add extra bonuses to some moves that forced a fail low
The previous patch on this idea was giving bonuses to this moves if best value of search is far below current static evaluation.
This patch does similar thing but adds extra bonus when best value of search is far below static evaluation before previous move.

Passed STC:
https://tests.stockfishchess.org/tests/view/66355fc819566d64b481d6a4
LLR: 2.93 (-2.94,2.94) <0.00,2.00>
Total: 454144 W: 116575 L: 115656 D: 221913
Ptnml(0-2): 1060, 53410, 117215, 54325, 1062

Passed LTC:
https://tests.stockfishchess.org/tests/view/6635c61a73559a8aa858012d
LLR: 2.95 (-2.94,2.94) <0.50,2.50>
Total: 136578 W: 34858 L: 34335 D: 67385

closes https://github.com/official-stockfish/Stockfish/pull/5209

Bench: 1614825
2024-05-05 12:42:30 +02:00
cj5716 8ee9905d8b Remove PSQT-only mode
Passed STC:
LLR: 2.94 (-2.94,2.94) <-1.75,0.25>
Total: 94208 W: 24270 L: 24112 D: 45826
Ptnml(0-2): 286, 11186, 24009, 11330, 293
https://tests.stockfishchess.org/tests/view/6635ddd773559a8aa8582826

Passed LTC:
LLR: 2.95 (-2.94,2.94) <-1.75,0.25>
Total: 114960 W: 29107 L: 28982 D: 56871
Ptnml(0-2): 37, 12683, 31924, 12790, 46
https://tests.stockfishchess.org/tests/view/663604a973559a8aa85881ed

closes #5214

Bench 1653939
2024-05-05 12:36:20 +02:00
Disservin be026bdcb2 Clear Workers after changing the network
ensures internal state (e.g. accumulator cache) is consistent with network

closes https://github.com/official-stockfish/Stockfish/pull/5204

No functional change
2024-05-05 12:30:28 +02:00
mstembera be142337d8 Accumulator cache bugfix and cleanup
STC:
https://tests.stockfishchess.org/tests/view/663068913a05f1bf7a511dc2
LLR: 2.98 (-2.94,2.94) <-1.75,0.25>
Total: 70304 W: 18211 L: 18026 D: 34067
Ptnml(0-2): 232, 7966, 18582, 8129, 243

1) Fixes a bug introduced in
   https://github.com/official-stockfish/Stockfish/pull/5194. Only one
   psqtOnly flag was used for two perspectives which was causing
   wrong entries to be cleared and marked.
2) The finny caches should be cleared like histories and not at the
   start of every search.

closes https://github.com/official-stockfish/Stockfish/pull/5203

No functional change
2024-05-01 14:17:32 +02:00
cj5716 6a9b8a0c7b Optimise NNUE Accumulator updates
Passed STC:
https://tests.stockfishchess.org/tests/view/662e3c6a5e9274400985a741
LLR: 2.94 (-2.94,2.94) <0.00,2.00>
Total: 86176 W: 22284 L: 21905 D: 41987
Ptnml(0-2): 254, 9572, 23051, 9963, 248

closes https://github.com/official-stockfish/Stockfish/pull/5202

No functional change
2024-05-01 14:10:57 +02:00
Ciekce eb20de36c0 Avoid unnecessary creation of accumulator cache
Saves a (currently) 800 KB allocation and deallocation when running
`eval`, not particularly significant and zero impact on play but not
necessary either.

closes https://github.com/official-stockfish/Stockfish/pull/5201

No functional change
2024-05-01 14:10:57 +02:00
Dubslow 5d72032559 Use capture history to better judge which sacrifices to explore
This idea has been bouncing around a while. @Vizvezdenec tried it a
couple years ago in Stockfish without results, but its recent arrival in
Ethereal inspired him and thence me to try it afresh in Stockfish.

(Also factor out the now-common code with futpruning for captures.)

STC:
https://tests.stockfishchess.org/tests/view/662355bc3fe04ce4cefc18ac
LLR: 2.92 (-2.94,2.94) <0.00,2.00>
Total: 45760 W: 11970 L: 11640 D: 22150
Ptnml(0-2): 124, 5371, 11625, 5571, 189

LTC:
https://tests.stockfishchess.org/tests/view/662dda396115ff6764c817c9
LLR: 2.94 (-2.94,2.94) <0.50,2.50>
Total: 243828 W: 62042 L: 61287 D: 120499
Ptnml(0-2): 211, 27202, 66329, 27965, 207

closes https://github.com/official-stockfish/Stockfish/pull/5200

Bench: 1480008
2024-05-01 14:10:50 +02:00
Stefan Geschwentner 0fe6428645 More reduction at cut nodes which are not a former PV node
But the tt move and first killer are excluded.

This idea is based on following LMR condition tuning
https://tests.stockfishchess.org/tests/view/66228bed3fe04ce4cefc0c71 by
using only the two largest terms P[0] and P[1].

Passed STC:
LLR: 2.93 (-2.94,2.94) <0.00,2.00>
Total: 173248 W: 45091 L: 44565 D: 83592
Ptnml(0-2): 693, 20534, 43673, 21002, 722
https://tests.stockfishchess.org/tests/view/6629603b3fe04ce4cefc7d37

Passed LTC:
LLR: 2.94 (-2.94,2.94) <0.50,2.50>
Total: 722394 W: 183231 L: 181487 D: 357676
Ptnml(0-2): 462, 80650, 197252, 82348, 485
https://tests.stockfishchess.org/tests/view/662cbe45d46f72253dcff7bf

closes https://github.com/official-stockfish/Stockfish/pull/5199

Bench: 1619613
2024-04-28 21:46:45 +02:00
Stefan Geschwentner 48a3b7c0ee Simplify non-pawn material divisor to a constant
Passed STC:
https://tests.stockfishchess.org/tests/view/662942603fe04ce4cefc7aba
LLR: 2.93 (-2.94,2.94) <-1.75,0.25>
Total: 272832 W: 70456 L: 70497 D: 131879
Ptnml(0-2): 1020, 32619, 69154, 32628, 995

Passed LTC:
https://tests.stockfishchess.org/tests/view/662dfe3b6115ff6764c829eb
LLR: 2.94 (-2.94,2.94) <-1.75,0.25>
Total: 100254 W: 25446 L: 25303 D: 49505
Ptnml(0-2): 121, 11292, 27166, 11419, 129

closes https://github.com/official-stockfish/Stockfish/pull/5198

Bench: 1544645
2024-04-28 21:43:46 +02:00
cj5716 834e8ff619 Penalise the TT move in multicut
Passed STC:
LLR: 2.99 (-2.94,2.94) <0.00,2.00>
Total: 185504 W: 48079 L: 47533 D: 89892
Ptnml(0-2): 716, 21866, 46988, 22520, 662
https://tests.stockfishchess.org/tests/view/662d9e1d6115ff6764c7f83d

Passed LTC:
LLR: 2.94 (-2.94,2.94) <0.50,2.50>
Total: 75612 W: 19351 L: 18948 D: 37313
Ptnml(0-2): 46, 8363, 20592, 8752, 53
https://tests.stockfishchess.org/tests/view/662dc9dc6115ff6764c80fea

closes https://github.com/official-stockfish/Stockfish/pull/5195

Bench: 1415435
2024-04-28 21:36:34 +02:00
mstembera a129c0695b Combine remove and add in update_accumulator_refresh_cache()
Combine remove and add in update_accumulator_refresh_cache().
Move remove before add to match other parts of the code.

STC:
https://tests.stockfishchess.org/tests/view/662d96dc6115ff6764c7f4ca
LLR: 2.95 (-2.94,2.94) <0.00,2.00>
Total: 364032 W: 94421 L: 93624 D: 175987
Ptnml(0-2): 1261, 41983, 94811, 42620, 1341

closes https://github.com/official-stockfish/Stockfish/pull/5194

Bench: 1836777
2024-04-28 21:35:48 +02:00
mstembera 940a3a7383 Cache small net w/ psqtOnly support
Caching the small net in the same way as the big net allows them to
share the same code path and completely removes
update_accumulator_refresh().

STC:
https://tests.stockfishchess.org/tests/view/662bfb5ed46f72253dcfed85
LLR: 2.94 (-2.94,2.94) <-1.75,0.25>
Total: 151712 W: 39252 L: 39158 D: 73302
Ptnml(0-2): 565, 17474, 39683, 17570, 564

closes https://github.com/official-stockfish/Stockfish/pull/5194

Bench: 1836777
2024-04-28 21:30:19 +02:00
Joost VandeVondele bc45cbc820 Output some basic info about the used networks
Adds size in memory as well as layer sizes as in

info string NNUE evaluation using nn-ae6a388e4a1a.nnue (132MiB, (22528, 3072, 15, 32, 1))
info string NNUE evaluation using nn-baff1ede1f90.nnue (6MiB, (22528, 128, 15, 32, 1))

For example, the size in MiB is useful to keep the fishtest memory sizes up-to-date,
the L1-L3 sizes give a useful hint about the architecture used.

closes https://github.com/official-stockfish/Stockfish/pull/5193

No functional change
2024-04-28 21:27:28 +02:00
Disservin 3502c8ae42 Fix missing initialization of AccumulatorCaches in Eval::trace
Add a constructor to `AccumulatorCaches` instead of just calling
`clear(networks)` to prevent similar issues from appearing in the
future.

fixes https://github.com/official-stockfish/Stockfish/issues/5190

closes https://github.com/official-stockfish/Stockfish/pull/5191

No functional change
2024-04-28 21:26:36 +02:00
xoto10 886ed90ec3 Use less time on recaptures
Credit for the idea goes to peregrine on discord.

Passed STC 10+0.1:
https://tests.stockfishchess.org/tests/view/662652623fe04ce4cefc48cf
LLR: 2.95 (-2.94,2.94) <0.00,2.00>
Total: 75712 W: 19793 L: 19423 D: 36496
Ptnml(0-2): 258, 8487, 20023, 8803, 285

Passed LTC 60+0.6:
https://tests.stockfishchess.org/tests/view/6627495e3fe04ce4cefc59b6
LLR: 2.94 (-2.94,2.94) <0.50,2.50>
Total: 49788 W: 12743 L: 12404 D: 24641
Ptnml(0-2): 29, 5141, 14215, 5480, 29

The code was updated slightly and tested for non-regression against the
original code at STC:

LLR: 2.94 (-2.94,2.94) <-1.75,0.25>
Total: 41952 W: 10912 L: 10698 D: 20342
Ptnml(0-2): 133, 4825, 10835, 5061, 122
https://tests.stockfishchess.org/tests/view/662d84f56115ff6764c7e438

closes https://github.com/official-stockfish/Stockfish/pull/5189

Bench: 1836777
2024-04-28 21:26:25 +02:00
gab8192 49ef4c935a Implement accumulator refresh table
For each thread persist an accumulator cache for the network, where each
cache contains multiple entries for each of the possible king squares.
When the accumulator needs to be refreshed, the cached entry is used to more
efficiently update the accumulator, instead of rebuilding it from scratch.
This idea, was first described by Luecx (author of Koivisto) and
is commonly referred to as "Finny Tables".

When the accumulator needs to be refreshed, instead of filling it with
biases and adding every piece from scratch, we...

1. Take the `AccumulatorRefreshEntry` associated with the new king bucket
2. Calculate the features to activate and deactivate (from differences
   between bitboards in the entry and bitboards of the actual position)
3. Apply the updates on the refresh entry
4. Copy the content of the refresh entry accumulator to the accumulator
   we were refreshing
5. Copy the bitboards from the position to the refresh entry, to match
   the newly updated accumulator

Results at STC:
https://tests.stockfishchess.org/tests/view/662301573fe04ce4cefc1386
(first version)
https://tests.stockfishchess.org/tests/view/6627fa063fe04ce4cefc6560
(final)

Non-Regression between first and final:
https://tests.stockfishchess.org/tests/view/662801e33fe04ce4cefc660a

STC SMP:
https://tests.stockfishchess.org/tests/view/662808133fe04ce4cefc667c

closes https://github.com/official-stockfish/Stockfish/pull/5183

No functional change
2024-04-24 18:38:20 +02:00
FauziAkram fcba524793 Tune Search Parameters
Parameters Tune, adding also another tunable parameter (npmDiv) to be
variable for different nets (bignet, smallnet, psqtOnly smallnet). P.s:
The changed values are only the parameters where there is agreement
among the different time controls, so in other words, the tunings are
telling us that changing these specific values to this specific
direction is good in all time controls, so there shouldn't be a high
risk of regressing at longer time controls.

Passed STC:
LLR: 2.97 (-2.94,2.94) <0.00,2.00>
Total: 39552 W: 10329 L: 9999 D: 19224
Ptnml(0-2): 156, 4592, 9989, 4844, 195
https://tests.stockfishchess.org/tests/view/661be9a0bd68065432a088c0

Passed LTC:
LLR: 2.94 (-2.94,2.94) <0.50,2.50>
Total: 56394 W: 14439 L: 14078 D: 27877
Ptnml(0-2): 30, 6152, 15480, 6497, 38
https://tests.stockfishchess.org/tests/view/661c746296961e72eb565406

closes https://github.com/official-stockfish/Stockfish/pull/5187

Bench: 1836777
2024-04-24 18:24:01 +02:00
Disservin ddd250b9d6 Restore NPS output for Perft
Previously it was possible to also get the node counter after running a bench with perft, i.e.
`./stockfish bench 1 1 5 current perft`, caused by a small regression from the uci refactoring.

```
Nodes searched: 4865609

===========================
Total time (ms) : 18
Nodes searched  : 4865609
Nodes/second    : 270311611
````

closes https://github.com/official-stockfish/Stockfish/pull/5188

No functional change
2024-04-24 18:20:55 +02:00
cj5716 d47aa639bd Tweak TT aging and replacement strategies
We change the definition of "age" from "age of this position" to "age of this TT entry".
In this way, despite being on the same position, when we save into TT, we always prefer the new entry as compared to the old one.

Passed STC:
LLR: 2.94 (-2.94,2.94) <0.00,2.00>
Total: 152256 W: 39597 L: 39110 D: 73549
Ptnml(0-2): 556, 17562, 39398, 18063, 549
https://tests.stockfishchess.org/tests/view/6620faee3fe04ce4cefbf215

Passed LTC:
LLR: 2.95 (-2.94,2.94) <0.50,2.50>
Total: 51564 W: 13242 L: 12895 D: 25427
Ptnml(0-2): 24, 5464, 14463, 5803, 28
https://tests.stockfishchess.org/tests/view/66231ab53fe04ce4cefc153e

closes #5184

Bench 1479416
2024-04-21 14:50:04 +02:00
Disservin 56a9cc512e Move ALSR change to CI Workflow file
It makes more sense to not (potentially) change the developers alsr entropy setting to make the test run through. This should be an active choice even if the test then might fail locally for them.

closes https://github.com/official-stockfish/Stockfish/pull/5182

No functional change
2024-04-21 14:49:11 +02:00
Joost VandeVondele 1a8de45b8c Improve CI
the recent refactoring has shown some limitations of our testing, hence we add a couple of more tests including:
* expected mate score
* expected mated score
* expected in TB win score
* expected in TB loss score
* expected info line output
* expected info line output (wdl)

closes https://github.com/official-stockfish/Stockfish/pull/5181

No functional change
2024-04-21 14:46:01 +02:00
Robert Nurnberg @ elitebook 6fc7da44ad update the WDL model
The patch only changes the displayed cp and wdl values.

closes https://github.com/official-stockfish/Stockfish/pull/5178

No functional change
2024-04-21 14:40:02 +02:00
Gahtan Nahdi d0e72c19fa fix clang compiler warning for avx512 build
Initialize variable in constexpr function to get rid of clang compiler warning for avx512 build.

closes https://github.com/official-stockfish/Stockfish/pull/5176

Non-functional change
2024-04-21 14:38:16 +02:00
Michael Chaly 9021a61807 Trivial cleanup
Make naming and declaration of futilityValue in search consistent between different places.

closes https://github.com/official-stockfish/Stockfish/pull/5165

No functional change.
2024-04-21 14:35:54 +02:00
Disservin d3fc1d835e Refactor elapsed time checks in search
Small improvement of the elapsed time usage in search, makes the code easier to read overall.
Also Search::Worker::iterative_deepening() now only checks the elapsed time once, instead of 3 times in a row.

Non Regression STC:
https://tests.stockfishchess.org/tests/view/6617005d5a4693796d965c3c
LLR: 2.97 (-2.94,2.94) <-1.75,0.25>
Total: 61024 W: 16002 L: 15806 D: 29216
Ptnml(0-2): 243, 6874, 16102, 7030, 263

closes https://github.com/official-stockfish/Stockfish/pull/5163

No functional change
2024-04-21 14:35:01 +02:00
Disservin 432995ad82 Update outdated comments
closes https://github.com/official-stockfish/Stockfish/pull/5158

No functional change
2024-04-21 14:32:26 +02:00
Disservin c55ae376f6 Fix wrong sign for 200 TB score
Fix another case of 9032c6cbe7

*    TB values can have a distance of 0, mainly when we are in a tb position but haven't found mate.
*    Add a missing whitespace to UCIEngine::on_update_no_moves()

Closes https://github.com/official-stockfish/Stockfish/pull/5172

No functional change
2024-04-13 22:05:19 +02:00
Disservin 4912f5b0b5 Remove duplicated Position object in UCIEngine
Also fixes searchmoves.

Drop the need of a Position object in uci.cpp.

A side note, it is still required for the static functions,
but these should be moved to a different namespace/class
later on, since sf kinda relies on them.

closes https://github.com/official-stockfish/Stockfish/pull/5169

No functional change
2024-04-12 19:37:39 +02:00
Shahin M. Shahin 14f6eab07d Fix some more UCI output
further fall-out of the refactoring, fixes:

* the position object in UCI is not never getting updated if position token is used
* duplicate string of " wdl "

See also:

https://discord.com/channels/435943710472011776/1032922913499783169/1228227522945351690
https://discord.com/channels/435943710472011776/813919248455827515/1228288106449338398

closes https://github.com/official-stockfish/Stockfish/pull/5168

No functional change

Co-Authored-By: disservin <45608332+disservin@users.noreply.github.com>
2024-04-12 18:11:54 +02:00
Robert Nurnberg @ elitebook e58b3b4665 Fix wrong mate sign
introduced yesterday by the UCI refactoring 9032c6cbe

fixes #5166
closes https://github.com/official-stockfish/Stockfish/pull/5167

No functional change
2024-04-12 09:30:34 +02:00
FauziAkram 249eec6715 Simplify the depth-dependent part of the best value adjustment formula in main search
Passed STC:
LLR: 2.95 (-2.94,2.94) <-1.75,0.25>
Total: 139648 W: 36171 L: 36061 D: 67416
Ptnml(0-2): 545, 16685, 35282, 16739, 573
https://tests.stockfishchess.org/tests/view/660d953b8ff4a059828d625d

Passed LTC:
LLR: 2.94 (-2.94,2.94) <-1.75,0.25>
Total: 222894 W: 56519 L: 56505 D: 109870
Ptnml(0-2): 112, 25145, 60971, 25055, 164
https://tests.stockfishchess.org/tests/view/660fd4afbfeb43334bf7d558

closes https://github.com/official-stockfish/Stockfish/pull/5164

bench: 1479416
2024-04-11 22:47:40 +02:00
gab8192 d6bdcec52c Remove an useless assignment
The assignment (ss + 1)->excludedMove = Move::none() can be simplified away because when that line is reached, (ss + 1)->excludedMove is always already none. The only moment stack[x]->excludedMove is modified, is during singular search, but it is reset to none right after the singular search is finished.

closes https://github.com/official-stockfish/Stockfish/pull/5153

No functional change
2024-04-11 22:43:00 +02:00
Disservin de2244284b Remove COMPILER from Makefile
The same functionality is available by using COMPCXX and having another variable which does the same is just confusing.
There was only one mention on Stockfish Wiki about this which has been changed to COMPCXX.

closes https://github.com/official-stockfish/Stockfish/pull/5154

No functional change
2024-04-11 22:41:35 +02:00
mstembera 94484db6e8 Avoid permuting inputs during transform()
Avoid permuting inputs during transform() and instead do it once at load time.
Affects AVX2 and newer Intel architectures only.

https://tests.stockfishchess.org/tests/view/661306613eb00c8ccc0033c7
LLR: 2.94 (-2.94,2.94) <0.00,2.00>
Total: 108480 W: 28319 L: 27898 D: 52263
Ptnml(0-2): 436, 12259, 28438, 12662, 445

speedups measured such as e.g.

```
Result of 100 runs
==================
base (./stockfish.master       ) =    1241128  +/- 3757
test (./stockfish.patch        ) =    1247713  +/- 3689
diff                             =      +6585  +/- 2583

speedup        = +0.0053
P(speedup > 0) =  1.0000
```

closes https://github.com/official-stockfish/Stockfish/pull/5160

No functional change
2024-04-11 22:38:38 +02:00
Muzhen Gaming 1adf8e1ae6 VVLTC search tune
Parameters were tuned in 3 stages:

* Using an earlier L1-3072 net, and with triple extension margin manually set to 0: https://tests.stockfishchess.org/tests/view/65ffdf5d0ec64f0526c544f2 (~30k games)
* Continue tuning, but with the previous master net (L1-2560). https://tests.stockfishchess.org/tests/view/660663f00ec64f0526c59c41 (~27k games)
* Starting with the parameters from step 2, use the current L1-3072 net, and allow the triple extension margin to be tuned starting from 0: https://tests.stockfishchess.org/tests/view/660c16b8216a13d9498e7536 (40k games)

Passed VVLTC 1st sprt: https://tests.stockfishchess.org/tests/view/66115eacbfeb43334bf7eddd
LLR: 2.95 (-2.94,2.94) <0.00,2.00>
Total: 27138 W: 7045 L: 6789 D: 13304
Ptnml(0-2): 1, 2421, 8471, 2673, 3

Passed VVLTC 2nd sprt: https://tests.stockfishchess.org/tests/view/661483623eb00c8ccc0049c1
LLR: 2.94 (-2.94,2.94) <0.50,2.50>
Total: 26242 W: 6807 L: 6535 D: 12900
Ptnml(0-2): 0, 2353, 8143, 2625, 0

STC Elo estimate: https://tests.stockfishchess.org/tests/view/66175ca55a4693796d96608c
Elo: -10.53 ± 2.4 (95%) LOS: 0.0%
Total: 21584 W: 5294 L: 5948 D: 10342
Ptnml(0-2): 102, 2937, 5363, 2293, 97
nElo: -19.99 ± 4.7 (95%) PairsRatio: 0.79

closes https://github.com/official-stockfish/Stockfish/pull/5162

Bench: 1381387
2024-04-11 22:23:52 +02:00
Disservin 9032c6cbe7 Transform search output to engine callbacks
Part 2 of the Split UCI into UCIEngine and Engine refactor.
This creates function callbacks for search to use when an update should occur.
The benching in uci.cpp for example does this to extract the total nodes
searched.

No functional change
2024-04-05 21:03:58 +02:00
Disservin 299707d2c2 Split UCI into UCIEngine and Engine
This is another refactor which aims to decouple uci from stockfish. A new engine
class manages all engine related logic and uci is a "small" wrapper around it.

In the future we should also try to remove the need for the Position object in
the uci and replace the options with an actual options struct instead of using a
map. Also convert the std::string's in the Info structs a string_view.

closes #5147

No functional change
2024-04-04 00:15:17 +02:00
Viren6 0716b845fd Update NNUE architecture to SFNNv9 and net nn-ae6a388e4a1a.nnue
Part 1: PyTorch Training, linrock

Trained with a 10-stage sequence from scratch, starting in May 2023:
https://github.com/linrock/nnue-tools/blob/master/exp-sequences/3072-10stage-SFNNv9.yml

While the training methods were similar to the L1-2560 training sequence,
the last two stages introduced min-v2 binpacks,
where bestmove capture and in-check position scores were not zeroed during minimization,
for compatibility with skipping SEE >= 0 positions and future research.

Training data can be found at:
https://robotmoon.com/nnue-training-data

This net was tested at epoch 679 of the 10th training stage:
https://tests.stockfishchess.org/tests/view/65f32e460ec64f0526c48dbc

Part 2: SPSA Training, Viren6

The net was then SPSA tuned.
This consisted of the output weights (32 * 8) and biases (8)
as well as the L3 biases (32 * 8) and L2 biases (16 * 8), totalling 648 params in total.

The SPSA tune can be found here:
https://tests.stockfishchess.org/tests/view/65fc33ba0ec64f0526c512e3

With the help of Disservin , the initial weights were extracted with:
https://github.com/Viren6/Stockfish/tree/new228

The net was saved with the tuned weights using:
https://github.com/Viren6/Stockfish/tree/new241

Earlier nets of the SPSA failed STC compared to the base 3072 net of part 1:
https://tests.stockfishchess.org/tests/view/65ff356e0ec64f0526c53c98
Therefore it is suspected that the SPSA at VVLTC has
added extra scaling on top of the scaling of increasing the L1 size.

Passed VVLTC 1:
https://tests.stockfishchess.org/tests/view/6604a9020ec64f0526c583da
LLR: 2.94 (-2.94,2.94) <0.00,2.00>
Total: 53042 W: 13554 L: 13256 D: 26232
Ptnml(0-2): 12, 5147, 15903, 5449, 10

Passed VVLTC 2:
https://tests.stockfishchess.org/tests/view/660ad1b60ec64f0526c5dd23
LLR: 2.94 (-2.94,2.94) <0.50,2.50>
Total: 17506 W: 4574 L: 4315 D: 8617
Ptnml(0-2): 1, 1567, 5362, 1818, 5

STC Elo estimate:
https://tests.stockfishchess.org/tests/view/660b834d01aaec5069f87cb0
Elo: -7.66 ± 3.8 (95%) LOS: 0.0%
Total: 9618 W: 2440 L: 2652 D: 4526
Ptnml(0-2): 80, 1281, 2261, 1145, 42
nElo: -13.94 ± 6.9 (95%) PairsRatio: 0.87

closes https://tests.stockfishchess.org/tests/view/660b834d01aaec5069f87cb0

bench 1823302

Co-Authored-By: Linmiao Xu <lin@robotmoon.com>
2024-04-02 08:49:48 +02:00
Joost VandeVondele c964942da2 Avoid a note related to an ABI change
current master triggers a gcc note:
parameter passing for argument of type 'std::pair<double, double>' when C++17 is enabled changed to match C++14 in GCC 10.1

while this is inconsequential, and just informative  https://gcc.gnu.org/bugzilla/show_bug.cgi?id=111516 we can easily avoid it.

closes https://github.com/official-stockfish/Stockfish/pull/5145

No functional change
2024-03-30 12:38:02 +01:00
Disservin ec598b380d Improve prerelease creation workflow
In the last couple of months we sometimes saw duplicated prereleases uploaded to GitHub, possibly due to some racy behavior when concurrent jobs create a prerelease. This now creates an empty prerelease at the beginning of the CI and the binaries are later just attached to this one.

closes https://github.com/official-stockfish/Stockfish/pull/5144

No functional change
2024-03-29 13:13:07 +01:00
Joost VandeVondele 68d58d94da Fix usage of abs vs std::abs
close https://github.com/official-stockfish/Stockfish/pull/5143

No functional change
2024-03-29 13:12:20 +01:00
Shawn Xu e13e4cfb83 Simplify NMP Condition
Remove eval >= ss->staticEval condition for Null Move Pruning.

Passed non-regression STC:
LLR: 2.93 (-2.94,2.94) <-1.75,0.25>
Total: 44000 W: 11420 L: 11202 D: 21378
Ptnml(0-2): 174, 5243, 10978, 5401, 204
https://tests.stockfishchess.org/tests/live_elo/6603ee490ec64f0526c57984

Passed non-regression LTC:
LLR: 2.94 (-2.94,2.94) <-1.75,0.25>
Total: 82956 W: 20978 L: 20818 D: 41160
Ptnml(0-2): 54, 9353, 22499, 9523, 49
https://tests.stockfishchess.org/tests/live_elo/660464b50ec64f0526c5804d

closes https://github.com/official-stockfish/Stockfish/pull/5142

Bench 1759189
2024-03-29 10:18:40 +01:00
Michael Chaly 0ef5d05102 Adjust best value after a pruned quiet move
Logic somewhat similar to how we adjust best value after pruned captures
in qsearch, but in search this patch does it after pruned quiet moves
and also to not full scale of futility value but to smth in between
best value and futility value.

Passed STC:
https://tests.stockfishchess.org/tests/view/6601cf900ec64f0526c55c30
LLR: 2.93 (-2.94,2.94) <0.00,2.00>
Total: 59936 W: 15722 L: 15369 D: 28845
Ptnml(0-2): 182, 7097, 15112, 7340, 237

Passed LTC:
https://tests.stockfishchess.org/tests/view/66029b2d0ec64f0526c566f1
LLR: 2.96 (-2.94,2.94) <0.50,2.50>
Total: 118362 W: 29953 L: 29460 D: 58949
Ptnml(0-2): 68, 13159, 32249, 13622, 83

closes https://github.com/official-stockfish/Stockfish/pull/5141

bench 1772608
2024-03-29 10:15:17 +01:00
xoto10 e636f73ab8 Vary time use with eval
Adjust time use depending on the current eval.

Passed STC :
LLR: 2.94 (-2.94,2.94) <0.00,2.00>
Total: 101696 W: 26651 L: 26238 D: 48807
Ptnml(0-2): 400, 11602, 26459, 11959, 428
https://tests.stockfishchess.org/tests/live_elo/660187a50ec64f0526c557f6

Passed LTC :
LLR: 2.94 (-2.94,2.94) <0.50,2.50>
Total: 60648 W: 15550 L: 15187 D: 29911
Ptnml(0-2): 40, 6356, 17171, 6715, 42
https://tests.stockfishchess.org/tests/live_elo/660298ed0ec64f0526c566d0

Values were found using two tunes with the final values taken from the ltc tune after 62k games :
stc - https://tests.stockfishchess.org/tests/view/65fb526b0ec64f0526c50694
ltc - https://tests.stockfishchess.org/tests/view/65fd36e60ec64f0526c5214b

Ideas for future work;

  * tune these values with the other TM adjustments
  * try narrower bands
  * calculate adjustment for exact eval by interpolation

closes https://github.com/official-stockfish/Stockfish/pull/5138

No functional change
2024-03-29 10:09:42 +01:00
Gahtan Nahdi ed24e3a0a6 Remove material imbalance from nnue eval
Passed non-reg STC:
https://tests.stockfishchess.org/tests/view/65fdf11f0ec64f0526c52b57
LLR: 2.93 (-2.94,2.94) <-1.75,0.25>
Total: 76480 W: 19893 L: 19712 D: 36875
Ptnml(0-2): 339, 9107, 19157, 9308, 329

Passed non-reg LTC:
https://tests.stockfishchess.org/tests/view/65fee22e0ec64f0526c53885
LLR: 2.95 (-2.94,2.94) <-1.75,0.25>
Total: 150948 W: 38078 L: 37988 D: 74882
Ptnml(0-2): 111, 16997, 41148, 17127, 91

closes https://github.com/official-stockfish/Stockfish/pull/5135

Bench: 2103324
2024-03-26 18:17:00 +01:00
FauziAkram d49b3738bc Tweak the stats bonus and malus
For depth 1 we don't have a negative score anymore.

Passed STC:
https://tests.stockfishchess.org/tests/view/65fb055c0ec64f0526c5024f
LLR: 2.95 (-2.94,2.94) <0.00,2.00>
Total: 117120 W: 30468 L: 30023 D: 56629
Ptnml(0-2): 526, 13759, 29539, 14216, 520

Passed LTC:
https://tests.stockfishchess.org/tests/view/65fdca4b0ec64f0526c5293f
LLR: 2.94 (-2.94,2.94) <0.50,2.50>
Total: 54816 W: 13955 L: 13595 D: 27266
Ptnml(0-2): 30, 6046, 14897, 6404, 31

closes https://github.com/official-stockfish/Stockfish/pull/5134

Bench: 1876428
2024-03-26 18:17:00 +01:00
Disservin 7998570414 Add functionality to export small net
Usage
```
export_net <filenameBigNet> <filenameSmallNet>
```

closes https://github.com/official-stockfish/Stockfish/pull/5133

No functional change
2024-03-26 18:17:00 +01:00
mstembera 5001d49f42 Update nnue_feature_transformer.h
Unroll update_accumulator_refresh to process two
active indices simultaneously.

The compiler might not unroll effectively because
the number of active indices isn't known at
compile time.

STC https://tests.stockfishchess.org/tests/view/65faa8850ec64f0526c4fca9
LLR: 2.93 (-2.94,2.94) <0.00,2.00>
Total: 130464 W: 33882 L: 33431 D: 63151
Ptnml(0-2): 539, 14591, 34501, 15082, 519

closes https://github.com/official-stockfish/Stockfish/pull/5125

No functional change
2024-03-26 18:06:49 +01:00
Muzhen Gaming d99f89506b VVLTC search tune
This set of parameters was derived from 3 tuning attempts:

    https://tests.stockfishchess.org/tests/view/65d19ab61d8e83c78bfd8436 (80+0.8 x8, ~40k games)
    Then tuned with one of linrock's early L1-3072 nets:
    https://tests.stockfishchess.org/tests/view/65def7b04b19edc854ebdec8 (VVLTC, ~36k games)
    Starting from the result of this tuning, the parameters were then tuned with the current master net:
    https://tests.stockfishchess.org/tests/view/65f11c420ec64f0526c46fc4 (VVLTC, ~45k games)

Additionally, at the start of the third tuning phase, 2 parameters were manually changed:

    Notably, the triple extension margin was decreased from 78 to 22. This idea was given by Vizvezdenec:
    https://tests.stockfishchess.org/tests/view/65f0a2360ec64f0526c46752.
    The PvNode extension margin was also adjusted from 50 to 40.

This tune also differs from previous tuning attempts by tuning the evaluation thresholds for smallnet and psqt-only.
The former was increased through the tuning, and this is hypothesized to scale better at VVLTC,
although there is not much evidence of it.

Passed VVLTC 1st sprt: https://tests.stockfishchess.org/tests/view/65f6761d0ec64f0526c4be88
LLR: 2.94 (-2.94,2.94) <0.00,2.00>
Total: 44688 W: 11421 L: 11140 D: 22127
Ptnml(0-2): 1, 4170, 13722, 4449, 2

Passed VVLTC 2nd sprt: https://tests.stockfishchess.org/tests/view/65fa31a30ec64f0526c4f611
LLR: 2.94 (-2.94,2.94) <0.50,2.50>
Total: 27450 W: 7057 L: 6778 D: 13615
Ptnml(0-2): 4, 2545, 8346, 2828, 2

STC Elo estimate: https://tests.stockfishchess.org/tests/view/65fd3e540ec64f0526c521ae
Elo: -7.84 ± 1.8 (95%) LOS: 0.0%
Total: 40000 W: 9899 L: 10802 D: 19299
Ptnml(0-2): 203, 5221, 10025, 4378, 173
nElo: -14.91 ± 3.4 (95%) PairsRatio: 0.84

closes https://github.com/official-stockfish/Stockfish/pull/5130

Bench: 1876107
2024-03-22 16:44:06 +01:00
Disservin 7e427639ce Add cmath header to movepick.h
No functional change
2024-03-20 16:36:18 +01:00
Gahtan Nahdi 8e61d70499 Remove reduction increase on repetition
Passed non-reg STC:
https://tests.stockfishchess.org/tests/view/65f89ae30ec64f0526c4e0ff
LLR: 2.93 (-2.94,2.94) <-1.75,0.25>
Total: 173568 W: 45005 L: 44936 D: 83627
Ptnml(0-2): 684, 19878, 45628, 19873, 721

Passed non-reg LTC:
https://tests.stockfishchess.org/tests/view/65fa0f370ec64f0526c4f42d
LLR: 2.95 (-2.94,2.94) <-1.75,0.25>
Total: 21138 W: 5432 L: 5216 D: 10490
Ptnml(0-2): 13, 2107, 6112, 2325, 12

closes https://github.com/official-stockfish/Stockfish/pull/5123

Bench: 2109005
2024-03-20 16:29:35 +01:00
Gahtan Nahdi 1a6c22c511 Evaluation adjustment for different eval types
Gives different eval scaling parameters for the three different types
of evaluation (bignet, smallnet, psqtOnly).

Passed STC:
https://tests.stockfishchess.org/tests/view/65f4b0020ec64f0526c4a3bd
LLR: 2.96 (-2.94,2.94) <0.00,2.00>
Total: 168064 W: 43507 L: 42987 D: 81570
Ptnml(0-2): 662, 19871, 42445, 20393, 661

Passed LTC:
https://tests.stockfishchess.org/tests/view/65f6be1a0ec64f0526c4c361
LLR: 2.94 (-2.94,2.94) <0.50,2.50>
Total: 162564 W: 41188 L: 40604 D: 80772
Ptnml(0-2): 120, 18112, 44216, 18732, 102

closes https://github.com/official-stockfish/Stockfish/pull/5122

Bench: 2113576
2024-03-20 16:29:35 +01:00
Robert Nurnberg 9b92ada935 Base WDL model on material count and normalize evals dynamically
This PR proposes to change the parameter dependence of Stockfish's
internal WDL model from full move counter to material count. In addition
it ensures that an evaluation of 100 centipawns always corresponds to a
50% win probability at fishtest LTC, whereas for master this holds only
at move number 32. See also
https://github.com/official-stockfish/Stockfish/pull/4920 and the
discussion therein.

The new model was fitted based on about 340M positions extracted from
5.6M fishtest LTC games from the last three weeks, involving SF versions
from e67cc979fd (SF 16.1) to current
master.

The involved commands are for
[WDL_model](https://github.com/official-stockfish/WDL_model) are:
```
./updateWDL.sh --firstrev e67cc979fd
python scoreWDL.py updateWDL.json --plot save --pgnName update_material.png --momType "material" --momTarget 58 --materialMin 10 --modelFitting optimizeProbability
```

The anchor `58` for the material count value was chosen to be as close
as possible to the observed average material count of fishtest LTC games
at move 32 (`43`), while not changing the value of
`NormalizeToPawnValue` compared to the move-based WDL model by more than
1.

The patch only affects the displayed cp and wdl values.

closes https://github.com/official-stockfish/Stockfish/pull/5121

No functional change
2024-03-20 16:29:35 +01:00
Disservin 117e08c264 Fix header name in Makefile
No functional change
2024-03-20 16:29:35 +01:00
Disservin 134e6d7bb4 Consistent use of anonymous namespace
Also change `bindThisThread` to match the current code style for function naming.

closes https://github.com/official-stockfish/Stockfish/pull/5118

No functional change
2024-03-20 16:15:37 +01:00
Michael Chaly ed60460004 Clamp history bonus to stats range
Before, one always had to keep track of the bonus one assigns to a history to stop
the stats from overflowing. This is a quality of life improvement. Since this would often go unnoticed during benching.

Passed non-regression bounds:
https://tests.stockfishchess.org/tests/view/65ef2af40ec64f0526c44cbc
LLR: 2.94 (-2.94,2.94) <-1.75,0.25>
Total: 179232 W: 46513 L: 46450 D: 86269
Ptnml(0-2): 716, 20323, 47452, 20432, 693

closes https://github.com/official-stockfish/Stockfish/pull/5116

No functional change
2024-03-20 16:14:00 +01:00
Disservin fb07281f55 Fix false positives from ThreadSanitizer
Since Linux Kernel 6.5 we are getting false positives from the ci,
lower the ALSR entropy to disable ALSR, which works as a temporary
workaround.

https://github.com/google/sanitizers/issues/1716
https://bugs.launchpad.net/ubuntu/+source/linux/+bug/2056762

closes https://github.com/official-stockfish/Stockfish/pull/5115

No functional change
2024-03-14 22:14:11 +01:00
cj5716 abd82396a1 Make effort part of RootMove struct
Also includes several small cleanups.

Passed STC:
https://tests.stockfishchess.org/tests/view/65f15cfe0ec64f0526c473a0
LLR: 2.94 (-2.94,2.94) <-1.75,0.25>
Total: 71136 W: 18456 L: 18273 D: 34407
Ptnml(0-2): 311, 8014, 18708, 8251, 284

closes https://github.com/official-stockfish/Stockfish/pull/5114

No functional change
2024-03-14 22:13:14 +01:00
Lemmy 23493de082 Sudden Death - Improve TM
Due to the 50 estimated move horizon, once a sudden death game got below
1 second, the time allocation for optimumTime would go into the negative
and SF would start instamoving.

To counter this, once limits.time is below 1 second, the move horizon
will start decreasing, at a rate of 1 move per 20ms. This was just what
seemed a reasonable rate of decay.

Fishtest sudden death TC 5+0
https://tests.stockfishchess.org/tests/live_elo/65ee2cdf0ec64f0526c43bbb
LLR: 2.99 (-2.94,2.94) <0.00,2.00>
Total: 3348 W: 1070 L: 727 D:1551
Ptnml(0-2): 46, 277, 738, 514, 99

Fishtest SD TC 10+0
https://tests.stockfishchess.org/tests/live_elo/65ee401e0ec64f0526c43cf7
LLR: 2.95 (-2.94,2.94) <0.00,2.00>
Total: 3780 W: 1097 L: 808 D: 1875
Ptnml(0-2): 11, 353, 919, 550, 57

Neutral Non-Regression STC 10+0.1
https://tests.stockfishchess.org/tests/live_elo/65ee45ff0ec64f0526c43d68
LLR: 2.95 (-2.94,2.94) <-1.75, 0.25>
Total: 123616 W: 32054 L: 31927 D:59635
Ptnml(0-2): 493, 14323, 32105, 14338, 549

Neutral Non-Regression LTC 60+0.6
https://tests.stockfishchess.org/tests/live_elo/65ef1eec0ec64f0526c44bc4
LLR: 2.95 (-2.94,2.94) <-1.75, 0.25>
Total: 130482 W: 32961 L: 32855 D:64666
Ptnml(0-2): 88, 13412, 38123, 13542, 76

closes https://github.com/official-stockfish/Stockfish/pull/5112

Bench: 2002517
2024-03-14 22:12:53 +01:00
Michael Chaly ee2ee6bdc4 Give more bonuses to quiet move that caused a fail low
Give extra bonus if search result is far below static evaluation of
position.

Passed STC:
https://tests.stockfishchess.org/tests/view/65edf1250ec64f0526c43787
LLR: 2.95 (-2.94,2.94) <0.00,2.00>
Total: 90816 W: 23713 L: 23307 D: 43796
Ptnml(0-2): 401, 10725, 22742, 11147, 393

Passed LTC:
https://tests.stockfishchess.org/tests/view/65ef5ed70ec64f0526c450af
LLR: 2.94 (-2.94,2.94) <0.50,2.50>
Total: 66618 W: 16950 L: 16565 D: 33103
Ptnml(0-2): 35, 7372, 18139, 7699, 64

closes https://github.com/official-stockfish/Stockfish/pull/5111

Bench: 2002517
2024-03-14 22:08:48 +01:00
Disservin 55df0ee009 Fix Raspberry Pi Compilation
Reported by @Torom over discord.

> dev build fails on Raspberry Pi 5 with clang

```
clang++ -o stockfish benchmark.o bitboard.o evaluate.o main.o misc.o movegen.o movepick.o position.o search.o thread.o timeman.o tt.o uci.o ucioption.o tune.o tbprobe.o nnue_misc.o half_ka_v2_hm.o network.o  -fprofile-instr-generate -latomic -lpthread  -Wall -Wcast-qual -fno-exceptions -std=c++17 -fprofile-instr-generate  -pedantic -Wextra -Wshadow -Wmissing-prototypes -Wconditional-uninitialized -DUSE_PTHREADS -DNDEBUG -O3 -funroll-loops -DIS_64BIT -DUSE_POPCNT -DUSE_NEON=8 -march=armv8.2-a+dotprod -DUSE_NEON_DOTPROD -DGIT_SHA=627974c9 -DGIT_DATE=20240312 -DARCH=armv8-dotprod -flto=full
/tmp/lto-llvm-e9300e.o: in function `_GLOBAL__sub_I_network.cpp':
ld-temp.o:(.text.startup+0x704c): relocation truncated to fit: R_AARCH64_LDST64_ABS_LO12_NC against symbol `gEmbeddedNNUEBigEnd' defined in .rodata section in /tmp/lto-llvm-e9300e.o
/usr/bin/ld: ld-temp.o:(.text.startup+0x704c): warning: one possible cause of this error is that the symbol is being referenced in the indicated code as if it had a larger alignment than was declared where it was defined
ld-temp.o:(.text.startup+0x7068): relocation truncated to fit: R_AARCH64_LDST64_ABS_LO12_NC against symbol `gEmbeddedNNUESmallEnd' defined in .rodata section in /tmp/lto-llvm-e9300e.o
/usr/bin/ld: ld-temp.o:(.text.startup+0x7068): warning: one possible cause of this error is that the symbol is being referenced in the indicated code as if it had a larger alignment than was declared where it was defined
clang: error: linker command failed with exit code 1 (use -v to see invocation)
make[2]: *** [Makefile:1051: stockfish] Error 1
make[2]: Leaving directory '/home/torsten/chess/Stockfish_master/src'
make[1]: *** [Makefile:1058: clang-profile-make] Error 2
make[1]: Leaving directory '/home/torsten/chess/Stockfish_master/src'
make: *** [Makefile:886: profile-build] Error 2
```

closes https://github.com/official-stockfish/Stockfish/pull/5106

No functional change
2024-03-12 19:09:50 +01:00
FauziAkram 627974c99f Search + Eval + Movepick Tune
Passed STC:
https://tests.stockfishchess.org/tests/view/65ef15220ec64f0526c44b04
LLR: 2.94 (-2.94,2.94) <0.00,2.00>
Total: 24480 W: 6459 L: 6153 D: 11868
Ptnml(0-2): 101, 2798, 6184, 3008, 149

Passed LTC:
https://tests.stockfishchess.org/tests/view/65ef4bac0ec64f0526c44f50
LLR: 2.94 (-2.94,2.94) <0.50,2.50>
Total: 53316 W: 13561 L: 13203 D: 26552
Ptnml(0-2): 27, 5925, 14408, 6259, 39

closes https://github.com/official-stockfish/Stockfish/pull/5104

Bench: 1715522
2024-03-12 16:47:11 +01:00
FauziAkram daa3ef9148 Simplify increaseDepth to boolean expression
Non-functional Simplification, maintaining the same logic as before. Big thanks
to @peregrineshahin for helping with the code.

Passed non-regression bounds:
https://tests.stockfishchess.org/tests/view/65ec93860ec64f0526c42375
LLR: 2.93 (-2.94,2.94) <-1.75,0.25>
Total: 101088 W: 26196 L: 26047 D: 48845
Ptnml(0-2): 405, 11580, 26473, 11633, 453

closes https://github.com/official-stockfish/Stockfish/pull/5103

No functional change
2024-03-12 16:43:10 +01:00
Disservin 1a26d698de Refactor Network Usage
Continuing from PR #4968, this update improves how Stockfish handles network
usage, making it easier to manage and modify networks in the future.

With the introduction of a dedicated Network class, creating networks has become
straightforward. See uci.cpp:
```cpp
NN::NetworkBig({EvalFileDefaultNameBig, "None", ""}, NN::embeddedNNUEBig)
```

The new `Network` encapsulates all network-related logic, significantly reducing
the complexity previously required to support multiple network types, such as
the distinction between small and big networks #4915.

Non-Regression STC:
https://tests.stockfishchess.org/tests/view/65edd26c0ec64f0526c43584
LLR: 2.94 (-2.94,2.94) <-1.75,0.25>
Total: 33760 W: 8887 L: 8661 D: 16212
Ptnml(0-2): 143, 3795, 8808, 3961, 173

Non-Regression SMP STC:
https://tests.stockfishchess.org/tests/view/65ed71970ec64f0526c42fdd
LLR: 2.96 (-2.94,2.94) <-1.75,0.25>
Total: 59088 W: 15121 L: 14931 D: 29036
Ptnml(0-2): 110, 6640, 15829, 6880, 85

Compiled with `make -j profile-build`
```
bash ./bench_parallel.sh ./stockfish ./stockfish-nnue 13 50

sf_base =  1568540 +/-   7637 (95%)
sf_test =  1573129 +/-   7301 (95%)
diff    =     4589 +/-   8720 (95%)
speedup = 0.29260% +/- 0.556% (95%)
```

Compiled with `make -j build`
```
bash ./bench_parallel.sh ./stockfish ./stockfish-nnue 13 50

sf_base =  1472653 +/-   7293 (95%)
sf_test =  1491928 +/-   7661 (95%)
diff    =    19275 +/-   7154 (95%)
speedup = 1.30886% +/- 0.486% (95%)
```

closes https://github.com/official-stockfish/Stockfish/pull/5100

No functional change
2024-03-12 16:41:08 +01:00
Gahtan Nahdi f072634e24 Simplify opponentWorsening condition
Passed non-reg STC:
https://tests.stockfishchess.org/tests/view/65ea18650ec64f0526c4033a
LLR: 2.95 (-2.94,2.94) <-1.75,0.25>
Total: 226624 W: 58601 L: 58589 D: 109434
Ptnml(0-2): 1030, 27193, 56819, 27275, 995

Passed non-reg LTC:
https://tests.stockfishchess.org/tests/view/65eb7a220ec64f0526c4161a
LLR: 2.95 (-2.94,2.94) <-1.75,0.25>
Total: 243882 W: 61462 L: 61469 D: 120951
Ptnml(0-2): 197, 27559, 66419, 27586, 180

closes https://github.com/official-stockfish/Stockfish/pull/5102

Bench: 1601012
2024-03-11 10:08:40 +01:00
Muzhen Gaming 10e2732978 VVLTC search tune
Result of 32k games of tuning at 60+0.6 8-thread. Link to the tuning
attempt:
https://tests.stockfishchess.org/tests/view/65def7b04b19edc854ebdec8

Passed VVLTC first SPRT:
https://tests.stockfishchess.org/tests/view/65e51b53416ecd92c162ab7f
LLR: 2.94 (-2.94,2.94) <0.00,2.00>
Total: 37570 W: 9613 L: 9342 D: 18615
Ptnml(0-2): 2, 3454, 11601, 3727, 1

Passed VVLTC second SPRT:
https://tests.stockfishchess.org/tests/view/65e87d1c0ec64f0526c3eb39
LLR: 2.94 (-2.94,2.94) <0.50,2.50>
Total: 123158 W: 31463 L: 31006 D: 60689
Ptnml(0-2): 5, 11589, 37935, 12044, 6

Note: The small net and psqt-only thresholds have been moved to
evaluate.h. The reasoning is that these values are used in both
`evaluate.cpp` and `evaluate_nnue.cpp`, and thus unifying their usage
avoids inconsistencies during testing, where one occurrence is changed
without the other (this happened during the search tune SPRT).

closes https://github.com/official-stockfish/Stockfish/pull/5101

Bench: 1741218
2024-03-11 10:04:37 +01:00
Disservin b6dfd6bd54 Assorted cleanups
- fix naming convention for `workingDirectory`
- use type alias for `EvalFiles` everywhere
- move `ponderMode` into `LimitsType`
- move limits parsing into standalone static function

closes https://github.com/official-stockfish/Stockfish/pull/5098

No functional change
2024-03-11 09:02:13 +01:00
Robert Nurnberg @ elitebook 632f1c21cd Fix wrong constant usage in go mate
Fixes an oversight in https://github.com/official-stockfish/Stockfish/pull/5094

In theory, master could stop search when run with `go mate 247` and return a TB loss (not a mate score). Also fixes the spelling of opponenWorsening.

closes https://github.com/official-stockfish/Stockfish/pull/5096

No functional change
2024-03-07 21:10:33 +01:00
Muzhen Gaming 0f01a516d2 VLTC time management tune
Result of 35k games of SPSA tuning at 180+1.8. Tuning attempt can be
found here:
https://tests.stockfishchess.org/tests/view/65e40599f2ef6c733362b03b

Passed VLTC 180+1.8:
https://tests.stockfishchess.org/tests/view/65e5a6f5416ecd92c162b5d4
LLR: 2.94 (-2.94,2.94) <0.00,2.00>
Total: 31950 W: 8225 L: 7949 D: 15776
Ptnml(0-2): 3, 3195, 9309, 3459, 9

Passed VLTC 240+2.4:
https://tests.stockfishchess.org/tests/view/65e714de0ec64f0526c3d1f1
LLR: 2.94 (-2.94,2.94) <0.50,2.50>
Total: 65108 W: 16558 L: 16202 D: 32348
Ptnml(0-2): 7, 6366, 19449, 6728, 4

closes https://github.com/official-stockfish/Stockfish/pull/5095

Bench: 1714391
2024-03-07 20:08:00 +01:00
Shahin M. Shahin 748791f80d Fix go mate x in multithreading
Fixes two issues with master for go mate x:

- when running go mate x in losing positions, master always goes to the
  maximal depth, arguably against what the UCI protocol demands

- when running go mate x in winning positions with multiple
  threads, master may return non-mate scores from the search (this issue
  is present in stockfish since at least sf16) The issues are fixed by
  (a) also checking if score is mate -x and by (b) only letting
  mainthread stop the search for go mate x commands, and by not looking
  for a best thread but using mainthread as per the default. Related:
    niklasf/python-chess#1070

More diagnostics can be found here peregrineshahin#6 (comment)

closes https://github.com/official-stockfish/Stockfish/pull/5094

No functional change

Co-Authored-By: Robert Nürnberg <28635489+robertnurnberg@users.noreply.github.com>
2024-03-07 19:58:33 +01:00
Michael Chaly 6136d094c5 Introduce double extensions for PV nodes
Our double/triple extensions were allowed only for non-pv nodes. This
patch allows them to be done for PV nodes, with some stricter
conditions.

Passed STC:
https://tests.stockfishchess.org/tests/view/65d657ec1d8e83c78bfddab8
LLR: 2.95 (-2.94,2.94) <0.00,2.00>
Total: 339424 W: 88097 L: 87318 D: 164009
Ptnml(0-2): 1573, 39935, 85729, 41090, 1385

Passed LTC:
https://tests.stockfishchess.org/tests/view/65dd63824b19edc854ebc433
LLR: 2.94 (-2.94,2.94) <0.50,2.50>
Total: 459564 W: 115812 L: 114614 D: 229138
Ptnml(0-2): 248, 51441, 125173, 52705, 215

closes https://github.com/official-stockfish/Stockfish/pull/5093

Bench: 1714391
2024-03-07 19:56:30 +01:00
rn5f107s2 1db969e620 Reduce futility_margin if opponents last move was bad
This reduces the futiltiy_margin if our opponents last move was bad by
around ~1/3 when not improving and ~1/2.7 when improving, the idea being
to retroactively futility prune moves that were played, but turned out
to be bad.  A bad move is being defined as their staticEval before their
move being lower as our staticEval now is. If the depth is 2 and we are
improving the opponent worsening flag is not set, in order to not risk
having a too low futility_margin, due to the fact that when these
conditions are met the futility_margin already drops quite low.

Passed STC:
https://tests.stockfishchess.org/tests/live_elo/65e3977bf2ef6c733362aae3
LLR: 2.94 (-2.94,2.94) <0.00,2.00>
Total: 122432 W: 31884 L: 31436 D: 59112
Ptnml(0-2): 467, 14404, 31035, 14834, 476

Passed LTC:
https://tests.stockfishchess.org/tests/live_elo/65e47f40f2ef6c733362b6d2
LLR: 2.94 (-2.94,2.94) <0.50,2.50>
Total: 421692 W: 106572 L: 105452 D: 209668
Ptnml(0-2): 216, 47217, 114865, 48327, 221

closes https://github.com/official-stockfish/Stockfish/pull/5092

Bench: 1565939
2024-03-07 19:55:51 +01:00
Linmiao Xu bd579ab5d1 Update default main net to nn-1ceb1ade0001.nnue
Created by retraining the previous main net `nn-b1a57edbea57.nnue` with:
- some of the same options as before:
  - ranger21, more WDL skipping, 15% more loss when Q is too high
- removal of the huge 514G pre-interleaved binpack
- removal of SF-generated dfrc data (dfrc99-16tb7p-filt-v2.min.binpack)
- interleaving many binpacks at training time
- training with some bestmove capture positions where SEE < 0
- increased usage of torch.compile to speed up training by up to 40%

```yaml
experiment-name: 2560--S10-dfrc0-to-dec2023-skip-more-wdl-15p-more-loss-high-q-see-ge0-sk28
nnue-pytorch-branch: linrock/nnue-pytorch/r21-more-wdl-skip-15p-more-loss-high-q-skip-see-ge0-torch-compile-more
start-from-engine-test-net: True

early-fen-skipping: 28
training-dataset:
  # similar, not the exact same as:
  # https://github.com/official-stockfish/Stockfish/pull/4635
  - /data/S5-5af/leela96.v2.min.binpack
  - /data/S5-5af/test60-2021-11-12-novdec-12tb7p.v6-dd.min.binpack
  - /data/S5-5af/test77-2021-12-dec-16tb7p.v6-dd.min.binpack
  - /data/S5-5af/test78-2022-01-to-05-jantomay-16tb7p.v6-dd.min.binpack
  - /data/S5-5af/test78-2022-06-to-09-juntosep-16tb7p.v6-dd.min.binpack
  - /data/S5-5af/test79-2022-04-apr-16tb7p.v6-dd.min.binpack
  - /data/S5-5af/test79-2022-05-may-16tb7p.v6-dd.min.binpack

  - /data/S5-5af/test80-2022-06-jun-16tb7p.v6-dd.min.unmin.binpack
  - /data/S5-5af/test80-2022-07-jul-16tb7p.v6-dd.min.binpack
  - /data/S5-5af/test80-2022-08-aug-16tb7p.v6-dd.min.binpack
  - /data/S5-5af/test80-2022-09-sep-16tb7p.v6-dd.min.unmin.binpack
  - /data/S5-5af/test80-2022-10-oct-16tb7p.v6-dd.min.binpack
  - /data/S5-5af/test80-2022-11-nov-16tb7p.v6-dd.min.binpack

  - /data/S5-5af/test80-2023-01-jan-16tb7p.v6-sk20.min.binpack
  - /data/S5-5af/test80-2023-02-feb-16tb7p.v6-dd.min.binpack
  - /data/S5-5af/test80-2023-03-mar-2tb7p.min.unmin.binpack
  - /data/S5-5af/test80-2023-04-apr-2tb7p.binpack
  - /data/S5-5af/test80-2023-05-may-2tb7p.min.dd.binpack

  # https://github.com/official-stockfish/Stockfish/pull/4782
  - /data/S6-1ee1aba5ed/test80-2023-06-jun-2tb7p.binpack
  - /data/S6-1ee1aba5ed/test80-2023-07-jul-2tb7p.min.binpack

  # https://github.com/official-stockfish/Stockfish/pull/4972
  - /data/S8-baff1edbea57/test80-2023-08-aug-2tb7p.v6.min.binpack
  - /data/S8-baff1edbea57/test80-2023-09-sep-2tb7p.binpack
  - /data/S8-baff1edbea57/test80-2023-10-oct-2tb7p.binpack

  # https://github.com/official-stockfish/Stockfish/pull/5056
  - /data/S9-b1a57edbea57/test80-2023-11-nov-2tb7p.binpack
  - /data/S9-b1a57edbea57/test80-2023-12-dec-2tb7p.binpack

num-epochs: 800
lr: 4.375e-4
gamma: 0.995
start-lambda: 1.0
end-lambda: 0.7
```

This particular net was reached at epoch 759. Use of more torch.compile decorators
in nnue-pytorch model.py than in the previous main net training run sped up training
by up to 40% on Tesla gpus when using recent pytorch compiled with cuda 12:
https://github.com/linrock/nnue-tools/blob/7fb9831/Dockerfile

Skipping positions with bestmove captures where static exchange evaluation is >= 0
is based on the implementation from Sopel's NNUE training & experimentation log:
https://docs.google.com/document/d/1gTlrr02qSNKiXNZ_SuO4-RjK4MXBiFlLE6jvNqqMkAY
Experiment 293 - only skip captures with see>=0

Positions with bestmove captures where score == 0 are always skipped for
compatibility with minimized binpacks, since the original minimizer sets
scores to 0 for slight improvements in compression.

The trainer branch used was:
https://github.com/linrock/nnue-pytorch/tree/r21-more-wdl-skip-15p-more-loss-high-q-skip-see-ge0-torch-compile-more

Binpacks were renamed to be sorted chronologically by default when sorted by name.
The binpack data are otherwise the same as binpacks with similar names in the prior
naming convention.

Training data can be found at:
https://robotmoon.com/nnue-training-data/

Passed STC:
https://tests.stockfishchess.org/tests/view/65e3ddd1f2ef6c733362ae5c
LLR: 2.92 (-2.94,2.94) <0.00,2.00>
Total: 149792 W: 39153 L: 38661 D: 71978
Ptnml(0-2): 675, 17586, 37905, 18032, 698

Passed LTC:
https://tests.stockfishchess.org/tests/view/65e4d91c416ecd92c162a69b
LLR: 2.94 (-2.94,2.94) <0.50,2.50>
Total: 64416 W: 16517 L: 16135 D: 31764
Ptnml(0-2): 38, 7218, 17313, 7602, 37

closes https://github.com/official-stockfish/Stockfish/pull/5090

Bench: 1373183
2024-03-07 19:53:48 +01:00
FauziAkram a96b0d4609 Update elo estimates
Tests used to change the elo worth of some functions:

https://tests.stockfishchess.org/tests/view/65c3f69dc865510db0283eef
https://tests.stockfishchess.org/tests/view/65c3f935c865510db0283f2a
https://tests.stockfishchess.org/tests/view/65d1489f1d8e83c78bfd7dbf
https://tests.stockfishchess.org/tests/view/65ce9d361d8e83c78bfd4951
https://tests.stockfishchess.org/tests/view/65cfcd901d8e83c78bfd6184

closes https://github.com/official-stockfish/Stockfish/pull/5089

No functional change
2024-03-07 19:53:48 +01:00
FauziAkram a615efb19f Simplify Time Management
Instead of having a formula for using extra time with larger increments.
Simply set it to 1 when the increment is lower than 0.5s and to 1.1 when
the increment is higher.

The values can later on be further improved.

Passed STC:
https://tests.stockfishchess.org/tests/view/65d25d3c1d8e83c78bfd9293
LLR: 2.93 (-2.94,2.94) <-1.75,0.25>
Total: 27488 W: 7077 L: 6848 D: 13563
Ptnml(0-2): 96, 3041, 7267, 3218, 122

Passed LTC:
https://tests.stockfishchess.org/tests/view/65d2a72c1d8e83c78bfd97fa
LLR: 2.94 (-2.94,2.94) <-1.75,0.25>
Total: 137568 W: 34612 L: 34512 D: 68444
Ptnml(0-2): 60, 14672, 39221, 14770, 61

Passed VLTC:
https://tests.stockfishchess.org/tests/view/65d7d7d39b2da0226a5a205b
LLR: 2.94 (-2.94,2.94) <-1.75,0.25>
Total: 139650 W: 35229 L: 35134 D: 69287
Ptnml(0-2): 33, 14227, 41218, 14306, 41

Passed also the TCEC TC style suggested by vondele:
https://tests.stockfishchess.org/tests/view/65e4ca73416ecd92c162a57d
LLR: 2.94 (-2.94,2.94) <-1.75,0.25>
Total: 134150 W: 34278 L: 34163 D: 65709
Ptnml(0-2): 561, 15727, 34444, 15722, 621

closes https://github.com/official-stockfish/Stockfish/pull/5076

Bench: 1553115
2024-03-07 19:49:01 +01:00
Gahtan Nahdi b0ac8a4e3b Simplify extension when ttMove is assumed to fail high over current beta
Simplify extension value to -3 when ttMove is assumed to fail high over current beta.

Passed non-reg STC:
https://tests.stockfishchess.org/tests/view/65d66ed81d8e83c78bfddcba
LLR: 2.95 (-2.94,2.94) <-1.75,0.25>
Total: 235136 W: 60711 L: 60708 D: 113717
Ptnml(0-2): 969, 27904, 59874, 27797, 1024

Passed non-reg LTC:
https://tests.stockfishchess.org/tests/view/65da2994944f2a78d4733107
LLR: 2.94 (-2.94,2.94) <-1.75,0.25>
Total: 662850 W: 166161 L: 166602 D: 330087
Ptnml(0-2): 394, 74895, 181274, 74482, 380

closes https://github.com/official-stockfish/Stockfish/pull/5088

Bench: 1553115
2024-03-03 15:45:13 +01:00
Gahtan Nahdi 6d0d430860 Simplify IIR
Simplified depth reduction for PV nodes without a ttMove to 3.

Passed STC non-reg:
https://tests.stockfishchess.org/tests/view/65d1a90a1d8e83c78bfd855a
LLR: 2.94 (-2.94,2.94) <-1.75,0.25>
Total: 363168 W: 93648 L: 93791 D: 175729
Ptnml(0-2): 1557, 43692, 91221, 43565, 1549

Passed LTC non-reg:
https://tests.stockfishchess.org/tests/view/65d5612d1d8e83c78bfdc8e2
LLR: 2.94 (-2.94,2.94) <-1.75,0.25>
Total: 58818 W: 14946 L: 14761 D: 29111
Ptnml(0-2): 36, 6595, 15962, 6780, 36

closes https://github.com/official-stockfish/Stockfish/pull/5062

Bench: 1505827
2024-03-03 15:42:17 +01:00
mstembera 7831131591 Only evaluate the PSQT part of the small net for large evals.
Thanks to Viren6 for suggesting to set complexity to 0.

STC https://tests.stockfishchess.org/tests/view/65d7d6709b2da0226a5a203f
LLR: 2.92 (-2.94,2.94) <0.00,2.00>
Total: 328384 W: 85316 L: 84554 D: 158514
Ptnml(0-2): 1414, 39076, 82486, 39766, 1450

LTC https://tests.stockfishchess.org/tests/view/65dce6d290f639b028a54d2e
LLR: 2.95 (-2.94,2.94) <0.50,2.50>
Total: 165162 W: 41918 L: 41330 D: 81914
Ptnml(0-2): 102, 18332, 45124, 18922, 101

closes https://github.com/official-stockfish/Stockfish/pull/5083

bench: 1504003
2024-03-03 15:29:58 +01:00
Disservin 0a3eb1d8fa Document TT code more
Slight refactor of the TT code with the goal to make it easier to understand / tweak.

Passed Non-Regression STC:
https://tests.stockfishchess.org/tests/view/65d51e401d8e83c78bfdc427
LLR: 2.95 (-2.94,2.94) <-1.75,0.25>
Total: 56416 W: 14750 L: 14550 D: 27116
Ptnml(0-2): 227, 6386, 14796, 6558, 241

closes https://github.com/official-stockfish/Stockfish/pull/5061

No functional change
2024-03-03 15:21:57 +01:00
Gahtan Nahdi f77eddfa2f Join conditions for move sorting heuristics
closes https://github.com/official-stockfish/Stockfish/pull/5078

No functional change.
2024-03-03 15:18:13 +01:00
Disservin 0c22d5bb1a Update Actions to Node20
ensure our CI continues to run after Node16 is obsolote on github.

closes https://github.com/official-stockfish/Stockfish/pull/5074

No functional change
2024-03-03 15:09:46 +01:00
Disservin c83c7f4e71 Make binaries executable again in CI
closes https://github.com/official-stockfish/Stockfish/pull/5072

No functional change
2024-03-03 15:07:32 +01:00
Disservin abcc090a62 Restore development
closes https://github.com/official-stockfish/Stockfish/pull/5073

No functional change
2024-03-03 15:01:29 +01:00
Disservin e67cc979fd Stockfish 16.1
Official release version of Stockfish 16.1

Bench: 1303971

---

Stockfish 16.1

Today, we have the pleasure to announce Stockfish 16.1. As always, you can
freely download it at https://stockfishchess.org/download and use it in the GUI
of your choice[1].

Don't forget to join our Discord server[2] to get in touch with the community of
developers and users of the project!

*Quality of chess play*

In our testing against its predecessor, Stockfish 16.1 shows a notable
improvement in performance, with an Elo gain of up to 27 points and winning over
2 times more game pairs[3] than it loses.

*Update highlights*

*Improved evaluation*

- Updated neural network architecture: The neural network architecture has
  undergone two updates and is currently in its 8th version[4].
- Removal of handcrafted evaluation (HCE): This release marks the removal of the
  traditional handcrafted evaluation and the transition to a fully neural
  network-based approach[5].
- Dual NNUE: For the first time, Stockfish includes a secondary neural
  network[6], used to quickly evaluate positions that are easily decided.

*UCI Options removed*

`Use NNUE` and `UCI_AnalyseMode`[7] have been removed as they no longer had any
effect. `SlowMover`[8] has also been removed in favor of `Move Overhead`.

*More binaries*

We now offer 13 new binaries. These new binaries include `avx512`, `vnni256`,
`vnni512`, `m1-apple-silicon`, and `armv8-dotprod`, which take advantage of
specific CPU instructions for improved performance.
For most users, using `sse41-popcnt` (formerly `modern`), `avx2`, or `bmi2`
should be enough, but if your CPU supports these new instructions, feel free to
try them!

*Development changes*

- Updated testing book: This new book[9], now derived exclusively from the open
  Lichess database[10], is 10 times larger than its predecessor, and has been
  used to test potential improvements to Stockfish over the past few months.
- Consolidation of repositories: Aiming to simplify access to our resources, we
  have moved most Stockfish-related repositories into the official Stockfish
  organization[11] on GitHub.
- Growing maintainer team: We welcome Disservin[12] to the team of maintainers
  of the project! This extra pair of hands will ensure the lasting success of
  Stockfish.

*Thank you*

The Stockfish project builds on a thriving community of enthusiasts (thanks
everybody!) who contribute their expertise, time, and resources to build a free
and open-source chess engine that is robust, widely available, and very strong.

We would like to express our gratitude for the 10k stars[13] that light up our
GitHub project! Thank you for your support and encouragement – your recognition
means a lot to us.

We invite our chess fans to join the Fishtest testing framework[14], and
programmers to contribute to the project either directly to Stockfish[15] (C++),
to Fishtest[16] (HTML, CSS, JavaScript, and Python), to our trainer
nnue-pytorch[17] (C++ and Python), or to our website[18] (HTML, CSS/SCSS, and
JavaScript).

The Stockfish team

[1] https://github.com/official-stockfish/Stockfish/wiki/Download-and-usage#download-a-chess-gui
[2] https://discord.gg/GWDRS3kU6R
[3] https://tests.stockfishchess.org/tests/view/65d666051d8e83c78bfddbd8
[4] https://github.com/official-stockfish/nnue-pytorch/blob/master/docs/nnue.md#sfnnv8-architecture
[5] https://github.com/official-stockfish/Stockfish/commit/af110e0
[6] https://github.com/official-stockfish/Stockfish/commit/584d9ef
[7] https://github.com/official-stockfish/Stockfish/commit/c53d2ec
[8] https://github.com/official-stockfish/Stockfish/commit/536d692
[9] https://github.com/official-stockfish/books/commit/426eca4
[10] https://database.lichess.org/
[11] https://github.com/official-stockfish/
[12] https://github.com/Disservin
[13] https://github.com/official-stockfish/Stockfish/stargazers
[14] https://github.com/official-stockfish/fishtest/wiki/Running-the-worker
[15] https://github.com/official-stockfish/Stockfish
[16] https://github.com/official-stockfish/fishtest
[17] https://github.com/official-stockfish/nnue-pytorch
[18] https://github.com/official-stockfish/stockfish-web
2024-02-24 18:15:04 +01:00
Robert Nurnberg @ elitebook 5c2b385957 Update the WDL model
Based on 130M positions from 2.1M games.

```
Look recursively in directory pgns for games from SPRT tests using books
matching "UHO_4060_v..epd|UHO_Lichess_4852_v1.epd" for SF revisions
between 8e75548f2a (from 2024-02-17
17:11:46 +0100) and HEAD (from 2024-02-17 17:13:07 +0100). Based on
127920843 positions from 2109240 games, NormalizeToPawnValue should
change from 345 to 356.
```

The patch only affects the UCI-reported cp and wdl values.

closes https://github.com/official-stockfish/Stockfish/pull/5070

No functional change
2024-02-24 17:59:41 +01:00
Disservin bec83a1869 Update Top CPU Contributors
closes https://github.com/official-stockfish/Stockfish/pull/5069

No functional change
2024-02-24 17:58:44 +01:00
Disservin d07033d5da Expose EvalFileSmall option for small net
Since https://github.com/official-stockfish/fishtest/pull/1870 has been merged
it's time for this update.

5k Fixed Games showed no problems.
https://tests.stockfishchess.org/tests/view/65d9cc274c0e22b904f574d7

closes https://github.com/official-stockfish/Stockfish/pull/5068

No functional change
2024-02-24 17:57:49 +01:00
cj5716 fc41f64dfd Simplify PV node reduction
Reduce less on PV nodes even with an upperbound TT entry.

Passed STC:
https://tests.stockfishchess.org/tests/view/65cb3a861d8e83c78bfd0497
LLR: 2.96 (-2.94,2.94) <-1.75,0.25>
Total: 118752 W: 30441 L: 30307 D: 58004
Ptnml(0-2): 476, 14179, 29921, 14335, 465

Passed LTC:
https://tests.stockfishchess.org/tests/view/65cd3b951d8e83c78bfd2b0d
LLR: 2.95 (-2.94,2.94) <-1.75,0.25>
Total: 155058 W: 38549 L: 38464 D: 78045
Ptnml(0-2): 85, 17521, 42219, 17632, 72

closes https://github.com/official-stockfish/Stockfish/pull/5057

Bench: 1303971
2024-02-17 17:13:07 +01:00
Linmiao Xu 8e75548f2a Update default main net to nn-b1a57edbea57.nnue
Created by retraining the previous main net `nn-baff1edbea57.nnue` with:
- some of the same options as before: ranger21, more WDL skipping
- the addition of T80 nov+dec 2023 data
- increasing loss by 15% when prediction is too high, up from 10%
- use of torch.compile to speed up training by over 25%

```yaml
experiment-name: 2560--S9-514G-T80-augtodec2023-more-wdl-skip-15p-more-loss-high-q-sk28

training-dataset:
  # https://github.com/official-stockfish/Stockfish/pull/4782
  - /data/S6-514G-1ee1aba5ed.binpack
  - /data/test80-aug2023-2tb7p.v6.min.binpack
  - /data/test80-sep2023-2tb7p.binpack
  - /data/test80-oct2023-2tb7p.binpack
  - /data/test80-nov2023-2tb7p.binpack
  - /data/test80-dec2023-2tb7p.binpack
early-fen-skipping: 28

start-from-engine-test-net: True
nnue-pytorch-branch: linrock/nnue-pytorch/r21-more-wdl-skip-15p-more-loss-high-q-torch-compile

num-epochs: 1000
lr: 4.375e-4
gamma: 0.995
start-lambda: 1.0
end-lambda: 0.7
```

Epoch 819 trained with the above config led to this PR. Use of torch.compile
decorators in nnue-pytorch model.py was found to speed up training by at least
25% on Ampere gpus when using recent pytorch compiled with cuda 12:
https://catalog.ngc.nvidia.com/orgs/nvidia/containers/pytorch

See recent main net PRs for more info on
- ranger21 and more WDL skipping: https://github.com/official-stockfish/Stockfish/pull/4942
- increasing loss when Q is too high: https://github.com/official-stockfish/Stockfish/pull/4972

Training data can be found at:
https://robotmoon.com/nnue-training-data/

Passed STC:
https://tests.stockfishchess.org/tests/view/65cd76151d8e83c78bfd2f52
LLR: 2.98 (-2.94,2.94) <0.00,2.00>
Total: 78336 W: 20504 L: 20115 D: 37717
Ptnml(0-2): 317, 9225, 19721, 9562, 343

Passed LTC:
https://tests.stockfishchess.org/tests/view/65ce5be61d8e83c78bfd43e9
LLR: 2.95 (-2.94,2.94) <0.50,2.50>
Total: 41016 W: 10492 L: 10159 D: 20365
Ptnml(0-2): 22, 4533, 11071, 4854, 28

closes https://github.com/official-stockfish/Stockfish/pull/5056

Bench: 1351997
2024-02-17 17:11:46 +01:00
cj5716 f3df0cfb84 Simplify TT PV reduction
This also removes some incorrect fail-high logic.

Passed STC:
https://tests.stockfishchess.org/tests/view/65cb3b641d8e83c78bfd04a9
LLR: 2.94 (-2.94,2.94) <-1.75,0.25>
Total: 87968 W: 22634 L: 22468 D: 42866
Ptnml(0-2): 315, 10436, 22323, 10588, 322

Passed LTC:
https://tests.stockfishchess.org/tests/view/65cccee21d8e83c78bfd222c
LLR: 2.95 (-2.94,2.94) <-1.75,0.25>
Total: 70794 W: 17846 L: 17672 D: 35276
Ptnml(0-2): 44, 7980, 19189, 8126, 58

closes https://github.com/official-stockfish/Stockfish/pull/5055

Bench: 1474424
2024-02-17 17:10:13 +01:00
Gahtan Nahdi 9d61822b5d Remove penalty for quiet ttMove that fails low
Passed STC non-reg:
https://tests.stockfishchess.org/tests/view/65c691a7c865510db0286e6e
LLR: 2.95 (-2.94,2.94) <-1.75,0.25>
Total: 234336 W: 60258 L: 60255 D: 113823
Ptnml(0-2): 966, 28141, 58918, 28210, 933

Passed LTC non-reg:
https://tests.stockfishchess.org/tests/view/65c8d0d31d8e83c78bfcd4a6
LLR: 2.95 (-2.94,2.94) <-1.75,0.25>
Total: 235206 W: 59134 L: 59132 D: 116940
Ptnml(0-2): 135, 26908, 63517, 26906, 137

https://github.com/official-stockfish/Stockfish/pull/5054

Bench: 1287996
2024-02-17 17:08:01 +01:00
Disservin bf2c7306ac Use node counting to early stop search
This introduces a form of node counting which can
be used to further tweak the usage of our search
time.
The current approach stops the search when almost
all nodes are searched on a single move.

The idea originally came from Koivisto, but the
implemention is a bit different, Koivisto scales
the optimal time by the nodes effort and then
determines if the search should be stopped.
We just scale down the `totalTime` and stop the
search if we exceed it and the effort is large
enough.

Passed STC:
https://tests.stockfishchess.org/tests/view/65c8e0661d8e83c78bfcd5ec
LLR: 2.97 (-2.94,2.94) <0.00,2.00>
Total: 88672 W: 22907 L: 22512 D: 43253
Ptnml(0-2): 310, 10163, 23041, 10466, 356

Passed LTC:
https://tests.stockfishchess.org/tests/view/65ca632b1d8e83c78bfcf554
LLR: 2.95 (-2.94,2.94) <0.50,2.50>
Total: 170856 W: 42910 L: 42320 D: 85626
Ptnml(0-2): 104, 18337, 47960, 18919, 108

closes https://github.com/official-stockfish/Stockfish/pull/5053

Bench: 1198939
2024-02-14 21:39:31 +01:00
Tierynn Byrnes f4f0b32d55 Refactor timeman.cpp
Move optExtra, optConstant and maxConstant into lower scope.

closes https://github.com/official-stockfish/Stockfish/pull/5052

No functional change
2024-02-14 21:38:17 +01:00
Muzhen Gaming 5c03883107 VVLTC search tune
Search parameters were tuned using 16k games at
VVLTC. They were tuned starting with the new
parameters (in search only) of PR #5039.

Passed VVLTC:
https://tests.stockfishchess.org/tests/view/65c8a8fc1d8e83c78bfcd163
LLR: 2.94 (-2.94,2.94) <0.00,2.00>
Total: 20826 W: 5355 L: 5100 D: 10371
Ptnml(0-2): 1, 1941, 6275, 2194, 2

Passed 2nd VVLTC:
https://tests.stockfishchess.org/tests/view/65cadc2d1d8e83c78bfcfdaf
LLR: 2.94 (-2.94,2.94) <0.50,2.50>
Total: 17710 W: 4611 L: 4352 D: 8747
Ptnml(0-2): 1, 1586, 5422, 1845, 1

STC Elo estimate:
https://tests.stockfishchess.org/tests/view/65cb6aed1d8e83c78bfd0802
Elo: -1.46 ± 1.8 (95%) LOS: 5.5%
Total: 40000 W: 10267 L: 10435 D: 19298
Ptnml(0-2): 200, 4860, 10023, 4742, 175
nElo: -2.77 ± 3.4 (95%) PairsRatio: 0.97

Bench: 1198939
2024-02-14 21:27:55 +01:00
Disservin 7ccde25baf Format code using clang-format
No functional change
2024-02-11 20:13:19 +01:00
Gahtan Nahdi c115e5171e Remove quiet tt move extensions
Passed STC:
https://tests.stockfishchess.org/tests/view/65c6934cc865510db0286e90
LLR: 2.99 (-2.94,2.94) <-1.75,0.25>
Total: 54016 W: 14065 L: 13854 D: 26097
Ptnml(0-2): 231, 6381, 13581, 6576, 239

Passed LTC:
https://tests.stockfishchess.org/tests/view/65c72b91c865510db0287a1a
LLR: 2.96 (-2.94,2.94) <-1.75,0.25>
Total: 55098 W: 13850 L: 13658 D: 27590
Ptnml(0-2): 37, 6257, 14777, 6433, 45

closes https://github.com/official-stockfish/Stockfish/pull/5049

Bench: 1027182
2024-02-11 19:58:35 +01:00
mstembera 531747ee78 Improve thread voting inefficiencies
Initialize the unordered map to a reasonable
number of buckets and make the move hashes well
distributed. For more see
https://github.com/official-stockfish/Stockfish/pull/4958#issuecomment-1937351190
Also make bestThreadPV and newThreadPV references
so we don't copy entire vectors.

closes https://github.com/official-stockfish/Stockfish/pull/5048

No functional change
2024-02-11 19:55:26 +01:00
Michael Chaly 91a4cea437 Adjust best value in main search depending on depth
This patch does similar thing to how it's done for
qsearch - in case of fail high adjust result to
lower value. Difference is that it is done only
for non-pv nodes and it's depth dependent - so
lower depth entries will have bigger adjustment
and higher depth entries will have smaller
adjustment.

Passed STC:
https://tests.stockfishchess.org/tests/view/65c3c0cbc865510db0283b21
LLR: 2.96 (-2.94,2.94) <0.00,2.00>
Total: 112032 W: 29142 L: 28705 D: 54185
Ptnml(0-2): 479, 13152, 28326, 13571, 488

Passed LTC:
https://tests.stockfishchess.org/tests/view/65c52e62c865510db02855d5
LLR: 2.96 (-2.94,2.94) <0.50,2.50>
Total: 132480 W: 33457 L: 32936 D: 66087
Ptnml(0-2): 67, 14697, 36222, 15156, 98

closes https://github.com/official-stockfish/Stockfish/pull/5047

Bench: 1168241
2024-02-11 19:53:45 +01:00
Disservin 9068fdc57b Assorted cleanups
Assorted cleanups

closes https://github.com/official-stockfish/Stockfish/pull/5046

No functional change

Co-Authored-By: Shahin M. Shahin <41402573+peregrineshahin@users.noreply.github.com>
Co-Authored-By: cj5716 <125858804+cj5716@users.noreply.github.com>
2024-02-11 19:52:00 +01:00
GoldenRare 3d5b16df7c Remove unnecessary assignments related to adjusted static evaluation
In both search and qsearch, there are instances
where we do unadjustedStaticEval = ss->staticEval
= eval/bestValue = tte->eval(), but immediately
after re-assign ss-static and eval/bestValue to
some new value, which makes the initial assignment
redundant.

closes https://github.com/official-stockfish/Stockfish/pull/5045

No functional change
2024-02-11 19:46:55 +01:00
Disservin 21dff6c276 Update CI actions
- Update codeql to v3
- Switch from dev-drprasad to native github cli
- Update softprops/action-gh-release to node 20 commit

`thollander/actions-comment-pull-request` needs to
be bumped to node20 too, but the author hasnt done
so atm

closes https://github.com/official-stockfish/Stockfish/pull/5044

No functional change
2024-02-11 19:40:33 +01:00
mstembera 9699f4f79a Fix the alignment of the transformer buffer
Fixes the issue mentioned in
https://github.com/official-stockfish/Stockfish/commit/584d9efedcde330eeb96a99215552ddfb06f52ba#r138417600.
Thanks to @cj5716 and @peregrineshahin for
spotting this!

closes https://github.com/official-stockfish/Stockfish/pull/5042

No functional change
2024-02-09 19:06:25 +01:00
Muzhen Gaming 96837bc439 Remove check extension
Passed simplification STC:
https://tests.stockfishchess.org/tests/view/65c38d2ac865510db02836cf
LLR: 2.93 (-2.94,2.94) <-1.75,0.25>
Total: 52288 W: 13578 L: 13371 D: 25339
Ptnml(0-2): 197, 6171, 13265, 6250, 261

Passed simplification LTC:
https://tests.stockfishchess.org/tests/view/65c4470ec865510db0284473
LLR: 2.95 (-2.94,2.94) <-1.75,0.25>
Total: 44958 W: 11255 L: 11055 D: 22648
Ptnml(0-2): 37, 4962, 12274, 5176, 30

closes https://github.com/official-stockfish/Stockfish/pull/5041

Bench: 1116591
2024-02-09 19:06:25 +01:00
gahtan-syarif 15093d43c4 Simplify opponent movecount reduction
This removes the reduction decrease that occured
when the previous ply had a movecount greater than
7.

Passed STC:
https://tests.stockfishchess.org/tests/view/65c3f6dac865510db0283ef6
LLR: 2.94 (-2.94,2.94) <-1.75,0.25>
Total: 11968 W: 3205 L: 2953 D: 5810
Ptnml(0-2): 38, 1310, 3064, 1506, 66

Passed LTC:
https://tests.stockfishchess.org/tests/view/65c42377c865510db0284217
LLR: 2.94 (-2.94,2.94) <-1.75,0.25>
Total: 35676 W: 9113 L: 8905 D: 17658
Ptnml(0-2): 22, 3893, 9802, 4097, 24

closes https://github.com/official-stockfish/Stockfish/pull/5040

Bench: 1148379
2024-02-09 19:06:25 +01:00
cj5716 c0107b3c27 Remove simple eval
With the recent introduction of the dual NNUE, the
need for simple eval is no longer there.

Passed STC:
https://tests.stockfishchess.org/tests/view/65c1f735c865510db0281652
LLR: 2.96 (-2.94,2.94) <-1.75,0.25>
Total: 85312 W: 22009 L: 21837 D: 41466
Ptnml(0-2): 334, 10155, 21567, 10205, 395

Passed LTC:
https://tests.stockfishchess.org/tests/view/65c2d64bc865510db0282810
LLR: 2.95 (-2.94,2.94) <-1.75,0.25>
Total: 49956 W: 12596 L: 12402 D: 24958
Ptnml(0-2): 28, 5553, 13624, 5743, 30

closes https://github.com/official-stockfish/Stockfish/pull/5037

Bench 1213676
2024-02-09 19:06:25 +01:00
Stefan Geschwentner f2984471c9 Tweak capture scoring for move ordering
Move divisor from capture scoring to good capture
check and sligthly increase it.

This has several effects:
- its a speedup because for quience and probcut
  search the division now never happens. For main
  search its delayed and can be avoided if a good
  capture triggers a cutoff
- through the higher resolution of scores we have
  a more granular sorting

STC: https://tests.stockfishchess.org/tests/view/65bf2a93c865510db027dc27
LLR: 2.93 (-2.94,2.94) <0.00,2.00>
Total: 470016 W: 122150 L: 121173 D: 226693
Ptnml(0-2): 2133, 55705, 118374, 56644, 2152

LTC: https://tests.stockfishchess.org/tests/view/65c1d16dc865510db0281339
LLR: 2.96 (-2.94,2.94) <0.50,2.50>
Total: 98988 W: 25121 L: 24667 D: 49200
Ptnml(0-2): 77, 10998, 26884, 11464, 71

closes https://github.com/official-stockfish/Stockfish/pull/5036

Bench: 1233867
2024-02-09 19:06:25 +01:00
Disservin a20726eb0b Refactor the CI workflows
This refactors the CI workflows to group some
logic and makes sure that all (pre)release
binaries are actually tested.

The screenshot below shows the execution logic of
the reworked ci,
https://github.com/Disservin/Stockfish/actions/runs/7773581379.
You can also hover over the cards to see the
execution flow.

The `matrix.json` and `arm_matrix.json` define the
binaries which will be uploaded to GitHub.
Afterwards a matrix is created and each job
compiles a profile guided build for that arch and
uploads that as an artifact to GitHub. The
Binaries/ARM_Binaries workflow's are called when
the previous step has been completed, and uploads
all artifacts to the (pre)release.

This also fixes some indentations and renames the
workflows, see
https://github.com/official-stockfish/Stockfish/actions,
where every workflow is called `Stockfish` vs
https://github.com/Disservin/Stockfish/actions. It
also increases the parallel compilation used for
make from `-j2 to -j4`.

It now also prevents the prerelease action from
running on forks.

A test release can be viewed here
https://github.com/Disservin/Stockfish/releases.

closes https://github.com/official-stockfish/Stockfish/pull/5035

No functional change
2024-02-09 19:06:25 +01:00
FauziAkram 59691d46a1 Assorted trivial cleanups
Renaming doubleExtensions variable to multiExtensions, since now we have also triple extensions.

Some extra cleanups.

Recent tests used to measure the elo worth:
https://tests.stockfishchess.org/tests/view/659fd0c379aa8af82b96abc3
https://tests.stockfishchess.org/tests/view/65a8f3da79aa8af82b9751e3
https://tests.stockfishchess.org/tests/view/65b51824c865510db0272740
https://tests.stockfishchess.org/tests/view/65b58fbfc865510db0272f5b

closes https://github.com/official-stockfish/Stockfish/pull/5032

No functional change
2024-02-09 19:06:24 +01:00
Muzhen Gaming ededadcd6f VVLTC search tune
Search parameters were tuned at 60+0.6 8-thread.
Link to the tuning attempt: https://tests.stockfishchess.org/tests/view/65b84e8dc865510db0276030

The most significant change is the triple extension parameter, from 200 to 78. This presumably improves scaling.
Additionally, the value < singularBeta - 2 condition for double extensions was removed.
This can simply be considered a parameter tweak from 2 to 0.

Passed VVLTC: https://tests.stockfishchess.org/tests/view/65baec69c865510db0278f19
LLR: 2.94 (-2.94,2.94) <0.00,2.00>
Total: 26136 W: 6564 L: 6305 D: 13267
Ptnml(0-2): 2, 2413, 7977, 2676, 0

Passed VVLTC vs passed PR #5027: https://tests.stockfishchess.org/tests/view/65bc2adfc865510db027a561
LLR: 2.95 (-2.94,2.94) <0.50,2.50>
Total: 52968 W: 13372 L: 13046 D: 26550
Ptnml(0-2): 4, 4944, 16265, 5264, 7

STC Elo estimate: https://tests.stockfishchess.org/tests/view/65be5514c865510db027cbc5

closes https://github.com/official-stockfish/Stockfish/pull/5029

Bench: 1478189
2024-02-03 17:40:07 +01:00
gab8192 e815227c30 Simplify LMR condition
Apply LMR on captures the same way it is applied on quiets

Passed Non-Reg STC:
https://tests.stockfishchess.org/tests/view/65bbf39bc865510db027a14a
LLR: 2.93 (-2.94,2.94) <-1.75,0.25>
Total: 77152 W: 19970 L: 19791 D: 37391
Ptnml(0-2): 304, 9159, 19496, 9288, 329

Passed Non-Reg LTC:
https://tests.stockfishchess.org/tests/view/65bc8889c865510db027ac9e
LLR: 2.94 (-2.94,2.94) <-1.75,0.25>
Total: 103230 W: 25997 L: 25858 D: 51375
Ptnml(0-2): 71, 11687, 27958, 11830, 69

Hit rate of removed condition (!ss->ttPv || !capture || (cutNode && (ss - 1)->moveCount > 1))
Total 1253801 Hits 1228904 Hit Rate (%) 98.0143

Hit rate of previous LMR (depth >= 2 && moveCount > 1 + rootNode && ...)
Total 1253801 Hits 727234 Hit Rate (%) 58.0023

Hit rate of simplified LMR (depth >= 2 && moveCount > 1 + rootNode)
Total 1201839 Hits 713540 Hit Rate (%) 59.3707

closes https://github.com/official-stockfish/Stockfish/pull/5028

Bench: 1438224
2024-02-03 17:30:41 +01:00
Viren6 f2b6b5cfc9 Introduce Triple Extensions
This replaces singularquietLMR with triple instead of double extending non-capture ttmoves that have value far below singularBeta. This threshold value is initially set to 200, there is scope for more scaling by reducing it as occured with double extensions.

Passed STC:
https://tests.stockfishchess.org/tests/view/65b683b8c865510db0274074
LLR: 2.95 (-2.94,2.94) <0.00,2.00>
Total: 222912 W: 58141 L: 57535 D: 107236
Ptnml(0-2): 1063, 26244, 56154, 27014, 981

Passed LTC:
https://tests.stockfishchess.org/tests/view/65bae6d4c865510db0278eb5
LLR: 2.94 (-2.94,2.94) <0.50,2.50>
Total: 66306 W: 16825 L: 16440 D: 33041
Ptnml(0-2): 40, 7374, 17952, 7735, 52

closes https://github.com/official-stockfish/Stockfish/pull/5027

bench 1394701
2024-02-03 17:26:42 +01:00
FauziAkram 56b342f9b2 Simplify the extension formula
Simplify the extension formula in the case of cutNode by removing the depth condition and always setting extension to -2.

Passed STC:
LLR: 2.97 (-2.94,2.94) <-1.75,0.25>
Total: 277280 W: 70760 L: 70802 D: 135718
Ptnml(0-2): 971, 31775, 73153, 31807, 934
https://tests.stockfishchess.org/tests/view/65ad08f779aa8af82b979dd6

Passed LTC:
LLR: 2.95 (-2.94,2.94) <-1.75,0.25>
Total: 452976 W: 112992 L: 113215 D: 226769
Ptnml(0-2): 266, 51041, 124112, 50788, 281
https://tests.stockfishchess.org/tests/view/65ae466fc865510db026a760

closes https://github.com/official-stockfish/Stockfish/pull/5021

Bench: 1492957
2024-02-03 17:09:05 +01:00
Disservin 3cce4c4cf4 Add Apple Silicon Runners to CI
GitHub CI runners are available for macOS 14, these runners are using apple silicon chips (M1).
https://github.blog/changelog/2024-01-30-github-actions-introducing-the-new-m1-macos-runner-available-to-open-source/

closes https://github.com/official-stockfish/Stockfish/pull/5025

No functional change
2024-02-03 16:55:10 +01:00
Disservin 16afec0582 Refactor pv printing
Also fix the case which is currently printing depth 0.

fixes #5019
closes https://github.com/official-stockfish/Stockfish/pull/5020

No functional change
2024-02-03 16:50:31 +01:00
Disservin 13eb023fc0 Simplify array initializations
also retire a few std::memset calls.

Passed non-regresion STC:
https://tests.stockfishchess.org/tests/view/65b8e162c865510db0276901
LLR: 2.95 (-2.94,2.94) <-1.75,0.25>
Total: 97504 W: 25294 L: 25140 D: 47070
Ptnml(1-2): 378, 11102, 25667, 11198, 407

closes https://github.com/official-stockfish/Stockfish/pull/5018

No functional change
2024-02-03 16:43:23 +01:00
Viren6 fcbb02ffde Use ttPv in depth condition of singular extensions
This replaces the PvNode condition and tte Pv call previously with using
the precomputed ttPv, and also removes the multiplier of 2.  This new
depth condition occurs with approximately equal frequency (47%) to the
old depth condition (measured when the other conditions in the if are
true), so non-linear scaling behaviour isn't expected.

Passed Non-Reg STC:
https://tests.stockfishchess.org/tests/view/65b0e132c865510db026da27
LLR: 2.97 (-2.94,2.94) <-1.75,0.25>
Total: 243232 W: 62432 L: 62437 D: 118363
Ptnml(0-2): 910, 28937, 61900, 28986, 883

Passed Non-Reg LTC:
https://tests.stockfishchess.org/tests/view/65b2053bc865510db026eea1
LLR: 2.94 (-2.94,2.94) <-1.75,0.25>
Total: 190596 W: 47666 L: 47618 D: 95312
Ptnml(0-2): 115, 21710, 51596, 21766, 111

closes https://github.com/official-stockfish/Stockfish/pull/5015

Bench: 1492957
2024-01-26 21:15:07 +01:00
Ahmed Kerimov c17ec9524d Move OnChange callback in Option ctors
Parameter 'f' is passed by value and only copied once. Moving it to
avoid unnecessary copies.

closes https://github.com/official-stockfish/Stockfish/pull/5014

No functional change
2024-01-26 21:00:41 +01:00
Michael Chaly 37bd1e774e Do more double extensions
Parameter tweak from Black Marlin chess engine. Choose a significantly
lower value that triggers in 95% of cases, compared to the usual 84% in
standard benchmark runs.

Since the introduction by
https://github.com/official-stockfish/Stockfish/commit/33a858eaa1f792b3413384a3d0993dba36aca92e
this constant has only decreased in value over time.
2-16-17-18-21-22-25-26-52-71-75-93-140

Failed STC really fast:
https://tests.stockfishchess.org/tests/view/65b11d05c865510db026df7b
LLR: -2.94 (-2.94,2.94) <0.00,2.00>
Total: 13216 W: 3242 L: 3485 D: 6489
Ptnml(0-2): 50, 1682, 3371, 1471, 34

Was reasonable at LTC:

https://tests.stockfishchess.org/tests/view/65b13e20c865510db026e210
Elo: 1.18 ± 1.5 (95%) LOS: 94.3%
Total: 50000 W: 12517 L: 12347 D: 25136
Ptnml(0-2): 31, 5598, 13579, 5754, 38
nElo: 2.45 ± 3.0 (95%) PairsRatio: 1.03

Passed VLTC with STC bounds:
https://tests.stockfishchess.org/tests/view/65b18870c865510db026e769
LLR: 2.95 (-2.94,2.94) <0.00,2.00>
Total: 30456 W: 7726 L: 7448 D: 15282
Ptnml(0-2): 6, 3111, 8717, 3387, 7

Passed VVLTC with LTC bounds:
https://tests.stockfishchess.org/tests/view/65b20b95c865510db026eef0
LLR: 2.95 (-2.94,2.94) <0.50,2.50>
Total: 36134 W: 9158 L: 8859 D: 18117
Ptnml(0-2): 3, 3455, 10850, 3758, 1

closes https://github.com/official-stockfish/Stockfish/pull/5013

Bench: 1503692
2024-01-26 20:55:16 +01:00
Disservin 1dfbde2d10 Move perft out of search
This splits the logic of search and perft. Before, threads were started,
which then constructed a search object, which then started perft and
returned immediately. All of this is unnecessary, instead uci should
start perft right away.

closes https://github.com/official-stockfish/Stockfish/pull/5008

No functional change
2024-01-26 20:52:26 +01:00
FauziAkram 3d49a99aaf Refactor history score calculation
Passed STC:
https://tests.stockfishchess.org/tests/view/65ad08b179aa8af82b979dd1
LLR: 2.93 (-2.94,2.94) <-1.75,0.25>
Total: 161376 W: 41582 L: 41498 D: 78296
Ptnml(0-2): 633, 19354, 40611, 19476, 614

Passed LTC:
https://tests.stockfishchess.org/tests/view/65af966fc865510db026c0f0
LLR: 2.95 (-2.94,2.94) <-1.75,0.25>
Total: 116526 W: 29269 L: 29143 D: 58114
Ptnml(0-2): 71, 13252, 31509, 13342, 89

closes https://github.com/official-stockfish/Stockfish/pull/5006

Bench: 1317504
2024-01-26 20:44:16 +01:00
FauziAkram 2b62c4452d Remove redundant max operation on lmrDepth
Removed a restriction that prohibited history heuristics sum in futility
pruning to exceed some negative value.

Passed STC:
LLR: 2.93 (-2.94,2.94) <-1.75,0.25>
Total: 279040 W: 71095 L: 71143 D: 136802
Ptnml(0-2): 949, 33574, 70474, 33622, 901
https://tests.stockfishchess.org/tests/view/65aaef4c79aa8af82b977631

Passed LTC:
LLR: 2.95 (-2.94,2.94) <-1.75,0.25>
Total: 75156 W: 18884 L: 18715 D: 37557
Ptnml(0-2): 52, 8445, 20408, 8628, 45
https://tests.stockfishchess.org/tests/view/65ae7ef3c865510db026abf5

closes https://github.com/official-stockfish/Stockfish/pull/5004

Bench: 1566543
2024-01-26 20:40:22 +01:00
Muzhen Gaming a6fd17f27d VLTC search tune
Search parameters were tuned using 152k games at 180+1.8.

Passed VLTC:
https://tests.stockfishchess.org/tests/view/65a7a81979aa8af82b973a20
LLR: 2.94 (-2.94,2.94) <0.00,2.00>
Total: 117338 W: 29244 L: 28848 D: 59246
Ptnml(0-2): 24, 12474, 33267, 12890, 14

Passed VVLTC:
https://tests.stockfishchess.org/tests/view/65ab246679aa8af82b977982
LLR: 2.94 (-2.94,2.94) <0.50,2.50>
Total: 28164 W: 7239 L: 6957 D: 13968
Ptnml(0-2): 3, 2651, 8490, 2937, 1

STC Elo estimate:
https://tests.stockfishchess.org/tests/view/65ac7c0979aa8af82b9792a6
Elo: -0.53 ± 2.0 (95%) LOS: 30.4%
Total: 30000 W: 7688 L: 7734 D: 14578
Ptnml(0-2): 102, 3617, 7614, 3559, 108
nElo: -1.03 ± 3.9 (95%) PairsRatio: 0.99

closes https://github.com/official-stockfish/Stockfish/pull/5003

Bench: 1235377
2024-01-21 12:49:30 +01:00
Robert Nurnberg @ elitebook a901474bf9 Update the WDL model
Update the internal WDL model. After the dual net merge, the internal
evaluations have drifted upwards a bit. With this PR
`NormalizeToPawnValue` changes from `328` to `345`.

The new model was fitted based on about 200M positions extracted from
3.4M fishtest LTC games from the last two weeks, involving SF versions
from 6deb88728f to current master.

Apart from the WDL model parameter update, this PR implements the
following changes:

WDL Model:
- an incorrect 8-move shift in master's WDL model has been fixed
- the polynomials `p_a` and `p_b` are fitted over the move range [8, 120]
- the coefficients for `p_a` and `p_b` are optimized by maximizing the
  probability of predicting the observed outcome (credits to @vondele)

SF code:
- for wdl values, move will be clamped to `max(8, min(120, move))`
- no longer clamp the internal eval to [-4000,4000]
- compute `NormalizeToPawnValue` with `round`, not `trunc`

The PR only affects displayed `cp` and `wdl` values.

closes https://github.com/official-stockfish/Stockfish/pull/5002

No functional change
2024-01-21 12:45:03 +01:00
Shahin M. Shahin ad9fcbc496 Refactor get_best_thread
Make get_best_thread function easier to understand.

Passed non-reg SMP STC:
https://tests.stockfishchess.org/tests/view/65a91c6679aa8af82b975500
LLR: 2.94 (-2.94,2.94) <-1.75,0.25>
Total: 186000 W: 46379 L: 46325 D: 93296
Ptnml(0-2): 269, 21374, 49634, 21480, 243

closes https://github.com/official-stockfish/Stockfish/pull/5001

No functional change
2024-01-21 12:42:28 +01:00
rn5f107s2 e860f620aa Reduce futility_margin further when improving
The idea of this is to unroll the futility_margin calculation to allow
for the improving flag to have a greater effect on the futility margin.
The current factor is 1.5 instead of the previous 1 resulting in a
deduction of an extra margin/2 from futilit_margin if improving. The
chosen value was not tuned, meaning that there is room for tweaking it.
This patch is partially inspired by @Vizvezdenec, who, although quite
different in execution, tested another idea where the futility_margin is
lowered further when improving [1].

[1]: (first take) https://tests.stockfishchess.org/tests/view/65a56b1879aa8af82b97164b

Passed STC:
https://tests.stockfishchess.org/tests/live_elo/65a8bfc179aa8af82b974e3c
LLR: 2.95 (-2.94,2.94) <0.00,2.00>
Total: 161152 W: 41321 L: 40816 D: 79015
Ptnml(0-2): 559, 19030, 40921, 19479, 587

Passed rebased LTC:
https://tests.stockfishchess.org/tests/live_elo/65a8b9ef79aa8af82b974dc0
LLR: 2.94 (-2.94,2.94) <0.50,2.50>
Total: 96024 W: 24172 L: 23728 D: 48124
Ptnml(0-2): 56, 10598, 26275, 11012, 71

closes https://github.com/official-stockfish/Stockfish/pull/5000

Bench: 1281703
2024-01-21 12:42:07 +01:00
Viren6 aa15a9179b Refactor ttPv reduction conditions
closes https://github.com/official-stockfish/Stockfish/pull/4999

No functional change
2024-01-21 12:33:08 +01:00
Disservin 856e60d12f Refactor NativeThread start_routine
Removes the free function and fixes the formatting for the function
call.

closes https://github.com/official-stockfish/Stockfish/pull/4995

No functional change
2024-01-21 12:21:01 +01:00
Viren6 c8bc2ce4fa Improve ttPv reduction
This patch allows a partial reduction decrease when a node is likely to
fail low, and increases the reduction decrease when a node has failed
high.

Passed STC:
https://tests.stockfishchess.org/tests/view/65a626e779aa8af82b9722bc
LLR: 2.93 (-2.94,2.94) <0.00,2.00>
Total: 157824 W: 40332 L: 39835 D: 77657
Ptnml(0-2): 543, 18617, 40098, 19108, 546

Passed LTC:
https://tests.stockfishchess.org/tests/view/65a7290279aa8af82b97328a
LLR: 2.94 (-2.94,2.94) <0.50,2.50>
Total: 57228 W: 14475 L: 14111 D: 28642
Ptnml(0-2): 34, 6278, 15633, 6628, 41

closes https://github.com/official-stockfish/Stockfish/pull/4994

Bench: 1364759
2024-01-17 18:56:37 +01:00
FauziAkram 9a9702d668 Remove threatenedByPawn from rook threat
Can be simplified away.

Passed STC:
https://tests.stockfishchess.org/tests/view/65a3fa4179aa8af82b96face
LLR: 2.92 (-2.94,2.94) <-1.75,0.25>
Total: 30592 W: 7903 L: 7674 D: 15015
Ptnml(0-2): 96, 3590, 7711, 3787, 112

Passed LTC:
https://tests.stockfishchess.org/tests/view/65a42b9a79aa8af82b96fe88
LLR: 2.95 (-2.94,2.94) <-1.75,0.25>
Total: 73656 W: 18382 L: 18212 D: 37062
Ptnml(0-2): 47, 8287, 19981, 8475, 38

closes https://github.com/official-stockfish/Stockfish/pull/4993

Bench: 1430061
2024-01-17 18:55:44 +01:00
pb00067 0fbad56c50 Refactor code for correcting unadjustedStaticEval
Passed non-regression STC:
https://tests.stockfishchess.org/tests/live_elo/65a4df6a79aa8af82b970ca0
LLR: 2.94 (-2.94,2.94) <-1.75,0.25>
Total: 43328 W: 11103 L: 10892 D: 21333
Ptnml(0-2): 120, 4920, 11407, 5063, 154

https://github.com/official-stockfish/Stockfish/pull/4992

No functional change
2024-01-17 18:51:03 +01:00
Torsten Hellwig 6c02329860 Fix dotprod detection
This fixes the detection of dotprod capable CPUs. Previously it looked
for the `dotprod` flag, but this does not exist
(https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git/tree/arch/arm64/kernel/cpuinfo.c#n50).
The correct flag that specifies the dotprod capability is the `asimddp`
flag.

fixes #4931

closes https://github.com/official-stockfish/Stockfish/pull/4991

No functional change
2024-01-17 18:32:20 +01:00
Shahin M. Shahin 0c7f56dea6 Fix mated-in behaviour
This addresses the issue where Stockfish may output non-proven checkmate
scores if the search is prematurely halted, either due to a time control
or node limit, before it explores other possibilities where the
checkmate score could have been delayed or refuted.

The fix also replaces staving off from proven mated scores in a
multithread environment making use of the threads instead of a negative
effect with multithreads (1t was better in proving mated in scores than
more threads).

Issue reported on mate tracker repo by and this PR is co-authored with
@robertnurnberg Special thanks to @AndyGrant for outlining that a fix is
eventually possible.

Passed Adj off SMP STC:
https://tests.stockfishchess.org/tests/view/65a125d779aa8af82b96c3eb
LLR: 2.96 (-2.94,2.94) <-1.75,0.25>
Total: 303256 W: 75823 L: 75892 D: 151541
Ptnml(0-2): 406, 35269, 80395, 35104, 454

Passed Adj off SMP LTC:
https://tests.stockfishchess.org/tests/view/65a37add79aa8af82b96f0f7
LLR: 2.94 (-2.94,2.94) <-1.75,0.25>
Total: 56056 W: 13951 L: 13770 D: 28335
Ptnml(0-2): 11, 5910, 16002, 6097, 8

Passed all tests in matetrack without any better mate for opponent found in 1t and multithreads.

Fixed bugs in https://github.com/official-stockfish/Stockfish/pull/4976

closes https://github.com/official-stockfish/Stockfish/pull/4990

Bench: 1308279

Co-Authored-By: Robert Nürnberg <28635489+robertnurnberg@users.noreply.github.com>
2024-01-17 18:12:16 +01:00
Disservin f15e4f50aa Update installation guide links in CONTRIBUTING.md
Link to more user friendly installation guides, these are shorter and
easier to follow.

closes https://github.com/official-stockfish/Stockfish/pull/4985

No functional change
2024-01-17 18:06:20 +01:00
Disservin a5675f19d8 Remove global TB variables from search.cpp
Follow up cleanup of #4968, removes the global variables from search and
instead uses a dedicated tb config struct.

closes https://github.com/official-stockfish/Stockfish/pull/4982

No functional change
2024-01-17 18:05:00 +01:00
mstembera 32e46fc47f Remove some outdated SIMD functions
Since https://github.com/official-stockfish/Stockfish/pull/4391 the x2
SIMD functions no longer serve any useful purpose.

Passed non-regression STC:
https://tests.stockfishchess.org/tests/view/659cf42579aa8af82b966d55
LLR: 2.95 (-2.94,2.94) <-1.75,0.25>
Total: 67392 W: 17222 L: 17037 D: 33133
Ptnml(0-2): 207, 7668, 17762, 7851, 208

closes https://github.com/official-stockfish/Stockfish/pull/4974

No functional change
2024-01-17 18:04:29 +01:00
Disservin b5e8169a85 Add ignoreRevsFile to CONTRIBUTING.md
closes https://github.com/official-stockfish/Stockfish/pull/4980

No functional change
2024-01-14 10:46:13 +01:00
Disservin 88331add0d Remove the dependency on a Worker from evaluate
Also remove dead code, `rootSimpleEval` is no longer used since the introduction of dual net.
`iterBestValue` is also no longer used in evaluate and can be reduced to a local variable.

closes https://github.com/official-stockfish/Stockfish/pull/4979

No functional change
2024-01-14 10:46:13 +01:00
Disservin 12e97701b2 Fix UCI options
Fixes the type for 'Clear Hash' and uses MAX_MOVES for 'MultiPV' as we
had before.

No functional change
2024-01-14 10:46:13 +01:00
Disservin cf5b070913 Remove unused method
init() is no longer used, and was previously replaced by the clear
function.

fixes https://github.com/official-stockfish/Stockfish/issues/4981

No functional change
2024-01-14 00:30:06 +01:00
mstembera eec361f64c Simplify bad quiets
The main difference is that instead of returning the first bad quiet as
a good one we fall through. This is actually more correct and simpler
to implement.

Non regression STC:
https://tests.stockfishchess.org/tests/view/659bbb3479aa8af82b964ec7
LLR: 2.93 (-2.94,2.94) <-1.75,0.25>
Total: 150944 W: 38399 L: 38305 D: 74240
Ptnml(0-2): 485, 18042, 38298, 18188, 459

Non regression LTC:
https://tests.stockfishchess.org/tests/view/659c6e6279aa8af82b9660eb
LLR: 2.96 (-2.94,2.94) <-1.75,0.25>
Total: 192060 W: 47871 L: 47823 D: 96366
Ptnml(0-2): 144, 21912, 51845, 22010, 119

The cutoff is now -8K instead of -7.5K.
-7.5K failed. https://tests.stockfishchess.org/tests/view/659a1f4b79aa8af82b962a0e
This was likely a false negative.

closes https://github.com/official-stockfish/Stockfish/pull/4975

Bench: 1308279
2024-01-13 19:40:53 +01:00
FauziAkram 3372ee9c26 Remove threatenedByPawn term for queen threats
Passed STC:
https://tests.stockfishchess.org/tests/view/659d614c79aa8af82b9677d0
LLR: 2.93 (-2.94,2.94) <-1.75,0.25>
Total: 151776 W: 38690 L: 38597 D: 74489
Ptnml(0-2): 522, 17841, 39015, 18042, 468

Passed LTC:
https://tests.stockfishchess.org/tests/view/659d94d379aa8af82b967cb2
LLR: 2.95 (-2.94,2.94) <-1.75,0.25>
Total: 91908 W: 23075 L: 22924 D: 45909
Ptnml(0-2): 70, 10311, 25037, 10470, 66

closes https://github.com/official-stockfish/Stockfish/pull/4977

Bench: 1266493
2024-01-13 19:40:53 +01:00
Disservin a107910951 Refactor global variables
This aims to remove some of the annoying global structure which Stockfish has.

Overall there is no major elo regression to be expected.

Non regression SMP STC (paused, early version):
https://tests.stockfishchess.org/tests/view/65983d7979aa8af82b9608f1
LLR: 0.23 (-2.94,2.94) <-1.75,0.25>
Total: 76232 W: 19035 L: 19096 D: 38101
Ptnml(0-2): 92, 8735, 20515, 8690, 84

Non regression STC (early version):
https://tests.stockfishchess.org/tests/view/6595b3a479aa8af82b95da7f
LLR: 2.93 (-2.94,2.94) <-1.75,0.25>
Total: 185344 W: 47027 L: 46972 D: 91345
Ptnml(0-2): 571, 21285, 48943, 21264, 609

Non regression SMP STC:
https://tests.stockfishchess.org/tests/view/65a0715c79aa8af82b96b7e4
LLR: 2.94 (-2.94,2.94) <-1.75,0.25>
Total: 142936 W: 35761 L: 35662 D: 71513
Ptnml(0-2): 209, 16400, 38135, 16531, 193

These global structures/variables add hidden dependencies and allow data
to be mutable from where it shouldn't it be (i.e. options). They also
prevent Stockfish from internal selfplay, which would be a nice thing to
be able to do, i.e. instantiate two Stockfish instances and let them
play against each other. It will also allow us to make Stockfish a
library, which can be easier used on other platforms.

For consistency with the old search code, `thisThread` has been kept,
even though it is not strictly necessary anymore. This the first major
refactor of this kind (in recent time), and future changes are required,
to achieve the previously described goals. This includes cleaning up the
dependencies, transforming the network to be self contained and coming
up with a plan to deal with proper tablebase memory management (see
comments for more information on this).

The removal of these global structures has been discussed in parts with
Vondele and Sopel.

closes https://github.com/official-stockfish/Stockfish/pull/4968

No functional change
2024-01-13 19:40:53 +01:00
Linmiao Xu 6deb88728f Update default main net to nn-baff1edbea57.nnue
Created by retraining the previous main net nn-b1e55edbea57.nnue with:
- some of the same options as before: ranger21 optimizer, more WDL
  skipping
- adding T80 aug filter-v6, sep, and oct 2023 data to the previous best
  dataset
- increasing training loss for positions where predicted win rates were
  higher than estimated match results from training data position scores

```yaml
experiment-name: 2560--S8-r21-more-wdl-skip-10p-more-loss-high-q-sk28

training-dataset:
  # https://github.com/official-stockfish/Stockfish/pull/4782
  - /data/S6-1ee1aba5ed.binpack
  - /data/test80-aug2023-2tb7p.v6.min.binpack
  - /data/test80-sep2023-2tb7p.binpack
  - /data/test80-oct2023-2tb7p.binpack
early-fen-skipping: 28

start-from-engine-test-net: True
nnue-pytorch-branch: linrock/nnue-pytorch/r21-more-wdl-skip-10p-more-loss-high-q

num-epochs: 1000
lr: 4.375e-4
gamma: 0.995
start-lambda: 1.0
end-lambda: 0.7
```

Training data can be found at:
https://robotmoon.com/nnue-training-data/

Training loss was increased by 10% for positions where predicted win
rates were higher than suggested by the win rate model based on the
training data, by multiplying with: ((qf > pt) * 0.1 + 1). This was a
variant of experiments from Sopel's NNUE training & experimentation log:
https://docs.google.com/document/d/1gTlrr02qSNKiXNZ_SuO4-RjK4MXBiFlLE6jvNqqMkAY
Experiment 302 - increase loss when prediction too high, vondele’s idea
Experiment 309 - increase loss when prediction too high, normalize in a
batch

Passed STC:
https://tests.stockfishchess.org/tests/view/6597a21c79aa8af82b95fd5c
LLR: 2.93 (-2.94,2.94) <0.00,2.00>
Total: 148320 W: 37960 L: 37475 D: 72885
Ptnml(0-2): 542, 17565, 37383, 18206, 464

Passed LTC:
https://tests.stockfishchess.org/tests/view/659834a679aa8af82b960845
LLR: 2.94 (-2.94,2.94) <0.50,2.50>
Total: 55188 W: 13955 L: 13592 D: 27641
Ptnml(0-2): 34, 6162, 14834, 6535, 29

closes https://github.com/official-stockfish/Stockfish/pull/4972

Bench: 1219824
2024-01-08 18:34:36 +01:00
Disservin 99cdb920fc Cleanup Evalfile handling
This cleans up the EvalFile handling after the merge of #4915,
which has become a bit confusing on what it is actually doing.

closes https://github.com/official-stockfish/Stockfish/pull/4971

No functional change
2024-01-08 18:33:38 +01:00
Disservin 7c5e3f2865 Prefix abs with std:: 2024-01-07 21:41:52 +01:00
Linmiao Xu f09adaa4a4 Update smallnet to nn-baff1ede1f90.nnue with wider eval range
Created by training an L1-128 net from scratch with a wider range of
evals in the training data and wld-fen-skipping disabled during
training. The differences in this training data compared to the first
dual nnue PR are:

- removal of all positions with 3 pieces
- when piece count >= 16, keep positions with simple eval above 750
- when piece count < 16, remove positions with simple eval above 3000

The asymmetric data filtering was meant to flatten the training data
piece count distribution, which was previously heavily skewed towards
positions with low piece counts.

Additionally, the simple eval range where the smallnet is used was
widened to cover more positions previously evaluated by the big net and
simple eval.

```yaml
experiment-name: 128--S1-hse-S7-v4-S3-v1-no-wld-skip

training-dataset:
  - /data/hse/S3/leela96-filt-v2.min.high-simple-eval-1k.binpack
  - /data/hse/S3/dfrc99-16tb7p-eval-filt-v2.min.high-simple-eval-1k.binpack
  - /data/hse/S3/test80-apr2022-16tb7p.min.high-simple-eval-1k.binpack

  - /data/hse/S7/test60-2020-2tb7p.v6-3072.high-simple-eval-v4.binpack
  - /data/hse/S7/test60-novdec2021-12tb7p-filter-v6-dd.min-mar2023.unmin.high-simple-eval-v4.binpack

  - /data/hse/S7/test77-nov2021-2tb7p.v6-3072.min.high-simple-eval-v4.binpack
  - /data/hse/S7/test77-dec2021-16tb7p-filter-v6-dd.min-mar2023.unmin.high-simple-eval-v4.binpack
  - /data/hse/S7/test77-jan2022-2tb7p.high-simple-eval-v4.binpack

  - /data/hse/S7/test78-jantomay2022-16tb7p-filter-v6-dd.min-mar2023.unmin.high-simple-eval-v4.binpack
  - /data/hse/S7/test78-juntosep2022-16tb7p-filter-v6-dd.min-mar2023.unmin.high-simple-eval-v4.binpack

  - /data/hse/S7/test79-apr2022-16tb7p-filter-v6-dd.min-mar2023.unmin.high-simple-eval-v4.binpack
  - /data/hse/S7/test79-may2022-16tb7p-filter-v6-dd.min-mar2023.unmin.high-simple-eval-v4.binpack

  - /data/hse/S7/test80-may2022-16tb7p.high-simple-eval-v4.binpack
  - /data/hse/S7/test80-jun2022-16tb7p-filter-v6-dd.min-mar2023.unmin.high-simple-eval-v4.binpack
  - /data/hse/S7/test80-jul2022-16tb7p.v6-dd.min.high-simple-eval-v4.binpack
  - /data/hse/S7/test80-aug2022-16tb7p-filter-v6-dd.min-mar2023.unmin.high-simple-eval-v4.binpack
  - /data/hse/S7/test80-sep2022-16tb7p-filter-v6-dd.min-mar2023.unmin.high-simple-eval-v4.binpack
  - /data/hse/S7/test80-oct2022-16tb7p.v6-dd.high-simple-eval-v4.binpack
  - /data/hse/S7/test80-nov2022-16tb7p-v6-dd.min.high-simple-eval-v4.binpack

  - /data/hse/S7/test80-jan2023-3of3-16tb7p-filter-v6-dd.min-mar2023.unmin.high-simple-eval-v4.binpack
  - /data/hse/S7/test80-feb2023-16tb7p-filter-v6-dd.min-mar2023.unmin.high-simple-eval-v4.binpack
  - /data/hse/S7/test80-mar2023-2tb7p.v6-sk16.min.high-simple-eval-v4.binpack
  - /data/hse/S7/test80-apr2023-2tb7p-filter-v6-sk16.min.high-simple-eval-v4.binpack
  - /data/hse/S7/test80-may2023-2tb7p.v6.min.high-simple-eval-v4.binpack
  - /data/hse/S7/test80-jun2023-2tb7p.v6-3072.min.high-simple-eval-v4.binpack
  - /data/hse/S7/test80-jul2023-2tb7p.v6-3072.min.high-simple-eval-v4.binpack
  - /data/hse/S7/test80-aug2023-2tb7p.v6.min.high-simple-eval-v4.binpack
  - /data/hse/S7/test80-sep2023-2tb7p.high-simple-eval-v4.binpack
  - /data/hse/S7/test80-oct2023-2tb7p.high-simple-eval-v4.binpack

wld-fen-skipping: False
start-from-engine-test-net: False

nnue-pytorch-branch: linrock/nnue-pytorch/L1-128
engine-test-branch: linrock/Stockfish/L1-128-nolazy
engine-base-branch: linrock/Stockfish/L1-128

num-epochs: 500
start-lambda: 1.0
end-lambda: 1.0
```

Experiment yaml configs converted to easy_train.sh commands with:
https://github.com/linrock/nnue-tools/blob/4339954/yaml_easy_train.py

Binpacks interleaved at training time with:
https://github.com/official-stockfish/nnue-pytorch/pull/259

FT weights permuted with 10k positions from fishpack32.binpack with:
https://github.com/official-stockfish/nnue-pytorch/pull/254

Data filtered for high simple eval positions (v4) with:
https://github.com/linrock/Stockfish/blob/b9c8440/src/tools/transform.cpp#L640-L675

Training data can be found at:
https://robotmoon.com/nnue-training-data/

Local elo at 25k nodes per move of
L1-128 smallnet (nnue-only eval) vs. L1-128 trained on standard S1 data:
nn-epoch319.nnue : -241.7 +/- 3.2

Passed STC vs. 36db936:
https://tests.stockfishchess.org/tests/view/6576b3484d789acf40aabbfe
LLR: 2.94 (-2.94,2.94) <0.00,2.00>
Total: 21920 W: 5680 L: 5381 D: 10859
Ptnml(0-2): 82, 2488, 5520, 2789, 81

Passed LTC vs. DualNNUE #4915:
https://tests.stockfishchess.org/tests/view/65775c034d789acf40aac7e3
LLR: 2.95 (-2.94,2.94) <0.50,2.50>
Total: 147606 W: 36619 L: 36063 D: 74924
Ptnml(0-2): 98, 16591, 39891, 17103, 120

closes https://github.com/official-stockfish/Stockfish/pull/4919

Bench: 1438336
2024-01-07 21:20:15 +01:00
Linmiao Xu 584d9efedc Dual NNUE with L1-128 smallnet
Credit goes to @mstembera for:
- writing the code enabling dual NNUE:
  https://github.com/official-stockfish/Stockfish/pull/4898
- the idea of trying L1-128 trained exclusively on high simple eval
  positions

The L1-128 smallnet is:
- epoch 399 of a single-stage training from scratch
- trained only on positions from filtered data with high material
  difference
  - defined by abs(simple_eval) > 1000

```yaml
experiment-name: 128--S1-only-hse-v2

training-dataset:
  - /data/hse/S3/dfrc99-16tb7p-eval-filt-v2.min.high-simple-eval-1k.binpack
  - /data/hse/S3/leela96-filt-v2.min.high-simple-eval-1k.binpack
  - /data/hse/S3/test80-apr2022-16tb7p.min.high-simple-eval-1k.binpack

  - /data/hse/S7/test60-2020-2tb7p.v6-3072.high-simple-eval-1k.binpack
  - /data/hse/S7/test60-novdec2021-12tb7p-filter-v6-dd.min-mar2023.unmin.high-simple-eval-1k.binpack

  - /data/hse/S7/test77-nov2021-2tb7p.v6-3072.min.high-simple-eval-1k.binpack
  - /data/hse/S7/test77-dec2021-16tb7p-filter-v6-dd.min-mar2023.unmin.high-simple-eval-1k.binpack
  - /data/hse/S7/test77-jan2022-2tb7p.high-simple-eval-1k.binpack

  - /data/hse/S7/test78-jantomay2022-16tb7p-filter-v6-dd.min-mar2023.unmin.high-simple-eval-1k.binpack
  - /data/hse/S7/test78-juntosep2022-16tb7p-filter-v6-dd.min-mar2023.unmin.high-simple-eval-1k.binpack

  - /data/hse/S7/test79-apr2022-16tb7p-filter-v6-dd.min-mar2023.unmin.high-simple-eval-1k.binpack
  - /data/hse/S7/test79-may2022-16tb7p-filter-v6-dd.min-mar2023.unmin.high-simple-eval-1k.binpack

  # T80 2022
  - /data/hse/S7/test80-may2022-16tb7p.high-simple-eval-1k.binpack
  - /data/hse/S7/test80-jun2022-16tb7p-filter-v6-dd.min-mar2023.unmin.high-simple-eval-1k.binpack
  - /data/hse/S7/test80-jul2022-16tb7p.v6-dd.min.high-simple-eval-1k.binpack
  - /data/hse/S7/test80-aug2022-16tb7p-filter-v6-dd.min-mar2023.unmin.high-simple-eval-1k.binpack
  - /data/hse/S7/test80-sep2022-16tb7p-filter-v6-dd.min-mar2023.unmin.high-simple-eval-1k.binpack
  - /data/hse/S7/test80-oct2022-16tb7p.v6-dd.high-simple-eval-1k.binpack
  - /data/hse/S7/test80-nov2022-16tb7p-v6-dd.min.high-simple-eval-1k.binpack

  # T80 2023
  - /data/hse/S7/test80-jan2023-3of3-16tb7p-filter-v6-dd.min-mar2023.unmin.high-simple-eval-1k.binpack
  - /data/hse/S7/test80-feb2023-16tb7p-filter-v6-dd.min-mar2023.unmin.high-simple-eval-1k.binpack
  - /data/hse/S7/test80-mar2023-2tb7p.v6-sk16.min.high-simple-eval-1k.binpack
  - /data/hse/S7/test80-apr2023-2tb7p-filter-v6-sk16.min.high-simple-eval-1k.binpack
  - /data/hse/S7/test80-may2023-2tb7p.v6.min.high-simple-eval-1k.binpack
  - /data/hse/S7/test80-jun2023-2tb7p.v6-3072.min.high-simple-eval-1k.binpack
  - /data/hse/S7/test80-jul2023-2tb7p.v6-3072.min.high-simple-eval-1k.binpack
  - /data/hse/S7/test80-aug2023-2tb7p.v6.min.high-simple-eval-1k.binpack
  - /data/hse/S7/test80-sep2023-2tb7p.high-simple-eval-1k.binpack
  - /data/hse/S7/test80-oct2023-2tb7p.high-simple-eval-1k.binpack

start-from-engine-test-net: False

nnue-pytorch-branch: linrock/nnue-pytorch/L1-128
engine-test-branch: linrock/Stockfish/L1-128-nolazy
engine-base-branch: linrock/Stockfish/L1-128

num-epochs: 500
lambda: 1.0
```

Experiment yaml configs converted to easy_train.sh commands with:
https://github.com/linrock/nnue-tools/blob/4339954/yaml_easy_train.py

Binpacks interleaved at training time with:
https://github.com/official-stockfish/nnue-pytorch/pull/259

Data filtered for high simple eval positions with:
https://github.com/linrock/nnue-data/blob/32d6a68/filter_high_simple_eval_plain.py
https://github.com/linrock/Stockfish/blob/61dbfe/src/tools/transform.cpp#L626-L655

Training data can be found at:
https://robotmoon.com/nnue-training-data/

Local elo at 25k nodes per move of
L1-128 smallnet (nnue-only eval) vs. L1-128 trained on standard S1 data:
nn-epoch399.nnue : -318.1 +/- 2.1

Passed STC:
https://tests.stockfishchess.org/tests/view/6574cb9d95ea6ba1fcd49e3b
LLR: 2.93 (-2.94,2.94) <0.00,2.00>
Total: 62432 W: 15875 L: 15521 D: 31036
Ptnml(0-2): 177, 7331, 15872, 7633, 203

Passed LTC:
https://tests.stockfishchess.org/tests/view/6575da2d4d789acf40aaac6e
LLR: 2.94 (-2.94,2.94) <0.50,2.50>
Total: 64830 W: 16118 L: 15738 D: 32974
Ptnml(0-2): 43, 7129, 17697, 7497, 49

closes https://github.com/official-stockfish/Stockfish/pulls

Bench: 1330050

Co-Authored-By: mstembera <5421953+mstembera@users.noreply.github.com>
2024-01-07 21:15:52 +01:00
mstembera a5a76a6370 Introduce BAD_QUIET movepicker stage
Split quiets into good and bad as we do with captures. When we find
the first quiet move below a certain threshold that has been sorted we
consider all subsequent quiets bad.  Inspired by @locutus2 idea to skip
bad captures.

Passed STC:
https://tests.stockfishchess.org/tests/view/6597759f79aa8af82b95fa17
LLR: 2.94 (-2.94,2.94) <0.00,2.00>
Total: 138688 W: 35566 L: 35096 D: 68026
Ptnml(0-2): 476, 16367, 35183, 16847, 471

Passed LTC:
https://tests.stockfishchess.org/tests/view/6598583c79aa8af82b960ad0
LLR: 2.94 (-2.94,2.94) <0.50,2.50>
Total: 84108 W: 21468 L: 21048 D: 41592
Ptnml(0-2): 38, 9355, 22858, 9755, 48

closes https://github.com/official-stockfish/Stockfish/pull/4970

Bench: 1336907
2024-01-07 13:41:50 +01:00
Disservin 19f9a197be Add .git-blame-ignore-revs
Add a `.git-blame-ignore-revs` file which can be used to skip specified
commits when blaming, this is useful to ignore formatting commits, like
clang-format #4790.

Github blame automatically supports this file format, as well as other
third party tools. Git itself needs to be told about the file name to
work, the following command will add it to the current git repo. `git
config blame.ignoreRevsFile .git-blame-ignore-revs`, alternatively one
has to specify it with every blame. `git blame --ignore-revs-file
.git-blame-ignore-revs search.cpp`

Supported since git 2.23.

closes https://github.com/official-stockfish/Stockfish/pull/4969

No functional change
2024-01-07 13:38:55 +01:00
Michael Chaly 6f9071c643 Tweak usage of correction history
Instead of using linear formula use quadratic one. Maximum impact of
correction history is doubled this way, it breaks even with previous
formula on half of maximum value.

Passed STC:
https://tests.stockfishchess.org/tests/view/659591e579aa8af82b95d7e8
LLR: 2.93 (-2.94,2.94) <0.00,2.00>
Total: 225216 W: 57616 L: 57019 D: 110581
Ptnml(0-2): 747, 26677, 57201, 27198, 785

Passed LTC:
https://tests.stockfishchess.org/tests/view/6596ee0b79aa8af82b95f08a
LLR: 2.94 (-2.94,2.94) <0.50,2.50>
Total: 73314 W: 18524 L: 18125 D: 36665
Ptnml(0-2): 41, 8159, 19875, 8524, 58

closes https://github.com/official-stockfish/Stockfish/pull/4967

Bench: 1464785
2024-01-07 13:37:28 +01:00
Miguel Lahoz a5f7386efb Remove unneeded operator overload macros
Only Direction type is using two of the enable overload macros.
Aside from this, only two of the overloads are even being used.

Therefore, we can just define the needed overloads and remove the macros.

closes https://github.com/official-stockfish/Stockfish/pull/4966

No functional change.
2024-01-07 13:37:12 +01:00
FauziAkram 8b4583bce7 Remove redundant int cast
Remove a redundant int cast in the calculation of fwdOut. The variable
OutputType is already defined as std::int32_t, which is an integer type, making
the cast unnecessary.

closes https://github.com/official-stockfish/Stockfish/pull/4961

No functional change
2024-01-04 15:56:53 +01:00
Disservin b987d4f033 Use type aliases instead of enums for Value types
The primary rationale behind this lies in the fact that enums were not
originally designed to be employed in the manner we currently utilize them.

The Value enum was used like a type alias throughout the code and was often
misused. Furthermore, changing the underlying size of the enum to int16_t broke
everything, mostly because of the operator overloads for the Value enum, were
causing data to be truncated. Since Value is now a type alias, the operator
overloads are no longer required.

Passed Non-Regression STC:
https://tests.stockfishchess.org/tests/view/6593b8bb79aa8af82b95b401
LLR: 2.95 (-2.94,2.94) <-1.75,0.25>
Total: 235296 W: 59919 L: 59917 D: 115460
Ptnml(0-2): 743, 27085, 62054, 26959, 807

closes https://github.com/official-stockfish/Stockfish/pull/4960

No functional change
2024-01-04 15:54:23 +01:00
RainRat 4930892985 Fix typo in tbprobe.cpp
closes https://github.com/official-stockfish/Stockfish/pull/4959

No functional change
2024-01-04 15:51:56 +01:00
Disservin cafbe8e8e8 Change the Move enum to a class
This changes the Move enum to a class, this way
all move related functions can be moved into the class
and be more self contained.

closes https://github.com/official-stockfish/Stockfish/pull/4958

No functional change
2024-01-04 15:51:04 +01:00
Viren6 28f8663f39 Modify ttPV reduction
This patch modifies ttPV reduction by reducing 1 more unless ttValue is above alpha.

Inspired from @pb00068 https://tests.stockfishchess.org/tests/view/658060796a3b4f6202215f1f

Passed STC:
https://tests.stockfishchess.org/tests/view/6591867679aa8af82b958328
LLR: 2.94 (-2.94,2.94) <0.00,2.00>
Total: 37856 W: 9727 L: 9407 D: 18722
Ptnml(0-2): 99, 4444, 9568, 4672, 145

Passed LTC:
https://tests.stockfishchess.org/tests/view/6591d9b679aa8af82b958a6c
LLR: 2.94 (-2.94,2.94) <0.50,2.50>
Total: 128256 W: 32152 L: 31639 D: 64465
Ptnml(0-2): 64, 14364, 34772, 14851, 77

closes https://github.com/official-stockfish/Stockfish/pull/4957

Bench: 1176235
2024-01-04 15:49:33 +01:00
FauziAkram 5546bc0a26 Simplification of partial_insertion_sort formula.
Passed STC:
https://tests.stockfishchess.org/tests/view/6590110879aa8af82b9562e9
LLR: 2.94 (-2.94,2.94) <-1.75,0.25>
Total: 134880 W: 34468 L: 34355 D: 66057
Ptnml(0-2): 476, 16060, 34220, 16243, 441

Passed LTC:
https://tests.stockfishchess.org/tests/view/659156ca79aa8af82b957f07
LLR: 2.94 (-2.94,2.94) <-1.75,0.25>
Total: 60780 W: 15179 L: 14996 D: 30605
Ptnml(0-2): 27, 6847, 16464, 7020, 32

closes https://github.com/official-stockfish/Stockfish/pull/4955

Bench: 1338331
2024-01-04 15:47:37 +01:00
Disservin 444f03ee95 Update copyright year
closes https://github.com/official-stockfish/Stockfish/pull/4954

No functional change
2024-01-04 15:47:10 +01:00
Disservin a25f48a236 Silence security alert warning about possible infinite loop
As some have noticed, a security alert has been complaining about a for loop in
our TB code for quite some now. Though it was never a real issue, so not of high
importance.

A few lines earlier the symlen vector is resized
`d->symlen.resize(number<uint16_t, LittleEndian>(data));` while this code seems
odd at first, it resizes the array to at most (2 << 16) - 1 elements, basically
making the infinite loop issue impossible to occur.

closes https://github.com/official-stockfish/Stockfish/pull/4953

No functional change
2024-01-04 15:45:33 +01:00
Joseph Huang 154abb337e Lower MultiPV max to MAX_MOVES
Link max value of MultiPV to that of MAX_MOVES which is 256

closes https://github.com/official-stockfish/Stockfish/pull/4951

No functional change
2024-01-04 15:45:03 +01:00
Disservin 0fca5605fa Fix formatting in search.cpp
fixes the formatting for 1fe562fdf3
2024-01-01 02:31:25 +01:00
Stefan Geschwentner 3cfaef7431 Tweak static eval history update
Modify the applied static eval bonus for main and pawn history with different
factors for positive and negative values.

Passed STC:
https://tests.stockfishchess.org/tests/view/659132e179aa8af82b957bb0
LLR: 2.93 (-2.94,2.94) <0.00,2.00>
Total: 12512 W: 3308 L: 3027 D: 6177
Ptnml(0-2): 32, 1372, 3189, 1609, 54

Passed LTC:
https://tests.stockfishchess.org/tests/view/65913e3d79aa8af82b957cd2
LLR: 2.94 (-2.94,2.94) <0.50,2.50>
Total: 35946 W: 9128 L: 8809 D: 18009
Ptnml(0-2): 19, 3879, 9862, 4190, 23

closes https://github.com/official-stockfish/Stockfish/pull/4952

Bench: 1392883
2023-12-31 20:09:09 +01:00
Michael Chaly b4d995d0d9 Introduce static evaluation correction history
Idea from Caissa (https://github.com/Witek902/Caissa) chess engine.

With given pawn structure collect data with how often search result and by how
much it was better / worse than static evalution of position and use it to
adjust static evaluation of positions with given pawn structure. Details:

1. excludes positions with fail highs and moves producing it being a capture;
2. update value is function of not only difference between best value and static
   evaluation but also is multiplied by linear function of depth;
3. maximum update value is maximum value of correction history divided by 2;
4. correction history itself is divided by 32 when applied so maximum value of
   static evaluation adjustment is 32 internal units.

Passed STC:
https://tests.stockfishchess.org/tests/view/658fc7b679aa8af82b955cac
LLR: 2.96 (-2.94,2.94) <0.00,2.00>
Total: 128672 W: 32757 L: 32299 D: 63616
Ptnml(0-2): 441, 15241, 32543, 15641, 470

Passed LTC:
https://tests.stockfishchess.org/tests/view/65903f6979aa8af82b9566f1
LLR: 2.95 (-2.94,2.94) <0.50,2.50>
Total: 97422 W: 24626 L: 24178 D: 48618
Ptnml(0-2): 41, 10837, 26527, 11245, 61

closes https://github.com/official-stockfish/Stockfish/pull/4950

Bench: 1157852
2023-12-31 20:00:06 +01:00
FauziAkram 4ff297a6df Mark square_bb() as constexpr
closes https://github.com/official-stockfish/Stockfish/pull/4949

No functional change
2023-12-31 19:58:10 +01:00
FauziAkram 1fe562fdf3 Simplify the improving flag calculation
Passed STC:
https://tests.stockfishchess.org/tests/view/658ec29979aa8af82b9547f6
LLR: 2.93 (-2.94,2.94) <-1.75,0.25>
Total: 93408 W: 23747 L: 23587 D: 46074
Ptnml(0-2): 340, 11178, 23527, 11300, 359

Passed LTC:
https://tests.stockfishchess.org/tests/view/658f73e479aa8af82b9555b6
LLR: 2.94 (-2.94,2.94) <-1.75,0.25>
Total: 64026 W: 15984 L: 15806 D: 32236
Ptnml(0-2): 31, 7113, 17552, 7281, 36

closes https://github.com/official-stockfish/Stockfish/pull/4948

Bench: 1143749
2023-12-31 19:57:34 +01:00
FauziAkram 833a2e2bc0 Cleanup comments
Tests used to derive some Elo worth comments:
https://tests.stockfishchess.org/tests/view/656a7f4e136acbc573555a31
https://tests.stockfishchess.org/tests/view/6585fb455457644dc984620f

closes https://github.com/official-stockfish/Stockfish/pull/4945

No functional change
2023-12-31 19:54:27 +01:00
Tobias Steinmann 4f99dfcae2 Update Makefile for android x86-64 builds
For developing an Android GUI it can be helpful to use the Emulator on Windows.
Therefor an android_x86-64 library of Stockfish is needed. It would be nice to
compile it "out-of-the-box".

This change is originally suggested by Craftyawesome

closes https://github.com/official-stockfish/Stockfish/pull/4927

No functional change
2023-12-31 19:51:04 +01:00
Shahin M. Shahin 1a69efbb40 Fix scores from reverse futility pruning
This fixes futility pruning return values after recent tweaks, `eval` is
guaranteed to be less than the mate-in range but it can be as low value such
that the average between eval and beta can still fall in the mated-in range when
beta is as low in mated range. i.e. (eval + beta) / 2 being at mated-range which
can break mates.

Passed non-regression STC:
https://tests.stockfishchess.org/tests/view/658f3eed79aa8af82b955139
LLR: 2.94 (-2.94,2.94) <-1.75,0.25>
Total: 117408 W: 29891 L: 29761 D: 57756
Ptnml(0-2): 386, 13355, 31120, 13429, 414

Passed non-regression LTC:
https://tests.stockfishchess.org/tests/view/658f8b7a79aa8af82b9557bd
LLR: 2.94 (-2.94,2.94) <-1.75,0.25>
Total: 60240 W: 14962 L: 14786 D: 30492
Ptnml(0-2): 22, 6257, 17390, 6425, 26

changes signature at higher depth e.g. `128 1 15`

closes https://github.com/official-stockfish/Stockfish/pull/4944

Bench: 1304666
2023-12-30 12:19:48 +01:00
Linmiao Xu f12035c88c Update default net to nn-b1e55edbea57.nnue
Created by retraining the master big net `nn-0000000000a0.nnue` on the same
dataset with the ranger21 optimizer and more WDL skipping at training time.

More WDL skipping is meant to increase lambda accuracy and train on fewer
misevaluated positions where position scores are unlikely to correlate
with game outcomes. Inspired by:
- repeated reports in discord #events-discuss about SF misplaying due to wrong endgame
  evals, possibly due to Leela's endgame weaknesses reflected in training data
- an attempt to reduce the skewed dataset piece count distribution where there
  are much more positions with less than 16 pieces, since the target piece count
  distribution in the trainer is symmetric around 16

The faster convergence seen with ranger21 is meant to:
- prune experiment ideas more quickly since fewer epochs are needed to reach elo maxima
- research faster potential trainings by shortening each run

```yaml
experiment-name: 2560-S7-Re-514G-ranger21-more-wdl-skip
training-dataset: /data/S6-514G.binpack
early-fen-skipping: 28

start-from-engine-test-net: True
nnue-pytorch-branch: linrock/nnue-pytorch/r21-more-wdl-skip

num-epochs: 1200
lr: 4.375e-4
gamma: 0.995
start-lambda: 1.0
end-lambda: 0.7
```

Experiment yaml configs converted to easy_train.sh commands with:
https://github.com/linrock/nnue-tools/blob/4339954/yaml_easy_train.py

Implementations based off of Sopel's NNUE training & experimentation log:
https://docs.google.com/document/d/1gTlrr02qSNKiXNZ_SuO4-RjK4MXBiFlLE6jvNqqMkAY
- Experiment 336 - ranger21 https://github.com/Sopel97/nnue-pytorch/tree/experiment_336
- Experiment 351 - more WDL skipping

The version of the ranger21 optimizer used is:
https://github.com/lessw2020/Ranger21/blob/b507df6/ranger21/ranger21.py

The dataset is the exact same as in:
https://github.com/official-stockfish/Stockfish/pull/4782

Local elo at 25k nodes per move:
nn-epoch619.nnue : 6.2 +/- 4.2

Passed STC:
https://tests.stockfishchess.org/tests/view/658a029779aa8af82b94fbe6
LLR: 2.93 (-2.94,2.94) <0.00,2.00>
Total: 46528 W: 11985 L: 11650 D: 22893
Ptnml(0-2): 154, 5489, 11688, 5734, 199

Passed LTC:
https://tests.stockfishchess.org/tests/view/658a448979aa8af82b95010f
LLR: 2.94 (-2.94,2.94) <0.50,2.50>
Total: 265326 W: 66378 L: 65574 D: 133374
Ptnml(0-2): 153, 30175, 71254, 30877, 204

This was additionally tested with the latest DualNNUE and passed SPRTs:

Passed STC vs. https://github.com/official-stockfish/Stockfish/pull/4919
https://tests.stockfishchess.org/tests/view/658bcd5c79aa8af82b951846
LLR: 2.93 (-2.94,2.94) <0.00,2.00>
Total: 296128 W: 76273 L: 75554 D: 144301
Ptnml(0-2): 1223, 35768, 73617, 35979, 1477

Passed LTC vs. https://github.com/official-stockfish/Stockfish/pull/4919
https://tests.stockfishchess.org/tests/view/658c988d79aa8af82b95240f
LLR: 2.95 (-2.94,2.94) <0.50,2.50>
Total: 75618 W: 19085 L: 18680 D: 37853
Ptnml(0-2): 45, 8420, 20497, 8779, 68

closes https://github.com/official-stockfish/Stockfish/pull/4942

Bench: 1304666
2023-12-30 11:08:03 +01:00
FauziAkram bab1cc300c Refactor bestvalue adjustment in qsearch
closes https://github.com/official-stockfish/Stockfish/pull/4935

No functional change
2023-12-30 11:05:19 +01:00
Michael Chaly f388e41809 Adjust value returned after TT cutoff
Instead of returning value from TT in case of a fail high return mix between it
and beta.

Passed STC:
https://tests.stockfishchess.org/tests/view/658465395457644dc98446c7
LLR: 2.93 (-2.94,2.94) <0.00,2.00>
Total: 220704 W: 56404 L: 55811 D: 108489
Ptnml(0-2): 750, 26214, 55921, 26627, 840

Passed LTC:
https://tests.stockfishchess.org/tests/view/6585c3f55457644dc9845db9
LLR: 2.97 (-2.94,2.94) <0.50,2.50>
Total: 124980 W: 31169 L: 30658 D: 63153
Ptnml(0-2): 57, 14147, 33603, 14594, 89

closes https://github.com/official-stockfish/Stockfish/pull/4934

Bench: 1191093
2023-12-30 11:01:32 +01:00
peregrineshahin 3f5adc037e Fix wrong mate/tb scores from probCut
This fixes returning wrong mated-in scores, or losing a proven mate-in score
from probCut after recent tweaks. The issue reported by @cj5716 on discord.

Passed non-reg STC:
https://tests.stockfishchess.org/tests/view/6583c36b5457644dc9843afe
LLR: 2.95 (-2.94,2.94) <-1.75,0.25>
Total: 295936 W: 75011 L: 75075 D: 145850
Ptnml(0-2): 978, 33947, 78146, 33955, 942

Passed non-reg LTC:
https://tests.stockfishchess.org/tests/view/658513075457644dc98451cd
LLR: 2.95 (-2.94,2.94) <-1.75,0.25>
Total: 55932 W: 13970 L: 13786 D: 28176
Ptnml(0-2): 33, 5933, 15837, 6143, 20

closes https://github.com/official-stockfish/Stockfish/pull/4933

Bench: 1308739
2023-12-30 10:57:48 +01:00
FauziAkram fbdf5d94a9 Tweak quiet move bonus
Improving quiet move bonus by replacing bestvalue and alpha comparison, with
checking the statScore of the previous search step instead.

Inspired by @locutus2

Passed STC:
https://tests.stockfishchess.org/tests/view/657f22fb893104ee25b614e8
LLR: 2.96 (-2.94,2.94) <0.00,2.00>
Total: 51296 W: 13121 L: 12774 D: 25401
Ptnml(0-2): 225, 5986, 12868, 6355, 214

Passed LTC:
https://tests.stockfishchess.org/tests/view/658024a2893104ee25b62587
LLR: 2.94 (-2.94,2.94) <0.50,2.50>
Total: 82758 W: 20606 L: 20189 D: 41963
Ptnml(0-2): 51, 9149, 22555, 9580, 44

closes https://github.com/official-stockfish/Stockfish/pull/4930

Bench: 1312822
2023-12-22 11:51:08 +01:00
Disservin 358a853790 Revert "Adjust stand pat in qsearch on pv nodes"
This reverts commit d9ec82e743.

Bench: 1249544
2023-12-22 11:48:43 +01:00
Michael Chaly 9be0360aa4 Adjust return value in qsearch after fail high
Instead of returning strict fail soft fail high return value between value from
search and beta (somewhat by analogy to futility pruning and probcut).

This seems to be somewhat depth sensitive heuristic which performed much worse
at LTC while performing much better at STC if it is more aggressive, passed
version is the least aggressive one.

Passed STC:
https://tests.stockfishchess.org/tests/view/657b06414d789acf40ab1475
LLR: 2.95 (-2.94,2.94) <0.00,2.00>
Total: 212352 W: 53900 L: 53315 D: 105137
Ptnml(0-2): 809, 25236, 53520, 25783, 828

Passed LTC:
https://tests.stockfishchess.org/tests/view/657ce36f393ac02e79120a7c
LLR: 2.94 (-2.94,2.94) <0.50,2.50>
Total: 319362 W: 79541 L: 78630 D: 161191
Ptnml(0-2): 202, 35839, 86709, 36708, 223

closes https://github.com/official-stockfish/Stockfish/pull/4928

Bench: 974739
2023-12-19 18:22:10 +01:00
FauziAkram a069a1bbbf Use std::abs over abs
closes https://github.com/official-stockfish/Stockfish/pull/4926
closes https://github.com/official-stockfish/Stockfish/pull/4909

No functional change

Co-Authored-By: fffelix-huang <72808219+fffelix-huang@users.noreply.github.com>
2023-12-19 18:22:10 +01:00
FauziAkram 07a2619b62 Improvement of Time Management Parameters
Passed STC:
https://tests.stockfishchess.org/tests/view/6579c5574d789acf40aaf914
LLR: 2.93 (-2.94,2.94) <0.00,2.00>
Total: 44672 W: 11354 L: 11030 D: 22288
Ptnml(0-2): 140, 5033, 11685, 5319, 159

Passed LTC:
https://tests.stockfishchess.org/tests/view/657ad7f44d789acf40ab105e
LLR: 2.94 (-2.94,2.94) <0.50,2.50>
Total: 40932 W: 10275 L: 9950 D: 20707
Ptnml(0-2): 21, 4316, 11473, 4629, 27

Passed non-regression Sudden death 10+0:
https://tests.stockfishchess.org/tests/view/657b9b9e393ac02e7911f1a8
LLR: 2.93 (-2.94,2.94) <-1.75,0.25>
Total: 21384 W: 5171 L: 4925 D: 11288
Ptnml(0-2): 112, 2420, 5409, 2612, 139

closes https://github.com/official-stockfish/Stockfish/pull/4923

No functional change
2023-12-19 18:22:10 +01:00
Michael Chaly d9ec82e743 Adjust stand pat in qsearch on pv nodes
Instead of immediately returning a fail high do this only at non-pv nodes, for
pv nodes adjust bestValue to value between alpha and beta and continue
searching. Idea is to do it the same way as it's done in search where we don't
return positive beta cutoffs after ttHits / zero window search at PvNodes and
instead fully search lines.

Passed STC:
https://tests.stockfishchess.org/tests/view/65739b0af09ce1261f122f33
LLR: 2.94 (-2.94,2.94) <0.00,2.00>
Total: 189216 W: 48142 L: 47598 D: 93476
Ptnml(0-2): 584, 22463, 48051, 22845, 665

Passed LTC:
https://tests.stockfishchess.org/tests/view/657701214d789acf40aac194
LLR: 2.94 (-2.94,2.94) <0.50,2.50>
Total: 82506 W: 20689 L: 20269 D: 41548
Ptnml(0-2): 56, 9236, 22268, 9618, 75

Two issues had to be resolved:
    - in rare cases it set alpha to the same value as beta and thus broke some asserts;
    - messed up with returning tb win values.

      Fix passed non-regression LTC vs this patch:
      https://tests.stockfishchess.org/tests/view/6578113b4d789acf40aad544
      LLR: 2.96 (-2.94,2.94) <-1.75,0.25>
      Total: 277308 W: 68839 L: 68880 D: 139589
      Ptnml(0-2): 167, 31580, 75212, 31517, 178

closes https://github.com/official-stockfish/Stockfish/pull/4922

Bench: 1069503

Co-Authored-By: Muzhen Gaming <61100393+XInTheDark@users.noreply.github.com>
Co-Authored-By: Shahin M. Shahin <41402573+peregrineshahin@users.noreply.github.com>
Co-Authored-By: fffelix-huang <72808219+fffelix-huang@users.noreply.github.com>
2023-12-19 18:22:10 +01:00
Muzhen Gaming c53d2ec253 Remove UCI_AnalyseMode Option
Simplify away the useless option, as documented: "An option handled by your GUI.
This currently doesn't do anything."

The option was originally added with the introduction of contempt
(https://github.com/official-stockfish/Stockfish/commit/e9aeaad05266ca557a9496b5a17b4c5f82f0e946),
but it is now no longer used.

closes https://github.com/official-stockfish/Stockfish/pull/4918

No functional change
2023-12-14 18:50:51 +01:00
FauziAkram 536d692a30 Remove SlowMover Option
The SlowMover option allows users to modify the timeLeft variant, impacting the
engine's time management. However, this feature, while theoretically flexible,
doesn't offer substantial benefits. Instead, it introduces the risk of
non-experienced users altering values without a clear understanding of the
effects, potentially leading to a weaker engine.

The vast majority of SF users don't use it anyway, and based on tests conducted
by fauzi several months ago suggest that changing it would only lose Elo.

Examples:
https://tests.stockfishchess.org/tests/view/651f309bac57711436726bba
https://tests.stockfishchess.org/tests/view/651fea29ac57711436727d85
https://tests.stockfishchess.org/tests/view/65257c343125598fc7eb68a1
https://tests.stockfishchess.org/tests/view/652296c83125598fc7eb2ad7
Tune:
https://tests.stockfishchess.org/tests/view/652a70313125598fc7ebd706
(keeping the value at 100, zz2)

closes https://github.com/official-stockfish/Stockfish/pull/4917

No functional change
2023-12-14 18:44:46 +01:00
Disservin 9fc064e872 Fix action deprecation warning for dev-drprasad
closes https://github.com/official-stockfish/Stockfish/pull/4914

No functional change
2023-12-14 18:43:02 +01:00
WangXiang cdfafb3426 Add loongarch64 support
Adding support for LoongArch64 architecture. Tested on Loongson 3A6000 EVB
Board. Since Loongson's SIMD extended instruction set
([LSX](https://gcc.gnu.org/onlinedocs/gcc/LoongArch-SX-Vector-Intrinsics.html),
[LASX](https://gcc.gnu.org/onlinedocs/gcc/LoongArch-ASX-Vector-Intrinsics.html))
is already supported by GCC, more optimizations are being developed.

Here's the benchmark result for Loongson 3A6000 (4c8t, 2.5Ghz) without SIMD
optimizations.
```
Total time (ms) : 17903
Nodes searched  : 1244386
Nodes/second    : 69507
```

closes https://github.com/official-stockfish/Stockfish/pull/4913

No functional change
2023-12-14 18:41:53 +01:00
peregrineshahin 7885fa5bd3 Track seldepth in qsearch too
Sometimes if we count the reported PV length, it turns out to be longer than the
selective depth reported. This fixes this behavior by applying the selective
depth to qsearch since we do report PVs from it as well.

Passed non-regression STC:
https://tests.stockfishchess.org/tests/view/656cf5b66980e15f69c7499d
LLR: 2.96 (-2.94,2.94) <-1.75,0.25>
Total: 223648 W: 56372 L: 56356 D: 110920
Ptnml(0-2): 710, 25580, 59231, 25590, 713

closes https://github.com/official-stockfish/Stockfish/pull/4903

No functional change
2023-12-14 18:36:45 +01:00
Shahin M. Shahin 282e15bf75 Fix TB score output in UCI without using TB
This is a rewrite of the fix introduced for
https://github.com/official-stockfish/Stockfish/issues/4413 in
https://github.com/official-stockfish/Stockfish/pull/4591 by @windfishballad it
targets only the relevant part of this issue that returns TB scores (CP 20000)
without using TB due to the downgrading of potentially false mates from the TT
to an optimal TB score.

the difference is that it is a much clearer code that introduces a separate
TB_VALUE constant to account for a correct distance from the TB_VALUE with
MAX_PLY.

the originally posted position in the issue does not trigger the problem
anymore, so here is a new position to test:
```
position fen 3k4/8/8/8/8/8/3BN3/3K4 w - - 0 1
go infinite
```

Passed non-regression STC:
https://tests.stockfishchess.org/tests/view/65578994136acbc57353b258
LLR: 2.96 (-2.94,2.94) <-1.75,0.25>
Total: 119264 W: 29993 L: 29863 D: 59408
Ptnml(0-2): 372, 13692, 31379, 13812, 377

Passed non-regression LTC:
https://tests.stockfishchess.org/tests/view/6558323f136acbc57353c1ca
LLR: 2.94 (-2.94,2.94) <-1.75,0.25>
Total: 237834 W: 58791 L: 58792 D: 120251
Ptnml(0-2): 193, 26200, 66111, 26241, 172

fixes https://github.com/official-stockfish/Stockfish/issues/4413
closes https://github.com/official-stockfish/Stockfish/pull/4591
closes https://github.com/official-stockfish/Stockfish/pull/4882

Bench: 1305821
2023-12-14 18:35:38 +01:00
Muzhen Gaming 36db936e76 VLTC Search parameters tune
The SPSA tuning was done for 44k games at 120+1.2.
https://tests.stockfishchess.org/tests/view/656ee2a76980e15f69c7767f.

Note that the tune was originally done in combination with the recent dual NNUE
idea (see #4910).

VLTC:
https://tests.stockfishchess.org/tests/view/65731ccbf09ce1261f12246e
LLR: 2.95 (-2.94,2.94) <0.00,2.00>
Total: 52806 W: 13069 L: 12760 D: 26977
Ptnml(0-2): 19, 5498, 15056, 5815, 15

VLTC SMP:
https://tests.stockfishchess.org/tests/view/65740ffaf09ce1261f1239ba
LLR: 2.94 (-2.94,2.94) <0.50,2.50>
Total: 27630 W: 6934 L: 6651 D: 14045
Ptnml(0-2): 1, 2643, 8243, 2928, 0

Estimated close to neutral at LTC:
https://tests.stockfishchess.org/tests/view/6575485a8ec68176cf7d9423
Elo: -0.59 ± 1.8 (95%) LOS: 26.6%
Total: 32060 W: 7859 L: 7913 D: 16288
Ptnml(0-2): 20, 3679, 8676, 3645, 10
nElo: -1.21 ± 3.8 (95%) PairsRatio: 0.99

closes https://github.com/official-stockfish/Stockfish/pull/4912

Bench: 1283323
2023-12-10 23:23:28 +01:00
ppigazzini 8724503d9c Simplify the code to get the native flags
closes https://github.com/official-stockfish/Stockfish/pull/4908

No functional change
2023-12-10 23:18:21 +01:00
Taras Vuk 53ad6d23b0 Remove moveMalus
Passed STC:
https://tests.stockfishchess.org/tests/view/656e0bb86980e15f69c763fa
LLR: 3.15 (-2.94,2.94) <-1.75,0.25>
Total: 123008 W: 30973 L: 30831 D: 61204
Ptnml(0-2): 368, 14032, 32568, 14162, 374

closes https://github.com/official-stockfish/Stockfish/pull/4905

No functional change
2023-12-10 23:17:14 +01:00
Disservin dadff46986 Revert "Temporarily disable CI include checks"
This reverts commit 8f65953583.

closes https://github.com/official-stockfish/Stockfish/pull/4904

No functional change
2023-12-10 23:16:12 +01:00
FauziAkram 7a8bcfc229 Remove cutNode condition
cutNode condition seems to be irrelevant.

Passed STC:
LLR: 2.93 (-2.94,2.94) <-1.75,0.25>
Total: 24224 W: 6206 L: 5970 D: 12048
Ptnml(0-2): 69, 2818, 6122, 3014, 89
https://tests.stockfishchess.org/tests/view/65686910136acbc5735529ec

Passed LTC:
LLR: 2.96 (-2.94,2.94) <-1.75,0.25>
Total: 236538 W: 58624 L: 58622 D: 119292
Ptnml(0-2): 136, 26955, 64091, 26945, 142
https://tests.stockfishchess.org/tests/view/6568925a136acbc573552d8f

closes https://github.com/official-stockfish/Stockfish/pull/4901

Bench: 1244386
2023-12-04 11:33:58 +01:00
ppigazzini 0ff2ea6549 Update GitHub workflows
- Use the latest version of the actions
- Use commit hash for actions from little providers
- Update Intel SDE to 9.27

closes https://github.com/official-stockfish/Stockfish/pull/4900

No functional change
2023-12-04 11:27:28 +01:00
Sebastian Buchwald 8f65953583 Temporarily disable CI include checks
The include checks currently fail because of broken LLVM nightly
packages: https://github.com/llvm/llvm-project/issues/73402.

closes https://github.com/official-stockfish/Stockfish/pull/4899

No functional change
2023-12-04 11:26:09 +01:00
lonfom169 08cdbca56f Tweak return value in futility pruning
In futility pruning, return the average between eval and beta.

Passed STC:
https://tests.stockfishchess.org/tests/view/65680bb6136acbc5735521d7
LLR: 2.93 (-2.94,2.94) <0.00,2.00>
Total: 15200 W: 3926 L: 3642 D: 7632
Ptnml(0-2): 36, 1699, 3867, 1941, 57

Passed LTC:
https://tests.stockfishchess.org/tests/view/656817fc136acbc573552304
LLR: 2.94 (-2.94,2.94) <0.50,2.50>
Total: 200376 W: 49700 L: 49036 D: 101640
Ptnml(0-2): 110, 22584, 54137, 23246, 111

closes https://github.com/official-stockfish/Stockfish/pull/4897

Bench: 1403703
2023-12-02 11:46:44 +01:00
cj5716 15d47a2b38 Remove recaptures stage in qsearch
Simplify an old commit
https://github.com/official-stockfish/Stockfish/commit/72760c05c64d1fb2bb71c2ac54acfbeecf513b87.

Search is not stuck on the test position given
r1n1n1b1/1P1P1P1P/1N1N1N2/2RnQrRq/2pKp3/3BNQbQ/k7/4Bq2 w - - 0 1

Passed STC:
https://tests.stockfishchess.org/tests/view/6567050d136acbc573550919
LLR: 2.93 (-2.94,2.94) <-1.75,0.25>
Total: 236160 W: 59475 L: 59475 D: 117210
Ptnml(0-2): 841, 28266, 59816, 28366, 791

Passed LTC:
https://tests.stockfishchess.org/tests/view/6567d133136acbc573551c78
LLR: 2.95 (-2.94,2.94) <-1.75,0.25>
Total: 201690 W: 49630 L: 49593 D: 102467
Ptnml(0-2): 128, 23214, 54122, 23255, 126

closes https://github.com/official-stockfish/Stockfish/pull/4896

Bench: 1604361
2023-12-02 11:45:38 +01:00
Taras Vuk 85403a89ba Skip LMR for 2nd move at the root only
This patch reverts commit by Vizvezdenec:
https://github.com/official-stockfish/Stockfish/commit/27139dedac14af400f5b18e2ab50aca3f8cf0e33

Passed STC:
https://tests.stockfishchess.org/tests/view/65660b4a136acbc57354f13d
LLR: 2.94 (-2.94,2.94) <-1.75,0.25>
Total: 301952 W: 76271 L: 76344 D: 149337
Ptnml(0-2): 1053, 36293, 76348, 36238, 1044

Passed LTC:
https://tests.stockfishchess.org/tests/view/656738ab136acbc573550e39
LLR: 2.94 (-2.94,2.94) <-1.75,0.25>
Total: 25050 W: 6283 L: 6063 D: 12704
Ptnml(0-2): 10, 2756, 6775, 2972, 12

closes https://github.com/official-stockfish/Stockfish/pull/4895

Bench: 1722961
2023-12-02 11:41:31 +01:00
FauziAkram 7dc40ac643 Simplify quietMoveMalus malus
Use a simple depth instead of depth + 1 in the quietMoveMalus formula.

Passed STC:
https://tests.stockfishchess.org/tests/view/65636bf0136acbc57354b662
LLR: 2.94 (-2.94,2.94) <-1.75,0.25>
Total: 105248 W: 26680 L: 26532 D: 52036
Ptnml(0-2): 409, 12590, 26481, 12732, 412

Passed LTC:
https://tests.stockfishchess.org/tests/view/6563b5db136acbc57354bcab
LLR: 2.94 (-2.94,2.94) <-1.75,0.25>
Total: 204204 W: 50200 L: 50166 D: 103838
Ptnml(0-2): 123, 23331, 55145, 23395, 108

closes https://github.com/official-stockfish/Stockfish/pull/4893

Bench: 1717495
2023-12-02 11:40:36 +01:00
cj5716 883163395e Simplify promotion move generation
closes https://github.com/official-stockfish/Stockfish/pull/4892

No functional change
2023-12-02 11:38:18 +01:00
FauziAkram f17db4641e Simplify doDeeperSearch
Removing dependence on d simplifies the doDeeperSearch formula and eliminates a
variable that is not necessary in this context.

Passed STC:
https://tests.stockfishchess.org/tests/view/65647980136acbc57354c9f6
LLR: 2.94 (-2.94,2.94) <-1.75,0.25>
Total: 37440 W: 9558 L: 9334 D: 18548
Ptnml(0-2): 127, 4439, 9375, 4641, 138

Passed LTC:
https://tests.stockfishchess.org/tests/view/6564c3f0136acbc57354d126
LLR: 2.95 (-2.94,2.94) <-1.75,0.25>
Total: 113946 W: 27993 L: 27864 D: 58089
Ptnml(0-2): 67, 12975, 30783, 13058, 90

closes https://github.com/official-stockfish/Stockfish/pull/4888

Bench: 1427733
2023-12-02 11:35:28 +01:00
Muzhen Gaming 757ae2ff53 Simplify move history reduction
Recent VLTC search tuning has suggested that the depth limit can be increased
by a lot. This patch simplifies away the depth-based bonus from statScore
reduction, making the divisor a constant.

Passed STC:
https://tests.stockfishchess.org/tests/view/656201f5136acbc573549791
LLR: 2.96 (-2.94,2.94) <-1.75,0.25>
Total: 91520 W: 23130 L: 22967 D: 45423
Ptnml(0-2): 282, 10947, 23141, 11106, 284

Passed LTC:
https://tests.stockfishchess.org/tests/view/6562b43a136acbc57354a581
LLR: 2.94 (-2.94,2.94) <-1.75,0.25>
Total: 352902 W: 86796 L: 86917 D: 179189
Ptnml(0-2): 190, 40227, 95741, 40100, 193

closes https://github.com/official-stockfish/Stockfish/pull/4886

Bench: 1297179
2023-12-02 11:30:47 +01:00
Stefan Geschwentner 13426a93c1 Simplify history update.
Removal of the slowdown factor from the history update formula with
corresponding adjustment of the stat bonus used in the search.

Passed STC:
https://tests.stockfishchess.org/tests/view/655e1079136acbc573544744
LLR: 2.93 (-2.94,2.94) <-1.75,0.25>
Total: 128096 W: 32355 L: 32235 D: 63506
Ptnml(0-2): 466, 15187, 32573, 15405, 417

Passed LTC:
https://tests.stockfishchess.org/tests/view/655f4e60136acbc573546266
LLR: 2.95 (-2.94,2.94) <-1.75,0.25>
Total: 50652 W: 12653 L: 12459 D: 25540
Ptnml(0-2): 28, 5666, 13751, 5846, 35

closes https://github.com/official-stockfish/Stockfish/pull/4883

Bench: 1303857
2023-12-02 11:23:15 +01:00
FauziAkram b4e9ee72e3 Reformat some comments
Tests used to derive some Elo worth comments:

https://tests.stockfishchess.org/tests/view/653cf6b7cc309ae83956263a
https://tests.stockfishchess.org/tests/view/655250b7136acbc573534711
https://tests.stockfishchess.org/tests/view/65525767136acbc5735347b9
https://tests.stockfishchess.org/tests/view/65525aa1136acbc573534801

closes https://github.com/official-stockfish/Stockfish/pull/4879

No functional change
2023-11-20 19:10:38 +01:00
FauziAkram b59786e750 Remove doEvenDeeperSearch
Passed STC:
LLR: 2.98 (-2.94,2.94) <-1.75,0.25>
Total: 51040 W: 13014 L: 12804 D: 25222
Ptnml(0-2): 166, 6032, 12917, 6236, 169
https://tests.stockfishchess.org/tests/view/65525aa1136acbc573534801

Passed LTC:
LLR: 2.94 (-2.94,2.94) <-1.75,0.25>
Total: 165168 W: 40863 L: 40789 D: 83516
Ptnml(0-2): 73, 18783, 44792, 18869, 67
https://tests.stockfishchess.org/tests/view/65535af5136acbc573535c84

closes https://github.com/official-stockfish/Stockfish/pull/4880

Bench: 1477007
2023-11-20 19:00:47 +01:00
FauziAkram 504bf0e8b8 Change depth - 1 to newDepth
Replacing 'depth - 1' with 'newDepth' in the singularbeta formula
utilizes existing variables more succinctly.

closes https://github.com/official-stockfish/Stockfish/pull/4876

No functional change
2023-11-20 18:59:01 +01:00
Stefan Geschwentner 7970236e9e Fix undefined behavior in search.
We use following line to clamp the search depth in some range:
Depth d = std::clamp(newDepth - r, 1, newDepth + 1);

Through negative extension its possible that the maximum value becomes smaller than the minimum value but then the behavior is undefined (see https://en.cppreference.com/w/cpp/algorithm/clamp). So replace this line with a safe implementation.

Remark:
We have in recent master already one line where up to 3 negative extensions are possible which could trigger this undefined behavior but this can only be happen for completed depth > 24 so its not discovered by our default bench. Recent negative extension tests by @fauzi shows then this undefined behavior with wrong bench numbers.

closes https://github.com/official-stockfish/Stockfish/pull/4877

No functional change
2023-11-16 09:10:20 +01:00
Joost VandeVondele d89217766b CI updates
- updates the SDE action to v2.2
- removes the linux x86-32 builds, which were almost unused,
  and the build process under SDE started failing recently,
  possibly related to glibc update (The futex facility returned an unexpected error code.)

closes https://github.com/official-stockfish/Stockfish/pull/4875

No functional change
2023-11-16 09:01:57 +01:00
Joost VandeVondele f9d8717844 Symmetrize optimism
Removes some additional parameters, making the term more logical at the same
time.

Passed STC:
https://tests.stockfishchess.org/tests/view/6550e896136acbc5735328ed
LLR: 2.93 (-2.94,2.94) <-1.75,0.25>
Total: 271104 W: 68441 L: 68480 D: 134183
Ptnml(0-2): 827, 32590, 68816, 32433, 886

Passed LTC:
https://tests.stockfishchess.org/tests/view/65523858136acbc5735344f7
LLR: 2.94 (-2.94,2.94) <-1.75,0.25>
Total: 198954 W: 49250 L: 49211 D: 100493
Ptnml(0-2): 93, 22565, 54117, 22614, 88

closes https://github.com/official-stockfish/Stockfish/pull/4874

Bench: 1334248
2023-11-15 19:35:14 +01:00
Taras Vuk 863a1f2b4c Introduce recapture extensions
When in a PV-node this patch extends ttMove if it is a recapture and has a good
history.

Passed STC:
LLR: 2.95 (-2.94,2.94) <0.00,2.00>
Total: 83840 W: 21560 L: 21166 D: 41114
Ptnml(0-2): 343, 9905, 21027, 10305, 340
https://tests.stockfishchess.org/tests/view/654f4b02136acbc5735308ab

Passed LTC:
LLR: 2.94 (-2.94,2.94) <0.50,2.50>
Total: 165318 W: 41068 L: 40476 D: 83774
Ptnml(0-2): 98, 18670, 44517, 19290, 84
https://tests.stockfishchess.org/tests/view/654fde04136acbc5735314e0

closes https://github.com/official-stockfish/Stockfish/pull/4872

Bench: 1393911
2023-11-15 19:32:59 +01:00
Linmiao Xu fbc6b27505 Simplify away optimism average score offset params
Passed non-regression STC:
https://tests.stockfishchess.org/tests/view/654abf6b136acbc57352ac4b
LLR: 2.97 (-2.94,2.94) <-1.75,0.25>
Total: 49664 W: 12687 L: 12477 D: 24500
Ptnml(0-2): 138, 5840, 12703, 5976, 175

Passed non-regression LTC:
https://tests.stockfishchess.org/tests/view/654b638e136acbc57352b961
LLR: 2.94 (-2.94,2.94) <-1.75,0.25>
Total: 347166 W: 85561 L: 85676 D: 175929
Ptnml(0-2): 206, 39569, 94150, 39450, 208

closes https://github.com/official-stockfish/Stockfish/pull/4871

bench 1257641
2023-11-11 15:26:56 +01:00
Stefan Geschwentner 80b0e37543 Double weight of pawn history for quiet move ordering.
I measured on my 1000 position bench the average additional added pawn history per depth.
This shows on average negative value with even smaller values with increaing depth.

A linear regression against depth get following formula:

-1960 - 130 * depth

For compensation add this to the used sort limit to maintain roughly the same proportion of sorted quiet moves.

Remarks:
1. using no compensation failed here https://tests.stockfishchess.org/tests/view/6547664f136acbc5735265f0
2. using only the compensation failed at LTC:
   passed STC: https://tests.stockfishchess.org/tests/view/65477457136acbc5735266f8
   failed LTC: https://tests.stockfishchess.org/tests/view/65487fc8136acbc573527d1c

STC:
LLR: 2.94 (-2.94,2.94) <0.00,2.00>
Total: 98528 W: 25109 L: 24699 D: 48720
Ptnml(0-2): 334, 11586, 25009, 12006, 329
https://tests.stockfishchess.org/tests/view/65475873136acbc5735264f7

LTC:
LLR: 2.95 (-2.94,2.94) <0.50,2.50>
Total: 69726 W: 17467 L: 17073 D: 35186
Ptnml(0-2): 39, 7814, 18769, 8196, 45
https://tests.stockfishchess.org/tests/view/6547e759136acbc573527071

closes https://github.com/official-stockfish/Stockfish/pull/4866

Bench: 1379422
2023-11-07 08:28:43 +01:00
Taras Vuk d0e87104aa Remove pawn history from ProbCut constructor
use same style as other history tables

Passed STC:
LLR: 2.94 (-2.94,2.94) <-1.75,0.25>
Total: 184672 W: 46953 L: 46896 D: 90823
Ptnml(0-2): 604, 21095, 48887, 21140, 610
https://tests.stockfishchess.org/tests/view/654766b4136acbc573526602

closes https://github.com/official-stockfish/Stockfish/pull/4865

No functional change
2023-11-07 08:23:11 +01:00
Taras Vuk 442c294a07 Use stat_malus when decreasing stats
This patch applies stat_bonus when increasing and stat_malus when decreasing stats.

Passed STC:
LLR: 2.93 (-2.94,2.94) <0.00,2.00>
Total: 133792 W: 34221 L: 33758 D: 65813
Ptnml(0-2): 477, 15764, 33959, 16211, 485
https://tests.stockfishchess.org/tests/view/654699f3136acbc5735256b2

Passed LTC:
LLR: 2.95 (-2.94,2.94) <0.50,2.50>
Total: 67374 W: 16912 L: 16523 D: 33939
Ptnml(0-2): 42, 7528, 18171, 7891, 55
https://tests.stockfishchess.org/tests/view/65474558136acbc5735263ab

closes https://github.com/official-stockfish/Stockfish/pull/4864

bench: 1114417
2023-11-05 19:54:59 +01:00
FauziAkram d4b46ea6db Set reduction to 0 if the move is a TT move
The reduction formula currently decreases by 1 if the move is a TT move.
This changes this by just setting the reduction to 0 instead.

Passed STC:
LLR: 2.94 (-2.94,2.94) <0.00,2.00>
Total: 83136 W: 21145 L: 20758 D: 41233
Ptnml(0-2): 279, 9772, 21090, 10137, 290
https://tests.stockfishchess.org/tests/view/653c0fbacc309ae839561584

Passed LTC:
LLR: 2.96 (-2.94,2.94) <0.50,2.50>
Total: 273150 W: 67987 L: 67171 D: 137992
Ptnml(0-2): 155, 30730, 73966, 31592, 132
https://tests.stockfishchess.org/tests/view/653d9d02cc309ae839562fdf

closes https://github.com/official-stockfish/Stockfish/pull/4863

bench: 1110556
2023-11-05 19:53:15 +01:00
Shahin M. Shahin 791419aab5 Enhance some comments
This documents some code and makes some hard code easier to understand for new developers.

closes https://github.com/official-stockfish/Stockfish/pull/4862

No functional change
2023-11-05 19:51:02 +01:00
FauziAkram 7f97ba775e Tweaking the futility pruning formula
Huge credit goes also to candirufish,
as the idea was first tried by him, and then tuned by me at multiple phases.

Tweaking the futility pruning formula to be a bit more selective about when pruning is applied.
Adjust the value added to the static eval based on the bestValue relative to ss->staticEval. If bestValue is significantly lower, we add a larger value.

Passed STC:
LLR: 2.98 (-2.94,2.94) <0.00,2.00>
Total: 37120 W: 9590 L: 9266 D: 18264
Ptnml(0-2): 130, 4301, 9385, 4603, 141
https://tests.stockfishchess.org/tests/view/6544cf90136acbc573523247

Passed LTC:
LLR: 2.94 (-2.94,2.94) <0.50,2.50>
Total: 49632 W: 12381 L: 12033 D: 25218
Ptnml(0-2): 30, 5429, 13549, 5779, 29
https://tests.stockfishchess.org/tests/view/65453bc1136acbc573523a3c

closes https://github.com/official-stockfish/Stockfish/pull/4861

bench: 1107118
2023-11-04 17:34:35 +01:00
Michael Chaly b4b704e686 Update pawn history based on static eval difference
Use the same logic as in main history but with 1/4 multiplier.

Passed STC:
https://tests.stockfishchess.org/tests/view/653c1282cc309ae8395615bf
LLR: 2.93 (-2.94,2.94) <0.00,2.00>
Total: 306624 W: 77811 L: 77094 D: 151719
Ptnml(0-2): 975, 36411, 77830, 37114, 982

Passed LTC:
https://tests.stockfishchess.org/tests/view/654258e2cc309ae83956818d
LLR: 2.94 (-2.94,2.94) <0.50,2.50>
Total: 99150 W: 24681 L: 24228 D: 50241
Ptnml(0-2): 56, 11107, 26792, 11568, 52

closes https://github.com/official-stockfish/Stockfish/pull/4859

bench 1330590
2023-11-03 22:50:05 +01:00
Stefan Geschwentner 1cb9afbdc0 Remove razoring history update.
The recently commit 'Rewarding Quiet Moves that Enable Razoring' add a history update if razoring. But its contains also many tuned values all over the search. Following tests shows that the tuned values and not the added history update is responsible for the elo gain. So remove later.

Passed STC:
LLR: 2.93 (-2.94,2.94) <-1.75,0.25>
Total: 29376 W: 7641 L: 7410 D: 14325
Ptnml(0-2): 100, 3411, 7451, 3610, 116
https://tests.stockfishchess.org/tests/view/653c9fe1cc309ae839562070

Passed LTC:
LLR: 2.95 (-2.94,2.94) <-1.75,0.25>
Total: 242922 W: 59879 L: 59885 D: 123158
Ptnml(0-2): 129, 27764, 65688, 27744, 136
https://tests.stockfishchess.org/tests/view/653d06cbcc309ae839562735

closes https://github.com/official-stockfish/Stockfish/pull/4858

Bench: 1286104
2023-11-03 22:47:31 +01:00
FauziAkram 101d2bb8ea Simplifying two formulas
by eliminating two multiplication operations.

Passed STC:
LLR: 2.94 (-2.94,2.94) <-1.75,0.25>
Total: 60000 W: 15193 L: 14996 D: 29811
Ptnml(0-2): 199, 7100, 15215, 7277, 209
https://tests.stockfishchess.org/tests/view/653beb69cc309ae83956129d

Passed LTC:
LLR: 2.94 (-2.94,2.94) <-1.75,0.25>
Total: 122910 W: 30471 L: 30353 D: 62086
Ptnml(0-2): 68, 13961, 33271, 14095, 60
https://tests.stockfishchess.org/tests/view/653c5848cc309ae839561ae7

closes https://github.com/official-stockfish/Stockfish/pull/4857

bench: 1216779
2023-11-03 22:40:43 +01:00
cj5716 e277dda716 Prefetch TT entries in probcut
Passed STC:
LLR: 2.93 (-2.94,2.94) <0.00,2.00>
Total: 101344 W: 25893 L: 25491 D: 49960
Ptnml(0-2): 303, 11350, 26991, 11698, 330
https://tests.stockfishchess.org/tests/view/6540daa6cc309ae83956669b

slight speedup:
```
Result of 100 runs
==================
base (./stockfish.master       ) =    1170705  +/- 3133
test (./stockfish.patch        ) =    1174545  +/- 2895
diff                             =      +3841  +/- 3196

speedup        = +0.0033
P(speedup > 0) =  0.9907
```

closes https://github.com/official-stockfish/Stockfish/pull/4856

No functional change
2023-11-03 22:39:04 +01:00
Muzhen Gaming 908811c24a Introduce asymmetric optimism
Introduce asymmetric optimism for both side to move and opponent. Parameter tuning was done with 200k LTC games.

STC: https://tests.stockfishchess.org/tests/view/653cc08fcc309ae8395622b3
LLR: 2.96 (-2.94,2.94) <0.00,2.00>
Total: 98336 W: 25074 L: 24661 D: 48601
Ptnml(0-2): 339, 11612, 24890, 11951, 376

LTC: https://tests.stockfishchess.org/tests/view/653db595cc309ae839563140
LLR: 2.94 (-2.94,2.94) <0.50,2.50>
Total: 83244 W: 20760 L: 20339 D: 42145
Ptnml(0-2): 51, 9306, 22498, 9705, 62

closes https://github.com/official-stockfish/Stockfish/pull/4853

Bench: 1371690
2023-10-30 07:51:27 +01:00
cj5716 38aa70adcf Small cleanups
Corrects some incorrect or outdated comments.
Credit is shared with yaneurao (see 38e830a#commitcomment-131131500) and locutus2

closes #4852

No functional change.
2023-10-30 07:49:15 +01:00
Disservin 347d613b0e remove outdated comment
Bench: 1258079
2023-10-27 18:35:52 +02:00
Disservin 08ed4c90db Format Code
No functional change
2023-10-27 17:33:59 +02:00
FauziAkram d30af4f669 Rewarding Quiet Moves that Enable Razoring
The main idea of the patch comes from @peregrineshahin :
https://tests.stockfishchess.org/tests/view/65205363ac57711436728781

Another small idea (tuning) comes from @Vizvezdenec
https://tests.stockfishchess.org/tests/view/652e071ade6d262d08d318f4 And a long
phases of tuning and tests was done by me in order to make the patch be able to
pass both tests.

The idea, as mentioned by Peregrine is that in our standard code, if no best
move found after searching all moves, we give a bonus to the previous move that
caused the fail high. So in razoring we assume no bestmove will be found so we
might as well do the same.

Passed STC:
LLR: 2.94 (-2.94,2.94) <0.00,2.00>
Total: 82336 W: 20997 L: 20610 D: 40729
Ptnml(0-2): 288, 9710, 20753, 10161, 256
https://tests.stockfishchess.org/tests/view/6538fafbcc309ae83955d8f0

Passed LTC:
LLR: 2.94 (-2.94,2.94) <0.50,2.50>
Total: 46584 W: 11753 L: 11411 D: 23420
Ptnml(0-2): 21, 5133, 12642, 5475, 21
https://tests.stockfishchess.org/tests/view/653a3f2ccc309ae83955f223

closes https://github.com/official-stockfish/Stockfish/pull/4850

Bench: 1258079

Co-Authored-By: Shahin M. Shahin <41402573+peregrineshahin@users.noreply.github.com>
2023-10-27 17:32:19 +02:00
Michael Chaly b0658f09b9 Introduce pawn structure based history
Original idea by Seer chess engine https://github.com/connormcmonigle/seer-nnue,
coding done by @Disservin, code refactoring done by @locutus2 to match the style
of other histories.

This patch introduces pawn structure based history, which assings moves values
based on last digits of pawn structure hash and piece type of moved piece and
landing square of the move. Idea is that good places for pieces are quite often
determined by pawn structure of position. Used in 3 different places
- sorting of quiet moves, sorting of quiet check evasions and in history based
pruning in search.

Passed STC:
https://tests.stockfishchess.org/tests/view/65391d08cc309ae83955dbaf
LLR: 2.95 (-2.94,2.94) <0.00,2.00>
Total: 155488 W: 39408 L: 38913 D: 77167
Ptnml(0-2): 500, 18427, 39408, 18896, 513

Passed LTC:
https://tests.stockfishchess.org/tests/view/653a36a2cc309ae83955f181
LLR: 2.94 (-2.94,2.94) <0.50,2.50>
Total: 70110 W: 17548 L: 17155 D: 35407
Ptnml(0-2): 33, 7859, 18889, 8230, 44

closes https://github.com/official-stockfish/Stockfish/pull/4849

Bench: 1257882

Co-Authored-By: Disservin <disservin.social@gmail.com>
Co-Authored-By: Stefan Geschwentner <locutus2@users.noreply.github.com>
2023-10-27 17:24:25 +02:00
Taras Vuk 871ab55f01 Simplify futility pruning formula
closes https://github.com/official-stockfish/Stockfish/pull/4848

No functional change
2023-10-27 17:16:28 +02:00
Linmiao Xu 0024133b08 Update 5 search params for pruning at shallow depth
Found by spsa tuning at 45+0.45 with:

```
int fpcEvalOffset = 188;
int fpcLmrDepthMult = 206;
int histDepthMult = -3232;
int histDenom = 5793;
int fpEvalOffset = 115;
int negSeeDepthMultSq = -27;
TUNE(SetRange(0, 394), fpcEvalOffset);
TUNE(SetRange(0, 412), fpcLmrDepthMult);
TUNE(SetRange(-6464, -1616), histDepthMult);
TUNE(SetRange(2896, 11586), histDenom);
TUNE(SetRange(0, 230), fpEvalOffset);
TUNE(SetRange(-54, 0), negSeeDepthMultSq);
```

Passed STC:
https://tests.stockfishchess.org/tests/view/6535551de746e058e6c0165d
LLR: 2.98 (-2.94,2.94) <0.00,2.00>
Total: 109056 W: 28025 L: 27599 D: 53432
Ptnml(0-2): 357, 12669, 28038, 13119, 345

Passed LTC:
https://tests.stockfishchess.org/tests/view/65364c6ff127f3553505175d
LLR: 2.94 (-2.94,2.94) <0.50,2.50>
Total: 61290 W: 15316 L: 14941 D: 31033
Ptnml(0-2): 34, 6849, 16498, 7236, 28

closes https://github.com/official-stockfish/Stockfish/pull/4847

bench 1167412
2023-10-24 17:46:18 +02:00
Joost VandeVondele ec02714b62 Cleanup comments and some code reorg.
passed STC:
https://tests.stockfishchess.org/tests/view/6536dc7dcc309ae83955b04d
LLR: 2.93 (-2.94,2.94) <-1.75,0.25>
Total: 58048 W: 14693 L: 14501 D: 28854
Ptnml(0-2): 200, 6399, 15595, 6669, 161

closes https://github.com/official-stockfish/Stockfish/pull/4846

No functional change
2023-10-24 17:43:05 +02:00
cj5716 d6a5c2b085 Small formatting improvements
Changes some C style casts to C++ style, and fixes some incorrect comments and variable names.

closes #4845

No functional change
2023-10-24 17:42:13 +02:00
Joost VandeVondele 49ece9f791 Follow up Makefile changes for clang-format
as reported on various OS, these changes help portability

closes https://github.com/official-stockfish/Stockfish/pull/4844

No functional change.
2023-10-23 20:39:48 +02:00
Muzhen Gaming cf3dbcb5ac Time management improvements
1. Tune time management parameters.
2. Scale the optimum time and maximum time parameters based on the amount of
   time left, using a logarithmic scale.

Many acknowledgements to @FauziAkram for tuning the parameters and for the
original idea (see
https://tests.stockfishchess.org/tests/view/652f0356de6d262d08d333c5).

STC: https://tests.stockfishchess.org/tests/view/6533938fde6d262d08d39e4d
LLR: 2.94 (-2.94,2.94) <0.00,2.00>
Total: 44320 W: 11301 L: 10982 D: 22037
Ptnml(0-2): 146, 4810, 11920, 5147, 137

LTC: https://tests.stockfishchess.org/tests/view/653477e4de6d262d08d3ae06
LLR: 2.95 (-2.94,2.94) <0.50,2.50>
Total: 146442 W: 37338 L: 36811 D: 72293
Ptnml(0-2): 60, 14975, 42645, 15460, 81

Verification runs:
3+0.03: https://tests.stockfishchess.org/tests/view/65364e7ef127f3553505178a
10+0: https://tests.stockfishchess.org/tests/view/65364e9ff127f3553505178f
180+1.8: https://tests.stockfishchess.org/tests/view/65364ec3f127f35535051794

closes https://github.com/official-stockfish/Stockfish/pull/4843

No functional change.

Co-Authored-By: FauziAkram <11150271+FauziAkram@users.noreply.github.com>
2023-10-23 20:39:48 +02:00
Disservin a105978bbd remove blank line between function and it's description
- remove the blank line between the declaration of the function and it's
  comment, leads to better IDE support when hovering over a function to see it's
  description
- remove the unnecessary duplication of the function name in the functions
  description
- slightly refactored code for lsb, msb in bitboard.h There are still a few
  things we can be improved later on, move the description of a function where
  it was declared (instead of implemented) and add descriptions to functions
  which are behind macros ifdefs

closes https://github.com/official-stockfish/Stockfish/pull/4840

No functional change
2023-10-23 20:39:48 +02:00
Disservin b187622233 use expanded variables for shell commands
Performance improvement for the shell commands in the Makefile.
By using expanded variables, the shell commands are only
evaluated once, instead of every time they are used.

closes https://github.com/official-stockfish/Stockfish/pull/4838

No functional change
2023-10-23 20:39:48 +02:00
MinetaS 40c6a84434 Fix a compiler bug on Clang 15+ with AVX-512
fixes https://github.com/official-stockfish/Stockfish/issues/4450
closes https://github.com/official-stockfish/Stockfish/pull/4830

No functional change.
2023-10-23 20:39:48 +02:00
Taras Vuk b7b7800e2b Simplify futilityBase formula
This patch replaces std::min(ss->staticEval, bestValue) with ss->staticEval in the futilityBase formula.
Original idea by Vizvezdenec: https://tests.stockfishchess.org/tests/view/64ce66795b17f7c21c0d85f3

Passed STC:
LLR: 2.94 (-2.94,2.94) <-1.75,0.25>
Total: 116928 W: 29925 L: 29793 D: 57210
Ptnml(0-2): 399, 13558, 30446, 13634, 427
https://tests.stockfishchess.org/tests/view/653285aade6d262d08d385dd

Passed LTC:
LLR: 2.96 (-2.94,2.94) <-1.75,0.25>
Total: 50868 W: 12947 L: 12757 D: 25164
Ptnml(0-2): 30, 5414, 14355, 5606, 29
https://tests.stockfishchess.org/tests/view/65336ffbde6d262d08d39ba0

closes https://github.com/official-stockfish/Stockfish/pull/4837

bench: 1241996
2023-10-22 16:16:02 +02:00
Disservin 2d0237db3f add clang-format
This introduces clang-format to enforce a consistent code style for Stockfish.

Having a documented and consistent style across the code will make contributing easier
for new developers, and will make larger changes to the codebase easier to make.

To facilitate formatting, this PR includes a Makefile target (`make format`) to format the code,
this requires clang-format (version 17 currently) to be installed locally.

Installing clang-format is straightforward on most OS and distros
(e.g. with https://apt.llvm.org/, brew install clang-format, etc), as this is part of quite commonly
used suite of tools and compilers (llvm / clang).

Additionally, a CI action is present that will verify if the code requires formatting,
and comment on the PR as needed. Initially, correct formatting is not required, it will be
done by maintainers as part of the merge or in later commits, but obviously this is encouraged.

fixes https://github.com/official-stockfish/Stockfish/issues/3608
closes https://github.com/official-stockfish/Stockfish/pull/4790

Co-Authored-By: Joost VandeVondele <Joost.VandeVondele@gmail.com>
2023-10-22 16:06:27 +02:00
mstembera 8366ec48ae Scale down stat bonus
STC https://tests.stockfishchess.org/tests/view/652eff58de6d262d08d33353
LLR: 2.94 (-2.94,2.94) <0.00,2.00>
Total: 88224 W: 22618 L: 22228 D: 43378
Ptnml(0-2): 282, 10177, 22783, 10609, 261

LTC https://tests.stockfishchess.org/tests/view/652fd13bde6d262d08d3481a
LLR: 2.95 (-2.94,2.94) <0.50,2.50>
Total: 143508 W: 36674 L: 36142 D: 70692
Ptnml(0-2): 92, 15240, 40534, 15820, 68

Reduces the stat bonus by 20%. Maybe future patches can tune the actual bonus calculations for different histories.

closes https://github.com/official-stockfish/Stockfish/pull/4836

bench: 1185932
2023-10-21 10:37:27 +02:00
Taras Vuk e18619d078 Subtract the margin from the value returned by ProbCut
This patch subtracts the margin from the value returned by ProbCut.

Passed STC:
LLR: 2.95 (-2.94,2.94) <0.00,2.00>
Total: 46112 W: 11940 L: 11610 D: 22562
Ptnml(0-2): 131, 5318, 11842, 5620, 145
https://tests.stockfishchess.org/tests/view/652ea42ade6d262d08d329dd

Passed LTC:
LLR: 2.94 (-2.94,2.94) <0.50,2.50>
Total: 86880 W: 22192 L: 21776 D: 42912
Ptnml(0-2): 43, 9213, 24510, 9633, 41
https://tests.stockfishchess.org/tests/view/652f70ffde6d262d08d33e8d

closes https://github.com/official-stockfish/Stockfish/pull/4835

bench: 1135313
2023-10-21 10:34:12 +02:00
FauziAkram 90c18b0b50 Removing history condition
Removing the bad history condition from the skip futility pruning formula.

Passed STC:
LLR: 2.93 (-2.94,2.94) <-1.75,0.25>
Total: 142688 W: 36420 L: 36317 D: 69951
Ptnml(0-2): 481, 16653, 36970, 16762, 478
https://tests.stockfishchess.org/tests/view/65270a663125598fc7eb8c67

Passed LTC:
LLR: 2.94 (-2.94,2.94) <-1.75,0.25>
Total: 435378 W: 110723 L: 110925 D: 213730
Ptnml(0-2): 278, 47251, 122788, 47139, 233
https://tests.stockfishchess.org/tests/view/6528595f3125598fc7eba8f5

closes https://github.com/official-stockfish/Stockfish/pull/4834

Bench: 1110579
2023-10-21 10:31:51 +02:00
mstembera d3d0c69dc1 Remove outdated Tile naming.
cleanup variable naming after  #4816

closes #4833

No functional change
2023-10-21 10:28:55 +02:00
Shahin M. Shahin 057046cc9a Cleanup qsearch continuation histories
Only (ss-1) and (ss-2) are used in qsearch.

closes https://github.com/official-stockfish/Stockfish/pull/4828

No functional change
2023-10-21 10:26:09 +02:00
FauziAkram edb4ab924f Standardize Comments
use double slashes (//) only for comments.

closes #4820

No functional change.
2023-10-21 10:25:03 +02:00
Stéphane Nicolet fe53a18f7a Reformat some comments and conditions
closes https://github.com/official-stockfish/Stockfish/pull/4814

No functional change
2023-10-21 10:15:48 +02:00
Shahin M. Shahin a4fedd8152 Fix greater than TB scores in null move pruning.
This patch is a simplification and a fix to dealing with null moves scores that returns proven mates or TB scores by preventing 'null move pruning' if the nullvalue is in that range.

Current solution downgrades nullValues on the non-PV node but the value can be used in a transposed PV-node to the same position afterwards (Triangulation), the later is prone to propagate a wrong score (96.05) to root that will not be refuted unless we search further.

Score of (96.05) can be obtained be two methods,

maxim static-eval returned on Pv update (mostly qSearch)
this downgrade (clamp) in NMP
and theoretically can happen with or without TBs but the second scenario is more dangerous than the first.
This fixes the reproducible case in very common scenarios with TBs as shown in the debugging at discord.

Fixes: #4699

Passed STC:
https://tests.stockfishchess.org/tests/view/64c1eca8dc56e1650abba6f9
LLR: 2.94 (-2.94,2.94) <-1.75,0.25>
Total: 670048 W: 171132 L: 171600 D: 327316
Ptnml(0-2): 2134, 75687, 179820, 75279, 2104

Passed LTC:
https://tests.stockfishchess.org/tests/view/64c5e130dc56e1650abc0438
LLR: 2.95 (-2.94,2.94) <-1.75,0.25>
Total: 92868 W: 23642 L: 23499 D: 45727
Ptnml(0-2): 52, 9509, 27171, 9648, 54

closes https://github.com/official-stockfish/Stockfish/pull/4715

Bench: 1327410
2023-10-21 10:01:26 +02:00
Michael Chaly 38e830af4b Use more continuation histories.
This patch allows stats updates and movepicker bonuses for continuation history 3 plies deep - so counter counter move.
Updates and movepicker usage are done with 1/4 multiplier compared to other histories.

Passed STC:
https://tests.stockfishchess.org/tests/view/6528f28d3125598fc7ebb5a3
LLR: 2.96 (-2.94,2.94) <0.00,2.00>
Total: 161344 W: 41369 L: 40868 D: 79107
Ptnml(0-2): 535, 18720, 41679, 19185, 553

Passed LTC:
https://tests.stockfishchess.org/tests/view/652a397a3125598fc7ebd1d6
LLR: 2.95 (-2.94,2.94) <0.50,2.50>
Total: 48564 W: 12556 L: 12215 D: 23793
Ptnml(0-2): 25, 5149, 13595, 5486, 27

closes https://github.com/official-stockfish/Stockfish/pull/4827

bench 1327410
2023-10-14 16:52:35 +02:00
Muzhen Gaming 002636362e Search parameters tune at 180+1.8
Passed VLTC: https://tests.stockfishchess.org/tests/view/65200c58ac577114367280bc
LLR: 2.95 (-2.94,2.94) <0.00,2.00>
Total: 146180 W: 37407 L: 36988 D: 71785
Ptnml(0-2): 21, 14474, 43675, 14905, 15

Passed VLTC SMP: https://tests.stockfishchess.org/tests/view/652403da3125598fc7eb4b6d
LLR: 2.94 (-2.94,2.94) <0.50,2.50>
Total: 57580 W: 15061 L: 14739 D: 27780
Ptnml(0-2): 2, 5001, 18460, 5327, 0

closes https://github.com/official-stockfish/Stockfish/pull/4826

Bench: 1099336
2023-10-10 17:45:32 +02:00
Taras Vuk 7a4de96159 Skip futility pruning if ttMove has bad history
Passed STC:
LLR: 2.96 (-2.94,2.94) <0.00,2.00>
Total: 52416 W: 13465 L: 13128 D: 25823
Ptnml(0-2): 128, 6024, 13604, 6287, 165
https://tests.stockfishchess.org/tests/view/651fadd4ac577114367277bf

Passed LTC:
LLR: 2.94 (-2.94,2.94) <0.50,2.50>
Total: 87348 W: 22234 L: 21818 D: 43296
Ptnml(0-2): 38, 9240, 24698, 9664, 34
https://tests.stockfishchess.org/tests/view/65201932ac57711436728218

closes https://github.com/official-stockfish/Stockfish/pull/4825

bench: 1246560
2023-10-08 07:56:07 +02:00
gabe f7fbc6880e Avoid recomputing moveCountPruning
In search, when moveCountPruning becomes true, it can never turn false again.

Passed STC https://tests.stockfishchess.org/tests/view/652075ceac57711436728aac
LLR: 2.94 (-2.94,2.94) <0.00,2.00>
Total: 136448 W: 34923 L: 34472 D: 67053
Ptnml(0-2): 420, 15094, 36767, 15501, 442

closes https://github.com/official-stockfish/Stockfish/pull/4823

Non functional change
2023-10-08 07:52:16 +02:00
candirufish 25d444ed60 Razor more if ss+1 cutoffCnt > 3
STC:
LLR: 2.95 (-2.94,2.94) <0.00,2.00>
Total: 221760 W: 56726 L: 56144 D: 108890
Ptnml(0-2): 655, 25453, 58123, 25953, 696
https://tests.stockfishchess.org/tests/view/651d34dbcff46e538ee05d91

LTC:
LLR: 2.95 (-2.94,2.94) <0.50,2.50>
Total: 130326 W: 33188 L: 32681 D: 64457
Ptnml(0-2): 69, 13949, 36620, 14456, 69
https://tests.stockfishchess.org/tests/view/651f844eac577114367273d5

closes https://github.com/official-stockfish/Stockfish/pull/4822

bench: 1291708
2023-10-08 07:50:03 +02:00
Stefan Geschwentner 008d59512a Simplify collection of bad moves for history updates.
1. collect only the first 32 moves searched and ignore the rest. So late bad moves get no further negative history updates.
2. collect now for quiet moves also at most 32 bad moves

STC:
https://tests.stockfishchess.org/tests/view/6517b3aeb3e74811c8af5651
LLR: 2.93 (-2.94,2.94) <-1.75,0.25>
Total: 51168 W: 13013 L: 12810 D: 25345
Ptnml(0-2): 120, 6006, 13186, 6095, 177

LTC:
https://tests.stockfishchess.org/tests/view/651adafecff46e538ee02734
LLR: 2.96 (-2.94,2.94) <-1.75,0.25>
Total: 109866 W: 27786 L: 27656 D: 54424
Ptnml(0-2): 52, 11816, 31069, 11942, 54

closes https://github.com/official-stockfish/Stockfish/pull/4818

Bench: 1338617
2023-10-08 07:46:26 +02:00
mstembera c17a657b04 Optimize the most common update accumalator cases w/o tiling
In the most common case where we only update a single state
it's faster to not use temporary accumulation registers and tiling.
(Also includes a couple of small cleanups.)

passed STC
https://tests.stockfishchess.org/tests/view/651918e3cff46e538ee0023b
LLR: 2.95 (-2.94,2.94) <0.00,2.00>
Total: 34944 W: 8989 L: 8687 D: 17268
Ptnml(0-2): 88, 3743, 9512, 4037, 92

A simpler version
https://tests.stockfishchess.org/tests/view/65190dfacff46e538ee00155
also passed but this version is stronger still
https://tests.stockfishchess.org/tests/view/6519b95fcff46e538ee00fa2

closes https://github.com/official-stockfish/Stockfish/pull/4816

No functional change
2023-10-08 07:42:39 +02:00
Stéphane Nicolet 040dfedb34 Remove one test in the move loop
Simplification passed STC test:
https://tests.stockfishchess.org/tests/view/6519fc91cff46e538ee014f6
LLR: 2.94 (-2.94,2.94) <-1.75,0.25>
Total: 191264 W: 48550 L: 48501 D: 94213
Ptnml(0-2): 576, 21529, 51392, 21540, 595

closes #4815

Non functional change
2023-10-08 07:41:16 +02:00
Robert Nurnberg @ elitebook f1ce1cd475 Update links in license
matches https://www.gnu.org/licenses/gpl-3.0.txt

closes https://github.com/official-stockfish/Stockfish/pull/4813

No functional change
2023-10-08 07:38:13 +02:00
mstembera 8a912951de Remove handcrafted MMX code
too small a benefit to maintain this old target

closes https://github.com/official-stockfish/Stockfish/pull/4804

No functional change
2023-10-08 07:37:01 +02:00
Linmiao Xu afe7f4d9b0 Update default net to nn-0000000000a0.nnue
This is a later epoch from the same experiment that led to the previous
master net. In training stage 6, max-epoch was raised to 1,200 near the
end of the first 1,000 epochs.

For more details, see https://github.com/official-stockfish/Stockfish/pull/4795

Local elo at 25k nodes per move (vs. L1-2048 nn-1ee1aba5ed4c.nnue)
ep1079 : 15.6 +/- 1.2

Passed STC:
https://tests.stockfishchess.org/tests/view/651503b3b3e74811c8af1e2a
LLR: 2.94 (-2.94,2.94) <0.00,2.00>
Total: 29408 W: 7607 L: 7304 D: 14497
Ptnml(0-2): 97, 3277, 7650, 3586, 94

Passed LTC:
https://tests.stockfishchess.org/tests/view/651585ceb3e74811c8af2a5f
LLR: 2.94 (-2.94,2.94) <0.50,2.50>
Total: 73164 W: 18828 L: 18440 D: 35896
Ptnml(0-2): 30, 7749, 20644, 8121, 38

closes https://github.com/official-stockfish/Stockfish/pull/4810

Bench: 1453057
2023-09-29 22:30:27 +02:00
cj5716 660da1ca7b Skip moves-loop pruning in qsearch if we have only pawns
At first my idea was only to cover movecount and futility pruning, but
@peregrineshahin suggested to test it on all moves-loop pruning and it worked.

Passed STC:
LLR: 2.94 (-2.94,2.94) <0.00,2.00>
Total: 167968 W: 42970 L: 42480 D: 82518
Ptnml(0-2): 444, 18324, 46002, 18726, 488
https://tests.stockfishchess.org/tests/view/6511181a55b420c569d0d54c

Passed LTC:
LLR: 2.95 (-2.94,2.94) <0.50,2.50>
Total: 40794 W: 10496 L: 10182 D: 20116
Ptnml(0-2): 12, 4021, 12025, 4319, 20
https://tests.stockfishchess.org/tests/view/6512ccc4b3e74811c8aee86c

closes https://github.com/official-stockfish/Stockfish/pull/4809

Bench: 1338472
2023-09-29 22:28:34 +02:00
Sebastian Buchwald 4f0fecad8a Use C++17 variable templates for type traits
The C++17 variable templates are slightly more readable and allow us to
remove the typename keyword in a few cases.

closes https://github.com/official-stockfish/Stockfish/pull/4806

No functional change
2023-09-29 22:22:40 +02:00
mstembera 31d0b7fe93 Remove unused see_ge() code
closes https://github.com/official-stockfish/Stockfish/pull/4805

No functional change
2023-09-29 22:19:08 +02:00
FauziAkram 243f7b264a Improve grammar of comments
closes https://github.com/official-stockfish/Stockfish/pull/4801

No functional change
2023-09-29 22:18:17 +02:00
FauziAkram 9739ed7a97 Simplify pawn count in evaluation
This simplifies the evaluation by removing the unnecessary pawn count term when
combining nnue and optimism values.

Passed STC
LLR: 2.95 (-2.94,2.94) <-1.75,0.25>
Total: 61472 W: 15748 L: 15554 D: 30170
Ptnml(0-2): 191, 7123, 15933, 7279, 210
https://tests.stockfishchess.org/tests/view/650c34cf7ca0d3f7bbf264ff

Passed LTC:
LLR: 2.94 (-2.94,2.94) <-1.75,0.25>
Total: 81264 W: 20657 L: 20500 D: 40107
Ptnml(0-2): 30, 8713, 22997, 8854, 38
https://tests.stockfishchess.org/tests/view/650cc30efb151d43ae6d5987

closes https://github.com/official-stockfish/Stockfish/pull/4800

Bench: 1530568
2023-09-29 22:12:46 +02:00
Jasper Shovelton ce99b4b2ef Increment minor section number from 3.7.1 to 3.8.1.
Pext has nothing to do with git commit sha/date, so separate the two
sub-sections.

closes https://github.com/official-stockfish/Stockfish/pull/4785

No functional change
2023-09-29 22:07:10 +02:00
Joost VandeVondele 22cdb6c1ea Explicitly invoke shell
in some cases the permission on the script might be incorrect (zip downloads?).
Explicitly invoke the shell

closes https://github.com/official-stockfish/Stockfish/pull/4803

No functional change
2023-09-24 20:04:42 +02:00
Linmiao Xu 70ba9de85c Update NNUE architecture to SFNNv8: L1-2560 nn-ac1dbea57aa3.nnue
Creating this net involved:
- a 6-stage training process from scratch. The datasets used in stages 1-5 were fully minimized.
- permuting L1 weights with https://github.com/official-stockfish/nnue-pytorch/pull/254

A strong epoch after each training stage was chosen for the next. The 6 stages were:

```
1. 400 epochs, lambda 1.0, default LR and gamma
   UHOx2-wIsRight-multinet-dfrc-n5000 (135G)
     nodes5000pv2_UHO.binpack
     data_pv-2_diff-100_nodes-5000.binpack
     wrongIsRight_nodes5000pv2.binpack
     multinet_pv-2_diff-100_nodes-5000.binpack
     dfrc_n5000.binpack

2. 800 epochs, end-lambda 0.75, LR 4.375e-4, gamma 0.995, skip 12
   LeelaFarseer-T78juntoaugT79marT80dec.binpack (141G)
     T60T70wIsRightFarseerT60T74T75T76.binpack
     test78-junjulaug2022-16tb7p.no-db.min.binpack
     test79-mar2022-16tb7p.no-db.min.binpack
     test80-dec2022-16tb7p.no-db.min.binpack

3. 800 epochs, end-lambda 0.725, LR 4.375e-4, gamma 0.995, skip 20
   leela93-v1-dfrc99-v2-T78juntosepT80jan-v6dd-T78janfebT79aprT80aprmay.min.binpack
     leela93-filt-v1.min.binpack
     dfrc99-16tb7p-filt-v2.min.binpack
     test78-juntosep2022-16tb7p-filter-v6-dd.min-mar2023.binpack
     test80-jan2023-3of3-16tb7p-filter-v6-dd.min-mar2023.binpack
     test78-janfeb2022-16tb7p.min.binpack
     test79-apr2022-16tb7p.min.binpack
     test80-apr2022-16tb7p.min.binpack
     test80-may2022-16tb7p.min.binpack

4. 800 epochs, end-lambda 0.7, LR 4.375e-4, gamma 0.995, skip 24
   leela96-dfrc99-v2-T78juntosepT79mayT80junsepnovjan-v6dd-T80mar23-v6-T60novdecT77decT78aprmayT79aprT80may23.min.binpack
     leela96-filt-v2.min.binpack
     dfrc99-16tb7p-filt-v2.min.binpack
     test78-juntosep2022-16tb7p-filter-v6-dd.min-mar2023.binpack
     test79-may2022-16tb7p.filter-v6-dd.min.binpack
     test80-jun2022-16tb7p.filter-v6-dd.min.binpack
     test80-sep2022-16tb7p.filter-v6-dd.min.binpack
     test80-nov2022-16tb7p.filter-v6-dd.min.binpack
     test80-jan2023-3of3-16tb7p-filter-v6-dd.min-mar2023.binpack
     test80-mar2023-2tb7p.v6-sk16.min.binpack
     test60-novdec2021-16tb7p.min.binpack
     test77-dec2021-16tb7p.min.binpack
     test78-aprmay2022-16tb7p.min.binpack
     test79-apr2022-16tb7p.min.binpack
     test80-may2023-2tb7p.min.binpack

5. 960 epochs, end-lambda 0.7, LR 4.375e-4, gamma 0.995, skip 28
   Increased max-epoch to 960 near the end of the first 800 epochs
   5af11540bbfe dataset: https://github.com/official-stockfish/Stockfish/pull/4635

6. 1000 epochs, end-lambda 0.7, LR 4.375e-4, gamma 0.995, skip 28
   Increased max-epoch to 1000 near the end of the first 800 epochs
   1ee1aba5ed dataset: https://github.com/official-stockfish/Stockfish/pull/4782
```

L1 weights permuted with:
```bash
python3 serialize.py $nnue $nnue_permuted \
  --features=HalfKAv2_hm \
  --ft_optimize \
  --ft_optimize_data=/data/fishpack32.binpack \
  --ft_optimize_count=10000
```

Speed measurements from 100 bench runs at depth 13 with profile-build x86-64-avx2:
```
sf_base =  1329051 +/-   2224 (95%)
sf_test =  1163344 +/-   2992 (95%)
diff    =  -165706 +/-   4913 (95%)
speedup = -12.46807% +/- 0.370% (95%)
```

Training data can be found at:
https://robotmoon.com/nnue-training-data/

Local elo at 25k nodes per move (vs. L1-2048 nn-1ee1aba5ed4c.nnue)
ep959 : 16.2 +/- 2.3

Failed 10+0.1 STC:
https://tests.stockfishchess.org/tests/view/6501beee2cd016da89abab21
LLR: -2.92 (-2.94,2.94) <0.00,2.00>
Total: 13184 W: 3285 L: 3535 D: 6364
Ptnml(0-2): 85, 1662, 3334, 1440, 71

Failed 180+1.8 VLTC:
https://tests.stockfishchess.org/tests/view/6505cf9a72620bc881ea908e
LLR: -2.94 (-2.94,2.94) <0.00,2.00>
Total: 64248 W: 16224 L: 16374 D: 31650
Ptnml(0-2): 26, 6788, 18640, 6650, 20

Passed 60+0.6 th 8 VLTC SMP (STC bounds):
https://tests.stockfishchess.org/tests/view/65084a4618698b74c2e541dc
LLR: 2.95 (-2.94,2.94) <0.00,2.00>
Total: 90630 W: 23372 L: 23033 D: 44225
Ptnml(0-2): 13, 8490, 27968, 8833, 11

Passed 60+0.6 th 8 VLTC SMP:
https://tests.stockfishchess.org/tests/view/6501d45d2cd016da89abacdb
LLR: 2.95 (-2.94,2.94) <0.50,2.50>
Total: 137804 W: 35764 L: 35276 D: 66764
Ptnml(0-2): 31, 13006, 42326, 13522, 17

closes https://github.com/official-stockfish/Stockfish/pull/4795

bench 1246812
2023-09-22 19:26:16 +02:00
Stefan Geschwentner 154b8d3ecb Remove VALUE_KNOWN_WIN.
After removing classic evaluation VALUE_KNOWN_WIN is not anymore returned explicit evaluation. So remove and replace it with VALUE_TB_WIN_IN_MAX_PLY.

Measurement on my big bench (bench 16 1 16 pos1000.fen) verifies that at least with current net the calculated evaluation lies always in the open interval  (-VALUE_KNOWN_WIN, VALUE_KNOWN_WIN).
So i consider this a non-functional change. But to be safe i tested this also at LTC as requested by Stephane Nicolet.

STC:
https://tests.stockfishchess.org/tests/view/64f9db40eaf01be8259a6ed5
LLR: 2.93 (-2.94,2.94) <-1.75,0.25>
Total: 455296 W: 115981 L: 116217 D: 223098
Ptnml(0-2): 1415, 50835, 123420, 50527, 1451

LTC:
https://tests.stockfishchess.org/tests/view/650bfd867ca0d3f7bbf25feb
LLR: 2.95 (-2.94,2.94) <-1.75,0.25>
Total: 35826 W: 9170 L: 8973 D: 17683
Ptnml(0-2): 12, 3523, 10645, 3722, 11

closes https://github.com/official-stockfish/Stockfish/pull/4792

Bench: 1603079
2023-09-22 19:25:57 +02:00
mstembera 95fe2b9a9d Reduce SIMD register count from 32 to 16
in the case of avx512 and vnni512 archs.

Up to 17% speedup, depending on the compiler, e.g.

```
AMD pro 7840u (zen4 phoenix apu 4nm)
bash bench_parallel.sh ./stockfish_avx512_gcc13 ./stockfish_avx512_pr_gcc13 20 10
sf_base =  1077737 +/-   8446 (95%)
sf_test =  1264268 +/-   8543 (95%)
diff    =   186531 +/-   4280 (95%)
speedup =  17.308% +/- 0.397% (95%)
```

Prior to this patch, it appears gcc spills registers.

closes https://github.com/official-stockfish/Stockfish/pull/4796

No functional change
2023-09-22 19:15:34 +02:00
cj5716 fce4cc1829 Make casting styles consistent
Make casting styles consistent with the rest of the code.

closes https://github.com/official-stockfish/Stockfish/pull/4793

No functional change
2023-09-22 19:14:29 +02:00
Sebastian Buchwald 952740b36c Let CI check C++ includes
The commit adds a CI workflow that uses the included-what-you-use (IWYU)
tool to check for missing or superfluous includes in .cpp files and
their corresponding .h files. This means that some .h files (especially
in the nnue folder) are not checked yet.

The CI setup looks like this:
- We build IWYU from source to include some yet unreleased fixes.
  This IWYU version targets LLVM 17. Thus, we get the latest release
  candidate of LLVM 17 from LLVM's nightly packages.
- The Makefile now has an analyze target that just build the object
  files (without linking)
- The CI uses the analyze target with the IWYU tool as compiler to
  analyze the compiled .cpp file and its corresponding .h file.
- If IWYU suggests a change the build fails (-Xiwyu --error).
- To avoid false positives we use LLVM's libc++ as standard library
- We have a custom mappings file that adds some mappings that are
  missing in IWYU's default mappings

We also had to add one IWYU pragma to prevent a false positive in
movegen.h.

https://github.com/official-stockfish/Stockfish/pull/4783

No functional change
2023-09-22 19:12:53 +02:00
Stéphane Nicolet e594aa7429 Export makefile ARCH in binary
Example of the `./stockfish compiler` command:

Compiled by                : g++ (GNUC) 10.3.0 on Apple
Compilation architecture   : x86-64-bmi2
Compilation settings       : 64bit BMI2 AVX2 SSE41 SSSE3 SSE2 POPCNT
Compiler __VERSION__ macro : 10.3.0

closes https://github.com/official-stockfish/Stockfish/pull/4789

no functional change
2023-09-22 19:09:20 +02:00
Joost VandeVondele 708319a433 Enable a default native ARCH
uses a posix compatible script to find the native arch.
(based on ppigazzini's https://github.com/ppigazzini/stockfish-downloader )
use that native arch by default, no changes if ARCH is specified explicitly.

SF can now be compiled in an optimal way simply using

make -j profile-build

closes https://github.com/official-stockfish/Stockfish/pull/4777

No functional change
2023-09-22 19:06:37 +02:00
mstembera 97f706ecc1 Sparse impl of affine_transform_non_ssse3()
deal with the general case

About a 8.6% speedup (for general arch)

Results for 200 tests for each version:

            Base      Test      Diff
    Mean    141741    153998    -12257
    StDev   2990      3042      3742

p-value: 0.999
speedup: 0.086

closes https://github.com/official-stockfish/Stockfish/pull/4786

No functional change
2023-09-22 19:03:47 +02:00
peregrineshahin 0e32287af4 Reorder some lines
Now that qsearch has its own repetition detection we can flip the order of lines and remove the guard of depth < 0 which is not needed after reordering (i.e. it was there to prevent checking repetition again at depth ==0).

Passed STC:
https://tests.stockfishchess.org/tests/view/6502ecbb2cd016da89abc3fb
LLR: 2.93 (-2.94,2.94) <-1.75,0.25>
Total: 69536 W: 17668 L: 17490 D: 34378
Ptnml(0-2): 190, 7652, 18929, 7784, 213

Passed LTC:
https://tests.stockfishchess.org/tests/view/6505ce9072620bc881ea9086
LLR: 2.94 (-2.94,2.94) <-1.75,0.25>
Total: 52116 W: 13294 L: 13113 D: 25709
Ptnml(0-2): 26, 5176, 15471, 5361, 24

closes https://github.com/official-stockfish/Stockfish/pull/4791

No functional change
2023-09-22 19:02:18 +02:00
Stéphane Nicolet 3f7fb5ac1d Reformat some comments
Also include the bench to make Continuation Integration happy on Github.

Bench: 1603079
2023-09-11 23:19:06 +02:00
Sebastian Buchwald b9319c4fa4 Cleanup code after dropping ICC support in favor of ICX
The commit removes all uses of ICC's __INTEL_COMPILER macro and other
references to ICC. It also adds ICX info to the compiler command and
fixes two typos in Makefile's help output.

closes https://github.com/official-stockfish/Stockfish/pull/4769

No functional change
2023-09-11 22:46:01 +02:00
Linmiao Xu 3d1b067d85 Update default net to nn-1ee1aba5ed4c.nnue
Created by retraining the master net on a dataset composed by:
- adding Leela data from T60 jul-dec 2020, T77 nov 2021, T80 jun-jul 2023
- deduplicating and unminimizing parts of the dataset before interleaving

Trained initially with max epoch 800, then increased near the end of training
twice. First to 960, then 1200. After training, post-processing involved:
- greedy permuting L1 weights with https://github.com/official-stockfish/Stockfish/pull/4620
- greedy 2- and 3- cycle permuting with https://github.com/official-stockfish/Stockfish/pull/4640

  python3 easy_train.py \
    --experiment-name 2048-retrain-S6-sk28 \
    --training-dataset /data/S6.binpack \
    --early-fen-skipping 28 \
    --start-from-engine-test-net True \
    --max_epoch 1200 \
    --lr 4.375e-4 \
    --gamma 0.995 \
    --start-lambda 1.0 \
    --end-lambda 0.7 \
    --tui False \
    --seed $RANDOM \
    --gpus 0

In the list of datasets below, periods in the filename represent the sequence of
steps applied to arrive at the particular binpack. For example:

test77-dec2021-16tb7p.filter-v6-dd.min-mar2023.unminimized.binpack
1. test77 dec2021 data rescored with 16 TB of syzygy tablebases during data conversion
2. filtered with csv_filter_v6_dd.py - v6 filtering and deduplication in one step
3. minimized with the original mar2023 implementation of `minimize_binpack` in
   the tools branch
4. unminimized by removing all positions with score == 32002 (`VALUE_NONE`)

Binpacks were:
- filtered with: https://github.com/linrock/nnue-data
- unminimized with: https://github.com/linrock/Stockfish/tree/tools-unminify
- deduplicated with: https://github.com/linrock/Stockfish/tree/tools-dd

  DATASETS=(
    leela96-filt-v2.min.unminimized.binpack
    dfrc99-16tb7p-eval-filt-v2.min.unminimized.binpack

    # most of the 0dd1cebea57 v6-dd dataset (without test80-jul2022)
    # https://github.com/official-stockfish/Stockfish/pull/4606
    test60-novdec2021-12tb7p.filter-v6-dd.min-mar2023.unminimized.binpack
    test77-dec2021-16tb7p.filter-v6-dd.min-mar2023.unminimized.binpack
    test78-jantomay2022-16tb7p.filter-v6-dd.min-mar2023.unminimized.binpack
    test78-juntosep2022-16tb7p.filter-v6-dd.min-mar2023.unminimized.binpack
    test79-apr2022-16tb7p.filter-v6-dd.min-mar2023.unminimized.binpack
    test79-may2022-16tb7p.filter-v6-dd.min-mar2023.unminimized.binpack
    test80-jun2022-16tb7p.filter-v6-dd.min-mar2023.unminimized.binpack
    test80-aug2022-16tb7p.filter-v6-dd.min-mar2023.unminimized.binpack
    test80-sep2022-16tb7p.filter-v6-dd.min-mar2023.unminimized.binpack
    test80-oct2022-16tb7p.filter-v6-dd.min.binpack
    test80-nov2022-16tb7p.filter-v6-dd.min.binpack
    test80-jan2023-3of3-16tb7p.filter-v6-dd.min-mar2023.unminimized.binpack
    test80-feb2023-16tb7p.filter-v6-dd.min-mar2023.unminimized.binpack

    # older Leela data, recently converted
    test60-octnovdec2020-2tb7p.min.unminimized.binpack
    test60-julaugsep2020-2tb7p.min.binpack
    test77-nov2021-2tb7p.min.dd.binpack

    # newer Leela data
    test80-mar2023-2tb7p.min.unminimized.binpack
    test80-apr2023-2tb7p.filter-v6-sk16.min.unminimized.binpack
    test80-may2023-2tb7p.min.dd.binpack
    test80-jun2023-2tb7p.min.binpack
    test80-jul2023-2tb7p.binpack
  )
  python3 interleave_binpacks.py ${DATASETS[@]} /data/S6.binpack

Training data can be found at:
https://robotmoon.com/nnue-training-data/

Local elo at 25k nodes per move:
nn-epoch1059 : 2.7 +/- 1.6

Passed STC:
https://tests.stockfishchess.org/tests/view/64fc8d705dab775b5359db42
LLR: 2.93 (-2.94,2.94) <0.00,2.00>
Total: 168352 W: 43216 L: 42704 D: 82432
Ptnml(0-2): 599, 19672, 43134, 20160, 611

Passed LTC:
https://tests.stockfishchess.org/tests/view/64fd44a75dab775b5359f065
LLR: 2.94 (-2.94,2.94) <0.50,2.50>
Total: 154194 W: 39436 L: 38881 D: 75877
Ptnml(0-2): 78, 16577, 43238, 17120, 84

closes https://github.com/official-stockfish/Stockfish/pull/4782

Bench: 1603079
2023-09-11 22:37:39 +02:00
Michael Chaly ef22829616 Do more futility pruning in qsearch
This patch introduces a third futility pruning heuristic in qsearch. The idea is
that the static exchange evaluation is much worse than the difference between
futility base and alpha. Thus we can assume that the probability of the move
being good enough to beat alpha is low so it can be pruned.

Passed STC:
https://tests.stockfishchess.org/tests/view/64fc982a5dab775b5359dc83
LLR: 2.94 (-2.94,2.94) <0.00,2.00>
Total: 36576 W: 9484 L: 9170 D: 17922
Ptnml(0-2): 121, 4119, 9495, 4431, 122

Passed LTC:
https://tests.stockfishchess.org/tests/view/64fcc7935dab775b5359e1a9
LLR: 2.94 (-2.94,2.94) <0.50,2.50>
Total: 135408 W: 34556 L: 34041 D: 66811
Ptnml(0-2): 56, 14462, 38165, 14953, 68

closes https://github.com/official-stockfish/Stockfish/pull/4781

Bench: 1330793
2023-09-11 22:36:26 +02:00
cj5716 6d85f43e26 Simplify cutnode depth condition
With this patch, the depth condition for the cutnodes reduction is loosened from
tte->depth() >= depth + 3 to just tte->depth() >= depth.

Passed STC:
LLR: 2.93 (-2.94,2.94) <-1.75,0.25>
Total: 101152 W: 25830 L: 25682 D: 49640
Ptnml(0-2): 312, 11788, 26258, 11876, 342
https://tests.stockfishchess.org/tests/view/64fd15635dab775b5359eaa6

Passed LTC:
LLR: 2.94 (-2.94,2.94) <-1.75,0.25>
Total: 82542 W: 20980 L: 20824 D: 40738
Ptnml(0-2): 42, 8795, 23440, 8953, 41
https://tests.stockfishchess.org/tests/view/64fda3545dab775b5359fbf1

closes https://github.com/official-stockfish/Stockfish/pull/4780

Bench: 1479029
2023-09-11 22:30:57 +02:00
Sebastian Buchwald 46a5cedc11 Cleanup git checkout actions
We now fetch only the current commit for jobs that don't need the git
history. For the Prerelease job, we don't checkout the code at all.

closes https://github.com/official-stockfish/Stockfish/pull/4779

No functional change
2023-09-11 22:15:22 +02:00
Tomasz Sobczyk 1461d861c8 Prevent usage of AVX-512 for the last layer.
Add more static checks regarding the SIMD width match.

STC: https://tests.stockfishchess.org/tests/view/64f5c568a9bc5a78c669e70e
LLR: 2.95 (-2.94,2.94) <-1.75,0.25>
Total: 125216 W: 31756 L: 31636 D: 61824
Ptnml(0-2): 327, 13993, 33848, 14113, 327

Fixes a bug introduced in 2f2f45f, where with AVX-512 the weights and input to
the last layer were being read out of bounds. Now AVX-512 is only used for the
layers it can be used for. Additional static assertions have been added to
prevent more errors like this in the future.

closes https://github.com/official-stockfish/Stockfish/pull/4773

No functional change
2023-09-11 22:11:30 +02:00
Sebastian Buchwald a8b4fd1671 Avoid "using namespace std"
This is a cleanup PR that prepares the automatic checking of missing or
superfluous #include directives via the include-what-you-use (IWYU) tool
on the CI. Unfortunately, IWYU proposes additional includes for
"namespace std" although we don't need them.

To avoid the problem, the commit removes all "using namespace std"
statements from the code and directly uses the std:: prefix instead.
Alternatively, we could add specific usings (e.g. "using std::string")
foreach used type. Also, a mix of both approaches would be possible.
I decided for the prefix approach because most of the files were already
using the std:: prefixes despite the "using namespace std".

closes https://github.com/official-stockfish/Stockfish/pull/4772

No functional change
2023-09-11 22:07:55 +02:00
Stéphane Nicolet b25d68f6ee Introduce simple_eval() for lazy evaluations
This patch implements the pure materialistic evaluation called simple_eval()
to gain a speed-up during Stockfish search.

We use the so-called lazy evaluation trick: replace the accurate but slow
NNUE network evaluation by the super-fast simple_eval() if the position
seems to be already won (high material advantage). To guard against some
of the most obvious blunders introduced by this idea, this patch uses the
following features which will raise the lazy evaluation threshold in some
situations:

- avoid lazy evals on shuffling branches in the search tree
- avoid lazy evals if the position at root already has a material imbalance
- avoid lazy evals if the search value at root is already winning/losing.

Moreover, we add a small random noise to the simple_eval() term. This idea
(stochastic mobility in the minimax tree) was worth about 200 Elo in the pure
simple_eval() player on Lichess.

Overall, the current implementation in this patch evaluates about 2% of the
leaves in the search tree lazily.

--------------------------------------------

STC:
LLR: 2.94 (-2.94,2.94) <0.00,2.00>
Total: 60352 W: 15585 L: 15234 D: 29533
Ptnml(0-2): 216, 6906, 15578, 7263, 213
https://tests.stockfishchess.org/tests/view/64f1d9bcbd9967ffae366209

LTC:
LLR: 2.94 (-2.94,2.94) <0.50,2.50>
Total: 35106 W: 8990 L: 8678 D: 17438
Ptnml(0-2): 14, 3668, 9887, 3960, 24
https://tests.stockfishchess.org/tests/view/64f25204f5b0c54e3f04c0e7

verification run at VLTC:
LLR: 2.94 (-2.94,2.94) <0.50,2.50>
Total: 74362 W: 19088 L: 18716 D: 36558
Ptnml(0-2): 6, 7226, 22348, 7592, 9
https://tests.stockfishchess.org/tests/view/64f2ecdbf5b0c54e3f04d3ae

All three tests above were run with adjudication off, we also verified that
there was no regression on matetracker (thanks Disservin!).

----------------------------------------------

closes https://github.com/official-stockfish/Stockfish/pull/4771

Bench: 1393714
2023-09-03 09:28:16 +02:00
FauziAkram adf29b3fd6 Rename one variable
To enhance code clarity and prevent potential confusion with the
'r' variable assigned to reduction later in the code, this pull
request renames it to 'reductionScale' when we use the same name
in the reduction() function.

Using distinct variable names for separate functions improves code
readability and maintainability.

closes https://github.com/official-stockfish/Stockfish/pull/4765

No functional change
2023-09-03 09:10:27 +02:00
pb00067 1f7ff8406d Simplify slider_blocker calculation
Now that classical evaluation was removed, we can adapt this method
to the needs of set_check_info.

STC:
2.95 (-2.94,2.94) <-1.75,0.25>
Total: 298176 W: 75802 L: 75868 D: 146506
Ptnml(0-2): 908, 33608, 80192, 33402, 978
https://tests.stockfishchess.org/tests/view/64e70b899009777747557b43

closes https://github.com/official-stockfish/Stockfish/pull/4753

no functional change
2023-09-03 08:57:43 +02:00
Disservin 4f7fe255c7 Simplify README
The UCI protocol is rather technical and has little value in our README. Instead
it should be explained in our wiki. "Contributing" is moved above "Compiling
Stockfish" to make it more prominent.

Also move the CONTRIBUTING.md into the root directory and include it in the
distributed artifacts/releases.

closes https://github.com/official-stockfish/Stockfish/pull/4766

No functional change
2023-09-03 08:40:08 +02:00
Disservin 3c0e86a91e Cleanup includes
Reorder a few includes, include "position.h" where it was previously missing
and apply include-what-you-use suggestions. Also make the order of the includes
consistent, in the following way:

1. Related header (for .cpp files)
2. A blank line
3. C/C++ headers
4. A blank line
5. All other header files

closes https://github.com/official-stockfish/Stockfish/pull/4763
fixes https://github.com/official-stockfish/Stockfish/issues/4707

No functional change
2023-09-03 08:24:51 +02:00
ttruscott 8cd5cbf693 Omit two unneeded tests
These redundant tests were intended as a speed-up, but they do not seem
to provide any speed anymore.

STC: https://tests.stockfishchess.org/tests/view/64e9079c85e3e95030fd8259
LLR: 2.96 (-2.94,2.94) <-1.75,0.25>
Total: 134688 W: 34338 L: 34226 D: 66124
Ptnml(0-2): 426, 15122, 36124, 15258, 414

closes https://github.com/official-stockfish/Stockfish/pull/4767

No functional change
2023-09-03 08:07:59 +02:00
Stéphane Nicolet 4c4cb185aa Play turbulent when defending, simpler when attacking
This patch decays a little the evaluation (up to a few percent) for
positions which have a large complexity measure (material imbalance,
positional compensations, etc).

This may have nice consequences on the playing style, as it modifies
the search differently for attack and defense, both effects being
desirable:

- to see the effect on positions when Stockfish is defending, let us
suppose for instance that the side to move is Stockfish and the nnue
evaluation on the principal variation is -100 : this patch will decay
positions with an evaluation of -103 (say) to the same level, provided
they have huge material imbalance or huge positional compensation.
In other words, chaotic positions with an evaluation of -103 are now
comparable in our search tree to stable positions with an evaluation
of -100, and chaotic positions with an evaluation of -102 are now
preferred to stable positions with an evaluation of -100.

- the effect on positions when Stockfish is attacking is the opposite.
Let us suppose for instance that the side to move is Stockfish and the
nnue evaluation on the principal variation is +100 : this patch will
decay the evaluation to +97 if the positions on the principal variation
have huge material imbalance or huge positional compensation. In other
words, stable positions with an evaluation of +97 are now comparable
in our search tree to chaotic positions with an evaluation of +100,
and stable positions with an evaluation of +98 are now preferred to
chaotic positions with an evaluation of +100.

So the effect of this small change of evaluation on the playing style
is that Stockfish should now play a little bit more turbulent when
defending, and choose slightly simpler lines when attacking.

passed STC:
LLR: 2.93 (-2.94,2.94) <0.00,2.00>
Total: 268448 W: 68713 L: 68055 D: 131680
Ptnml(0-2): 856, 31514, 68943, 31938, 973
https://tests.stockfishchess.org/tests/view/64e252bb99700912526653ed

passed LTC:
LLR: 2.94 (-2.94,2.94) <0.50,2.50>
Total: 141060 W: 36066 L: 35537 D: 69457
Ptnml(0-2): 71, 15179, 39522, 15666, 92
https://tests.stockfishchess.org/tests/view/64e4447a9009777747553725

closes https://github.com/official-stockfish/Stockfish/pull/4762

Bench: 1426295
2023-08-24 08:11:17 +02:00
Shahin M. Shahin 440feecb4d Reduce repetitions branches
Increase reduction on retrying a move we just retreated that falls in a repetition:
if current move can be the same move from previous previous turn then we retreated
that move on the previous turn, this patch increases reduction if retrying that move
results in a repetition.

How to continue from there? Maybe we some variants of this idea could bring Elo too
(only testing the destination square, or triangulations, etc.)

Passed STC:
https://tests.stockfishchess.org/tests/view/64e1aede883cbb7cbd9ad976
LLR: 2.94 (-2.94,2.94) <0.00,2.00>
Total: 424000 W: 108675 L: 107809 D: 207516
Ptnml(0-2): 1296, 47350, 113896, 48108, 1350

Passed LTC:
https://tests.stockfishchess.org/tests/view/64e32d629970091252666872
LLR: 2.94 (-2.94,2.94) <0.50,2.50>
Total: 89682 W: 22976 L: 22569 D: 44137
Ptnml(0-2): 39, 8843, 26675, 9240, 44

closes https://github.com/official-stockfish/Stockfish/pull/4757

bench: 1574347
2023-08-22 11:32:51 +02:00
cj5716 030b87182a Do more full window searches
Remove the value < beta condition for doing full window searches.
As an added bonus the condition for full-window search is now much
more similar to other fail-soft engines.

Passed STC:
LLR: 2.95 (-2.94,2.94) <-1.75,0.25>
Total: 244608 W: 62286 L: 62294 D: 120028
Ptnml(0-2): 758, 28772, 63214, 28840, 720
https://tests.stockfishchess.org/tests/view/64d72d365b17f7c21c0e6675

Passed LTC:
LLR: 2.94 (-2.94,2.94) <-1.75,0.25>
Total: 311460 W: 78909 L: 78985 D: 153566
Ptnml(0-2): 129, 33959, 87656, 33831, 155
https://tests.stockfishchess.org/tests/view/64dca2265b17f7c21c0ee06c

closes https://github.com/official-stockfish/Stockfish/pull/4755

Bench: 1624221
2023-08-22 11:22:15 +02:00
Gian-Carlo Pascutto c6f62363a6 Simplify Square Clipped ReLU code.
Squared numbers are never negative, so barring any wraparound there
is no need to clamp to 0. From reading the code, there's no obvious
way to get wraparound, so the entire operation can be simplified
away. Updated original truncated code comments to be sensible.

Verified by running ./stockfish bench 128 1 24 and by the following test:

STC: https://tests.stockfishchess.org/tests/view/64da4db95b17f7c21c0eabe7
LLR: 2.94 (-2.94,2.94) <-1.75,0.25>
Total: 60224 W: 15425 L: 15236 D: 29563
Ptnml(0-2): 195, 6576, 16382, 6763, 196

closes https://github.com/official-stockfish/Stockfish/pull/4751

No functional change
2023-08-22 11:14:19 +02:00
Stéphane Nicolet 4c5919fa95 Fix some tabs in Makefile
Avoid mixing spaces and tabs for indentation in Makefile

closes https://github.com/official-stockfish/Stockfish/pull/4759

No functional change
2023-08-22 10:59:39 +02:00
Joost VandeVondele fe7353f702 Update links to fishtest
Fishtest has moved to https://github.com/official-stockfish/fishtest/

closes https://github.com/official-stockfish/Stockfish/pull/4758

No functional change
2023-08-22 10:53:49 +02:00
Matthies 9abef246a9 Allow compilation on Raspi (for ARMv8)
Current master fails to compile for ARMv8 on Raspi cause gcc (version 10.2.1)
does not like to cast between signed and unsigned vector types. This patch
fixes it by using unsigned vector pointer for ARM to avoid implicite cast.

closes https://github.com/official-stockfish/Stockfish/pull/4752

No functional change
2023-08-22 10:43:51 +02:00
Stéphane Nicolet a9a0dbbcd0 Fix some 'possible loss of data' warnings
Patch by Maxim Masiutin

closes https://github.com/official-stockfish/Stockfish/pull/4440

No functional change
2023-08-22 10:39:03 +02:00
Disservin 46756996e7 Add -funroll-loops to CXXFLAGS
Optimize profiling data accuracy by enabling -funroll-loops during the profile
generation phase, in addition to its default activation by -fprofile-use.
This seems to produce a slightly faster binary, for most compilers.

make -j profile-build ARCH=x86-64-avx2

sf_base =  1392875 +/-   5905 (95%)
sf_test =  1402332 +/-   7303 (95%)
diff    =     9457 +/-   4413 (95%)
speedup = 0.67896% +/- 0.317% (95%)

STC:
LLR: 2.93 (-2.94,2.94) <0.00,2.00>
Total: 34784 W: 8970 L: 8665 D: 17149
Ptnml(0-2): 115, 3730, 9405, 4019, 123
https://tests.stockfishchess.org/tests/view/64d944815b17f7c21c0e92e1

closes https://github.com/official-stockfish/Stockfish/pull/4750

No functional change
2023-08-16 21:25:42 +02:00
Muzhen Gaming fe0dca12f1 Simplify PvNode Reduction
Remove the depth condition for PvNode reduction.

Simplification STC:
https://tests.stockfishchess.org/tests/view/64d308fa5b17f7c21c0e0303
LLR: 2.93 (-2.94,2.94) <-1.75,0.25>
Total: 38976 W: 10106 L: 9889 D: 18981
Ptnml(0-2): 129, 4479, 10040, 4726, 114

Simplification LTC:
https://tests.stockfishchess.org/tests/view/64d457db5b17f7c21c0e236f
LLR: 2.94 (-2.94,2.94) <-1.75,0.25>
Total: 156402 W: 39727 L: 39645 D: 77030
Ptnml(0-2): 71, 17143, 43696, 17215, 76

closes https://github.com/official-stockfish/Stockfish/pull/4747

Bench: 1493904
2023-08-16 21:24:58 +02:00
SzilBalazs 3e5a817fd2 Fix dead link to compression algorithm in tbprobe
closes https://github.com/official-stockfish/Stockfish/pull/4746

No functional change
2023-08-16 21:24:58 +02:00
Disservin a77a8448ff Add CONTRIBUTING.md
closes https://github.com/official-stockfish/Stockfish/pull/4741

No functional change
2023-08-16 21:24:54 +02:00
mstembera 9b80897657 Simplify material difference in evaluate
STC: https://tests.stockfishchess.org/tests/view/64d166235b17f7c21c0ddc15
LLR: 2.94 (-2.94,2.94) <-1.75,0.25>
Total: 100032 W: 25698 L: 25547 D: 48787
Ptnml(0-2): 308, 11748, 25771, 11863, 326

LTC: https://tests.stockfishchess.org/tests/view/64d28c085b17f7c21c0df775
LLR: 2.94 (-2.94,2.94) <-1.75,0.25>
Total: 123870 W: 31463 L: 31348 D: 61059
Ptnml(0-2): 63, 13487, 34719, 13604, 62

Besides rebasing I replaced PawnValueMg w/ 126 explicitly to decouple from https://tests.stockfishchess.org/tests/view/64d212de5b17f7c21c0debbb by @peregrineshahin which also passed. #4734

closes https://github.com/official-stockfish/Stockfish/pull/4731

Bench: 1447866
2023-08-13 11:59:06 +02:00
Shahin M. Shahin 3322349c1a Simplify pieceValue to one phase.
Simplifies the usage of pieceValues to mg values with the exception of pawnValues, After the removal of PSQT.

passed STC:
https://tests.stockfishchess.org/tests/view/64d147845b17f7c21c0dd86c
LLR: 2.94 (-2.94,2.94) <-1.75,0.25>
Total: 197248 W: 50168 L: 50125 D: 96955
Ptnml(0-2): 651, 23029, 51222, 23070, 652

passed LTC:
https://tests.stockfishchess.org/tests/view/64d212de5b17f7c21c0debbb
LLR: 2.94 (-2.94,2.94) <-1.75,0.25>
Total: 181170 W: 45949 L: 45893 D: 89328
Ptnml(0-2): 84, 19656, 51052, 19706, 87

closes https://github.com/official-stockfish/Stockfish/pull/4734

Bench: 1494401
2023-08-13 11:58:08 +02:00
Stéphane Nicolet 495852fecd Simplify SEE pruning for captures
It seems that the current search is smart enough to allow us to remove
(again) the block of code that checks for discovered attacks after the
first pruning condition for captures.

STC:
LLR: 2.94 (-2.94,2.94) <-1.75,0.25>
Total: 278848 W: 70856 L: 70903 D: 137089
Ptnml(0-2): 960, 32829, 71894, 32780, 961
https://tests.stockfishchess.org/tests/view/64d0af095b17f7c21c0dc440

LTC:
LLR: 2.95 (-2.94,2.94) <-1.75,0.25>
Total: 100704 W: 25564 L: 25425 D: 49715
Ptnml(0-2): 56, 10858, 28381, 11005, 52
https://tests.stockfishchess.org/tests/view/64d293e85b17f7c21c0df844

closes https://github.com/official-stockfish/Stockfish/pull/4736

Bench: 1470572
2023-08-13 11:52:47 +02:00
FauziAkram c02ee70927 Simplify prior countermove bonus
Swapping a multiplication operation between two terms with a simple constant

Passed STC:
LLR: 2.93 (-2.94,2.94) <-1.75,0.25>
Total: 60512 W: 15424 L: 15231 D: 29857
Ptnml(0-2): 200, 6985, 15712, 7140, 219
https://tests.stockfishchess.org/tests/view/64d2addf5b17f7c21c0dfae6

Passed LTC:
LLR: 2.96 (-2.94,2.94) <-1.75,0.25>
Total: 108456 W: 27545 L: 27414 D: 53497
Ptnml(0-2): 63, 11629, 30698, 11790, 48
https://tests.stockfishchess.org/tests/view/64d3ab6e5b17f7c21c0e1188

closes https://github.com/official-stockfish/Stockfish/pull/4738

Bench: 1636213
2023-08-13 11:48:32 +02:00
ppigazzini 796d9df643 Check compiler for docker builds in CI
closes https://github.com/official-stockfish/Stockfish/pull/4739

No functional change
2023-08-13 11:47:52 +02:00
Gabrik 84e97a38a3 Remove the unused enum ScaleFactor
closes https://github.com/official-stockfish/Stockfish/pull/4740

No functional change
2023-08-13 11:46:48 +02:00
Shahin M. Shahin b7b7a3f3fa Detect repetitions before they happen in qsearch
Passed STC:
https://tests.stockfishchess.org/tests/view/64d495995b17f7c21c0e29ed
LLR: 2.95 (-2.94,2.94) <0.00,2.00>
Total: 340288 W: 86664 L: 85910 D: 167714
Ptnml(0-2): 1030, 38855, 89697, 39455, 1107

Passed LTC:
https://tests.stockfishchess.org/tests/view/64d5e1085b17f7c21c0e4ab5
LLR: 2.94 (-2.94,2.94) <0.50,2.50>
Total: 193230 W: 49235 L: 48606 D: 95389
Ptnml(0-2): 98, 20432, 54921, 21071, 93

closes https://github.com/official-stockfish/Stockfish/pull/4742

Bench: 1579576
2023-08-13 11:44:17 +02:00
cj5716 222f3ea55b Simplify a depth condition
As the negative extension term has sensitive scaling, it would make more sense to allow more negative extension also at lower depth, and not just a region between low and high depth.

Passed STC:
LLR: 2.96 (-2.94,2.94) <-1.75,0.25>
Total: 124096 W: 31611 L: 31485 D: 61000
Ptnml(0-2): 422, 14437, 32205, 14561, 423
https://tests.stockfishchess.org/tests/view/64d205d75b17f7c21c0dea82

Passed LTC:
LLR: 2.94 (-2.94,2.94) <-1.75,0.25>
Total: 387882 W: 97840 L: 97993 D: 192049
Ptnml(0-2): 198, 42004, 109668, 41895, 176
https://tests.stockfishchess.org/tests/view/64d333f85b17f7c21c0e06c6

closes https://github.com/official-stockfish/Stockfish/pull/4743

Bench: 1542357
2023-08-13 11:40:35 +02:00
Michael Chaly d97a02ea2b Give extra bonus to main history for moves that caused a fail low. #4744
Current master gives this type of bonuses to continuation history, this patch also gives them to main history.

Passed STC:
https://tests.stockfishchess.org/tests/view/64d4802a5b17f7c21c0e27b3
LLR: 2.94 (-2.94,2.94) <0.00,2.00>
Total: 480768 W: 122767 L: 121798 D: 236203
Ptnml(0-2): 1563, 56190, 123834, 57309, 1488

Passed LTC:
https://tests.stockfishchess.org/tests/view/64d7e4c05b17f7c21c0e7456
LLR: 2.95 (-2.94,2.94) <0.50,2.50>
Total: 32052 W: 8329 L: 8022 D: 15701
Ptnml(0-2): 19, 3335, 9015, 3634, 23

closes https://github.com/official-stockfish/Stockfish/pull/4744

Bench: 1711793
2023-08-13 11:38:24 +02:00
Joost VandeVondele 4be94f41a6 Update sanitizer CI to ubuntu 22.04
might fix the tsan errors

closes https://github.com/official-stockfish/Stockfish/pull/4745

No functional change
2023-08-13 11:34:00 +02:00
Joost VandeVondele 8192945870 Improve testing coverage, remove unused code
a) Add further tests to CI to cover most features. This uncovered a potential race
in case setoption was sent between two searches. As the UCI protocol requires
this sent to be went the engine is not searching, setoption now ensures that
this is the case.

b) Remove some unused code

closes https://github.com/official-stockfish/Stockfish/pull/4730

No functional change
2023-08-11 19:27:46 +02:00
Tomasz Sobczyk 0d2ddb81ef Fix Makefile for incorrect nnue file
If an incorrect network file is present at the start of the compilation stage, the
Makefile script now correctly removes it before trying to download a clean version.

closes https://github.com/official-stockfish/Stockfish/pull/4726

No functional change
2023-08-11 19:20:29 +02:00
Cody Ho e64b817e0a Remove all references to Score type
Score is obsolete with the removal of psqt.

No functional change.

Signed-off-by: Cody Ho <codyho@stanford.edu>

closes https://github.com/official-stockfish/Stockfish/pull/4724
2023-08-09 18:27:16 +02:00
Michael Chaly 5c2111cc30 Adjust futility pruning base in qsearch
Current master used value from transposition table there if it existed,
this patch uses minimum between this tt value and the static eval instead
(this thus is closer to the main search function, which uses the static eval).

Passed STC:
https://tests.stockfishchess.org/tests/view/64cd57285b17f7c21c0d6a8c
LLR: 2.94 (-2.94,2.94) <0.00,2.00>
Total: 252544 W: 64671 L: 64039 D: 123834
Ptnml(0-2): 839, 29207, 65575, 29785, 866

Passed LTC:
https://tests.stockfishchess.org/tests/view/64cf6c915b17f7c21c0d9fcb
LLR: 2.95 (-2.94,2.94) <0.50,2.50>
Total: 60150 W: 15374 L: 15012 D: 29764
Ptnml(0-2): 24, 6321, 17024, 6681, 25

closes https://github.com/official-stockfish/Stockfish/pull/4725

Bench: 1573024
2023-08-07 07:24:11 +02:00
FauziAkram a26f8d37e1 Tweak formula for pruning moves losing material
Simplify the "Prune moves with negative SEE" formula,
by removing one multiplication and subtraction operation.

Passed STC:
LLR: 2.93 (-2.94,2.94) <-1.75,0.25>
Total: 214272 W: 54596 L: 54572 D: 105104
Ptnml(0-2): 741, 25160, 55320, 25164, 751
https://tests.stockfishchess.org/tests/view/64c430d1dc56e1650abbdbf6

Passed LTC:
LLR: 2.95 (-2.94,2.94) <-1.75,0.25>
Total: 238380 W: 60600 L: 60601 D: 117179
Ptnml(0-2): 132, 26069, 66791, 26064, 134
https://tests.stockfishchess.org/tests/view/64c81f155b17f7c21c0cee2b

closes https://github.com/official-stockfish/Stockfish/pull/4721

bench: 1655337
2023-08-06 22:25:58 +02:00
Linmiao Xu 0ad9b51dea Remove classical psqt
Based on vondele's deletepsqt branch:
https://github.com/vondele/Stockfish/commit/369f5b051

This huge simplification uses a weighted material differences instead of
the positional piece square tables (psqt) in the semi-classical complexity
calculation. Tuned weights using spsa at 45+0.45 with:

int pawnMult = 100;
int knightMult = 325;
int bishopMult = 350;
int rookMult = 500;
int queenMult = 900;
TUNE(SetRange(0, 200), pawnMult);
TUNE(SetRange(0, 650), knightMult);
TUNE(SetRange(0, 700), bishopMult);
TUNE(SetRange(200, 800), rookMult);
TUNE(SetRange(600, 1200), queenMult);

The values obtained via this tuning session were for a model where
the psqt replacement formula was always from the point of view of White,
even if the side to move was Black. We re-used the same values for an
implementation with a psqt replacement from the point of view of the side
to move, testing the result both on our standard book on positions with
a strong White bias, and an alternate book with positions with a strong
Black bias.

We note that with the patch the last use of the venerable "Score" type
disappears in Stockfish codebase (the Score type was used in classical
evaluation to get a tampered eval interpolating values smoothly from the
early midgame stage to the endgame stage). We leave it to another commit
to clean all occurrences of Score in the code and the comments.

-------

Passed non-regression LTC:
LLR: 2.94 (-2.94,2.94) <-1.75,0.25>
Total: 142542 W: 36264 L: 36168 D: 70110
Ptnml(0-2): 76, 15578, 39856, 15696, 65
https://tests.stockfishchess.org/tests/view/64c8cb495b17f7c21c0cf9f8

Passed non-regression LTC (with a book with Black bias):
https://tests.stockfishchess.org/tests/view/64c8f9295b17f7c21c0cfdaf
LLR: 2.94 (-2.94,2.94) <-1.75,0.25>
Total: 494814 W: 125565 L: 125827 D: 243422
Ptnml(0-2): 244, 53926, 139346, 53630, 261

------

closes https://github.com/official-stockfish/Stockfish/pull/4713

Bench: 1655985
2023-08-06 22:16:52 +02:00
AndrovT a6d9a302b8 Implement AffineTransformSparseInput for armv8
Implements AffineTransformSparseInput layer for the NNUE evaluation
for the armv8 and armv8-dotprod architectures. We measured some nice
speed improvements via 10 runs of our benchmark:

armv8, Cortex-X1                  :   18.5% speed-up
armv8, Cortex-A76                 :   13.2% speed-up
armv8-dotprod, Cortex-X1          :   27.1% speed-up
armv8-dotprod, Cortex-A76         :   12.1% speed-up
armv8, Cortex-A72, Raspberry Pi 4 :    8.2% speed-up (thanks Torom!)

closes https://github.com/official-stockfish/Stockfish/pull/4719

No functional change
2023-08-06 21:22:37 +02:00
ppigazzini 4c43e1e27c Add new CPU archs in CI Tests workflow
Add CPU archs: armv8-dotprod, riscv64 and ppc64le.
The last two archs are built using QEMU multiarch docker container.

References:
https://docs.docker.com/build/building/multi-platform/
https://github.com/docker/setup-buildx-action
https://github.com/docker/setup-qemu-action
https://github.com/tonistiigi/binfmt
https://stackoverflow.com/questions/72444103/what-does-running-the-multiarch-qemu-user-static-does-before-building-a-containe

closes https://github.com/official-stockfish/Stockfish/pull/4718

No functional change
2023-08-06 21:17:33 +02:00
Niklas Fiekas 002a50457c Identify NEON_DOTPROD in compiler_info()
closes https://github.com/official-stockfish/Stockfish/pull/4712

No functional change
2023-08-06 21:14:39 +02:00
rn5f107s2 65ece7d985 Malus during move ordering for putting pieces en prise
The original idea is the reverse of a previous patch [1] which added bonuses
in our move picker to moves escaping threats. In this patch, in addition to
bonuses for evading threats, we apply penalties to moves moving to threatened
squares.

Further tweaks of that basic idea resulted in this specific version which
further increases the penalty of moves moving to squares threatend depending
on the piece threatening it. So for example a queen moving to a square attacked
by a pawn would receive a larger penalty than a queen moving to square attacked
by a rook.

[1]: https://github.com/official-stockfish/Stockfish/commit/08e0f52b77edb929989c68c49e954b9bc5d7d67e

--------

Passed STC:
https://tests.stockfishchess.org/tests/live_elo/64c11269dc56e1650abb935d
LLR: 2.94 (-2.94,2.94) <0.00,2.00>
Total: 95552 W: 24654 L: 24250 D: 46648
Ptnml(0-2): 322, 11098, 24562, 11442, 352

Passed LTC:
https://tests.stockfishchess.org/tests/live_elo/64c2004ddc56e1650abba8b3
LLR: 2.94 (-2.94,2.94) <0.50,2.50>
Total: 190230 W: 48806 L: 48178 D: 93246
Ptnml(0-2): 90, 20439, 53453, 21019, 114

-------

closes https://github.com/official-stockfish/Stockfish/pull/4711

Bench: 1350831
2023-07-29 00:56:26 +02:00
Stéphane Nicolet f84eb1f3ef Improve some comments
- clarify the examples for the bench command
- typo  in search.cpp

closes https://github.com/official-stockfish/Stockfish/pull/4710

No functional change
2023-07-28 23:38:49 +02:00
mstembera cb22520a9c Remove unused return type from propagate()
Also make two get_weight_index() static methods constexpr, for
consistency with the other static get_hash_value() method right above.
Tested for speed by user Torom (thanks).

closes https://github.com/official-stockfish/Stockfish/pull/4708

No functional change
2023-07-28 23:24:42 +02:00
FauziAkram 2667316ffc Simplify one multicut extension
Simplify away the ttValue <= alpha extension in the multicut block.

Passed STC:
LLR: 2.93 (-2.94,2.94) <-1.75,0.25>
Total: 318336 W: 81307 L: 81398 D: 155631
Ptnml(0-2): 1088, 37291, 82469, 37264, 1056
https://tests.stockfishchess.org/tests/view/64b8589fdc56e1650abad61d

Passed LTC:
LLR: 2.95 (-2.94,2.94) <-1.75,0.25>
Total: 89388 W: 22925 L: 22775 D: 43688
Ptnml(0-2): 34, 9635, 25210, 9777, 38
https://tests.stockfishchess.org/tests/view/64bc41d0dc56e1650abb29cb

closes https://github.com/official-stockfish/Stockfish/pull/4709

bench: 1604592
2023-07-25 16:43:35 +02:00
Stephen Touset 027713c4b4 Remove Zobrist::noPawns
Zobrist::noPawns is no longer used.

closes https://github.com/official-stockfish/Stockfish/pull/4344

no functional change
2023-07-25 00:13:38 +02:00
Stefan Geschwentner 76e1e8fd39 Simplify TT cutoff
Remove the exact bound condition from TT depth check.

STC:
https://tests.stockfishchess.org/tests/view/64b30b320cdec37b957359e9
LLR: 2.93 (-2.94,2.94) <-1.75,0.25>
Total: 332928 W: 84895 L: 85003 D: 163030
Ptnml(0-2): 1242, 39200, 85604, 39260, 1158

LTC:
https://tests.stockfishchess.org/tests/view/64b74e2adc56e1650abac0b6
LLR: 2.94 (-2.94,2.94) <-1.75,0.25>
Total: 92946 W: 23628 L: 23482 D: 45836
Ptnml(0-2): 38, 10033, 26192, 10165, 45

closes https://github.com/official-stockfish/Stockfish/pull/4702

Bench: 1601764
2023-07-24 02:23:43 +02:00
windfishballad 78e3d2ad78 Simplify some qsearch conditions
Use the assert which ensures that beta == alpha+1 at PVNodes
to simplify a little bit the conditions further down in the code.

passed STC:
LLR: 2.95 (-2.94,2.94) <-1.75,0.25>
Total: 56160 W: 14370 L: 14173 D: 27617
Ptnml(0-2): 210, 6192, 15076, 6395, 207
https://tests.stockfishchess.org/tests/view/64bc769cdc56e1650abb2e26

closes https://tests.stockfishchess.org/tests/view/64bc769cdc56e1650abb2e26

No functional change
2023-07-24 02:09:44 +02:00
Joost VandeVondele 4b2979760f Check clock more often
This patch changes the frequency with which the time is checked, changing
frequency from every 1024 counted nodes to every 512 counted nodes. The
master value was tuned for the old classical eval, the patch takes the
roughly 2x slowdown in nps with SFNNUEv7 into account. This could reduce
a bit the losses on time on fishtest, but they are probably unrelated.

passed STC:
https://tests.stockfishchess.org/tests/view/64bb8ae5dc56e1650abb1b11
LLR: 2.95 (-2.94,2.94) <-1.75,0.25>
Total: 76576 W: 19677 L: 19501 D: 37398
Ptnml(0-2): 274, 8592, 20396, 8736, 290

closes https://github.com/official-stockfish/Stockfish/pull/4704

No functional change
2023-07-24 01:56:20 +02:00
Michael Chaly 5ea1cbc778 Do more futility pruning for cutNodes that are not in TT
This is somewhat similar to IIR for cutnodes but instead of reducing
depth for cutnodes that don't have tt move we reduce margin multiplier
in futility pruning for cutnodes that are not in TT.

Passed STC:
https://tests.stockfishchess.org/tests/view/64b244b90cdec37b95734c5b
LLR: 2.95 (-2.94,2.94) <0.00,2.00>
Total: 75552 W: 19404 L: 19029 D: 37119
Ptnml(0-2): 233, 8806, 19378, 9071, 288

Passed LTC:
https://tests.stockfishchess.org/tests/view/64b3ae5a0cdec37b95736516
LLR: 2.95 (-2.94,2.94) <0.50,2.50>
Total: 104988 W: 27152 L: 26697 D: 51139
Ptnml(0-2): 41, 11259, 29446, 11700, 48

closes https://github.com/official-stockfish/Stockfish/pull/4700

bench 1727577
2023-07-19 21:40:38 +02:00
mstembera 1444837887 Remove inline assembly
closes https://github.com/official-stockfish/Stockfish/pull/4698

No functional change
2023-07-19 21:39:51 +02:00
Cody Ho 3fe0d5c533 Unused code cleanup
closes https://github.com/official-stockfish/Stockfish/pull/4696

No functional change
2023-07-19 21:38:39 +02:00
Jorge 6abd0bd9fb Add CodeQL workflow
add CI tooling to detect security bugs.

closes https://github.com/official-stockfish/Stockfish/pull/4659

No functional change
2023-07-19 21:36:38 +02:00
rn5f107s2 42d28424bc Removes a few Bitboards and functions
No longer used

closes https://github.com/official-stockfish/Stockfish/pull/4695

No functional change
2023-07-18 08:10:11 +02:00
Robert Nurnberg @ elitebook 6a31f54d3c remove evalType from bench
no longer used

closes https://github.com/official-stockfish/Stockfish/pull/4694

No functional change
2023-07-18 08:09:52 +02:00
Joost VandeVondele 34d0c1b527 Switch to macos 13 for CI
allows for building x86-64-avx2 and x86-64-bmi2 binaries for mac

install coreutils
show hardware capabilities as seen by the compilers
move some tests from sse41 to avx2 as platforms support it

closes https://github.com/official-stockfish/Stockfish/pull/4692

No functional change
2023-07-16 22:27:13 +02:00
Joost VandeVondele d70a905ce3 Deprecate the x86-64-modern arch
Explicitly describe the architecture as deprecated,
it remains available as its current alias x86-64-sse41-popcnt

CPUs that support just this instruction set are now years old,
any few years old Intel or AMD CPU supports x86-64-avx2. However,
naming things 'modern' doesn't age well, so instead use explicit names.

Adjust CI accordingly. Wiki, fishtest, downloader done as well.

closes https://github.com/official-stockfish/Stockfish/pull/4691

No functional change.
2023-07-16 17:47:25 +02:00
Michael Chaly 913574f421 Remove improvement variable
No longer used in a meaningful way.
Improve comments.

Closes https://github.com/official-stockfish/Stockfish/pull/4688

No functional change
2023-07-16 15:18:41 +02:00
maxim 18fdc2df3c Remove pawnKey from StateInfo
Remove pawnKey since it is not used anymore.

Passed Non-regression STC:
https://tests.stockfishchess.org/tests/view/64b023110cdec37b9573265c
LLR: 2.96 (-2.94,2.94) <-1.75,0.25>
Total: 334848 W: 85440 L: 85545 D: 163863
Ptnml(0-2): 1134, 38101, 89075, 37964, 1150

closes https://github.com/official-stockfish/Stockfish/pull/4687

No functional change
2023-07-16 15:16:14 +02:00
Joost VandeVondele e8a5c64988 Consolidate to centipawns conversion
avoid doing this calculations in multiple places.

closes https://github.com/official-stockfish/Stockfish/pull/4686

No functional change
2023-07-16 15:14:50 +02:00
Joost VandeVondele e89469925d Remove some CI parts not yet working
downgrading compiler didn't work for windows build. Stick to gcc 13 for now.
Windows x86-32 not a 32bit binary, remove.

closes https://github.com/official-stockfish/Stockfish/pull/4685

No functional change
2023-07-16 15:13:24 +02:00
AndrovT a42ab95e1f remove large input specialization
Removes unused large input specialization for dense affine transform. It has been obsolete since #4612 was merged.

closes https://github.com/official-stockfish/Stockfish/pull/4684

No functional change
2023-07-16 15:12:21 +02:00
Linmiao Xu ee53f8ed2f Reintroduce nnue eval pawn count multipliers again
With separate multipliers for nnue eval and optimism scaling.
This patch used 4 out of 7 params tuned with spsa at 30+0.3
using this tuning config:

Value LazyThreshold1 = Value(3622);
Value LazyThreshold2 = Value(1962);
int psqThresh = 2048;
int nnueNpmBase = 945;
int nnuePcMult = 0;
int optNpmBase = 150;
int optPcMult = 0;
TUNE(SetRange(3322, 3922), LazyThreshold1);
TUNE(SetRange(1662, 2262), LazyThreshold2);
TUNE(SetRange(1748, 2348), psqThresh);
TUNE(SetRange(745, 1145), nnueNpmBase);
TUNE(SetRange(-16, 16), nnuePcMult);
TUNE(SetRange(0, 300), optNpmBase);
TUNE(SetRange(-16, 16), optPcMult);

Passed STC:
https://tests.stockfishchess.org/tests/view/64a5a9b402cd07745c60ed07
LLR: 2.95 (-2.94,2.94) <0.00,2.00>
Total: 173632 W: 44417 L: 43903 D: 85312
Ptnml(0-2): 547, 20025, 45068, 20719, 457

Passed LTC:
https://tests.stockfishchess.org/tests/view/64a972a302cd07745c6136af
LLR: 2.94 (-2.94,2.94) <0.50,2.50>
Total: 277644 W: 70955 L: 70147 D: 136542
Ptnml(0-2): 193, 29902, 77787, 30784, 156

closes https://github.com/official-stockfish/Stockfish/pull/4681

bench 1556301
2023-07-15 09:16:09 +02:00
Joost VandeVondele a3a91f3f9f Build and test more binaries in CI
use a fixed compiler on Linux and Windows (right now gcc 11).
build avxvnni on Windows (Linux needs updated core utils)
build x86-32 on Linux (Windows needs other mingw)
fix a Makefile issue where a failed PGOBENCH would not stop the build
reuse the WINE_PATH for SDE as we do for QEMU
use WINE_PATH variable also for the signature
verify the bench for each of the binaries
do not build x86-64-avx2 on macos

closes https://github.com/official-stockfish/Stockfish/pull/4682

No functional change
2023-07-15 09:15:16 +02:00
FauziAkram acdbf45171 Use more expressive names for bonus1 and bonus2
closes https://github.com/official-stockfish/Stockfish/pull/4683

No functional change
2023-07-15 09:13:02 +02:00
Joost VandeVondele f5ab5832c6 Generate binaries for more advanced architectures
use intel's Software Development Emulator (SDE) in the actions that build the binaries.
This allows for building on Windows and Linux binaries for
- x86-64-avx512
- x86-64-vnni256
- x86-64-vnni512

(x86-64-avxvnni needs more recent gcc in the actions)

also build x86-64-avx2 on macos.

closes https://github.com/official-stockfish/Stockfish/pull/4679

No functional change
2023-07-13 08:21:17 +02:00
mstembera 529d3be8e2 More simplifications and cleanup in affine_transform_sparse_input.h
closes https://github.com/official-stockfish/Stockfish/pull/4677

No functional change
2023-07-13 08:20:33 +02:00
Sebastian Buchwald f972947492 Cleanup code after removal of classical evaluation
This includes the following changes:
- Remove declaration of removed global variable
- Adapt string that mentions removed UCI option

closes https://github.com/official-stockfish/Stockfish/pull/4675

No functional change
2023-07-13 08:19:37 +02:00
Joost VandeVondele af110e02ec Remove classical evaluation
since the introduction of NNUE (first released with Stockfish 12), we
have maintained the classical evaluation as part of SF in frozen form.
The idea that this code could lead to further inputs to the NN or
search did not materialize. Now, after five releases, this PR removes
the classical evaluation from SF. Even though this evaluation is
probably the best of its class, it has become unimportant for the
engine's strength, and there is little need to maintain this
code (roughly 25% of SF) going forward, or to expend resources on
trying to improve its integration in the NNUE eval.

Indeed, it had still a very limited use in the current SF, namely
for the evaluation of positions that are nearly decided based on
material difference, where the speed of the classical evaluation
outweights its inaccuracies. This impact on strength is small,
roughly 2Elo, and probably decreasing in importance as the TC grows.

Potentially, removal of this code could lead to the development of
techniques to have faster, but less accurate NN evaluation,
for certain positions.

STC
https://tests.stockfishchess.org/tests/view/64a320173ee09aa549c52157
Elo: -2.35 ± 1.1 (95%) LOS: 0.0%
Total: 100000 W: 24916 L: 25592 D: 49492
Ptnml(0-2): 287, 12123, 25841, 11477, 272
nElo: -4.62 ± 2.2 (95%) PairsRatio: 0.95

LTC
https://tests.stockfishchess.org/tests/view/64a320293ee09aa549c5215b
 Elo: -1.74 ± 1.0 (95%) LOS: 0.0%
Total: 100000 W: 25010 L: 25512 D: 49478
Ptnml(0-2): 44, 11069, 28270, 10579, 38
nElo: -3.72 ± 2.2 (95%) PairsRatio: 0.96

VLTC SMP
https://tests.stockfishchess.org/tests/view/64a3207c3ee09aa549c52168
 Elo: -1.70 ± 0.9 (95%) LOS: 0.0%
Total: 100000 W: 25673 L: 26162 D: 48165
Ptnml(0-2): 8, 9455, 31569, 8954, 14
nElo: -3.95 ± 2.2 (95%) PairsRatio: 0.95

closes https://github.com/official-stockfish/Stockfish/pull/4674

Bench: 1444646
2023-07-11 22:56:49 +02:00
Muzhen Gaming 6a8767a0d5 Simplify PvNode reduction
Simplification STC: https://tests.stockfishchess.org/tests/view/64a415803ee09aa549c539c3
LLR: 2.93 (-2.94,2.94) <-1.75,0.25>
Total: 37856 W: 9719 L: 9504 D: 18633
Ptnml(0-2): 98, 4277, 9977, 4464, 112

Simplification LTC: https://tests.stockfishchess.org/tests/view/64a5ffe202cd07745c60f360
LLR: 2.96 (-2.94,2.94) <-1.75,0.25>
Total: 55878 W: 14323 L: 14138 D: 27417
Ptnml(0-2): 21, 5993, 15732, 6166, 27

closes https://github.com/official-stockfish/Stockfish/pull/4673

Bench: 2604965
2023-07-11 22:55:00 +02:00
Joost VandeVondele ee023d7fd7 Fix CI output
closes https://github.com/official-stockfish/Stockfish/pull/4669

No functional change
2023-07-11 22:53:15 +02:00
Linmiao Xu e699fee513 Update default net to nn-c38c3d8d3920.nnue
This was a later epoch from the same experiment that led to the
previous master net. After training, it was prepared the same way:

1. greedy permuting L1 weights with https://github.com/official-stockfish/Stockfish/pull/4620
2. leb128 compression with https://github.com/glinscott/nnue-pytorch/pull/251
3. greedy 2- and 3- cycle permuting with https://github.com/official-stockfish/Stockfish/pull/4640

Local elo at 25k nodes per move (vs. L1-1536 nn-fdc1d0fe6455.nnue):
nn-epoch739.nnue : 20.2 +/- 1.7

Passed STC:
https://tests.stockfishchess.org/tests/view/64a050b33ee09aa549c4e4c8
LLR: 2.95 (-2.94,2.94) <0.00,2.00>
Total: 195552 W: 49977 L: 49430 D: 96145
Ptnml(0-2): 556, 22775, 50607, 23242, 596

Passed LTC:
https://tests.stockfishchess.org/tests/view/64a127bd3ee09aa549c4f60c
LLR: 2.94 (-2.94,2.94) <0.50,2.50>
Total: 235452 W: 60327 L: 59609 D: 115516
Ptnml(0-2): 119, 25173, 66426, 25887, 121

closes https://github.com/official-stockfish/Stockfish/pull/4666

bench 2427629
2023-07-06 23:03:58 +02:00
Joost VandeVondele 9ba24912c1 Add armv8-dotprod to CI binaries
also generate binaries for more recent Android hardware.

closes https://github.com/official-stockfish/Stockfish/pull/4663

No functional change
2023-07-06 23:03:16 +02:00
mstembera f8e65d82eb Simplify away lookup_count.
https://tests.stockfishchess.org/tests/view/64a3c1a93ee09aa549c53167
LLR: 2.94 (-2.94,2.94) <-1.75,0.25>
Total: 32832 W: 8497 L: 8280 D: 16055
Ptnml(0-2): 80, 3544, 8967, 3729, 96

closes https://github.com/official-stockfish/Stockfish/pull/4662

No functional change
2023-07-06 23:02:11 +02:00
Joost VandeVondele 19e2a88504 Revise extract bench from git log in CI
order commits differently

closes https://github.com/official-stockfish/Stockfish/pull/4668

No functional change
2023-07-06 23:01:27 +02:00
ppigazzini e87e103ca9 Remove leftover braces for if conditional in CI
closes https://github.com/official-stockfish/Stockfish/pull/4660

No functional change
2023-07-03 20:17:14 +02:00
ppigazzini ca5d9a5ff0 Extract bench according to wiki instructions
- loop through the commits starting from the latest one
- read the bench value from the last match, if any, of the template
  in the commit body text

closes https://github.com/official-stockfish/Stockfish/pull/4627

No functional change
2023-07-03 19:07:06 +02:00
rn5f107s2 95ce443aaa simplified gives check castling
tested verifying perft and bench is unchanged
on a larger set of epds for both standard and FRC chess.

Passed non-regression STC:
https://tests.stockfishchess.org/tests/live_elo/648587be65ffe077ca123d78
LLR: 2.95 (-2.94,2.94) <-1.75,0.25>
Total: 153632 W: 41015 L: 40928 D: 71689
Ptnml(0-2): 377, 16077, 43816, 16174, 372

closes https://github.com/official-stockfish/Stockfish/pull/4628

No functional change
2023-07-03 18:54:22 +02:00
FauziAkram 9cd563cb54 Improving grammar and readability of comments
closes https://github.com/official-stockfish/Stockfish/pull/4643

No functional change
2023-07-03 18:38:41 +02:00
Muzhen Gaming 5f8480a730 Simplify score improvement reduction
Reduce depth by 2 based on score improvement, only for depths 3 to 11.

Simplification STC: https://tests.stockfishchess.org/tests/view/64929a53dc7002ce609c7807
LLR: 2.95 (-2.94,2.94) <-1.75,0.25>
Total: 238912 W: 63466 L: 63468 D: 111978
Ptnml(0-2): 564, 26262, 65805, 26262, 563

Simplification LTC: https://tests.stockfishchess.org/tests/view/64942e47dc7002ce609c9e07
LLR: 2.94 (-2.94,2.94) <-1.75,0.25>
Total: 64452 W: 17485 L: 17320 D: 29647
Ptnml(0-2): 19, 6161, 19706, 6316, 24

closes https://github.com/official-stockfish/Stockfish/pull/4637

Bench: 2740142
2023-07-03 18:33:27 +02:00
Muzhen Gaming eb9aaf9489 Simplify away improvement term in null move search
passed STC:
https://tests.stockfishchess.org/tests/view/649c0d2edc7002ce609d33b5
LLR: 2.95 (-2.94,2.94) <-1.75,0.25>
Total: 271104 W: 72181 L: 72217 D: 126706
Ptnml(0-2): 691, 30042, 74129, 29992, 698

passed LTC:
https://tests.stockfishchess.org/tests/view/649d0dd7dc7002ce609d4efa
LLR: 2.94 (-2.94,2.94) <-1.75,0.25>
Total: 183120 W: 49469 L: 49418 D: 84233
Ptnml(0-2): 84, 17636, 56063, 17699, 78

closes https://github.com/official-stockfish/Stockfish/pull/4650

Bench: 2642851
2023-07-03 18:27:33 +02:00
peregrineshahin fa143922ae Fix pruning to (in TB loss) in Null move pruning.
Current logic can apply Null move pruning
on a dead-lost position returning an unproven loss
(i.e. in TB loss score or mated in losing score) on nonPv nodes.

on a default bench, this can be observed by adding this debugging line:
```
if (nullValue >= beta)
{
    // Do not return unproven mate or TB scores
    nullValue = std::min(nullValue, VALUE_TB_WIN_IN_MAX_PLY-1);
    dbg_hit_on(nullValue <= VALUE_TB_LOSS_IN_MAX_PLY); // Hit #0: Total 73983 Hits 1 Hit Rate (%) 0.00135166
    if (thisThread->nmpMinPly || depth < 14)
        return nullValue;
```

This fixes this very rare issue (happens at ~0.00135166% of the time) by
eliminating the need to try Null Move Pruning with dead-lost positions
and leaving it to be determined by a normal searching flow.

The previous try to fix was not as safe enough because it was capping
the returned value to (out of TB range) thus reviving the dead-lost position
based on an artificial clamp (i.e. the in TB score/mate score can be lost on that nonPv node):
https://tests.stockfishchess.org/tests/view/649756d5dc7002ce609cd794

Final fix:
Passed STC:
https://tests.stockfishchess.org/tests/view/649a5446dc7002ce609d1049
LLR: 2.93 (-2.94,2.94) <-1.75,0.25>
Total: 577280 W: 153613 L: 153965 D: 269702
Ptnml(0-2): 1320, 60594, 165190, 60190, 1346

Passed LTC:
https://tests.stockfishchess.org/tests/view/649cd048dc7002ce609d4801
LLR: 2.94 (-2.94,2.94) <-1.75,0.25>
Total: 246432 W: 66769 L: 66778 D: 112885
Ptnml(0-2): 83, 22105, 78847, 22100, 81

closes https://github.com/official-stockfish/Stockfish/pull/4649

Bench: 2425978
2023-07-03 18:24:41 +02:00
mstembera 80564bcfcd Simplify lookup_count and clean up pieces().
https://github.com/official-stockfish/Stockfish/pull/4656

No functional change
2023-07-03 18:20:10 +02:00
disservin 8634717c64 Add bmi2 to CI generated binaries
verify bench for avx2 and bmi2 as well

closes https://github.com/official-stockfish/Stockfish/pull/4658

No functional change
2023-07-03 18:17:20 +02:00
ppigazzini 9a2d50eccc Make posix and msys2 shells consistent in CI
In CI, it is typical for the process to halt immediately when an error
is encountered. However, with our `shell: bash {0}` configuration,
the process continues despite errors for posix shells.
This commit updates the behavior of posix and msys2 shells to ensure
consistency in terms of pipeline exit codes and stop conditions.
We adopt the most appropriate default behavior as recommended
by the GitHub documentation.

Update the code that searches for the bench value in the git log:
- to be compatible with the new shell settings
- to retry the value from the first line that contains
  only the template and spaces/tabs/newlines

see also

https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions#jobsjob_idstepsshell
https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions#exit-codes-and-error-action-preference
https://github.com/msys2/setup-msys2/blob/main/main.js

closes https://github.com/official-stockfish/Stockfish/pull/4653

No functional change
2023-07-02 10:32:36 +02:00
Linmiao Xu 915532181f Update NNUE architecture to SFNNv7 with larger L1 size of 2048
Creating this net involved:
- a 5-step training process from scratch
- greedy permuting L1 weights with https://github.com/official-stockfish/Stockfish/pull/4620
- leb128 compression with https://github.com/glinscott/nnue-pytorch/pull/251
- greedy 2- and 3- cycle permuting with https://github.com/official-stockfish/Stockfish/pull/4640

The 5 training steps were:

1. 400 epochs, lambda 1.0, lr 9.75e-4
   UHOx2-wIsRight-multinet-dfrc-n5000-largeGensfen-d9.binpack (178G)
     nodes5000pv2_UHO.binpack
     data_pv-2_diff-100_nodes-5000.binpack
     wrongIsRight_nodes5000pv2.binpack
     multinet_pv-2_diff-100_nodes-5000.binpack
     dfrc_n5000.binpack
     large_gensfen_multipvdiff_100_d9.binpack
   ep399 chosen as start model for step2

2. 800 epochs, end-lambda 0.75, skip 16
   LeelaFarseer-T78juntoaugT79marT80dec.binpack (141G)
     T60T70wIsRightFarseerT60T74T75T76.binpack
     test78-junjulaug2022-16tb7p.no-db.min.binpack
     test79-mar2022-16tb7p.no-db.min.binpack
     test80-dec2022-16tb7p.no-db.min.binpack
   ep559 chosen as start model for step3

3. 800 epochs, end-lambda 0.725, skip 20
   leela96-dfrc99-v2-T80dectofeb-sk20-mar-v6-T77decT78janfebT79apr.binpack (223G)
     leela96-filt-v2.min.binpack
     dfrc99-16tb7p-eval-filt-v2.min.binpack
     test80-dec2022-16tb7p-filter-v6-sk20.min-mar2023.binpack
     test80-jan2023-16tb7p-filter-v6-sk20.min-mar2023.binpack
     test80-feb2023-16tb7p-filter-v6-sk20.min-mar2023.binpack
     test80-mar2023-2tb7p-filter-v6.min.binpack
     test77-dec2021-16tb7p.no-db.min.binpack
     test78-janfeb2022-16tb7p.no-db.min.binpack
     test79-apr2022-16tb7p.no-db.min.binpack
   ep499 chosen as start model for step4

4. 800 epochs, end-lambda 0.7, skip 24
   0dd1cebea57 dataset https://github.com/official-stockfish/Stockfish/pull/4606
   ep599 chosen as start model for step5

5. 800 epochs, end-lambda 0.7, skip 28
   same dataset as step4
   ep619 became nn-1b951f8b449d.nnue

For the final step5 training:

python3 easy_train.py \
  --experiment-name L1-2048-S5-sameData-sk28-S4-0dd1cebea57-shuffled-S3-leela96-dfrc99-v2-T80dectofeb-sk20-mar-v6-T77decT78janfebT79apr-sk20-S2-LeelaFarseerT78T79T80-ep399-S1-UHOx2-wIsRight-multinet-dfrc-n5000-largeGensfen-d9 \
  --training-dataset /data/leela96-dfrc99-T60novdec-v2-T80juntonovjanfebT79aprmayT78jantosepT77dec-v6dd-T80apr.binpack \
  --early-fen-skipping 28 \
  --nnue-pytorch-branch linrock/nnue-pytorch/misc-fixes-L1-2048 \
  --engine-test-branch linrock/Stockfish/L1-2048 \
  --start-from-engine-test-net False \
  --start-from-model /data/experiments/experiment_L1-2048-S4-0dd1cebea57-shuffled-S3-leela96-dfrc99-v2-T80dectofeb-sk20-mar-v6-T77decT78janfebT79apr-sk20-S2-LeelaFarseerT78T79T80-ep399-S1-UHOx2-wIsRight-multinet-dfrc-n5000-largeGensfen-d9/training/run_0/nn-epoch599.nnue
  --max_epoch 800 \
  --lr 4.375e-4 \
  --gamma 0.995 \
  --start-lambda 1.0 \
  --end-lambda 0.7 \
  --tui False \
  --seed $RANDOM \
  --gpus 0

SF training data components for the step1 dataset:
https://drive.google.com/drive/folders/1yLCEmioC3Xx9KQr4T7uB6GnLm5icAYGU

Leela training data for steps 2-5 can be found at:
https://robotmoon.com/nnue-training-data/

Due to larger L1 size and slower inference, the speed penalty loses elo
at STC. Measurements from 100 bench runs at depth 13 with x86-64-modern
on Intel Core i5-1038NG7 2.00GHz:

sf_base =  1240730  +/-   3443 (95%)
sf_test =  1153341  +/-   2832 (95%)
diff    =   -87388  +/-   1616 (95%)
speedup = -7.04330% +/- 0.130% (95%)

Local elo at 25k nodes per move (vs. L1-1536 nn-fdc1d0fe6455.nnue):
nn-epoch619.nnue : 21.1 +/- 3.2

Failed STC:
https://tests.stockfishchess.org/tests/view/6498ee93dc7002ce609cf979
LLR: -2.95 (-2.94,2.94) <0.00,2.00>
Total: 11680 W: 3058 L: 3299 D: 5323
Ptnml(0-2): 44, 1422, 3149, 1181, 44

LTC:
https://tests.stockfishchess.org/tests/view/649b32f5dc7002ce609d20cf
Elo: 0.68 ± 1.5 (95%) LOS: 80.5%
Total: 40000 W: 10887 L: 10809 D: 18304
Ptnml(0-2): 36, 3938, 11958, 4048, 20
nElo: 1.50 ± 3.4 (95%) PairsRatio: 1.02

Passed VLTC 180+1.8:
https://tests.stockfishchess.org/tests/view/64992b43dc7002ce609cfd20
LLR: 3.06 (-2.94,2.94) <0.00,2.00>
Total: 38086 W: 10612 L: 10338 D: 17136
Ptnml(0-2): 9, 3316, 12115, 3598, 5

Passed VLTC SMP 60+0.6 th 8:
https://tests.stockfishchess.org/tests/view/649a21fedc7002ce609d0c7d
LLR: 2.95 (-2.94,2.94) <0.50,2.50>
Total: 38936 W: 11091 L: 10820 D: 17025
Ptnml(0-2): 1, 2948, 13305, 3207, 7

closes https://github.com/official-stockfish/Stockfish/pull/4646

Bench: 2505168
2023-07-01 13:34:30 +02:00
cj5716 e551964ef6 Negative extension on cutNodes based on depth
This patch was inspired by candirufish original attempt at negative extensions
here that failed yellow: https://tests.stockfishchess.org/tests/view/6486529065ffe077ca124f32

I tested some variations of the idea and tuned a depth condition for
a modified version of it here https://tests.stockfishchess.org/tests/view/648db80a91c58631ce31fe00
after noticing abnormal scaling (ie many passed STC but not LTC)
After some small tweaks I got the final version here

Passed STC:
LLR: 2.98 (-2.94,2.94) <0.00,2.00>
Total: 122208 W: 32776 L: 32350 D: 57082
Ptnml(0-2): 310, 13250, 33553, 13686, 305
https://tests.stockfishchess.org/tests/view/64997934dc7002ce609d01e3

Passed LTC:
LLR: 2.94 (-2.94,2.94) <0.50,2.50>
Total: 145092 W: 39617 L: 39115 D: 66360
Ptnml(0-2): 54, 13691, 44552, 14197, 52
https://tests.stockfishchess.org/tests/view/649a1c5ddc7002ce609d0bff

closes https://github.com/official-stockfish/Stockfish/pull/4644

Bench: 2637784
2023-07-01 13:06:49 +02:00
Stéphane Nicolet e355c70594 Document the LEB128 patch
Add some comments and harmonize style for the LEB128 patch.

closes https://github.com/official-stockfish/Stockfish/pull/4642

No functional change
2023-07-01 13:01:28 +02:00
Daniel Monroe ef94f77f8c Update default net to nn-a3d1bfca1672.nnue
faster permutation of master net weights

Activation data taken from https://drive.google.com/drive/folders/1Ec9YuuRx4N03GPnVPoQOW70eucOKngQe?usp=sharing
Permutation found using https://github.com/Ergodice/nnue-pytorch/blob/836387a0e5e690431d404158c46648710f13904d/ftperm.py
See also https://github.com/glinscott/nnue-pytorch/pull/254

The algorithm greedily selects 2- and 3-cycles that can be permuted to increase the number of runs of zeroes. The percent of zero runs from the master net increased from 68.46 to 70.11 from 2-cycles and only increased to 70.32 when considering 3-cycles. Interestingly, allowing both halves of L1 to intermix when creating zero runs can give another 0.5% zero-run density increase with this method.

Measured speedup:

```
CPU: 16 x AMD Ryzen 9 3950X 16-Core Processor
Result of 50 runs

base (./stockfish.master ) = 1561556 +/- 5439
test (./stockfish.patch ) = 1575788 +/- 5427
diff = +14231 +/- 2636

speedup = +0.0091
P(speedup > 0) = 1.0000
```

closes https://github.com/official-stockfish/Stockfish/pull/4640

No functional change
2023-07-01 12:59:28 +02:00
Joost VandeVondele 0fd186fb28 Restore development
closes https://github.com/official-stockfish/Stockfish/pull/4651

No functional change
2023-07-01 12:52:31 +02:00
106 changed files with 17047 additions and 13971 deletions
+44
View File
@@ -0,0 +1,44 @@
AccessModifierOffset: -1
AlignAfterOpenBracket: Align
AlignConsecutiveAssignments: Consecutive
AlignConsecutiveDeclarations: Consecutive
AlignEscapedNewlines: DontAlign
AlignOperands: AlignAfterOperator
AlignTrailingComments: true
AllowAllParametersOfDeclarationOnNextLine: true
AllowShortCaseLabelsOnASingleLine: false
AllowShortEnumsOnASingleLine: false
AllowShortIfStatementsOnASingleLine: false
AlwaysBreakTemplateDeclarations: Yes
BasedOnStyle: WebKit
BitFieldColonSpacing: After
BinPackParameters: false
BreakBeforeBinaryOperators: NonAssignment
BreakBeforeBraces: Custom
BraceWrapping:
AfterFunction: false
AfterClass: false
AfterControlStatement: true
BeforeElse: true
BreakBeforeTernaryOperators: true
BreakConstructorInitializers: AfterColon
BreakStringLiterals: false
ColumnLimit: 100
ContinuationIndentWidth: 2
Cpp11BracedListStyle: true
IndentGotoLabels: false
IndentPPDirectives: BeforeHash
IndentWidth: 4
MaxEmptyLinesToKeep: 2
NamespaceIndentation: None
PackConstructorInitializers: Never
ReflowComments: false
SortIncludes: false
SortUsingDeclarations: false
SpaceAfterCStyleCast: true
SpaceAfterTemplateKeyword: false
SpaceBeforeCaseColon: true
SpaceBeforeCpp11BracedList: false
SpaceBeforeInheritanceColon: false
SpaceInEmptyBlock: false
SpacesBeforeTrailingComments: 2
+7
View File
@@ -0,0 +1,7 @@
# .git-blame-ignore-revs
# Ignore commit which added clang-format
2d0237db3f0e596fb06e3ffbadba84dcc4e018f6
# Post commit formatting fixes
0fca5605fa2e5e7240fde5e1aae50952b2612231
08ed4c90db31959521b7ef3186c026edd1e90307
+1 -1
View File
@@ -2,7 +2,7 @@ blank_issues_enabled: false
contact_links: contact_links:
- name: Discord server - name: Discord server
url: https://discord.gg/GWDRS3kU6R url: https://discord.gg/GWDRS3kU6R
about: Feel free to ask for support or have a chat with us in our Discord server! about: Feel free to ask for support or have a chat with us on our Discord server!
- name: Discussions, Q&A, ideas, show us something... - name: Discussions, Q&A, ideas, show us something...
url: https://github.com/official-stockfish/Stockfish/discussions/new 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! about: Do you have an idea for Stockfish? Do you want to show something that you made? Please open a discussion about it!
+51
View File
@@ -0,0 +1,51 @@
{
"config": [
{
"name": "Android NDK aarch64",
"os": "ubuntu-22.04",
"simple_name": "android",
"compiler": "aarch64-linux-android21-clang++",
"emu": "qemu-aarch64",
"comp": "ndk",
"shell": "bash",
"archive_ext": "tar"
},
{
"name": "Android NDK arm",
"os": "ubuntu-22.04",
"simple_name": "android",
"compiler": "armv7a-linux-androideabi21-clang++",
"emu": "qemu-arm",
"comp": "ndk",
"shell": "bash",
"archive_ext": "tar"
}
],
"binaries": ["armv8-dotprod", "armv8", "armv7", "armv7-neon"],
"exclude": [
{
"binaries": "armv8-dotprod",
"config": {
"compiler": "armv7a-linux-androideabi21-clang++"
}
},
{
"binaries": "armv8",
"config": {
"compiler": "armv7a-linux-androideabi21-clang++"
}
},
{
"binaries": "armv7",
"config": {
"compiler": "aarch64-linux-android21-clang++"
}
},
{
"binaries": "armv7-neon",
"config": {
"compiler": "aarch64-linux-android21-clang++"
}
}
]
}
+22
View File
@@ -0,0 +1,22 @@
[
# Mappings for libcxx's internal headers
{ include: [ "<__fwd/fstream.h>", private, "<iosfwd>", public ] },
{ include: [ "<__fwd/ios.h>", private, "<iosfwd>", public ] },
{ include: [ "<__fwd/istream.h>", private, "<iosfwd>", public ] },
{ include: [ "<__fwd/ostream.h>", private, "<iosfwd>", public ] },
{ include: [ "<__fwd/sstream.h>", private, "<iosfwd>", public ] },
{ include: [ "<__fwd/streambuf.h>", private, "<iosfwd>", public ] },
{ include: [ "<__fwd/string_view.h>", private, "<string_view>", public ] },
{ include: [ "<__system_error/errc.h>", private, "<system_error>", public ] },
# Mappings for includes between public headers
{ include: [ "<ios>", public, "<iostream>", public ] },
{ include: [ "<streambuf>", public, "<iostream>", public ] },
{ include: [ "<istream>", public, "<iostream>", public ] },
{ include: [ "<ostream>", public, "<iostream>", public ] },
{ include: [ "<iosfwd>", public, "<iostream>", public ] },
# Missing mappings in include-what-you-use's libcxx.imp
{ include: ["@<__condition_variable/.*>", private, "<condition_variable>", public ] },
{ include: ["@<__mutex/.*>", private, "<mutex>", public ] },
]
+160
View File
@@ -0,0 +1,160 @@
{
"config": [
{
"name": "Ubuntu 22.04 GCC",
"os": "ubuntu-22.04",
"simple_name": "ubuntu",
"compiler": "g++",
"comp": "gcc",
"shell": "bash",
"archive_ext": "tar",
"sde": "/home/runner/work/Stockfish/Stockfish/.output/sde-temp-files/sde-external-9.27.0-2023-09-13-lin/sde -future --"
},
{
"name": "MacOS 13 Apple Clang",
"os": "macos-13",
"simple_name": "macos",
"compiler": "clang++",
"comp": "clang",
"shell": "bash",
"archive_ext": "tar"
},
{
"name": "MacOS 14 Apple Clang M1",
"os": "macos-14",
"simple_name": "macos-m1",
"compiler": "clang++",
"comp": "clang",
"shell": "bash",
"archive_ext": "tar"
},
{
"name": "Windows 2022 Mingw-w64 GCC x86_64",
"os": "windows-2022",
"simple_name": "windows",
"compiler": "g++",
"comp": "mingw",
"msys_sys": "mingw64",
"msys_env": "x86_64-gcc",
"shell": "msys2 {0}",
"ext": ".exe",
"sde": "/d/a/Stockfish/Stockfish/.output/sde-temp-files/sde-external-9.27.0-2023-09-13-win/sde.exe -future --",
"archive_ext": "zip"
}
],
"binaries": [
"x86-64",
"x86-64-sse41-popcnt",
"x86-64-avx2",
"x86-64-bmi2",
"x86-64-avxvnni",
"x86-64-avx512",
"x86-64-vnni256",
"x86-64-vnni512",
"apple-silicon"
],
"exclude": [
{
"binaries": "x86-64",
"config": {
"os": "macos-14"
}
},
{
"binaries": "x86-64-sse41-popcnt",
"config": {
"os": "macos-14"
}
},
{
"binaries": "x86-64-avx2",
"config": {
"os": "macos-14"
}
},
{
"binaries": "x86-64-bmi2",
"config": {
"os": "macos-14"
}
},
{
"binaries": "x86-64-avxvnni",
"config": {
"os": "macos-14"
}
},
{
"binaries": "x86-64-avxvnni",
"config": {
"os": "macos-14"
}
},
{
"binaries": "x86-64-avx512",
"config": {
"os": "macos-14"
}
},
{
"binaries": "x86-64-vnni256",
"config": {
"os": "macos-14"
}
},
{
"binaries": "x86-64-vnni512",
"config": {
"os": "macos-14"
}
},
{
"binaries": "x86-64-avxvnni",
"config": {
"ubuntu-22.04": null
}
},
{
"binaries": "x86-64-avxvnni",
"config": {
"os": "macos-13"
}
},
{
"binaries": "x86-64-avx512",
"config": {
"os": "macos-13"
}
},
{
"binaries": "x86-64-vnni256",
"config": {
"os": "macos-13"
}
},
{
"binaries": "x86-64-vnni512",
"config": {
"os": "macos-13"
}
},
{
"binaries": "apple-silicon",
"config": {
"os": "windows-2022"
}
},
{
"binaries": "apple-silicon",
"config": {
"os": "macos-13"
}
},
{
"binaries": "apple-silicon",
"config": {
"os": "ubuntu-22.04"
}
}
]
}
+98
View File
@@ -0,0 +1,98 @@
name: Compilation
on:
workflow_call:
inputs:
matrix:
type: string
required: true
jobs:
Compilation:
name: ${{ matrix.config.name }} ${{ matrix.binaries }}
runs-on: ${{ matrix.config.os }}
env:
COMPCXX: ${{ matrix.config.compiler }}
COMP: ${{ matrix.config.comp }}
EMU: ${{ matrix.config.emu }}
EXT: ${{ matrix.config.ext }}
BINARY: ${{ matrix.binaries }}
strategy:
fail-fast: false
matrix: ${{ fromJson(inputs.matrix) }}
defaults:
run:
working-directory: src
shell: ${{ matrix.config.shell }}
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0
persist-credentials: false
- name: Download required linux packages
if: runner.os == 'Linux'
run: |
sudo apt update
sudo apt install qemu-user
- name: Install NDK
if: runner.os == 'Linux'
run: |
if [ $COMP == ndk ]; then
NDKV="21.4.7075529"
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;$NDKV"
ANDROID_NDK_ROOT=$ANDROID_SDK_ROOT/ndk/$NDKV
ANDROID_NDK_BIN=$ANDROID_NDK_ROOT/toolchains/llvm/prebuilt/linux-x86_64/bin
echo "ANDROID_NDK_BIN=$ANDROID_NDK_BIN" >> $GITHUB_ENV
fi
- name: Extract the bench number from the commit history
run: |
for hash in $(git rev-list -100 HEAD); do
benchref=$(git show -s $hash | tac | grep -m 1 -o -x '[[:space:]]*\b[Bb]ench[ :]\+[1-9][0-9]\{5,7\}\b[[:space:]]*' | sed 's/[^0-9]//g') && break || true
done
[[ -n "$benchref" ]] && echo "benchref=$benchref" >> $GITHUB_ENV && echo "From commit: $hash" && echo "Reference bench: $benchref" || echo "No bench found"
- name: Download the used network from the fishtest framework
run: make net
- name: Check compiler
run: |
if [ $COMP == ndk ]; then
export PATH=${{ env.ANDROID_NDK_BIN }}:$PATH
fi
$COMPCXX -v
- name: Test help target
run: make help
- name: Check git
run: git --version
# Compile profile guided builds
- name: Compile ${{ matrix.binaries }} build
run: |
if [ $COMP == ndk ]; then
export PATH=${{ env.ANDROID_NDK_BIN }}:$PATH
export LDFLAGS="-static -Wno-unused-command-line-argument"
fi
make clean
make -j4 profile-build ARCH=$BINARY COMP=$COMP WINE_PATH=$EMU
make strip ARCH=$BINARY COMP=$COMP
WINE_PATH=$EMU ../tests/signature.sh $benchref
mv ./stockfish$EXT ../stockfish-android-$BINARY$EXT
- name: Remove non src files
run: git clean -fx
- name: Upload artifact for (pre)-release
uses: actions/upload-artifact@v4
with:
name: ${{ matrix.config.simple_name }} ${{ matrix.binaries }}
path: |
.
!.git
!.output
+57
View File
@@ -0,0 +1,57 @@
# This workflow will run clang-format and comment on the PR.
# Because of security reasons, it is crucial that this workflow
# executes no shell script nor runs make.
# Read this before editing: https://securitylab.github.com/research/github-actions-preventing-pwn-requests/
name: Clang-Format
on:
pull_request_target:
branches:
- "master"
paths:
- "**.cpp"
- "**.h"
permissions:
pull-requests: write
jobs:
Clang-Format:
name: Clang-Format
runs-on: ubuntu-22.04
steps:
- uses: actions/checkout@v4
with:
ref: ${{ github.event.pull_request.head.sha }}
- name: Run clang-format style check
uses: jidicula/clang-format-action@f62da5e3d3a2d88ff364771d9d938773a618ab5e # @v4.11.0
id: clang-format
continue-on-error: true
with:
clang-format-version: "18"
exclude-regex: "incbin"
- name: Comment on PR
if: steps.clang-format.outcome == 'failure'
uses: thollander/actions-comment-pull-request@fabd468d3a1a0b97feee5f6b9e499eab0dd903f6 # @v2.5.0
with:
message: |
clang-format 18 needs to be run on this PR.
If you do not have clang-format installed, the maintainer will run it when merging.
For the exact version please see https://packages.ubuntu.com/noble/clang-format-18.
_(execution **${{ github.run_id }}** / attempt **${{ github.run_attempt }}**)_
comment_tag: execution
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
- name: Comment on PR
if: steps.clang-format.outcome != 'failure'
uses: thollander/actions-comment-pull-request@fabd468d3a1a0b97feee5f6b9e499eab0dd903f6 # @v2.5.0
with:
message: |
_(execution **${{ github.run_id }}** / attempt **${{ github.run_attempt }}**)_
create_if_not_exists: false
comment_tag: execution
mode: delete
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
+55
View File
@@ -0,0 +1,55 @@
name: "CodeQL"
on:
push:
branches: ["master"]
pull_request:
# The branches below must be a subset of the branches above
branches: ["master"]
schedule:
- cron: "17 18 * * 1"
jobs:
analyze:
name: Analyze
runs-on: ubuntu-latest
permissions:
actions: read
contents: read
security-events: write
strategy:
fail-fast: false
matrix:
language: ["cpp"]
# CodeQL supports [ 'cpp', 'csharp', 'go', 'java', 'javascript', 'python', 'ruby' ]
# Use only 'java' to analyze code written in Java, Kotlin, or both
# Use only 'javascript' to analyze code written in JavaScript, TypeScript or both
# Learn more about CodeQL language support at https://aka.ms/codeql-docs/language-support
steps:
- name: Checkout repository
uses: actions/checkout@v4
with:
persist-credentials: false
# Initializes the CodeQL tools for scanning.
- name: Initialize CodeQL
uses: github/codeql-action/init@v3
with:
languages: ${{ matrix.language }}
# If you wish to specify custom queries, you can do so here or in a config file.
# By default, queries listed here will override any specified in a config file.
# Prefix the list here with "+" to use these queries and those in the config file.
# For more details on CodeQL's query packs, refer to: https://docs.github.com/en/code-security/code-scanning/automatically-scanning-your-code-for-vulnerabilities-and-errors/configuring-code-scanning#using-queries-in-ql-packs
# queries: security-extended,security-and-quality
- name: Build
working-directory: src
run: make -j build ARCH=x86-64-modern
- name: Perform CodeQL Analysis
uses: github/codeql-action/analyze@v3
with:
category: "/language:${{matrix.language}}"
+94
View File
@@ -0,0 +1,94 @@
name: Compilation
on:
workflow_call:
inputs:
matrix:
type: string
required: true
jobs:
Compilation:
name: ${{ matrix.config.name }} ${{ matrix.binaries }}
runs-on: ${{ matrix.config.os }}
env:
COMPCXX: ${{ matrix.config.compiler }}
COMP: ${{ matrix.config.comp }}
EXT: ${{ matrix.config.ext }}
NAME: ${{ matrix.config.simple_name }}
BINARY: ${{ matrix.binaries }}
SDE: ${{ matrix.config.sde }}
strategy:
fail-fast: false
matrix: ${{ fromJson(inputs.matrix) }}
defaults:
run:
working-directory: src
shell: ${{ matrix.config.shell }}
steps:
- uses: actions/checkout@v4
with:
persist-credentials: false
- name: Install fixed GCC on Linux
if: runner.os == 'Linux'
uses: egor-tensin/setup-gcc@eaa888eb19115a521fa72b65cd94fe1f25bbcaac # @v1.3
with:
version: 11
- 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 zip
- name: Download SDE package
if: runner.os == 'Linux' || runner.os == 'Windows'
uses: petarpetrovt/setup-sde@91a1a03434384e064706634125a15f7446d2aafb # @v2.3
with:
environmentVariableName: SDE_DIR
sdeVersion: 9.27.0
- name: Download the used network from the fishtest framework
run: make net
- name: Check compiler
run: $COMPCXX -v
- name: Test help target
run: make help
- name: Check git
run: git --version
- name: Check compiler
run: $COMPCXX -v
- name: Show g++ cpu info
if: runner.os != 'macOS'
run: g++ -Q -march=native --help=target
- name: Show clang++ cpu info
if: runner.os == 'macOS'
run: clang++ -E - -march=native -###
# x86-64 with newer extensions tests
- name: Compile ${{ matrix.config.binaries }} build
run: |
make clean
make -j4 profile-build ARCH=$BINARY COMP=$COMP WINE_PATH="$SDE"
make strip ARCH=$BINARY COMP=$COMP
WINE_PATH="$SDE" ../tests/signature.sh $benchref
mv ./stockfish$EXT ../stockfish-$NAME-$BINARY$EXT
- name: Remove non src files
run: git clean -fx
- name: Upload artifact for (pre)-release
uses: actions/upload-artifact@v4
with:
name: ${{ matrix.config.simple_name }} ${{ matrix.binaries }}
path: |
.
!.git
!.output
+43
View File
@@ -0,0 +1,43 @@
# This workflow will play games with a debug enabled SF using the PR
name: Games
on:
workflow_call:
jobs:
Matetrack:
name: Games
runs-on: ubuntu-22.04
steps:
- name: Checkout SF repo
uses: actions/checkout@v4
with:
ref: ${{ github.event.pull_request.head.sha }}
path: Stockfish
persist-credentials: false
- name: build debug enabled version of SF
working-directory: Stockfish/src
run: make -j build debug=yes
- name: Checkout fastchess repo
uses: actions/checkout@v4
with:
repository: Disservin/fastchess
path: fastchess
ref: 894616028492ae6114835195f14a899f6fa237d3
persist-credentials: false
- name: fastchess build
working-directory: fastchess
run: make -j
- name: Run games
working-directory: fastchess
run: |
./fastchess -rounds 4 -games 2 -repeat -concurrency 4 -openings file=app/tests/data/openings.epd format=epd order=random -srand $RANDOM\
-engine name=sf1 cmd=/home/runner/work/Stockfish/Stockfish/Stockfish/src/stockfish\
-engine name=sf2 cmd=/home/runner/work/Stockfish/Stockfish/Stockfish/src/stockfish\
-ratinginterval 1 -report penta=true -each proto=uci tc=4+0.04 -log file=fast.log | tee fast.out
cat fast.log
! grep "Assertion" fast.log > /dev/null
! grep "disconnect" fast.out > /dev/null
+49
View File
@@ -0,0 +1,49 @@
name: IWYU
on:
workflow_call:
jobs:
Analyzers:
name: Check includes
runs-on: ubuntu-22.04
defaults:
run:
working-directory: Stockfish/src
shell: bash
steps:
- name: Checkout Stockfish
uses: actions/checkout@v4
with:
path: Stockfish
persist-credentials: false
- name: Checkout include-what-you-use
uses: actions/checkout@v4
with:
repository: include-what-you-use/include-what-you-use
ref: f25caa280dc3277c4086ec345ad279a2463fea0f
path: include-what-you-use
persist-credentials: false
- name: Download required linux packages
run: |
sudo add-apt-repository 'deb http://apt.llvm.org/jammy/ llvm-toolchain-jammy-17 main'
wget -O - https://apt.llvm.org/llvm-snapshot.gpg.key | sudo apt-key add -
sudo apt update
sudo apt install -y libclang-17-dev clang-17 libc++-17-dev
- name: Set up include-what-you-use
run: |
mkdir build && cd build
cmake -G "Unix Makefiles" -DCMAKE_PREFIX_PATH="/usr/lib/llvm-17" ..
sudo make install
working-directory: include-what-you-use
- name: Check include-what-you-use
run: include-what-you-use --version
- name: Check includes
run: >
make analyze
COMP=clang
CXX=include-what-you-use
CXXFLAGS="-stdlib=libc++ -Xiwyu --comment_style=long -Xiwyu --mapping='${{ github.workspace }}/Stockfish/.github/ci/libcxx17.imp' -Xiwyu --error"
+71
View File
@@ -0,0 +1,71 @@
# This workflow will run matetrack on the PR
name: Matetrack
on:
workflow_call:
jobs:
Matetrack:
name: Matetrack
runs-on: ubuntu-22.04
steps:
- name: Checkout SF repo
uses: actions/checkout@v4
with:
ref: ${{ github.event.pull_request.head.sha }}
path: Stockfish
persist-credentials: false
- name: build SF
working-directory: Stockfish/src
run: make -j profile-build
- name: Checkout matetrack repo
uses: actions/checkout@v4
with:
repository: vondele/matetrack
path: matetrack
ref: 4f8a80860ed8f3607f05a9195df8b40203bdc360
persist-credentials: false
- name: matetrack install deps
working-directory: matetrack
run: pip install -r requirements.txt
- name: cache syzygy
id: cache-syzygy
uses: actions/cache@v4
with:
path: |
matetrack/3-4-5-wdl/
matetrack/3-4-5-dtz/
key: key-syzygy
- name: download syzygy 3-4-5 if needed
working-directory: matetrack
if: steps.cache-syzygy.outputs.cache-hit != 'true'
run: |
wget --no-verbose -r -nH --cut-dirs=2 --no-parent --reject="index.html*" -e robots=off https://tablebase.lichess.ovh/tables/standard/3-4-5-wdl/
wget --no-verbose -r -nH --cut-dirs=2 --no-parent --reject="index.html*" -e robots=off https://tablebase.lichess.ovh/tables/standard/3-4-5-dtz/
- name: Run matetrack
working-directory: matetrack
run: |
python matecheck.py --syzygyPath 3-4-5-wdl/:3-4-5-dtz/ --engine /home/runner/work/Stockfish/Stockfish/Stockfish/src/stockfish --epdFile mates2000.epd --nodes 100000 | tee matecheckout.out
! grep "issues were detected" matecheckout.out > /dev/null
- name: Run matetrack with --syzygy50MoveRule false
working-directory: matetrack
run: |
grep 5men cursed.epd > cursed5.epd
python matecheck.py --syzygyPath 3-4-5-wdl/:3-4-5-dtz/ --engine /home/runner/work/Stockfish/Stockfish/Stockfish/src/stockfish --epdFile cursed5.epd --nodes 100000 --syzygy50MoveRule false | tee matecheckcursed.out
! grep "issues were detected" matecheckcursed.out > /dev/null
- name: Verify mate and TB win count for matecheckcursed.out
working-directory: matetrack
run: |
mates=$(grep "Found mates:" matecheckcursed.out | awk '{print $3}')
tbwins=$(grep "Found TB wins:" matecheckcursed.out | awk '{print $4}')
if [ $(($mates + $tbwins)) -ne 32 ]; then
echo "Sum of mates and TB wins is not 32 in matecheckcursed.out" >&2
exit 1
fi
+87
View File
@@ -0,0 +1,87 @@
name: Sanitizers
on:
workflow_call:
jobs:
Test-under-sanitizers:
name: ${{ matrix.sanitizers.name }}
runs-on: ${{ matrix.config.os }}
env:
COMPCXX: ${{ matrix.config.compiler }}
COMP: ${{ matrix.config.comp }}
CXXFLAGS: "-Werror"
strategy:
fail-fast: false
matrix:
config:
- name: Ubuntu 22.04 GCC
os: ubuntu-22.04
compiler: g++
comp: gcc
shell: bash
sanitizers:
- name: Run with thread sanitizer
make_option: sanitize=thread
cxx_extra_flags: ""
instrumented_option: sanitizer-thread
- name: Run with UB sanitizer
make_option: sanitize=undefined
cxx_extra_flags: ""
instrumented_option: sanitizer-undefined
- name: Run under valgrind
make_option: ""
cxx_extra_flags: ""
instrumented_option: valgrind
- name: Run under valgrind-thread
make_option: ""
cxx_extra_flags: ""
instrumented_option: valgrind-thread
- name: Run non-instrumented
make_option: ""
cxx_extra_flags: ""
instrumented_option: none
- name: Run with glibcxx assertions
make_option: ""
cxx_extra_flags: -D_GLIBCXX_ASSERTIONS
instrumented_option: non
defaults:
run:
working-directory: src
shell: ${{ matrix.config.shell }}
steps:
- uses: actions/checkout@v4
with:
persist-credentials: false
- name: Download required linux packages
run: |
sudo apt update
sudo apt install expect valgrind g++-multilib
- name: Download the used network from the fishtest framework
run: make net
- name: Check compiler
run: $COMPCXX -v
- name: Test help target
run: make help
- name: Check git
run: git --version
# Since Linux Kernel 6.5 we are getting false positives from the ci,
# lower the ALSR entropy to disable ALSR, which works as a temporary workaround.
# https://github.com/google/sanitizers/issues/1716
# https://bugs.launchpad.net/ubuntu/+source/linux/+bug/2056762
- name: Lower ALSR entropy
run: sudo sysctl -w vm.mmap_rnd_bits=28
# Sanitizers
- name: ${{ matrix.sanitizers.name }}
run: |
export CXXFLAGS="-O1 -fno-inline ${{ matrix.sanitizers.cxx_extra_flags }}"
make clean
make -j4 ARCH=x86-64-sse41-popcnt ${{ matrix.sanitizers.make_option }} debug=yes optimize=no build > /dev/null
python3 ../tests/instrumented.py --${{ matrix.sanitizers.instrumented_option }} ./stockfish
+89 -18
View File
@@ -1,8 +1,8 @@
name: Stockfish name: Stockfish
on: on:
push: push:
tags: tags:
- '*' - "*"
branches: branches:
- master - master
- tools - tools
@@ -13,12 +13,14 @@ on:
- tools - tools
jobs: jobs:
Prerelease: Prerelease:
if: github.ref == 'refs/heads/master' if: github.repository == 'official-stockfish/Stockfish' && (github.ref == 'refs/heads/master' || (startsWith(github.ref_name, 'sf_') && github.ref_type == 'tag'))
runs-on: ubuntu-latest runs-on: ubuntu-latest
permissions:
contents: write # For deleting/creating a prerelease
steps: steps:
- uses: actions/checkout@v3 - uses: actions/checkout@v4
with: with:
fetch-depth: 0 persist-credentials: false
# returns null if no pre-release exists # returns null if no pre-release exists
- name: Get Commit SHA of Latest Pre-release - name: Get Commit SHA of Latest Pre-release
@@ -27,25 +29,94 @@ jobs:
sudo apt-get update sudo apt-get update
sudo apt-get install -y curl jq sudo apt-get install -y curl jq
echo "COMMIT_SHA=$(jq -r 'map(select(.prerelease)) | first | .tag_name' <<< $(curl -s https://api.github.com/repos/${{ github.repository_owner }}/Stockfish/releases))" >> $GITHUB_ENV echo "COMMIT_SHA_TAG=$(jq -r 'map(select(.prerelease)) | first | .tag_name' <<< $(curl -s https://api.github.com/repos/${{ github.repository_owner }}/Stockfish/releases))" >> $GITHUB_ENV
# delete old previous pre-release and tag # delete old previous pre-release and tag
- uses: dev-drprasad/delete-tag-and-release@v0.2.1 - run: gh release delete ${{ env.COMMIT_SHA_TAG }} --cleanup-tag
if: env.COMMIT_SHA != 'null' if: env.COMMIT_SHA_TAG != 'null'
with:
tag_name: ${{ env.COMMIT_SHA }}
env: env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
# Make sure that an old ci that still runs on master doesn't recreate a prerelease
- name: Check Pullable Commits
id: check_commits
run: |
git fetch
CHANGES=$(git rev-list HEAD..origin/master --count)
echo "CHANGES=$CHANGES" >> $GITHUB_ENV
- name: Get last commit SHA
id: last_commit
run: echo "COMMIT_SHA=$(git rev-parse HEAD | cut -c 1-8)" >> $GITHUB_ENV
- name: Get commit date
id: commit_date
run: echo "COMMIT_DATE=$(git show -s --date=format:'%Y%m%d' --format=%cd HEAD)" >> $GITHUB_ENV
# Create a new pre-release, the other upload_binaries.yml will upload the binaries
# to this pre-release.
- name: Create Prerelease
if: github.ref_name == 'master' && env.CHANGES == '0'
uses: softprops/action-gh-release@4634c16e79c963813287e889244c50009e7f0981
with:
name: Stockfish dev-${{ env.COMMIT_DATE }}-${{ env.COMMIT_SHA }}
tag_name: stockfish-dev-${{ env.COMMIT_DATE }}-${{ env.COMMIT_SHA }}
prerelease: true
Matrix:
runs-on: ubuntu-latest
outputs:
matrix: ${{ steps.set-matrix.outputs.matrix }}
arm_matrix: ${{ steps.set-arm-matrix.outputs.arm_matrix }}
steps:
- uses: actions/checkout@v4
with:
persist-credentials: false
- id: set-matrix
run: |
TASKS=$(echo $(cat .github/ci/matrix.json) )
echo "MATRIX=$TASKS" >> $GITHUB_OUTPUT
- id: set-arm-matrix
run: |
TASKS_ARM=$(echo $(cat .github/ci/arm_matrix.json) )
echo "ARM_MATRIX=$TASKS_ARM" >> $GITHUB_OUTPUT
Compilation:
needs: [Matrix]
uses: ./.github/workflows/compilation.yml
with:
matrix: ${{ needs.Matrix.outputs.matrix }}
ARMCompilation:
needs: [Matrix]
uses: ./.github/workflows/arm_compilation.yml
with:
matrix: ${{ needs.Matrix.outputs.arm_matrix }}
IWYU:
uses: ./.github/workflows/iwyu.yml
Sanitizers: Sanitizers:
uses: ./.github/workflows/stockfish_sanitizers.yml uses: ./.github/workflows/sanitizers.yml
Tests: Tests:
uses: ./.github/workflows/stockfish_test.yml uses: ./.github/workflows/tests.yml
Compiles: Matetrack:
uses: ./.github/workflows/stockfish_compile_test.yml uses: ./.github/workflows/matetrack.yml
Games:
uses: ./.github/workflows/games.yml
Binaries: Binaries:
if: github.ref == 'refs/heads/master' || (startsWith(github.ref_name, 'sf_') && github.ref_type == 'tag') if: github.repository == 'official-stockfish/Stockfish'
uses: ./.github/workflows/stockfish_binaries.yml needs: [Matrix, Prerelease, Compilation]
uses: ./.github/workflows/upload_binaries.yml
with:
matrix: ${{ needs.Matrix.outputs.matrix }}
permissions:
contents: write # For deleting/creating a (pre)release
secrets:
token: ${{ secrets.GITHUB_TOKEN }}
ARM_Binaries: ARM_Binaries:
if: github.ref == 'refs/heads/master' || (startsWith(github.ref_name, 'sf_') && github.ref_type == 'tag') if: github.repository == 'official-stockfish/Stockfish'
uses: ./.github/workflows/stockfish_arm_binaries.yml needs: [Matrix, Prerelease, ARMCompilation]
uses: ./.github/workflows/upload_binaries.yml
with:
matrix: ${{ needs.Matrix.outputs.arm_matrix }}
permissions:
contents: write # For deleting/creating a (pre)release
secrets:
token: ${{ secrets.GITHUB_TOKEN }}
@@ -1,158 +0,0 @@
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 }}
EMU: ${{ matrix.config.emu }}
EXT: ${{ matrix.config.ext }}
OS: ${{ matrix.config.os }}
BINARY: ${{ matrix.binaries }}
strategy:
matrix:
config:
- name: Android NDK aarch64
os: ubuntu-22.04
compiler: aarch64-linux-android21-clang++
emu: qemu-aarch64
comp: ndk
shell: bash {0}
- name: Android NDK arm
os: ubuntu-22.04
compiler: armv7a-linux-androideabi21-clang++
emu: qemu-arm
comp: ndk
shell: bash {0}
binaries:
- armv8
- armv7
- armv7-neon
exclude:
- binaries: armv8
config: {compiler: armv7a-linux-androideabi21-clang++}
- binaries: armv7
config: {compiler: aarch64-linux-android21-clang++}
- binaries: armv7-neon
config: {compiler: aarch64-linux-android21-clang++}
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 qemu-user
- name: Install NDK
if: runner.os == 'Linux'
run: |
if [ $COMP == ndk ]; then
NDKV="21.4.7075529"
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;$NDKV"
ANDROID_NDK_ROOT=$ANDROID_SDK_ROOT/ndk/$NDKV
ANDROID_NDK_BIN=$ANDROID_NDK_ROOT/toolchains/llvm/prebuilt/linux-x86_64/bin
echo "ANDROID_NDK_BIN=$ANDROID_NDK_BIN" >> $GITHUB_ENV
fi
- name: Download the used network from the fishtest framework
run: make net
- name: Check compiler
run: |
if [ $COMP == ndk ]; then
export PATH=${{ env.ANDROID_NDK_BIN }}:$PATH
fi
$COMPILER -v
- name: Test help target
run: make help
- name: Check git
run: git --version
# Compile profile guided builds
- name: Compile ${{ matrix.binaries }} build
run: |
if [ $COMP == ndk ]; then
export PATH=${{ env.ANDROID_NDK_BIN }}:$PATH
export LDFLAGS="-static -Wno-unused-command-line-argument"
fi
make clean
make -j2 profile-build ARCH=$BINARY COMP=$COMP WINE_PATH=$EMU
make strip ARCH=$BINARY COMP=$COMP
mv ./stockfish$EXT ../stockfish-android-$BINARY$EXT
- name: Remove non src files
run: rm -f *.o .depend *.nnue
- name: Download wiki
run: |
git clone https://github.com/official-stockfish/Stockfish.wiki.git ../wiki
cd ../wiki
rm -rf .git
- name: Create tar archive.
run: |
cd ..
mkdir stockfish
cp -r wiki stockfish/
cp -r src stockfish/
cp stockfish-android-$BINARY$EXT stockfish/
cp "Top CPU Contributors.txt" stockfish/
cp Copying.txt stockfish/
cp AUTHORS stockfish/
cp CITATION.cff stockfish/
cp README.md stockfish/
tar -cvf stockfish-android-$BINARY.tar stockfish
- name: Upload binaries
uses: actions/upload-artifact@v3
with:
name: stockfish-android-${{ matrix.binaries }}
path: stockfish-android-${{ matrix.binaries }}.tar
- name: Release
if: startsWith(github.ref_name, 'sf_') && github.ref_type == 'tag'
uses: softprops/action-gh-release@v1
with:
files: stockfish-android-${{ matrix.binaries }}.tar
- name: Get last commit sha
id: last_commit
run: echo "COMMIT_SHA=$(git rev-parse HEAD | cut -c 1-8)" >> $GITHUB_ENV
- name: Get commit date
id: commit_date
run: echo "COMMIT_DATE=$(git show -s --date=format:'%Y%m%d' --format=%cd HEAD)" >> $GITHUB_ENV
# Make sure that an old ci which still runs on master doesn't recreate a prerelease
- name: Check Pullable Commits
id: check_commits
run: |
git fetch
CHANGES=$(git rev-list HEAD..origin/master --count)
echo "CHANGES=$CHANGES" >> $GITHUB_ENV
- name: Prerelease
if: github.ref_name == 'master' && env.CHANGES == '0'
continue-on-error: true
uses: softprops/action-gh-release@v1
with:
name: Stockfish dev-${{ env.COMMIT_DATE }}-${{ env.COMMIT_SHA }}
tag_name: stockfish-dev-${{ env.COMMIT_DATE }}-${{ env.COMMIT_SHA }}
prerelease: true
files: stockfish-android-${{ matrix.binaries }}.tar
-168
View File
@@ -1,168 +0,0 @@
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 }}
NAME: ${{ matrix.config.simple_name }}
BINARY: ${{ matrix.binaries }}
strategy:
matrix:
config:
- name: Ubuntu 20.04 GCC
os: ubuntu-20.04
simple_name: ubuntu
compiler: g++
comp: gcc
shell: bash {0}
archive_ext: tar
- name: MacOS 12 Apple Clang
os: macos-12
simple_name: macos
compiler: clang++
comp: clang
shell: bash {0}
archive_ext: tar
- name: Windows 2022 Mingw-w64 GCC x86_64
os: windows-2022
simple_name: windows
compiler: g++
comp: mingw
msys_sys: mingw64
msys_env: x86_64-gcc
shell: msys2 {0}
ext: .exe
archive_ext: zip
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 zip
- name: Download the used network from the fishtest framework
run: make net
- name: Check compiler
run: $COMPILER -v
- name: Test help target
run: make help
- name: Check git
run: git --version
# Compile profile guided builds
- name: Compile ${{ matrix.binaries }} build
run: |
make -j2 profile-build ARCH=$BINARY COMP=$COMP
make strip ARCH=$BINARY COMP=$COMP
mv ./stockfish$EXT ../stockfish-$NAME-$BINARY$EXT
- name: Remove non src files
run: git clean -fx
- name: Download wiki
run: |
git clone https://github.com/official-stockfish/Stockfish.wiki.git ../wiki
rm -rf ../wiki/.git
- name: Create directory.
run: |
cd ..
mkdir stockfish
cp -r wiki stockfish/
cp -r src stockfish/
cp stockfish-$NAME-$BINARY$EXT stockfish/
cp "Top CPU Contributors.txt" stockfish/
cp Copying.txt stockfish/
cp AUTHORS stockfish/
cp CITATION.cff stockfish/
cp README.md stockfish/
- name: Create tar
if: runner.os != 'Windows'
run: |
cd ..
tar -cvf stockfish-$NAME-$BINARY.tar stockfish
- name: Create zip
if: runner.os == 'Windows'
run: |
cd ..
zip -r stockfish-$NAME-$BINARY.zip stockfish
- name: Upload binaries
if: runner.os != 'Windows'
uses: actions/upload-artifact@v3
with:
name: stockfish-${{ matrix.config.os }}-${{ matrix.binaries }}
path: stockfish-${{ matrix.config.simple_name }}-${{ matrix.binaries }}.tar
# Artifacts automatically get zipped
# to avoid double zipping, we use the unzipped directory
- name: Upload binaries
if: runner.os == 'Windows'
uses: actions/upload-artifact@v3
with:
name: stockfish-${{ matrix.config.os }}-${{ matrix.binaries }}
path: stockfish
- name: Release
if: startsWith(github.ref_name, 'sf_') && github.ref_type == 'tag'
uses: softprops/action-gh-release@v1
with:
files: stockfish-${{ matrix.config.simple_name }}-${{ matrix.binaries }}.${{ matrix.config.archive_ext }}
- name: Get last commit sha
id: last_commit
run: echo "COMMIT_SHA=$(git rev-parse HEAD | cut -c 1-8)" >> $GITHUB_ENV
- name: Get commit date
id: commit_date
run: echo "COMMIT_DATE=$(git show -s --date=format:'%Y%m%d' --format=%cd HEAD)" >> $GITHUB_ENV
# Make sure that an old ci which still runs on master doesn't recreate a prerelease
- name: Check Pullable Commits
id: check_commits
run: |
git fetch
CHANGES=$(git rev-list HEAD..origin/master --count)
echo "CHANGES=$CHANGES" >> $GITHUB_ENV
- name: Prerelease
if: github.ref_name == 'master' && env.CHANGES == '0'
continue-on-error: true
uses: softprops/action-gh-release@v1
with:
name: Stockfish dev-${{ env.COMMIT_DATE }}-${{ env.COMMIT_SHA }}
tag_name: stockfish-dev-${{ env.COMMIT_DATE }}-${{ env.COMMIT_SHA }}
prerelease: true
files: stockfish-${{ matrix.config.simple_name }}-${{ matrix.binaries }}.${{ matrix.config.archive_ext }}
@@ -1,102 +0,0 @@
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
- name: Download the used network from the fishtest framework
run: make net
- name: Check compiler
run: $COMPILER -v
- name: Test help target
run: make help
- name: Check git
run: git --version
# 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
@@ -1,66 +0,0 @@
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
- name: Download the used network from the fishtest framework
run: make net
- name: Check compiler
run: $COMPILER -v
- name: Test help target
run: make help
- name: Check git
run: git --version
# 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 }}
-256
View File
@@ -1,256 +0,0 @@
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: Android NDK aarch64
os: ubuntu-22.04
compiler: aarch64-linux-android21-clang++
comp: ndk
run_armv8_tests: true
shell: bash {0}
- name: Android NDK arm
os: ubuntu-22.04
compiler: armv7a-linux-androideabi21-clang++
comp: ndk
run_armv7_tests: true
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}
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: Install NDK
if: runner.os == 'Linux'
run: |
if [ $COMP == ndk ]; then
NDKV="21.4.7075529"
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;$NDKV"
ANDROID_NDK_ROOT=$ANDROID_SDK_ROOT/ndk/$NDKV
ANDROID_NDK_BIN=$ANDROID_NDK_ROOT/toolchains/llvm/prebuilt/linux-x86_64/bin
echo "ANDROID_NDK_BIN=$ANDROID_NDK_BIN" >> $GITHUB_ENV
fi
- 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 -o "\b[Bb]ench[ :]\+[1-9][0-9]\{5,9\}\b" | head -n 1 | sed "s/[^0-9]//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: |
if [ $COMP == ndk ]; then
export PATH=${{ env.ANDROID_NDK_BIN }}:$PATH
fi
$COMPILER -v
- name: Test help target
run: make help
- name: Check git
run: git --version
# 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: |
export PATH=${{ env.ANDROID_NDK_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=${{ env.ANDROID_NDK_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=${{ env.ANDROID_NDK_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
+366
View File
@@ -0,0 +1,366 @@
name: Tests
on:
workflow_call:
jobs:
Test-Targets:
name: ${{ matrix.config.name }}
runs-on: ${{ matrix.config.os }}
env:
COMPCXX: ${{ matrix.config.compiler }}
COMP: ${{ matrix.config.comp }}
CXXFLAGS: "-Werror"
strategy:
fail-fast: false
matrix:
config:
- name: Ubuntu 22.04 GCC
os: ubuntu-22.04
compiler: g++
comp: gcc
run_32bit_tests: true
run_64bit_tests: true
shell: bash
- name: Ubuntu 22.04 Clang
os: ubuntu-22.04
compiler: clang++
comp: clang
run_32bit_tests: true
run_64bit_tests: true
shell: bash
- name: Android NDK aarch64
os: ubuntu-22.04
compiler: aarch64-linux-android21-clang++
comp: ndk
run_armv8_tests: true
shell: bash
- name: Android NDK arm
os: ubuntu-22.04
compiler: armv7a-linux-androideabi21-clang++
comp: ndk
run_armv7_tests: true
shell: bash
- name: Linux GCC riscv64
os: ubuntu-22.04
compiler: g++
comp: gcc
run_riscv64_tests: true
base_image: "riscv64/alpine:edge"
platform: linux/riscv64
shell: bash
- name: Linux GCC ppc64
os: ubuntu-22.04
compiler: g++
comp: gcc
run_ppc64_tests: true
base_image: "ppc64le/alpine:latest"
platform: linux/ppc64le
shell: bash
- name: MacOS 13 Apple Clang
os: macos-13
compiler: clang++
comp: clang
run_64bit_tests: true
shell: bash
- name: MacOS 14 Apple Clang M1
os: macos-14
compiler: clang++
comp: clang
run_64bit_tests: false
run_m1_tests: true
shell: bash
- name: MacOS 13 GCC 11
os: macos-13
compiler: g++-11
comp: gcc
run_64bit_tests: true
shell: bash
- 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@v4
with:
fetch-depth: 0
persist-credentials: false
- name: Download required linux packages
if: runner.os == 'Linux'
run: |
sudo apt update
sudo apt install expect valgrind g++-multilib qemu-user-static
- name: Install NDK
if: runner.os == 'Linux'
run: |
if [ $COMP == ndk ]; then
NDKV="21.4.7075529"
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;$NDKV"
ANDROID_NDK_ROOT=$ANDROID_SDK_ROOT/ndk/$NDKV
ANDROID_NDK_BIN=$ANDROID_NDK_ROOT/toolchains/llvm/prebuilt/linux-x86_64/bin
echo "ANDROID_NDK_BIN=$ANDROID_NDK_BIN" >> $GITHUB_ENV
fi
- name: Set up QEMU
if: matrix.config.base_image
uses: docker/setup-qemu-action@v3
- name: Set up Docker Buildx
if: matrix.config.base_image
uses: docker/setup-buildx-action@v3
- name: Build Docker container
if: matrix.config.base_image
run: |
docker buildx build --platform ${{ matrix.config.platform }} --load -t sf_builder - << EOF
FROM ${{ matrix.config.base_image }}
WORKDIR /app
RUN apk update && apk add make g++
CMD ["sh", "src/script.sh"]
EOF
- name: Download required macOS packages
if: runner.os == 'macOS'
run: brew install coreutils gcc@11
- 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: |
for hash in $(git rev-list -100 HEAD); do
benchref=$(git show -s $hash | tac | grep -m 1 -o -x '[[:space:]]*\b[Bb]ench[ :]\+[1-9][0-9]\{5,7\}\b[[:space:]]*' | sed 's/[^0-9]//g') && break || true
done
[[ -n "$benchref" ]] && echo "benchref=$benchref" >> $GITHUB_ENV && echo "From commit: $hash" && echo "Reference bench: $benchref" || echo "No bench found"
- name: Check compiler
run: |
if [ -z "${{ matrix.config.base_image }}" ]; then
if [ $COMP == ndk ]; then
export PATH=${{ env.ANDROID_NDK_BIN }}:$PATH
fi
$COMPCXX -v
else
echo "$COMPCXX -v" > script.sh
docker run --rm --platform ${{ matrix.config.platform }} -v ${{ github.workspace }}:/app sf_builder
fi
- name: Test help target
run: make help
- name: Check git
run: git --version
# 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 -j4 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 -j4 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 -j4 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 -j4 ARCH=x86-32-sse2 build
../tests/signature.sh $benchref
- name: Test general-32 build
if: matrix.config.run_32bit_tests
run: |
make clean
make -j4 ARCH=general-32 build
../tests/signature.sh $benchref
# x86-64 tests
- name: Test debug x86-64-avx2 build
if: matrix.config.run_64bit_tests
run: |
export CXXFLAGS="-Werror -D_GLIBCXX_DEBUG"
make clean
make -j4 ARCH=x86-64-avx2 optimize=no debug=yes build
../tests/signature.sh $benchref
- name: Test x86-64-bmi2 build
if: matrix.config.run_64bit_tests
run: |
make clean
make -j4 ARCH=x86-64-bmi2 build
../tests/signature.sh $benchref
- name: Test x86-64-avx2 build
if: matrix.config.run_64bit_tests
run: |
make clean
make -j4 ARCH=x86-64-avx2 build
../tests/signature.sh $benchref
# Test a deprecated arch
- name: Test x86-64-modern build
if: matrix.config.run_64bit_tests
run: |
make clean
make -j4 ARCH=x86-64-modern build
../tests/signature.sh $benchref
- name: Test x86-64-sse41-popcnt build
if: matrix.config.run_64bit_tests
run: |
make clean
make -j4 ARCH=x86-64-sse41-popcnt build
../tests/signature.sh $benchref
- name: Test x86-64-ssse3 build
if: matrix.config.run_64bit_tests
run: |
make clean
make -j4 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 -j4 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 -j4 ARCH=x86-64 build
../tests/signature.sh $benchref
- name: Test general-64 build
if: matrix.config.run_64bit_tests
run: |
make clean
make -j4 ARCH=general-64 build
../tests/signature.sh $benchref
- name: Test apple-silicon build
if: matrix.config.run_m1_tests
run: |
make clean
make -j4 ARCH=apple-silicon build
../tests/signature.sh $benchref
# armv8 tests
- name: Test armv8 build
if: matrix.config.run_armv8_tests
run: |
export PATH=${{ env.ANDROID_NDK_BIN }}:$PATH
export LDFLAGS="-static -Wno-unused-command-line-argument"
make clean
make -j4 ARCH=armv8 build
../tests/signature.sh $benchref
- name: Test armv8-dotprod build
if: matrix.config.run_armv8_tests
run: |
export PATH=${{ env.ANDROID_NDK_BIN }}:$PATH
export LDFLAGS="-static -Wno-unused-command-line-argument"
make clean
make -j4 ARCH=armv8-dotprod build
../tests/signature.sh $benchref
# armv7 tests
- name: Test armv7 build
if: matrix.config.run_armv7_tests
run: |
export PATH=${{ env.ANDROID_NDK_BIN }}:$PATH
export LDFLAGS="-static -Wno-unused-command-line-argument"
make clean
make -j4 ARCH=armv7 build
../tests/signature.sh $benchref
- name: Test armv7-neon build
if: matrix.config.run_armv7_tests
run: |
export PATH=${{ env.ANDROID_NDK_BIN }}:$PATH
export LDFLAGS="-static -Wno-unused-command-line-argument"
make clean
make -j4 ARCH=armv7-neon build
../tests/signature.sh $benchref
# riscv64 tests
- name: Test riscv64 build
if: matrix.config.run_riscv64_tests
run: |
echo "cd src && export LDFLAGS='-static' && make clean && make -j4 ARCH=riscv64 build" > script.sh
docker run --rm --platform ${{ matrix.config.platform }} -v ${{ github.workspace }}:/app sf_builder
../tests/signature.sh $benchref
# ppc64 tests
- name: Test ppc64 build
if: matrix.config.run_ppc64_tests
run: |
echo "cd src && export LDFLAGS='-static' && make clean && make -j4 ARCH=ppc-64 build" > script.sh
docker run --rm --platform ${{ matrix.config.platform }} -v ${{ github.workspace }}:/app sf_builder
../tests/signature.sh $benchref
# Other tests
- name: Check perft and search reproducibility
if: matrix.config.run_64bit_tests
run: |
make clean
make -j4 ARCH=x86-64-avx2 build
../tests/perft.sh
../tests/reprosearch.sh
+114
View File
@@ -0,0 +1,114 @@
name: Upload Binaries
on:
workflow_call:
inputs:
matrix:
type: string
required: true
secrets:
token:
required: true
jobs:
Artifacts:
name: ${{ matrix.config.name }} ${{ matrix.binaries }}
runs-on: ${{ matrix.config.os }}
env:
COMPCXX: ${{ matrix.config.compiler }}
COMP: ${{ matrix.config.comp }}
EXT: ${{ matrix.config.ext }}
NAME: ${{ matrix.config.simple_name }}
BINARY: ${{ matrix.binaries }}
SDE: ${{ matrix.config.sde }}
strategy:
fail-fast: false
matrix: ${{ fromJson(inputs.matrix) }}
defaults:
run:
shell: ${{ matrix.config.shell }}
steps:
- uses: actions/checkout@v4
with:
persist-credentials: false
- name: Download artifact from compilation
uses: actions/download-artifact@v4
with:
name: ${{ matrix.config.simple_name }} ${{ matrix.binaries }}
path: ${{ matrix.config.simple_name }} ${{ matrix.binaries }}
- 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 zip
- name: Create Package
run: |
mkdir stockfish
- name: Download wiki
run: |
git clone https://github.com/official-stockfish/Stockfish.wiki.git wiki
rm -rf wiki/.git
mv wiki stockfish/
- name: Copy files
run: |
mv "${{ matrix.config.simple_name }} ${{ matrix.binaries }}" stockfish-workflow
cd stockfish-workflow
cp -r src ../stockfish/
cp -r scripts ../stockfish/
cp stockfish-$NAME-$BINARY$EXT ../stockfish/
cp "Top CPU Contributors.txt" ../stockfish/
cp Copying.txt ../stockfish/
cp AUTHORS ../stockfish/
cp CITATION.cff ../stockfish/
cp README.md ../stockfish/
cp CONTRIBUTING.md ../stockfish/
- name: Create tar
if: runner.os != 'Windows'
run: |
chmod +x ./stockfish/stockfish-$NAME-$BINARY$EXT
tar -cvf stockfish-$NAME-$BINARY.tar stockfish
- name: Create zip
if: runner.os == 'Windows'
run: |
zip -r stockfish-$NAME-$BINARY.zip stockfish
- name: Release
if: startsWith(github.ref_name, 'sf_') && github.ref_type == 'tag'
uses: softprops/action-gh-release@4634c16e79c963813287e889244c50009e7f0981
with:
files: stockfish-${{ matrix.config.simple_name }}-${{ matrix.binaries }}.${{ matrix.config.archive_ext }}
token: ${{ secrets.token }}
- name: Get last commit sha
id: last_commit
run: echo "COMMIT_SHA=$(git rev-parse HEAD | cut -c 1-8)" >> $GITHUB_ENV
- name: Get commit date
id: commit_date
run: echo "COMMIT_DATE=$(git show -s --date=format:'%Y%m%d' --format=%cd HEAD)" >> $GITHUB_ENV
# Make sure that an old ci that still runs on master doesn't recreate a prerelease
- name: Check Pullable Commits
id: check_commits
run: |
git fetch
CHANGES=$(git rev-list HEAD..origin/master --count)
echo "CHANGES=$CHANGES" >> $GITHUB_ENV
- name: Prerelease
if: github.ref_name == 'master' && env.CHANGES == '0'
continue-on-error: true
uses: softprops/action-gh-release@4634c16e79c963813287e889244c50009e7f0981
with:
name: Stockfish dev-${{ env.COMMIT_DATE }}-${{ env.COMMIT_SHA }}
tag_name: stockfish-dev-${{ env.COMMIT_DATE }}-${{ env.COMMIT_SHA }}
prerelease: true
files: stockfish-${{ matrix.config.simple_name }}-${{ matrix.binaries }}.${{ matrix.config.archive_ext }}
token: ${{ secrets.token }}
+5
View File
@@ -10,3 +10,8 @@ src/-lstdc++.res
# Neural network for the NNUE evaluation # Neural network for the NNUE evaluation
**/*.nnue **/*.nnue
# Files generated by the instrumented tests
tsan.supp
__pycache__/
tests/syzygy
tests/bench_tmp.epd
+31 -2
View File
@@ -12,6 +12,7 @@ Hisayori Noda (nodchip)
# All other authors of Stockfish code (in alphabetical order) # All other authors of Stockfish code (in alphabetical order)
Aditya (absimaldata) Aditya (absimaldata)
Adrian Petrescu (apetresc) Adrian Petrescu (apetresc)
Ahmed Kerimov (wcdbmv)
Ajith Chandy Jose (ajithcj) Ajith Chandy Jose (ajithcj)
Alain Savard (Rocky640) Alain Savard (Rocky640)
Alayan Feh (Alayan-stk-2) Alayan Feh (Alayan-stk-2)
@@ -19,6 +20,7 @@ Alexander Kure
Alexander Pagel (Lolligerhans) Alexander Pagel (Lolligerhans)
Alfredo Menezes (lonfom169) Alfredo Menezes (lonfom169)
Ali AlZhrani (Cooffe) Ali AlZhrani (Cooffe)
Andreas Jan van der Meulen (Andyson007)
Andreas Matthies (Matthies) Andreas Matthies (Matthies)
Andrei Vetrov (proukornew) Andrei Vetrov (proukornew)
Andrew Grant (AndyGrant) Andrew Grant (AndyGrant)
@@ -29,6 +31,7 @@ Aram Tumanian (atumanian)
Arjun Temurnikar Arjun Temurnikar
Artem Solopiy (EntityFX) Artem Solopiy (EntityFX)
Auguste Pop Auguste Pop
Balazs Szilagyi
Balint Pfliegel Balint Pfliegel
Ben Chaney (Chaneybenjamini) Ben Chaney (Chaneybenjamini)
Ben Koshy (BKSpurgeon) Ben Koshy (BKSpurgeon)
@@ -42,12 +45,18 @@ Bruno de Melo Costa (BM123499)
Bruno Pellanda (pellanda) Bruno Pellanda (pellanda)
Bryan Cross (crossbr) Bryan Cross (crossbr)
candirufish candirufish
Carlos Esparza Sánchez (ces42)
Chess13234 Chess13234
Chris Bao (sscg13)
Chris Cain (ceebo) Chris Cain (ceebo)
Ciekce
clefrks clefrks
Clemens L. (rn5f107s2)
Cody Ho (aesrentai)
Dale Weiler (graphitemaster) Dale Weiler (graphitemaster)
Daniel Axtens (daxtens) Daniel Axtens (daxtens)
Daniel Dugovic (ddugovic) Daniel Dugovic (ddugovic)
Daniel Monroe (Ergodice)
Dan Schmidt (dfannius) Dan Schmidt (dfannius)
Dariusz Orzechowski (dorzechowski) Dariusz Orzechowski (dorzechowski)
David (dav1312) David (dav1312)
@@ -62,16 +71,20 @@ Douglas Matos Gomes (dsmsgms)
Dubslow Dubslow
Eduardo Cáceres (eduherminio) Eduardo Cáceres (eduherminio)
Eelco de Groot (KingDefender) Eelco de Groot (KingDefender)
Ehsan Rashid (erashid)
Elvin Liu (solarlight2) Elvin Liu (solarlight2)
erbsenzaehler erbsenzaehler
Ernesto Gatti Ernesto Gatti
evqsx
Fabian Beuke (madnight) Fabian Beuke (madnight)
Fabian Fichter (ianfab) Fabian Fichter (ianfab)
Fanael Linithien (Fanael) Fanael Linithien (Fanael)
fanon fanon
Fauzi Akram Dabat (FauziAkram) Fauzi Akram Dabat (fauzi2)
Felix Wittmann Felix Wittmann
gamander gamander
Gabriele Lombardo (gabe)
Gahtan Nahdi
Gary Heckman (gheckman) Gary Heckman (gheckman)
George Sobala (gsobala) George Sobala (gsobala)
gguliash gguliash
@@ -94,6 +107,7 @@ Jake Senne (w1wwwwww)
Jan Ondruš (hxim) Jan Ondruš (hxim)
Jared Kish (Kurtbusch, kurt22i) Jared Kish (Kurtbusch, kurt22i)
Jarrod Torriero (DU-jdto) Jarrod Torriero (DU-jdto)
Jasper Shovelton (Beanie496)
Jean-Francois Romang (jromang) Jean-Francois Romang (jromang)
Jean Gauthier (OuaisBla) Jean Gauthier (OuaisBla)
Jekaa Jekaa
@@ -111,13 +125,16 @@ jundery
Justin Blanchard (UncombedCoconut) Justin Blanchard (UncombedCoconut)
Kelly Wilson Kelly Wilson
Ken Takusagawa Ken Takusagawa
Kenneth Lee (kennethlee33)
Kian E (KJE-98) Kian E (KJE-98)
kinderchocolate kinderchocolate
Kiran Panditrao (Krgp) Kiran Panditrao (Krgp)
Kojirion Kojirion
Krisztián Peőcz
Krystian Kuzniarek (kuzkry) Krystian Kuzniarek (kuzkry)
Leonardo Ljubičić (ICCF World Champion) Leonardo Ljubičić (ICCF World Champion)
Leonid Pechenik (lp--) Leonid Pechenik (lp--)
Li Ying (yl25946)
Liam Keegan (lkeegan) Liam Keegan (lkeegan)
Linmiao Xu (linrock) Linmiao Xu (linrock)
Linus Arver (listx) Linus Arver (listx)
@@ -130,6 +147,7 @@ Maciej Żenczykowski (zenczykowski)
Malcolm Campbell (xoto10) Malcolm Campbell (xoto10)
Mark Tenzer (31m059) Mark Tenzer (31m059)
marotear marotear
Mathias Parnaudeau (mparnaudeau)
Matt Ginsberg (mattginsberg) Matt Ginsberg (mattginsberg)
Matthew Lai (matthewlai) Matthew Lai (matthewlai)
Matthew Sullivan (Matt14916) Matthew Sullivan (Matt14916)
@@ -158,10 +176,12 @@ Niklas Fiekas (niklasf)
Nikolay Kostov (NikolayIT) Nikolay Kostov (NikolayIT)
Norman Schmidt (FireFather) Norman Schmidt (FireFather)
notruck notruck
Nour Berakdar (Nonlinear)
Ofek Shochat (OfekShochat, ghostway) Ofek Shochat (OfekShochat, ghostway)
Ondrej Mosnáček (WOnder93) Ondrej Mosnáček (WOnder93)
Ondřej Mišina (AndrovT) Ondřej Mišina (AndrovT)
Oskar Werkelin Ahlin Oskar Werkelin Ahlin
Ömer Faruk Tutkun (OmerFarukTutkun)
Pablo Vazquez Pablo Vazquez
Panthee Panthee
Pascal Romaret Pascal Romaret
@@ -178,6 +198,7 @@ Raminder Singh
renouve renouve
Reuven Peleg (R-Peleg) Reuven Peleg (R-Peleg)
Richard Lloyd (Richard-Lloyd) Richard Lloyd (Richard-Lloyd)
Robert Nürnberg (robertnurnberg)
Rodrigo Exterckötter Tjäder Rodrigo Exterckötter Tjäder
Rodrigo Roim (roim) Rodrigo Roim (roim)
Ronald de Man (syzygy1, syzygy) Ronald de Man (syzygy1, syzygy)
@@ -195,16 +216,22 @@ sf-x
Shahin M. Shahin (peregrine) Shahin M. Shahin (peregrine)
Shane Booth (shane31) Shane Booth (shane31)
Shawn Varghese (xXH4CKST3RXx) Shawn Varghese (xXH4CKST3RXx)
Shawn Xu (xu-shawn)
Siad Daboul (Topologist) Siad Daboul (Topologist)
Stefan Geschwentner (locutus2) Stefan Geschwentner (locutus2)
Stefano Cardanobile (Stefano80) Stefano Cardanobile (Stefano80)
Stefano Di Martino (StefanoD) Stefano Di Martino (StefanoD)
Steinar Gunderson (sesse) Steinar Gunderson (sesse)
Stéphane Nicolet (snicolet) Stéphane Nicolet (snicolet)
Stephen Touset (stouset)
Syine Mineta (MinetaS) Syine Mineta (MinetaS)
Taras Vuk (TarasVuk)
Thanar2 Thanar2
thaspel thaspel
theo77186 theo77186
TierynnB
Ting-Hsuan Huang (fffelix-huang)
Tobias Steinmann
Tomasz Sobczyk (Sopel97) Tomasz Sobczyk (Sopel97)
Tom Truscott Tom Truscott
Tom Vijlbrief (tomtor) Tom Vijlbrief (tomtor)
@@ -216,11 +243,13 @@ Unai Corzo (unaiic)
Uri Blass (uriblass) Uri Blass (uriblass)
Vince Negri (cuddlestmonkey) Vince Negri (cuddlestmonkey)
Viren Viren
Wencey Wang
windfishballad windfishballad
xefoci7612 xefoci7612
Xiang Wang (KatyushaScarlet)
zz4032 zz4032
# Additionally, we acknowledge the authors and maintainers of fishtest, # Additionally, we acknowledge the authors and maintainers of fishtest,
# an amazing and essential framework for Stockfish development! # an amazing and essential framework for Stockfish development!
# #
# https://github.com/glinscott/fishtest/blob/master/AUTHORS # https://github.com/official-stockfish/fishtest/blob/master/AUTHORS
+96
View File
@@ -0,0 +1,96 @@
# Contributing to Stockfish
Welcome to the Stockfish project! We are excited that you are interested in
contributing. This document outlines the guidelines and steps to follow when
making contributions to Stockfish.
## Table of Contents
- [Building Stockfish](#building-stockfish)
- [Making Contributions](#making-contributions)
- [Reporting Issues](#reporting-issues)
- [Submitting Pull Requests](#submitting-pull-requests)
- [Code Style](#code-style)
- [Community and Communication](#community-and-communication)
- [License](#license)
## Building Stockfish
In case you do not have a C++ compiler installed, you can follow the
instructions from our wiki.
- [Ubuntu][ubuntu-compiling-link]
- [Windows][windows-compiling-link]
- [macOS][macos-compiling-link]
## Making Contributions
### Reporting Issues
If you find a bug, please open an issue on the
[issue tracker][issue-tracker-link]. Be sure to include relevant information
like your operating system, build environment, and a detailed description of the
problem.
_Please note that Stockfish's development is not focused on adding new features.
Thus any issue regarding missing features will potentially be closed without
further discussion._
### Submitting Pull Requests
- Functional changes need to be tested on fishtest. See
[Creating my First Test][creating-my-first-test] for more details.
The accompanying pull request should include a link to the test results and
the new bench.
- Non-functional changes (e.g. refactoring, code style, documentation) do not
need to be tested on fishtest, unless they might impact performance.
- Provide a clear and concise description of the changes in the pull request
description.
_First time contributors should add their name to [AUTHORS](./AUTHORS)._
_Stockfish's development is not focused on adding new features. Thus any pull
request introducing new features will potentially be closed without further
discussion._
## Code Style
Changes to Stockfish C++ code should respect our coding style defined by
[.clang-format](.clang-format). You can format your changes by running
`make format`. This requires clang-format version 18 to be installed on your system.
## Navigate
For experienced Git users who frequently use git blame, it is recommended to
configure the blame.ignoreRevsFile setting.
This setting is useful for excluding noisy formatting commits.
```bash
git config blame.ignoreRevsFile .git-blame-ignore-revs
```
## Community and Communication
- Join the [Stockfish discord][discord-link] to discuss ideas, issues, and
development.
- Participate in the [Stockfish GitHub discussions][discussions-link] for
broader conversations.
## License
By contributing to Stockfish, you agree that your contributions will be licensed
under the GNU General Public License v3.0. See [Copying.txt][copying-link] for
more details.
Thank you for contributing to Stockfish and helping us make it even better!
[copying-link]: https://github.com/official-stockfish/Stockfish/blob/master/Copying.txt
[discord-link]: https://discord.gg/GWDRS3kU6R
[discussions-link]: https://github.com/official-stockfish/Stockfish/discussions/new
[creating-my-first-test]: https://github.com/official-stockfish/fishtest/wiki/Creating-my-first-test#create-your-test
[issue-tracker-link]: https://github.com/official-stockfish/Stockfish/issues
[ubuntu-compiling-link]: https://github.com/official-stockfish/Stockfish/wiki/Developers#user-content-installing-a-compiler-1
[windows-compiling-link]: https://github.com/official-stockfish/Stockfish/wiki/Developers#user-content-installing-a-compiler
[macos-compiling-link]: https://github.com/official-stockfish/Stockfish/wiki/Developers#user-content-installing-a-compiler-2
+674 -674
View File
File diff suppressed because it is too large Load Diff
+32 -35
View File
@@ -59,39 +59,10 @@ This distribution of Stockfish consists of the following files:
* 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. Binary distributions will have this file embedded. evaluation. Binary distributions will have this file embedded.
## The UCI protocol
The [Universal Chess Interface][uci-link] (UCI) is a standard text-based protocol
used to communicate with 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.
Developers can see the default values for the UCI options available in Stockfish
by typing `./stockfish uci` in a terminal, but most users should typically use a
chess GUI to interact with Stockfish.
For more information on UCI or debug commands, see our [documentation][wiki-commands-link].
## Compiling Stockfish
Stockfish has support for 32 or 64-bit CPUs, certain hardware instructions,
big-endian machines such as Power PC, and other platforms.
On Unix-like systems, it should be easy to compile Stockfish directly from the
source code with the included Makefile in the folder `src`. In general, it is
recommended to run `make help` to see a list of make targets with corresponding
descriptions.
```
cd src
make -j build ARCH=x86-64-modern
```
Detailed compilation instructions for all platforms can be found in our
[documentation][wiki-compile-link].
## Contributing ## Contributing
__See [Contributing Guide](CONTRIBUTING.md).__
### Donating hardware ### Donating hardware
Improving Stockfish requires a massive amount of testing. You can donate your Improving Stockfish requires a massive amount of testing. You can donate your
@@ -114,6 +85,25 @@ Discussions about Stockfish take place these days mainly in the Stockfish
[Discord server][discord-link]. This is also the best place to ask questions [Discord server][discord-link]. This is also the best place to ask questions
about the codebase and how to improve it. about the codebase and how to improve it.
## Compiling Stockfish
Stockfish has support for 32 or 64-bit CPUs, certain hardware instructions,
big-endian machines such as Power PC, and other platforms.
On Unix-like systems, it should be easy to compile Stockfish directly from the
source code with the included Makefile in the folder `src`. In general, it is
recommended to run `make help` to see a list of make targets with corresponding
descriptions. An example suitable for most Intel and AMD chips:
```
cd src
make -j profile-build
```
Detailed compilation instructions for all platforms can be found in our
[documentation][wiki-compile-link]. Our wiki also has information about
the [UCI commands][wiki-uci-link] supported by Stockfish.
## Terms of use ## Terms of use
Stockfish is free and distributed under the Stockfish is free and distributed under the
@@ -130,6 +120,11 @@ where the source code can be found) to generate the exact binary you are
distributing. If you make any changes to the source code, these changes must distributing. If you make any changes to the source code, these changes must
also be made available under GPL v3. also be made available under GPL v3.
## Acknowledgements
Stockfish uses neural networks trained on [data provided by the Leela Chess Zero
project][lc0-data-link], which is made available under the [Open Database License][odbl-link] (ODbL).
[authors-link]: https://github.com/official-stockfish/Stockfish/blob/master/AUTHORS [authors-link]: https://github.com/official-stockfish/Stockfish/blob/master/AUTHORS
[build-link]: https://github.com/official-stockfish/Stockfish/actions/workflows/stockfish.yml [build-link]: https://github.com/official-stockfish/Stockfish/actions/workflows/stockfish.yml
@@ -138,7 +133,7 @@ also be made available under GPL v3.
[issue-link]: https://github.com/official-stockfish/Stockfish/issues/new?assignees=&labels=&template=BUG-REPORT.yml [issue-link]: https://github.com/official-stockfish/Stockfish/issues/new?assignees=&labels=&template=BUG-REPORT.yml
[discussions-link]: https://github.com/official-stockfish/Stockfish/discussions/new [discussions-link]: https://github.com/official-stockfish/Stockfish/discussions/new
[fishtest-link]: https://tests.stockfishchess.org/tests [fishtest-link]: https://tests.stockfishchess.org/tests
[guideline-link]: https://github.com/glinscott/fishtest/wiki/Creating-my-first-test [guideline-link]: https://github.com/official-stockfish/fishtest/wiki/Creating-my-first-test
[license-link]: https://github.com/official-stockfish/Stockfish/blob/master/Copying.txt [license-link]: https://github.com/official-stockfish/Stockfish/blob/master/Copying.txt
[programming-link]: https://www.chessprogramming.org/Main_Page [programming-link]: https://www.chessprogramming.org/Main_Page
[programmingsf-link]: https://www.chessprogramming.org/Stockfish [programmingsf-link]: https://www.chessprogramming.org/Stockfish
@@ -150,10 +145,12 @@ also be made available under GPL v3.
[website-link]: https://stockfishchess.org [website-link]: https://stockfishchess.org
[website-blog-link]: https://stockfishchess.org/blog/ [website-blog-link]: https://stockfishchess.org/blog/
[wiki-link]: https://github.com/official-stockfish/Stockfish/wiki [wiki-link]: https://github.com/official-stockfish/Stockfish/wiki
[wiki-usage-link]: https://github.com/official-stockfish/Stockfish/wiki/Download-and-usage
[wiki-compile-link]: https://github.com/official-stockfish/Stockfish/wiki/Compiling-from-source [wiki-compile-link]: https://github.com/official-stockfish/Stockfish/wiki/Compiling-from-source
[wiki-commands-link]: https://github.com/official-stockfish/Stockfish/wiki/Commands [wiki-uci-link]: https://github.com/official-stockfish/Stockfish/wiki/UCI-&-Commands
[worker-link]: https://github.com/glinscott/fishtest/wiki/Running-the-worker [wiki-usage-link]: https://github.com/official-stockfish/Stockfish/wiki/Download-and-usage
[worker-link]: https://github.com/official-stockfish/fishtest/wiki/Running-the-worker
[lc0-data-link]: https://storage.lczero.org/files/training_data
[odbl-link]: https://opendatacommons.org/licenses/odbl/odbl-10.txt
[build-badge]: https://img.shields.io/github/actions/workflow/status/official-stockfish/Stockfish/stockfish.yml?branch=master&style=for-the-badge&label=stockfish&logo=github [build-badge]: https://img.shields.io/github/actions/workflow/status/official-stockfish/Stockfish/stockfish.yml?branch=master&style=for-the-badge&label=stockfish&logo=github
[commits-badge]: https://img.shields.io/github/commits-since/official-stockfish/Stockfish/latest?style=for-the-badge [commits-badge]: https://img.shields.io/github/commits-since/official-stockfish/Stockfish/latest?style=for-the-badge
+129 -95
View File
@@ -1,139 +1,155 @@
Contributors to Fishtest with >10,000 CPU hours, as of 2023-06-20. Contributors to Fishtest with >10,000 CPU hours, as of 2024-08-31.
Thank you! Thank you!
Username CPU Hours Games played Username CPU Hours Games played
------------------------------------------------------------------ ------------------------------------------------------------------
noobpwnftw 37457426 2850540907 noobpwnftw 40428649 3164740143
technologov 14135647 742892808 technologov 23581394 1076895482
linrock 4423514 303254809 vdv 19425375 718302718
linrock 10034115 643194527
mlang 3026000 200065824 mlang 3026000 200065824
okrout 2572676 237511408
pemo 1836785 62226157
dew 1689162 100033738 dew 1689162 100033738
okrout 1578136 148855886 TueRens 1648780 77891164
pemo 1508508 48814305 sebastronomy 1468328 60859092
grandphish2 1461406 91540343 grandphish2 1466110 91776075
TueRens 1194790 70400852 JojoM 1130625 73666098
JojoM 947612 61773190 olafm 1067009 74807270
tvijlbrief 796125 51897690 tvijlbrief 796125 51897690
sebastronomy 742434 38218524 oz 781847 53910686
rpngn 768460 49812975
gvreuls 751085 52177668
mibere 703840 46867607 mibere 703840 46867607
gvreuls 651026 42988582 leszek 566598 42024615
oz 543438 39314736 cw 519601 34988161
cw 517858 34869755
fastgm 503862 30260818 fastgm 503862 30260818
leszek 467278 33514883 CSU_Dynasty 468784 31385034
CSU_Dynasty 464940 31177118 maximmasiutin 439192 27893522
ctoks 434416 28506889 ctoks 435148 28541909
crunchy 427035 27344275 crunchy 427414 27371625
maximmasiutin 424795 26577722 bcross 415724 29061187
bcross 415722 29060963 robal 371112 24642270
olafm 395922 32268020 mgrabiak 367963 26464704
rpngn 348378 24560289 velislav 342588 22140902
velislav 342567 22138992 ncfish1 329039 20624527
Fisherman 327231 21829379 Fisherman 327231 21829379
mgrabiak 300612 20608380
Dantist 296386 18031762 Dantist 296386 18031762
nordlandia 246201 16189678 tolkki963 262050 22049676
robal 241300 15656382 Sylvain27 255595 8864404
nordlandia 249322 16420192
Fifis 237657 13065577
marrco 234581 17714473 marrco 234581 17714473
ncfish1 227517 15233777 Calis007 217537 14450582
glinscott 208125 13277240 glinscott 208125 13277240
drabel 204167 13930674 drabel 204167 13930674
mhoram 202894 12601997 mhoram 202894 12601997
bking_US 198894 11876016 bking_US 198894 11876016
Thanar 179852 12365359 Thanar 179852 12365359
vdv 175544 9904472 javran 169679 13481966
armo9494 162863 10937118
spams 157128 10319326 spams 157128 10319326
DesolatedDodo 156683 10211206
Wencey 152308 8375444
sqrt2 147963 9724586 sqrt2 147963 9724586
DesolatedDodo 146350 9536172 vdbergh 140311 9225125
Calis007 143165 9478764 jcAEie 140086 10603658
vdbergh 138650 9064413
CoffeeOne 137100 5024116 CoffeeOne 137100 5024116
armo9494 136191 9460264
malala 136182 8002293 malala 136182 8002293
xoto 133759 9159372 xoto 133759 9159372
Dubslow 129614 8519312
davar 129023 8376525 davar 129023 8376525
DMBK 122960 8980062 DMBK 122960 8980062
dsmith 122059 7570238 dsmith 122059 7570238
CypressChess 120784 8672620
sschnee 120526 7547722
maposora 119734 10749710
amicic 119661 7938029 amicic 119661 7938029
Wolfgang 115713 8159062
Data 113305 8220352 Data 113305 8220352
BrunoBanani 112960 7436849 BrunoBanani 112960 7436849
CypressChess 108331 7759788 markkulix 112897 9133168
cuistot 109802 7121030
skiminki 107583 7218170 skiminki 107583 7218170
jcAEie 105675 8238962 sterni1971 104431 5938282
MaZePallas 102823 6633619 MaZePallas 102823 6633619
sterni1971 100532 5880772
sunu 100167 7040199 sunu 100167 7040199
zeryl 99331 6221261 zeryl 99331 6221261
thirdlife 99124 2242380 thirdlife 99156 2245320
ElbertoOne 99028 7023771 ElbertoOne 99028 7023771
cuistot 98853 6069816 megaman7de 98456 6675076
bigpen0r 94809 6529203 Goatminola 96765 8257832
bigpen0r 94825 6529241
brabos 92118 6186135 brabos 92118 6186135
Wolfgang 91939 6105872 Maxim 90818 3283364
psk 89957 5984901 psk 89957 5984901
sschnee 88235 5268000
racerschmacer 85805 6122790 racerschmacer 85805 6122790
Fifis 85722 5709729
Dubslow 84986 6042456
Vizvezdenec 83761 5344740 Vizvezdenec 83761 5344740
0x3C33 82614 5271253 0x3C33 82614 5271253
szupaw 82495 7151686
BRAVONE 81239 5054681 BRAVONE 81239 5054681
nssy 76497 5259388 nssy 76497 5259388
cody 76126 4492126
jromang 76106 5236025 jromang 76106 5236025
MarcusTullius 76103 5061991
woutboat 76072 6022922
Spprtr 75977 5252287
teddybaer 75125 5407666 teddybaer 75125 5407666
tolkki963 74762 5149662
megaman7de 74351 4940352
Wencey 74181 4711488
Pking_cda 73776 5293873 Pking_cda 73776 5293873
yurikvelo 73150 5004382 yurikvelo 73611 5046822
markkulix 72607 5304642 Mineta 71130 4711422
Bobo1239 70579 4794999 Bobo1239 70579 4794999
solarlight 70517 5028306 solarlight 70517 5028306
dv8silencer 70287 3883992 dv8silencer 70287 3883992
manap 66273 4121774 manap 66273 4121774
tinker 64333 4268790 tinker 64333 4268790
qurashee 61208 3429862 qurashee 61208 3429862
Mineta 59357 4418202 AGI 58195 4329580
Spprtr 58723 3911011
AGI 58147 4325994
robnjr 57262 4053117 robnjr 57262 4053117
Freja 56938 3733019 Freja 56938 3733019
MaxKlaxxMiner 56879 3423958 MaxKlaxxMiner 56879 3423958
MarcusTullius 56746 3762951
ttruscott 56010 3680085 ttruscott 56010 3680085
rkl 55132 4164467 rkl 55132 4164467
jmdana 54697 4012593
notchris 53936 4184018
renouve 53811 3501516 renouve 53811 3501516
javran 53785 4627608
finfish 51360 3370515 finfish 51360 3370515
eva42 51272 3599691 eva42 51272 3599691
eastorwest 51117 3454811 eastorwest 51117 3454811
rap 49985 3219146 rap 49985 3219146
pb00067 49733 3298934 pb00067 49733 3298934
GPUex 48686 3684998
OuaisBla 48626 3445134 OuaisBla 48626 3445134
ronaldjerum 47654 3240695 ronaldjerum 47654 3240695
biffhero 46564 3111352 biffhero 46564 3111352
oryx 45639 3546530
VoyagerOne 45476 3452465 VoyagerOne 45476 3452465
jmdana 44893 3065205
maposora 44597 4039578
oryx 44570 3454238
speedycpu 43842 3003273 speedycpu 43842 3003273
jbwiebe 43305 2805433 jbwiebe 43305 2805433
GPUex 42378 3133332
Antihistamine 41788 2761312 Antihistamine 41788 2761312
mhunt 41735 2691355 mhunt 41735 2691355
jibarbosa 41640 4145702
homyur 39893 2850481 homyur 39893 2850481
gri 39871 2515779 gri 39871 2515779
DeepnessFulled 39020 3323102
Garf 37741 2999686 Garf 37741 2999686
SC 37299 2731694 SC 37299 2731694
Gaster319 37118 3279678
naclosagc 36562 1279618
csnodgrass 36207 2688994 csnodgrass 36207 2688994
strelock 34716 2074055 strelock 34716 2074055
szupaw 34102 2880346 gopeto 33717 2245606
EthanOConnor 33370 2090311 EthanOConnor 33370 2090311
slakovv 32915 2021889 slakovv 32915 2021889
jojo2357 32890 2826662
shawnxu 32019 2802552
Gelma 31771 1551204 Gelma 31771 1551204
gopeto 31671 2060990 vidar808 31560 1351810
kdave 31157 2198362 kdave 31157 2198362
manapbk 30987 1810399 manapbk 30987 1810399
ZacHFX 30966 2272416
TataneSan 30713 1513402
votoanthuan 30691 2460856
Prcuvu 30377 2170122 Prcuvu 30377 2170122
anst 30301 2190091 anst 30301 2190091
jkiiski 30136 1904470 jkiiski 30136 1904470
@@ -142,126 +158,144 @@ hyperbolic.tom 29840 2017394
chuckstablers 29659 2093438 chuckstablers 29659 2093438
Pyafue 29650 1902349 Pyafue 29650 1902349
belzedar94 28846 1811530 belzedar94 28846 1811530
mecevdimitar 27610 1721382
chriswk 26902 1868317 chriswk 26902 1868317
xwziegtm 26897 2124586 xwziegtm 26897 2124586
achambord 26582 1767323 achambord 26582 1767323
somethingintheshadows 26496 2186404
Patrick_G 26276 1801617 Patrick_G 26276 1801617
yorkman 26193 1992080 yorkman 26193 1992080
Ulysses 25288 1689730 srowen 25743 1490684
Ulysses 25413 1702830
Jopo12321 25227 1652482
SFTUser 25182 1675689 SFTUser 25182 1675689
nabildanial 24942 1519409 nabildanial 25068 1531665
Sharaf_DG 24765 1786697 Sharaf_DG 24765 1786697
Maxim 24705 1502062
rodneyc 24376 1416402 rodneyc 24376 1416402
jsys14 24297 1721230
agg177 23890 1395014 agg177 23890 1395014
Goatminola 23763 1956036 AndreasKrug 23754 1890115
Ente 23639 1671638 Ente 23752 1678188
Jopo12321 23467 1483172
JanErik 23408 1703875 JanErik 23408 1703875
Isidor 23388 1680691 Isidor 23388 1680691
Norabor 23371 1603244 Norabor 23371 1603244
WoodMan777 23253 2023048
Nullvalue 23155 2022752
cisco2015 22920 1763301 cisco2015 22920 1763301
jsys14 22824 1591906
Zirie 22542 1472937 Zirie 22542 1472937
team-oh 22272 1636708 team-oh 22272 1636708
Roady 22220 1465606 Roady 22220 1465606
MazeOfGalious 21978 1629593 MazeOfGalious 21978 1629593
sg4032 21947 1643353 sg4032 21950 1643373
tsim67 21747 1330880
ianh2105 21725 1632562 ianh2105 21725 1632562
Skiff84 21711 1014212
xor12 21628 1680365 xor12 21628 1680365
dex 21612 1467203 dex 21612 1467203
nesoneg 21494 1463031 nesoneg 21494 1463031
user213718 21454 1404128 user213718 21454 1404128
Serpensin 21452 1790510
sphinx 21211 1384728 sphinx 21211 1384728
AndreasKrug 21097 1634811 qoo_charly_cai 21136 1514927
IslandLambda 21062 1220838
jjoshua2 21001 1423089 jjoshua2 21001 1423089
Zake9298 20938 1565848 Zake9298 20938 1565848
horst.prack 20878 1465656 horst.prack 20878 1465656
fishtester 20729 1348888
0xB00B1ES 20590 1208666 0xB00B1ES 20590 1208666
ols 20477 1195945
Dinde 20459 1292774
j3corre 20405 941444 j3corre 20405 941444
Adrian.Schmidt123 20316 1281436 Adrian.Schmidt123 20316 1281436
wei 19973 1745989 wei 19973 1745989
notchris 19958 1800128 teenychess 19819 1762006
Serpensin 19840 1697528
Gaster319 19712 1677310
fishtester 19617 1257388
rstoesser 19569 1293588 rstoesser 19569 1293588
eudhan 19274 1283717 eudhan 19274 1283717
votoanthuan 19108 1609992
vulcan 18871 1729392 vulcan 18871 1729392
wizardassassin 18795 1376884
Karpovbot 18766 1053178 Karpovbot 18766 1053178
qoo_charly_cai 18543 1284937
jundery 18445 1115855 jundery 18445 1115855
mkstockfishtester 18350 1690676
ville 17883 1384026 ville 17883 1384026
chris 17698 1487385 chris 17698 1487385
purplefishies 17595 1092533 purplefishies 17595 1092533
dju 17414 981289 dju 17414 981289
iisiraider 17275 1049015 iisiraider 17275 1049015
DragonLord 17014 1162790 DragonLord 17014 1162790
Karby 17008 1013160
pirt 16965 1271519
redstone59 16842 1461780 redstone59 16842 1461780
Alb11747 16787 1213926 Alb11747 16787 1213990
Naven94 16414 951718
scuzzi 16115 994341
IgorLeMasson 16064 1147232 IgorLeMasson 16064 1147232
Karby 15982 979610
scuzzi 15757 968735
ako027ako 15671 1173203 ako027ako 15671 1173203
infinigon 15285 965966
Nikolay.IT 15154 1068349 Nikolay.IT 15154 1068349
Andrew Grant 15114 895539 Andrew Grant 15114 895539
Naven94 15054 834762
OssumOpossum 14857 1007129 OssumOpossum 14857 1007129
ZacHFX 14783 1021842 LunaticBFF57 14525 1190310
enedene 14476 905279 enedene 14476 905279
Hjax 14394 1005013
bpfliegel 14233 882523 bpfliegel 14233 882523
YELNAMRON 14230 1128094
mpx86 14019 759568 mpx86 14019 759568
jpulman 13982 870599 jpulman 13982 870599
Skiff84 13826 721996 getraideBFF 13871 1172846
Nesa92 13806 1116101
crocogoat 13803 1117422 crocogoat 13803 1117422
Nesa92 13786 1114691
joster 13710 946160 joster 13710 946160
mbeier 13650 1044928 mbeier 13650 1044928
Hjax 13535 915487 Pablohn26 13552 1088532
Nullvalue 13468 1140498 wxt9861 13550 1312306
Dark_wizzie 13422 1007152 Dark_wizzie 13422 1007152
Rudolphous 13244 883140 Rudolphous 13244 883140
pirt 13100 1009897
Machariel 13010 863104 Machariel 13010 863104
infinigon 12991 943216 nalanzeyu 12996 232590
mabichito 12903 749391 mabichito 12903 749391
Jackfish 12895 868928
thijsk 12886 722107 thijsk 12886 722107
AdrianSA 12860 804972 AdrianSA 12860 804972
Flopzee 12698 894821 Flopzee 12698 894821
whelanh 12682 266404
mschmidt 12644 863193
korposzczur 12606 838168 korposzczur 12606 838168
fatmurphy 12547 853210 fatmurphy 12547 853210
Oakwen 12532 855759
icewulf 12447 854878
SapphireBrand 12416 969604 SapphireBrand 12416 969604
Oakwen 12399 844109
deflectooor 12386 579392 deflectooor 12386 579392
modolief 12386 896470 modolief 12386 896470
Farseer 12249 694108 Farseer 12249 694108
Jackfish 12213 805008 Hongildong 12201 648712
pgontarz 12151 848794 pgontarz 12151 848794
dbernier 12103 860824 dbernier 12103 860824
getraideBFF 12072 1024966 szczur90 12035 942376
FormazChar 12019 910409
rensonthemove 11999 971993
stocky 11954 699440 stocky 11954 699440
mschmidt 11941 803401 MooTheCow 11923 779432
MooTheCow 11870 773598 3cho 11842 1036786
FormazChar 11766 885707 ckaz 11792 732276
whelanh 11557 245188
3cho 11494 1031076
infinity 11470 727027 infinity 11470 727027
aga 11412 695127 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
Def9Infinity 11345 696552
d64 11263 789184 d64 11263 789184
ali-al-zhrani 11245 779246 ali-al-zhrani 11245 779246
ImperiumAeternum 11155 952000
snicolet 11106 869170 snicolet 11106 869170
dapper 11032 771402 dapper 11032 771402
ols 10947 624903 Ethnikoi 10993 945906
Karmatron 10828 677458 Snuuka 10938 435504
Karmatron 10871 678306
basepi 10637 744851 basepi 10637 744851
Cubox 10621 826448 Cubox 10621 826448
gerbil 10519 971688
michaelrpg 10509 739239 michaelrpg 10509 739239
OIVAS7572 10420 995586 OIVAS7572 10420 995586
jojo2357 10419 929708
WoodMan777 10380 873720
Garruk 10365 706465 Garruk 10365 706465
dzjp 10343 732529 dzjp 10343 732529
RickGroszkiewicz 10263 990798
+1
View File
@@ -0,0 +1 @@
*.sh text eol=lf
+153
View File
@@ -0,0 +1,153 @@
#!/bin/sh
#
# Returns properties of the native system.
# best architecture as supported by the CPU
# filename of the best binary uploaded as an artifact during CI
#
# Check if all the given flags are present in the CPU flags list
check_flags() {
for flag; do
printf '%s\n' "$flags" | grep -q -w "$flag" || return 1
done
}
# Set the CPU flags list
# remove underscores and points from flags, e.g. gcc uses avx512vnni, while some cpuinfo can have avx512_vnni, some systems use sse4_1 others sse4.1
get_flags() {
flags=$(awk '/^flags[ \t]*:|^Features[ \t]*:/{gsub(/^flags[ \t]*:[ \t]*|^Features[ \t]*:[ \t]*|[_.]/, ""); line=$0} END{print line}' /proc/cpuinfo)
}
# Check for gcc march "znver1" or "znver2" https://en.wikichip.org/wiki/amd/cpuid
check_znver_1_2() {
vendor_id=$(awk '/^vendor_id/{print $3; exit}' /proc/cpuinfo)
cpu_family=$(awk '/^cpu family/{print $4; exit}' /proc/cpuinfo)
[ "$vendor_id" = "AuthenticAMD" ] && [ "$cpu_family" = "23" ] && znver_1_2=true
}
# Set the file CPU loongarch64 architecture
set_arch_loongarch64() {
if check_flags 'lasx'; then
true_arch='loongarch64-lasx'
elif check_flags 'lsx'; then
true_arch='lonngarch64-lsx'
else
true_arch='loongarch64'
fi
}
# Set the file CPU x86_64 architecture
set_arch_x86_64() {
if check_flags 'avx512vnni' 'avx512dq' 'avx512f' 'avx512bw' 'avx512vl'; then
true_arch='x86-64-vnni256'
elif check_flags 'avx512f' 'avx512bw'; then
true_arch='x86-64-avx512'
elif [ -z "${znver_1_2+1}" ] && check_flags 'bmi2'; then
true_arch='x86-64-bmi2'
elif check_flags 'avx2'; then
true_arch='x86-64-avx2'
elif check_flags 'sse41' && check_flags 'popcnt'; then
true_arch='x86-64-sse41-popcnt'
else
true_arch='x86-64'
fi
}
set_arch_ppc_64() {
if $(grep -q -w "altivec" /proc/cpuinfo); then
power=$(grep -oP -m 1 'cpu\t+: POWER\K\d+' /proc/cpuinfo)
if [ "0$power" -gt 7 ]; then
# VSX started with POWER8
true_arch='ppc-64-vsx'
else
true_arch='ppc-64-altivec'
fi
else
true_arch='ppc-64'
fi
}
# Check the system type
uname_s=$(uname -s)
uname_m=$(uname -m)
case $uname_s in
'Darwin') # Mac OSX system
case $uname_m in
'arm64')
true_arch='apple-silicon'
file_arch='m1-apple-silicon'
;;
'x86_64')
flags=$(sysctl -n machdep.cpu.features machdep.cpu.leaf7_features | tr '\n' ' ' | tr '[:upper:]' '[:lower:]' | tr -d '_.')
set_arch_x86_64
if [ "$true_arch" = 'x86-64-vnni256' ] || [ "$true_arch" = 'x86-64-avx512' ]; then
file_arch='x86-64-bmi2'
fi
;;
esac
file_os='macos'
file_ext='tar'
;;
'Linux') # Linux system
get_flags
case $uname_m in
'x86_64')
file_os='ubuntu'
check_znver_1_2
set_arch_x86_64
;;
'i686')
file_os='ubuntu'
true_arch='x86-32'
;;
'ppc64'*)
file_os='ubuntu'
set_arch_ppc_64
;;
'aarch64')
file_os='android'
true_arch='armv8'
if check_flags 'asimddp'; then
true_arch="$true_arch-dotprod"
fi
;;
'armv7'*)
file_os='android'
true_arch='armv7'
if check_flags 'neon'; then
true_arch="$true_arch-neon"
fi
;;
'loongarch64'*)
file_os='linux'
set_arch_loongarch64
;;
*) # Unsupported machine type, exit with error
printf 'Unsupported machine type: %s\n' "$uname_m"
exit 1
;;
esac
file_ext='tar'
;;
'CYGWIN'*|'MINGW'*|'MSYS'*) # Windows system with POSIX compatibility layer
get_flags
check_znver_1_2
set_arch_x86_64
file_os='windows'
file_ext='zip'
;;
*)
# Unknown system type, exit with error
printf 'Unsupported system type: %s\n' "$uname_s"
exit 1
;;
esac
if [ -z "$file_arch" ]; then
file_arch=$true_arch
fi
file_name="stockfish-$file_os-$file_arch.$file_ext"
printf '%s %s\n' "$true_arch" "$file_name"
Executable
+75
View File
@@ -0,0 +1,75 @@
#!/bin/sh
wget_or_curl=$( (command -v wget > /dev/null 2>&1 && echo "wget -qO-") || \
(command -v curl > /dev/null 2>&1 && echo "curl -skL"))
if [ -z "$wget_or_curl" ]; then
>&2 printf "%s\n" "Neither wget or curl is installed." \
"Install one of these tools to download NNUE files automatically."
exit 1
fi
sha256sum=$( (command -v shasum > /dev/null 2>&1 && echo "shasum -a 256") || \
(command -v sha256sum > /dev/null 2>&1 && echo "sha256sum"))
if [ -z "$sha256sum" ]; then
>&2 echo "sha256sum not found, NNUE files will be assumed valid."
fi
get_nnue_filename() {
grep "$1" evaluate.h | grep "#define" | sed "s/.*\(nn-[a-z0-9]\{12\}.nnue\).*/\1/"
}
validate_network() {
# If no sha256sum command is available, assume the file is always valid.
if [ -n "$sha256sum" ] && [ -f "$1" ]; then
if [ "$1" != "nn-$($sha256sum "$1" | cut -c 1-12).nnue" ]; then
rm -f "$1"
return 1
fi
fi
}
fetch_network() {
_filename="$(get_nnue_filename "$1")"
if [ -z "$_filename" ]; then
>&2 echo "NNUE file name not found for: $1"
return 1
fi
if [ -f "$_filename" ]; then
if validate_network "$_filename"; then
echo "Existing $_filename validated, skipping download"
return
else
echo "Removing invalid NNUE file: $_filename"
fi
fi
for url in \
"https://tests.stockfishchess.org/api/nn/$_filename" \
"https://github.com/official-stockfish/networks/raw/master/$_filename"; do
echo "Downloading from $url ..."
if $wget_or_curl "$url" > "$_filename"; then
if validate_network "$_filename"; then
echo "Successfully validated $_filename"
else
echo "Downloaded $_filename is invalid"
continue
fi
else
echo "Failed to download from $url"
fi
if [ -f "$_filename" ]; then
return
fi
done
# Download was not successful in the loop, return false.
>&2 echo "Failed to download $_filename"
return 1
}
fetch_network EvalFileDefaultNameBig && \
fetch_network EvalFileDefaultNameSmall
+281 -202
View File
@@ -1,5 +1,5 @@
# Stockfish, a UCI chess playing engine derived from Glaurung 2.1 # Stockfish, a UCI chess playing engine derived from Glaurung 2.1
# Copyright (C) 2004-2023 The Stockfish developers (see AUTHORS file) # Copyright (C) 2004-2025 The Stockfish developers (see AUTHORS file)
# #
# Stockfish is free software: you can redistribute it and/or modify # Stockfish is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by # it under the terms of the GNU General Public License as published by
@@ -20,9 +20,9 @@
### ========================================================================== ### ==========================================================================
### Establish the operating system name ### Establish the operating system name
KERNEL = $(shell uname -s) KERNEL := $(shell uname -s)
ifeq ($(KERNEL),Linux) ifeq ($(KERNEL),Linux)
OS = $(shell uname -o) OS := $(shell uname -o)
endif endif
### Target Windows OS ### Target Windows OS
@@ -33,7 +33,7 @@ ifeq ($(OS),Windows_NT)
else ifeq ($(COMP),mingw) else ifeq ($(COMP),mingw)
target_windows = yes target_windows = yes
ifeq ($(WINE_PATH),) ifeq ($(WINE_PATH),)
WINE_PATH = $(shell which wine) WINE_PATH := $(shell which wine)
endif endif
endif endif
@@ -49,17 +49,21 @@ PREFIX = /usr/local
BINDIR = $(PREFIX)/bin BINDIR = $(PREFIX)/bin
### Built-in benchmark for pgo-builds ### Built-in benchmark for pgo-builds
ifeq ($(SDE_PATH),) PGOBENCH = $(WINE_PATH) ./$(EXE) bench
PGOBENCH = $(WINE_PATH) ./$(EXE) bench
else
PGOBENCH = $(SDE_PATH) -- $(WINE_PATH) ./$(EXE) bench
endif
### Source and object files ### Source and object files
SRCS = benchmark.cpp bitbase.cpp bitboard.cpp endgame.cpp evaluate.cpp main.cpp \ SRCS = benchmark.cpp bitboard.cpp evaluate.cpp main.cpp \
material.cpp misc.cpp movegen.cpp movepick.cpp pawns.cpp position.cpp psqt.cpp \ misc.cpp movegen.cpp movepick.cpp position.cpp \
search.cpp thread.cpp timeman.cpp tt.cpp uci.cpp ucioption.cpp tune.cpp syzygy/tbprobe.cpp \ search.cpp thread.cpp timeman.cpp tt.cpp uci.cpp ucioption.cpp tune.cpp syzygy/tbprobe.cpp \
nnue/evaluate_nnue.cpp nnue/features/half_ka_v2_hm.cpp nnue/nnue_misc.cpp nnue/features/half_ka_v2_hm.cpp nnue/network.cpp engine.cpp score.cpp memory.cpp
HEADERS = benchmark.h bitboard.h evaluate.h misc.h movegen.h movepick.h history.h \
nnue/nnue_misc.h nnue/features/half_ka_v2_hm.h nnue/layers/affine_transform.h \
nnue/layers/affine_transform_sparse_input.h nnue/layers/clipped_relu.h nnue/layers/simd.h \
nnue/layers/sqr_clipped_relu.h nnue/nnue_accumulator.h nnue/nnue_architecture.h \
nnue/nnue_common.h nnue/nnue_feature_transformer.h position.h \
search.h syzygy/tbprobe.h thread.h thread_win32_osx.h timeman.h \
tt.h tune.h types.h uci.h ucioption.h perft.h nnue/network.h engine.h score.h numa.h memory.h
OBJS = $(notdir $(SRCS:.cpp=.o)) OBJS = $(notdir $(SRCS:.cpp=.o))
@@ -94,8 +98,12 @@ VPATH = syzygy:nnue:nnue/features
# avx512 = yes/no --- -mavx512bw --- Use Intel Advanced Vector Extensions 512 # avx512 = yes/no --- -mavx512bw --- Use Intel Advanced Vector Extensions 512
# vnni256 = yes/no --- -mavx256vnni --- Use Intel Vector Neural Network Instructions 512 with 256bit operands # vnni256 = yes/no --- -mavx256vnni --- Use Intel Vector Neural Network Instructions 512 with 256bit operands
# vnni512 = yes/no --- -mavx512vnni --- Use Intel Vector Neural Network Instructions 512 # vnni512 = yes/no --- -mavx512vnni --- Use Intel Vector Neural Network Instructions 512
# altivec = yes/no --- -maltivec --- Use PowerPC Altivec SIMD extension
# vsx = yes/no --- -mvsx --- Use POWER VSX SIMD extension
# neon = yes/no --- -DUSE_NEON --- Use ARM SIMD architecture # neon = yes/no --- -DUSE_NEON --- Use ARM SIMD architecture
# dotprod = yes/no --- -DUSE_NEON_DOTPROD --- Use ARM advanced SIMD Int8 dot product instructions # dotprod = yes/no --- -DUSE_NEON_DOTPROD --- Use ARM advanced SIMD Int8 dot product instructions
# lsx = yes/no --- -mlsx --- Use Loongson SIMD eXtension
# lasx = yes/no --- -mlasx --- use Loongson Advanced SIMD eXtension
# #
# Note that Makefile is space sensitive, so when adding new architectures # Note that Makefile is space sensitive, so when adding new architectures
# or modifying existing flags, you have to make sure there are no extra spaces # or modifying existing flags, you have to make sure there are no extra spaces
@@ -108,16 +116,21 @@ VPATH = syzygy:nnue:nnue/features
### 2.1. General and architecture defaults ### 2.1. General and architecture defaults
ifeq ($(ARCH),) ifeq ($(ARCH),)
ARCH = x86-64-modern ARCH = native
help_skip_sanity = yes
endif endif
ifeq ($(ARCH), native)
override ARCH := $(shell $(SHELL) ../scripts/get_native_properties.sh | cut -d " " -f 1)
endif
# explicitly check for the list of supported architectures (as listed with make help), # explicitly check for the list of supported architectures (as listed with make help),
# the user can override with `make ARCH=x86-32-vnni256 SUPPORTED_ARCH=true` # the user can override with `make ARCH=x86-32-vnni256 SUPPORTED_ARCH=true`
ifeq ($(ARCH), $(filter $(ARCH), \ 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-64-altivec ppc-64-vsx ppc-32 e2k \
armv7 armv7-neon armv8 armv8-dotprod apple-silicon general-64 general-32 riscv64)) armv7 armv7-neon armv8 armv8-dotprod apple-silicon general-64 general-32 riscv64 \
loongarch64 loongarch64-lsx loongarch64-lasx))
SUPPORTED_ARCH=true SUPPORTED_ARCH=true
else else
SUPPORTED_ARCH=false SUPPORTED_ARCH=false
@@ -140,11 +153,21 @@ avxvnni = no
avx512 = no avx512 = no
vnni256 = no vnni256 = no
vnni512 = no vnni512 = no
altivec = no
vsx = no
neon = no neon = no
dotprod = no dotprod = no
arm_version = 0 arm_version = 0
lsx = no
lasx = no
STRIP = strip STRIP = strip
ifneq ($(shell which clang-format-18 2> /dev/null),)
CLANG-FORMAT = clang-format-18
else
CLANG-FORMAT = clang-format
endif
### 2.2 Architecture specific ### 2.2 Architecture specific
ifeq ($(findstring x86,$(ARCH)),x86) ifeq ($(findstring x86,$(ARCH)),x86)
@@ -193,6 +216,8 @@ ifeq ($(findstring -sse41,$(ARCH)),-sse41)
endif endif
ifeq ($(findstring -modern,$(ARCH)),-modern) ifeq ($(findstring -modern,$(ARCH)),-modern)
$(warning *** ARCH=$(ARCH) is deprecated, defaulting to ARCH=x86-64-sse41-popcnt. Execute `make help` for a list of available architectures. ***)
$(shell sleep 5)
popcnt = yes popcnt = yes
sse = yes sse = yes
sse2 = yes sse2 = yes
@@ -339,6 +364,20 @@ ifeq ($(ARCH),ppc-64)
prefetch = yes prefetch = yes
endif endif
ifeq ($(ARCH),ppc-64-altivec)
arch = ppc64
popcnt = yes
prefetch = yes
altivec = yes
endif
ifeq ($(ARCH),ppc-64-vsx)
arch = ppc64
popcnt = yes
prefetch = yes
vsx = yes
endif
ifeq ($(findstring e2k,$(ARCH)),e2k) ifeq ($(findstring e2k,$(ARCH)),e2k)
arch = e2k arch = e2k
mmx = yes mmx = yes
@@ -353,6 +392,21 @@ endif
ifeq ($(ARCH),riscv64) ifeq ($(ARCH),riscv64)
arch = riscv64 arch = riscv64
endif endif
ifeq ($(findstring loongarch64,$(ARCH)),loongarch64)
arch = loongarch64
prefetch = yes
ifeq ($(findstring -lasx,$(ARCH)),-lasx)
lsx = yes
lasx = yes
endif
ifeq ($(findstring -lsx,$(ARCH)),-lsx)
lsx = yes
endif
endif
endif endif
@@ -388,6 +442,8 @@ ifeq ($(COMP),gcc)
ifeq ($(ARCH),riscv64) ifeq ($(ARCH),riscv64)
CXXFLAGS += -latomic CXXFLAGS += -latomic
endif endif
else ifeq ($(arch),loongarch64)
CXXFLAGS += -latomic
else else
CXXFLAGS += -m$(bits) CXXFLAGS += -m$(bits)
LDFLAGS += -m$(bits) LDFLAGS += -m$(bits)
@@ -458,6 +514,8 @@ ifeq ($(COMP),clang)
ifeq ($(ARCH),riscv64) ifeq ($(ARCH),riscv64)
CXXFLAGS += -latomic CXXFLAGS += -latomic
endif endif
else ifeq ($(arch),loongarch64)
CXXFLAGS += -latomic
else else
CXXFLAGS += -m$(bits) CXXFLAGS += -m$(bits)
LDFLAGS += -m$(bits) LDFLAGS += -m$(bits)
@@ -465,8 +523,8 @@ ifeq ($(COMP),clang)
endif endif
ifeq ($(KERNEL),Darwin) ifeq ($(KERNEL),Darwin)
CXXFLAGS += -mmacosx-version-min=10.14 CXXFLAGS += -mmacosx-version-min=10.15
LDFLAGS += -mmacosx-version-min=10.14 LDFLAGS += -mmacosx-version-min=10.15
ifneq ($(arch),any) ifneq ($(arch),any)
CXXFLAGS += -arch $(arch) CXXFLAGS += -arch $(arch)
LDFLAGS += -arch $(arch) LDFLAGS += -arch $(arch)
@@ -497,6 +555,14 @@ ifeq ($(COMP),ndk)
STRIP=llvm-strip STRIP=llvm-strip
endif endif
endif endif
ifeq ($(arch),x86_64)
CXX=x86_64-linux-android21-clang++
ifneq ($(shell which x86_64-linux-android-strip 2>/dev/null),)
STRIP=x86_64-linux-android-strip
else
STRIP=llvm-strip
endif
endif
LDFLAGS += -static-libstdc++ -pie -lm -latomic LDFLAGS += -static-libstdc++ -pie -lm -latomic
endif endif
@@ -514,11 +580,6 @@ else
endif endif
endif endif
### Travis CI script uses COMPILER to overwrite CXX
ifdef COMPILER
COMPCXX=$(COMPILER)
endif
### Allow overwriting CXX from command line ### Allow overwriting CXX from command line
ifdef COMPCXX ifdef COMPCXX
CXX=$(COMPCXX) CXX=$(COMPCXX)
@@ -526,8 +587,8 @@ endif
### Sometimes gcc is really clang ### Sometimes gcc is really clang
ifeq ($(COMP),gcc) ifeq ($(COMP),gcc)
gccversion = $(shell $(CXX) --version 2>/dev/null) gccversion := $(shell $(CXX) --version 2>/dev/null)
gccisclang = $(findstring clang,$(gccversion)) gccisclang := $(findstring clang,$(gccversion))
ifneq ($(gccisclang),) ifneq ($(gccisclang),)
profile_make = clang-profile-make profile_make = clang-profile-make
profile_use = clang-profile-use profile_use = clang-profile-use
@@ -564,7 +625,7 @@ endif
### 3.3 Optimization ### 3.3 Optimization
ifeq ($(optimize),yes) ifeq ($(optimize),yes)
CXXFLAGS += -O3 CXXFLAGS += -O3 -funroll-loops
ifeq ($(comp),gcc) ifeq ($(comp),gcc)
ifeq ($(OS), Android) ifeq ($(OS), Android)
@@ -585,7 +646,7 @@ ifeq ($(optimize),yes)
endif endif
ifeq ($(comp),clang) ifeq ($(comp),clang)
clangmajorversion = $(shell $(CXX) -dumpversion 2>/dev/null | cut -f1 -d.) clangmajorversion := $(shell $(CXX) -dumpversion 2>/dev/null | cut -f1 -d.)
ifeq ($(shell expr $(clangmajorversion) \< 16),1) ifeq ($(shell expr $(clangmajorversion) \< 16),1)
CXXFLAGS += -fexperimental-new-pass-manager CXXFLAGS += -fexperimental-new-pass-manager
endif endif
@@ -607,7 +668,7 @@ else
endif endif
ifeq ($(popcnt),yes) ifeq ($(popcnt),yes)
ifeq ($(arch),$(filter $(arch),ppc64 armv7 armv8 arm64)) ifeq ($(arch),$(filter $(arch),ppc64 ppc64-altivec ppc64-vsx armv7 armv8 arm64))
CXXFLAGS += -DUSE_POPCNT CXXFLAGS += -DUSE_POPCNT
else else
CXXFLAGS += -msse3 -mpopcnt -DUSE_POPCNT CXXFLAGS += -msse3 -mpopcnt -DUSE_POPCNT
@@ -672,12 +733,25 @@ ifeq ($(sse2),yes)
endif endif
ifeq ($(mmx),yes) ifeq ($(mmx),yes)
CXXFLAGS += -DUSE_MMX
ifeq ($(comp),$(filter $(comp),gcc clang mingw icx)) ifeq ($(comp),$(filter $(comp),gcc clang mingw icx))
CXXFLAGS += -mmmx CXXFLAGS += -mmmx
endif endif
endif endif
ifeq ($(altivec),yes)
CXXFLAGS += -maltivec
ifeq ($(COMP),gcc)
CXXFLAGS += -mabi=altivec
endif
endif
ifeq ($(vsx),yes)
CXXFLAGS += -mvsx
ifeq ($(COMP),gcc)
CXXFLAGS += -DNO_WARN_X86_INTRINSICS -DUSE_SSE2
endif
endif
ifeq ($(neon),yes) ifeq ($(neon),yes)
CXXFLAGS += -DUSE_NEON=$(arm_version) CXXFLAGS += -DUSE_NEON=$(arm_version)
ifeq ($(KERNEL),Linux) ifeq ($(KERNEL),Linux)
@@ -693,6 +767,18 @@ ifeq ($(dotprod),yes)
CXXFLAGS += -march=armv8.2-a+dotprod -DUSE_NEON_DOTPROD CXXFLAGS += -march=armv8.2-a+dotprod -DUSE_NEON_DOTPROD
endif endif
ifeq ($(lasx),yes)
ifeq ($(comp),$(filter $(comp),gcc clang mingw icx))
CXXFLAGS += -mlasx
endif
endif
ifeq ($(lsx),yes)
ifeq ($(comp),$(filter $(comp),gcc clang mingw icx))
CXXFLAGS += -mlsx
endif
endif
### 3.7 pext ### 3.7 pext
ifeq ($(pext),yes) ifeq ($(pext),yes)
CXXFLAGS += -DUSE_PEXT CXXFLAGS += -DUSE_PEXT
@@ -701,19 +787,24 @@ ifeq ($(pext),yes)
endif endif
endif endif
### 3.7.1 Try to include git commit sha for versioning ### 3.8.1 Try to include git commit sha for versioning
GIT_SHA = $(shell git rev-parse HEAD 2>/dev/null | cut -c 1-8) GIT_SHA := $(shell git rev-parse HEAD 2>/dev/null | cut -c 1-8)
ifneq ($(GIT_SHA), ) ifneq ($(GIT_SHA), )
CXXFLAGS += -DGIT_SHA=$(GIT_SHA) CXXFLAGS += -DGIT_SHA=$(GIT_SHA)
endif endif
### 3.7.2 Try to include git commit date for versioning ### 3.8.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) GIT_DATE := $(shell git show -s --date=format:'%Y%m%d' --format=%cd HEAD 2>/dev/null)
ifneq ($(GIT_DATE), ) ifneq ($(GIT_DATE), )
CXXFLAGS += -DGIT_DATE=$(GIT_DATE) CXXFLAGS += -DGIT_DATE=$(GIT_DATE)
endif endif
### 3.8 Link Time Optimization ### 3.8.3 Try to include architecture
ifneq ($(ARCH), )
CXXFLAGS += -DARCH=$(ARCH)
endif
### 3.9 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)
@@ -748,7 +839,7 @@ ifeq ($(debug), no)
endif endif
endif endif
### 3.9 Android 5 can only run position independent executables. Note that this ### 3.10 Android 5 can only run position independent executables. Note that this
### breaks Android 4.0 and earlier. ### breaks Android 4.0 and earlier.
ifeq ($(OS), Android) ifeq ($(OS), Android)
CXXFLAGS += -fPIE CXXFLAGS += -fPIE
@@ -759,86 +850,91 @@ endif
### Section 4. Public Targets ### Section 4. Public Targets
### ========================================================================== ### ==========================================================================
help: help:
@echo "" @echo "" && \
@echo "To compile stockfish, type: " echo "To compile stockfish, type: " && \
@echo "" echo "" && \
@echo "make target ARCH=arch [COMP=compiler] [COMPCXX=cxx]" echo "make -j target [ARCH=arch] [COMP=compiler] [COMPCXX=cxx]" && \
@echo "" echo "" && \
@echo "Supported targets:" echo "Supported targets:" && \
@echo "" echo "" && \
@echo "help > Display architecture details" echo "help > Display architecture details" && \
@echo "profile-build > standard build with profile-guided optimization" echo "profile-build > standard build with profile-guided optimization" && \
@echo "build > skip profile-guided optimization" echo "build > skip profile-guided optimization" && \
@echo "net > Download the default nnue net" echo "net > Download the default nnue nets" && \
@echo "strip > Strip executable" echo "strip > Strip executable" && \
@echo "install > Install executable" echo "install > Install executable" && \
@echo "clean > Clean up" echo "clean > Clean up" && \
@echo "" echo "" && \
@echo "Supported archs:" echo "Supported archs:" && \
@echo "" echo "" && \
@echo "x86-64-vnni512 > x86 64-bit with vnni 512bit support" echo "native > select the best architecture for the host processor (default)" && \
@echo "x86-64-vnni256 > x86 64-bit with vnni 512bit support, limit operands to 256bit wide" echo "x86-64-vnni512 > x86 64-bit with vnni 512bit support" && \
@echo "x86-64-avx512 > x86 64-bit with avx512 support" echo "x86-64-vnni256 > x86 64-bit with vnni 512bit support, limit operands to 256bit wide" && \
@echo "x86-64-avxvnni > x86 64-bit with vnni 256bit support" echo "x86-64-avx512 > x86 64-bit with avx512 support" && \
@echo "x86-64-bmi2 > x86 64-bit with bmi2 support" echo "x86-64-avxvnni > x86 64-bit with vnni 256bit support" && \
@echo "x86-64-avx2 > x86 64-bit with avx2 support" echo "x86-64-bmi2 > x86 64-bit with bmi2 support" && \
@echo "x86-64-sse41-popcnt > x86 64-bit with sse41 and popcnt support" echo "x86-64-avx2 > x86 64-bit with avx2 support" && \
@echo "x86-64-modern > common modern CPU, currently x86-64-sse41-popcnt" echo "x86-64-sse41-popcnt > x86 64-bit with sse41 and popcnt support" && \
@echo "x86-64-ssse3 > x86 64-bit with ssse3 support" echo "x86-64-modern > deprecated, currently x86-64-sse41-popcnt" && \
@echo "x86-64-sse3-popcnt > x86 64-bit with sse3 and popcnt support" echo "x86-64-ssse3 > x86 64-bit with ssse3 support" && \
@echo "x86-64 > x86 64-bit generic (with sse2 support)" echo "x86-64-sse3-popcnt > x86 64-bit with sse3 compile and popcnt support" && \
@echo "x86-32-sse41-popcnt > x86 32-bit with sse41 and popcnt support" echo "x86-64 > x86 64-bit generic (with sse2 support)" && \
@echo "x86-32-sse2 > x86 32-bit with sse2 support" echo "x86-32-sse41-popcnt > x86 32-bit with sse41 and popcnt support" && \
@echo "x86-32 > x86 32-bit generic (with mmx and sse support)" echo "x86-32-sse2 > x86 32-bit with sse2 support" && \
@echo "ppc-64 > PPC 64-bit" echo "x86-32 > x86 32-bit generic (with mmx compile support)" && \
@echo "ppc-32 > PPC 32-bit" echo "ppc-64 > PPC 64-bit" && \
@echo "armv7 > ARMv7 32-bit" echo "ppc-64-altivec > PPC 64-bit with altivec support" && \
@echo "armv7-neon > ARMv7 32-bit with popcnt and neon" echo "ppc-64-vsx > PPC 64-bit with vsx support" && \
@echo "armv8 > ARMv8 64-bit with popcnt and neon" echo "ppc-32 > PPC 32-bit" && \
@echo "armv8-dotprod > ARMv8 64-bit with popcnt, neon and dot product support" echo "armv7 > ARMv7 32-bit" && \
@echo "e2k > Elbrus 2000" echo "armv7-neon > ARMv7 32-bit with popcnt and neon" && \
@echo "apple-silicon > Apple silicon ARM64" echo "armv8 > ARMv8 64-bit with popcnt and neon" && \
@echo "general-64 > unspecified 64-bit" echo "armv8-dotprod > ARMv8 64-bit with popcnt, neon and dot product support" && \
@echo "general-32 > unspecified 32-bit" echo "e2k > Elbrus 2000" && \
@echo "riscv64 > RISC-V 64-bit" echo "apple-silicon > Apple silicon ARM64" && \
@echo "" echo "general-64 > unspecified 64-bit" && \
@echo "Supported compilers:" echo "general-32 > unspecified 32-bit" && \
@echo "" echo "riscv64 > RISC-V 64-bit" && \
@echo "gcc > Gnu compiler (default)" echo "loongarch64 > LoongArch 64-bit" && \
@echo "mingw > Gnu compiler with MinGW under Windows" echo "loongarch64-lsx > LoongArch 64-bit with SIMD eXtension" && \
@echo "clang > LLVM Clang compiler" echo "loongarch64-lasx > LoongArch 64-bit with Advanced SIMD eXtension" && \
@echo "icx > Intel oneAPI DPC++/C++ Compiler" echo "" && \
@echo "ndk > Google NDK to cross-compile for Android" echo "Supported compilers:" && \
@echo "" echo "" && \
@echo "Simple examples. If you don't know what to do, you likely want to run one of: " echo "gcc > GNU compiler (default)" && \
@echo "" echo "mingw > GNU compiler with MinGW under Windows" && \
@echo "make -j profile-build ARCH=x86-64-avx2 # typically a fast compile for common systems " echo "clang > LLVM Clang compiler" && \
@echo "make -j profile-build ARCH=x86-64-modern # A more portable compile for 64-bit systems " echo "icx > Intel oneAPI DPC++/C++ Compiler" && \
@echo "make -j profile-build ARCH=x86-64 # A portable compile for 64-bit systems " echo "ndk > Google NDK to cross-compile for Android" && \
@echo "" echo "" && \
@echo "Advanced examples, for experienced users: " echo "Simple examples. If you don't know what to do, you likely want to run one of: " && \
@echo "" echo "" && \
@echo "make -j profile-build ARCH=x86-64-bmi2" echo "make -j profile-build ARCH=x86-64-avx2 # typically a fast compile for common systems " && \
@echo "make -j profile-build ARCH=x86-64-bmi2 COMP=gcc COMPCXX=g++-9.0" echo "make -j profile-build ARCH=x86-64-sse41-popcnt # A more portable compile for 64-bit systems " && \
@echo "make -j build ARCH=x86-64-ssse3 COMP=clang" echo "make -j profile-build ARCH=x86-64 # A portable compile for 64-bit systems " && \
@echo "" echo "" && \
@echo "-------------------------------" echo "Advanced examples, for experienced users: " && \
ifeq ($(SUPPORTED_ARCH)$(help_skip_sanity), true) echo "" && \
@echo "The selected architecture $(ARCH) will enable the following configuration: " echo "make -j profile-build ARCH=x86-64-avxvnni" && \
@$(MAKE) ARCH=$(ARCH) COMP=$(COMP) config-sanity echo "make -j profile-build ARCH=x86-64-avxvnni COMP=gcc COMPCXX=g++-12.0" && \
else echo "make -j build ARCH=x86-64-ssse3 COMP=clang" && \
echo ""
ifneq ($(SUPPORTED_ARCH), true)
@echo "Specify a supported architecture with the ARCH option for more details" @echo "Specify a supported architecture with the ARCH option for more details"
@echo "" @echo ""
endif endif
.PHONY: help build profile-build strip install clean net objclean profileclean \ .PHONY: help analyze build profile-build strip install clean net \
config-sanity \ objclean profileclean config-sanity \
icx-profile-use icx-profile-make \ icx-profile-use icx-profile-make \
gcc-profile-use gcc-profile-make \ gcc-profile-use gcc-profile-make \
clang-profile-use clang-profile-make FORCE clang-profile-use clang-profile-make FORCE \
format analyze
analyze: net config-sanity objclean
$(MAKE) -k ARCH=$(ARCH) COMP=$(COMP) $(OBJS)
build: net config-sanity build: net config-sanity
$(MAKE) ARCH=$(ARCH) COMP=$(COMP) all $(MAKE) ARCH=$(ARCH) COMP=$(COMP) all
@@ -849,7 +945,8 @@ profile-build: net config-sanity objclean profileclean
$(MAKE) ARCH=$(ARCH) COMP=$(COMP) $(profile_make) $(MAKE) ARCH=$(ARCH) COMP=$(COMP) $(profile_make)
@echo "" @echo ""
@echo "Step 2/4. Running benchmark for pgo-build ..." @echo "Step 2/4. Running benchmark for pgo-build ..."
$(PGOBENCH) 2>&1 | tail -n 4 $(PGOBENCH) > PGOBENCH.out 2>&1
tail -n 4 PGOBENCH.out
@echo "" @echo ""
@echo "Step 3/4. Building optimized executable ..." @echo "Step 3/4. Building optimized executable ..."
$(MAKE) ARCH=$(ARCH) COMP=$(COMP) objclean $(MAKE) ARCH=$(ARCH) COMP=$(COMP) objclean
@@ -870,42 +967,6 @@ install:
clean: objclean profileclean clean: objclean profileclean
@rm -f .depend *~ core @rm -f .depend *~ core
# evaluation network (nnue)
net:
$(eval nnuenet := $(shell grep EvalFileDefaultName evaluate.h | grep define | sed 's/.*\(nn-[a-z0-9]\{12\}.nnue\).*/\1/'))
@echo "Default net: $(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))
@if [ "x$(curl_or_wget)" = "x" ]; then \
echo "Neither curl nor wget is installed. Install one of these tools unless the net has been downloaded manually"; \
fi
$(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 \
echo "shasum / sha256sum not found, skipping net validation"; \
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);\
else \
echo "No net found and download not possible"; exit 1;\
fi; \
fi; \
if [ "x$(shasum_command)" != "x" ]; then \
if [ "$(nnuenet)" != "nn-"`$(shasum_command) $(nnuenet) | cut -c1-12`".nnue" ]; then \
echo "Removing failed download"; rm -f $(nnuenet); \
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:
@rm -f stockfish stockfish.exe *.o ./syzygy/*.o ./nnue/*.o ./nnue/features/*.o @rm -f stockfish stockfish.exe *.o ./syzygy/*.o ./nnue/*.o ./nnue/features/*.o
@@ -913,13 +974,21 @@ objclean:
# clean auxiliary profiling files # clean auxiliary profiling files
profileclean: profileclean:
@rm -rf profdir @rm -rf profdir
@rm -f bench.txt *.gcda *.gcno ./syzygy/*.gcda ./nnue/*.gcda ./nnue/features/*.gcda *.s @rm -f bench.txt *.gcda *.gcno ./syzygy/*.gcda ./nnue/*.gcda ./nnue/features/*.gcda *.s PGOBENCH.out
@rm -f stockfish.profdata *.profraw @rm -f stockfish.profdata *.profraw
@rm -f stockfish.*args* @rm -f stockfish.*args*
@rm -f stockfish.*lt* @rm -f stockfish.*lt*
@rm -f stockfish.res @rm -f stockfish.res
@rm -f ./-lstdc++.res @rm -f ./-lstdc++.res
# evaluation network (nnue)
net:
@$(SHELL) ../scripts/net.sh
format:
$(CLANG-FORMAT) -i $(SRCS) $(HEADERS) -style=file
# default target
default: default:
help help
@@ -931,61 +1000,71 @@ all: $(EXE) .depend
config-sanity: net config-sanity: net
@echo "" @echo ""
@echo "Config:" @echo "Config:" && \
@echo "debug: '$(debug)'" echo "debug: '$(debug)'" && \
@echo "sanitize: '$(sanitize)'" echo "sanitize: '$(sanitize)'" && \
@echo "optimize: '$(optimize)'" echo "optimize: '$(optimize)'" && \
@echo "arch: '$(arch)'" echo "arch: '$(arch)'" && \
@echo "bits: '$(bits)'" echo "bits: '$(bits)'" && \
@echo "kernel: '$(KERNEL)'" echo "kernel: '$(KERNEL)'" && \
@echo "os: '$(OS)'" echo "os: '$(OS)'" && \
@echo "prefetch: '$(prefetch)'" echo "prefetch: '$(prefetch)'" && \
@echo "popcnt: '$(popcnt)'" echo "popcnt: '$(popcnt)'" && \
@echo "pext: '$(pext)'" echo "pext: '$(pext)'" && \
@echo "sse: '$(sse)'" echo "sse: '$(sse)'" && \
@echo "mmx: '$(mmx)'" echo "mmx: '$(mmx)'" && \
@echo "sse2: '$(sse2)'" echo "sse2: '$(sse2)'" && \
@echo "ssse3: '$(ssse3)'" echo "ssse3: '$(ssse3)'" && \
@echo "sse41: '$(sse41)'" echo "sse41: '$(sse41)'" && \
@echo "avx2: '$(avx2)'" echo "avx2: '$(avx2)'" && \
@echo "avxvnni: '$(avxvnni)'" echo "avxvnni: '$(avxvnni)'" && \
@echo "avx512: '$(avx512)'" echo "avx512: '$(avx512)'" && \
@echo "vnni256: '$(vnni256)'" echo "vnni256: '$(vnni256)'" && \
@echo "vnni512: '$(vnni512)'" echo "vnni512: '$(vnni512)'" && \
@echo "neon: '$(neon)'" echo "altivec: '$(altivec)'" && \
@echo "dotprod: '$(dotprod)'" echo "vsx: '$(vsx)'" && \
@echo "arm_version: '$(arm_version)'" echo "neon: '$(neon)'" && \
@echo "target_windows: '$(target_windows)'" echo "dotprod: '$(dotprod)'" && \
@echo "" echo "arm_version: '$(arm_version)'" && \
@echo "Flags:" echo "lsx: '$(lsx)'" && \
@echo "CXX: $(CXX)" echo "lasx: '$(lasx)'" && \
@echo "CXXFLAGS: $(CXXFLAGS)" echo "target_windows: '$(target_windows)'" && \
@echo "LDFLAGS: $(LDFLAGS)" echo "" && \
@echo "" echo "Flags:" && \
@echo "Testing config sanity. If this fails, try 'make help' ..." echo "CXX: $(CXX)" && \
@echo "" echo "CXXFLAGS: $(CXXFLAGS)" && \
@test "$(debug)" = "yes" || test "$(debug)" = "no" echo "LDFLAGS: $(LDFLAGS)" && \
@test "$(optimize)" = "yes" || test "$(optimize)" = "no" echo "" && \
@test "$(SUPPORTED_ARCH)" = "true" echo "Testing config sanity. If this fails, try 'make help' ..." && \
@test "$(arch)" = "any" || test "$(arch)" = "x86_64" || test "$(arch)" = "i386" || \ echo "" && \
(test "$(debug)" = "yes" || test "$(debug)" = "no") && \
(test "$(optimize)" = "yes" || test "$(optimize)" = "no") && \
(test "$(SUPPORTED_ARCH)" = "true") && \
(test "$(arch)" = "any" || test "$(arch)" = "x86_64" || test "$(arch)" = "i386" || \
test "$(arch)" = "ppc64" || test "$(arch)" = "ppc" || test "$(arch)" = "e2k" || \ test "$(arch)" = "ppc64" || test "$(arch)" = "ppc" || test "$(arch)" = "e2k" || \
test "$(arch)" = "armv7" || test "$(arch)" = "armv8" || test "$(arch)" = "arm64" || test "$(arch)" = "riscv64" test "$(arch)" = "armv7" || test "$(arch)" = "armv8" || test "$(arch)" = "arm64" || \
@test "$(bits)" = "32" || test "$(bits)" = "64" test "$(arch)" = "riscv64" || test "$(arch)" = "loongarch64") && \
@test "$(prefetch)" = "yes" || test "$(prefetch)" = "no" (test "$(bits)" = "32" || test "$(bits)" = "64") && \
@test "$(popcnt)" = "yes" || test "$(popcnt)" = "no" (test "$(prefetch)" = "yes" || test "$(prefetch)" = "no") && \
@test "$(pext)" = "yes" || test "$(pext)" = "no" (test "$(popcnt)" = "yes" || test "$(popcnt)" = "no") && \
@test "$(sse)" = "yes" || test "$(sse)" = "no" (test "$(pext)" = "yes" || test "$(pext)" = "no") && \
@test "$(mmx)" = "yes" || test "$(mmx)" = "no" (test "$(sse)" = "yes" || test "$(sse)" = "no") && \
@test "$(sse2)" = "yes" || test "$(sse2)" = "no" (test "$(mmx)" = "yes" || test "$(mmx)" = "no") && \
@test "$(ssse3)" = "yes" || test "$(ssse3)" = "no" (test "$(sse2)" = "yes" || test "$(sse2)" = "no") && \
@test "$(sse41)" = "yes" || test "$(sse41)" = "no" (test "$(ssse3)" = "yes" || test "$(ssse3)" = "no") && \
@test "$(avx2)" = "yes" || test "$(avx2)" = "no" (test "$(sse41)" = "yes" || test "$(sse41)" = "no") && \
@test "$(avx512)" = "yes" || test "$(avx512)" = "no" (test "$(avx2)" = "yes" || test "$(avx2)" = "no") && \
@test "$(vnni256)" = "yes" || test "$(vnni256)" = "no" (test "$(avx512)" = "yes" || test "$(avx512)" = "no") && \
@test "$(vnni512)" = "yes" || test "$(vnni512)" = "no" (test "$(vnni256)" = "yes" || test "$(vnni256)" = "no") && \
@test "$(neon)" = "yes" || test "$(neon)" = "no" (test "$(vnni512)" = "yes" || test "$(vnni512)" = "no") && \
@test "$(comp)" = "gcc" || test "$(comp)" = "icx" || test "$(comp)" = "mingw" || test "$(comp)" = "clang" \ (test "$(altivec)" = "yes" || test "$(altivec)" = "no") && \
|| test "$(comp)" = "armv7a-linux-androideabi16-clang" || test "$(comp)" = "aarch64-linux-android21-clang" (test "$(vsx)" = "yes" || test "$(vsx)" = "no") && \
(test "$(neon)" = "yes" || test "$(neon)" = "no") && \
(test "$(lsx)" = "yes" || test "$(lsx)" = "no") && \
(test "$(lasx)" = "yes" || test "$(lasx)" = "no") && \
(test "$(comp)" = "gcc" || test "$(comp)" = "icx" || test "$(comp)" = "mingw" || \
test "$(comp)" = "clang" || test "$(comp)" = "armv7a-linux-androideabi16-clang" || \
test "$(comp)" = "aarch64-linux-android21-clang")
$(EXE): $(OBJS) $(EXE): $(OBJS)
+$(CXX) -o $@ $(OBJS) $(LDFLAGS) +$(CXX) -o $@ $(OBJS) $(LDFLAGS)
@@ -996,14 +1075,14 @@ FORCE:
clang-profile-make: clang-profile-make:
$(MAKE) ARCH=$(ARCH) COMP=$(COMP) \ $(MAKE) ARCH=$(ARCH) COMP=$(COMP) \
EXTRACXXFLAGS='-fprofile-instr-generate ' \ EXTRACXXFLAGS='-fprofile-generate ' \
EXTRALDFLAGS=' -fprofile-instr-generate' \ EXTRALDFLAGS=' -fprofile-generate' \
all all
clang-profile-use: clang-profile-use:
$(XCRUN) llvm-profdata merge -output=stockfish.profdata *.profraw $(XCRUN) llvm-profdata merge -output=stockfish.profdata *.profraw
$(MAKE) ARCH=$(ARCH) COMP=$(COMP) \ $(MAKE) ARCH=$(ARCH) COMP=$(COMP) \
EXTRACXXFLAGS='-fprofile-instr-use=stockfish.profdata' \ EXTRACXXFLAGS='-fprofile-use=stockfish.profdata' \
EXTRALDFLAGS='-fprofile-use ' \ EXTRALDFLAGS='-fprofile-use ' \
all all
+407 -72
View File
@@ -1,6 +1,6 @@
/* /*
Stockfish, a UCI chess playing engine derived from Glaurung 2.1 Stockfish, a UCI chess playing engine derived from Glaurung 2.1
Copyright (C) 2004-2023 The Stockfish developers (see AUTHORS file) Copyright (C) 2004-2025 The Stockfish developers (see AUTHORS file)
Stockfish is free software: you can redistribute it and/or modify Stockfish is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by it under the terms of the GNU General Public License as published by
@@ -17,19 +17,17 @@
*/ */
#include "benchmark.h" #include "benchmark.h"
#include "numa.h"
#include <cstdlib>
#include <fstream> #include <fstream>
#include <iostream> #include <iostream>
#include <istream>
#include <vector> #include <vector>
#include "position.h"
using namespace std;
namespace { namespace {
const vector<string> Defaults = { // clang-format off
const std::vector<std::string> Defaults = {
"setoption name UCI_Chess960 value false", "setoption name UCI_Chess960 value false",
"rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq - 0 1", "rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq - 0 1",
"r3k2r/p1ppqpb1/bn2pnp1/3PN3/1p2P3/2N2Q1p/PPPBBPPP/R3K2R w KQkq - 0 10", "r3k2r/p1ppqpb1/bn2pnp1/3PN3/1p2P3/2N2Q1p/PPPBBPPP/R3K2R w KQkq - 0 10",
@@ -92,86 +90,423 @@ const vector<string> Defaults = {
"nqbnrkrb/pppppppp/8/8/8/8/PPPPPPPP/NQBNRKRB w KQkq - 0 1", "nqbnrkrb/pppppppp/8/8/8/8/PPPPPPPP/NQBNRKRB w KQkq - 0 1",
"setoption name UCI_Chess960 value false" "setoption name UCI_Chess960 value false"
}; };
// clang-format on
} // namespace // clang-format off
// human-randomly picked 5 games with <60 moves from
// https://tests.stockfishchess.org/tests/view/665c71f9fd45fb0f907c21e0
// only moves for one side
const std::vector<std::vector<std::string>> BenchmarkPositions = {
{
"rnbq1k1r/ppp1bppp/4pn2/8/2B5/2NP1N2/PPP2PPP/R1BQR1K1 b - - 2 8",
"rnbq1k1r/pp2bppp/4pn2/2p5/2B2B2/2NP1N2/PPP2PPP/R2QR1K1 b - - 1 9",
"r1bq1k1r/pp2bppp/2n1pn2/2p5/2B1NB2/3P1N2/PPP2PPP/R2QR1K1 b - - 3 10",
"r1bq1k1r/pp2bppp/2n1p3/2p5/2B1PB2/5N2/PPP2PPP/R2QR1K1 b - - 0 11",
"r1b2k1r/pp2bppp/2n1p3/2p5/2B1PB2/5N2/PPP2PPP/3RR1K1 b - - 0 12",
"r1b1k2r/pp2bppp/2n1p3/2p5/2B1PB2/2P2N2/PP3PPP/3RR1K1 b - - 0 13",
"r1b1k2r/1p2bppp/p1n1p3/2p5/4PB2/2P2N2/PP2BPPP/3RR1K1 b - - 1 14",
"r1b1k2r/4bppp/p1n1p3/1pp5/P3PB2/2P2N2/1P2BPPP/3RR1K1 b - - 0 15",
"r1b1k2r/4bppp/p1n1p3/1P6/2p1PB2/2P2N2/1P2BPPP/3RR1K1 b - - 0 16",
"r1b1k2r/4bppp/2n1p3/1p6/2p1PB2/1PP2N2/4BPPP/3RR1K1 b - - 0 17",
"r3k2r/3bbppp/2n1p3/1p6/2P1PB2/2P2N2/4BPPP/3RR1K1 b - - 0 18",
"r3k2r/3bbppp/2n1p3/8/1pP1P3/2P2N2/3BBPPP/3RR1K1 b - - 1 19",
"1r2k2r/3bbppp/2n1p3/8/1pPNP3/2P5/3BBPPP/3RR1K1 b - - 3 20",
"1r2k2r/3bbppp/2n1p3/8/2PNP3/2B5/4BPPP/3RR1K1 b - - 0 21",
"1r2k2r/3bb1pp/2n1pp2/1N6/2P1P3/2B5/4BPPP/3RR1K1 b - - 1 22",
"1r2k2r/3b2pp/2n1pp2/1N6/1BP1P3/8/4BPPP/3RR1K1 b - - 0 23",
"1r2k2r/3b2pp/4pp2/1N6/1nP1P3/8/3RBPPP/4R1K1 b - - 1 24",
"1r5r/3bk1pp/4pp2/1N6/1nP1PP2/8/3RB1PP/4R1K1 b - - 0 25",
"1r5r/3bk1pp/2n1pp2/1N6/2P1PP2/8/3RBKPP/4R3 b - - 2 26",
"1r5r/3bk1pp/2n2p2/1N2p3/2P1PP2/6P1/3RBK1P/4R3 b - - 0 27",
"1r1r4/3bk1pp/2n2p2/1N2p3/2P1PP2/6P1/3RBK1P/R7 b - - 2 28",
"1r1r4/N3k1pp/2n1bp2/4p3/2P1PP2/6P1/3RBK1P/R7 b - - 4 29",
"1r1r4/3bk1pp/2N2p2/4p3/2P1PP2/6P1/3RBK1P/R7 b - - 0 30",
"1r1R4/4k1pp/2b2p2/4p3/2P1PP2/6P1/4BK1P/R7 b - - 0 31",
"3r4/4k1pp/2b2p2/4P3/2P1P3/6P1/4BK1P/R7 b - - 0 32",
"3r4/R3k1pp/2b5/4p3/2P1P3/6P1/4BK1P/8 b - - 1 33",
"8/3rk1pp/2b5/R3p3/2P1P3/6P1/4BK1P/8 b - - 3 34",
"8/3r2pp/2bk4/R1P1p3/4P3/6P1/4BK1P/8 b - - 0 35",
"8/2kr2pp/2b5/R1P1p3/4P3/4K1P1/4B2P/8 b - - 2 36",
"1k6/3r2pp/2b5/RBP1p3/4P3/4K1P1/7P/8 b - - 4 37",
"8/1k1r2pp/2b5/R1P1p3/4P3/3BK1P1/7P/8 b - - 6 38",
"1k6/3r2pp/2b5/2P1p3/4P3/3BK1P1/7P/R7 b - - 8 39",
"1k6/r5pp/2b5/2P1p3/4P3/3BK1P1/7P/5R2 b - - 10 40",
"1k3R2/6pp/2b5/2P1p3/4P3/r2BK1P1/7P/8 b - - 12 41",
"5R2/2k3pp/2b5/2P1p3/4P3/r2B2P1/3K3P/8 b - - 14 42",
"5R2/2k3pp/2b5/2P1p3/4P3/3BK1P1/r6P/8 b - - 16 43",
"5R2/2k3pp/2b5/2P1p3/4P3/r2B2P1/4K2P/8 b - - 18 44",
"5R2/2k3pp/2b5/2P1p3/4P3/3B1KP1/r6P/8 b - - 20 45",
"8/2k2Rpp/2b5/2P1p3/4P3/r2B1KP1/7P/8 b - - 22 46",
"3k4/5Rpp/2b5/2P1p3/4P3/r2B2P1/4K2P/8 b - - 24 47",
"3k4/5Rpp/2b5/2P1p3/4P3/3B1KP1/r6P/8 b - - 26 48",
"3k4/5Rpp/2b5/2P1p3/4P3/r2B2P1/4K2P/8 b - - 28 49",
"3k4/5Rpp/2b5/2P1p3/4P3/3BK1P1/r6P/8 b - - 30 50",
"3k4/5Rpp/2b5/2P1p3/4P3/r2B2P1/3K3P/8 b - - 32 51",
"3k4/5Rpp/2b5/2P1p3/4P3/2KB2P1/r6P/8 b - - 34 52",
"3k4/5Rpp/2b5/2P1p3/4P3/r2B2P1/2K4P/8 b - - 36 53",
"3k4/5Rpp/2b5/2P1p3/4P3/1K1B2P1/r6P/8 b - - 38 54",
"3k4/6Rp/2b5/2P1p3/4P3/1K1B2P1/7r/8 b - - 0 55",
"3k4/8/2b3Rp/2P1p3/4P3/1K1B2P1/7r/8 b - - 1 56",
"8/2k3R1/2b4p/2P1p3/4P3/1K1B2P1/7r/8 b - - 3 57",
"3k4/8/2b3Rp/2P1p3/4P3/1K1B2P1/7r/8 b - - 5 58",
"8/2k5/2b3Rp/2P1p3/1K2P3/3B2P1/7r/8 b - - 7 59",
"8/2k5/2b3Rp/2P1p3/4P3/2KB2P1/3r4/8 b - - 9 60",
"8/2k5/2b3Rp/2P1p3/1K2P3/3B2P1/6r1/8 b - - 11 61",
"8/2k5/2b3Rp/2P1p3/4P3/2KB2P1/3r4/8 b - - 13 62",
"8/2k5/2b3Rp/2P1p3/2K1P3/3B2P1/6r1/8 b - - 15 63",
"4b3/2k3R1/7p/2P1p3/2K1P3/3B2P1/6r1/8 b - - 17 64",
},
{
"r1bqkbnr/npp1pppp/p7/3P4/4pB2/2N5/PPP2PPP/R2QKBNR w KQkq - 1 6",
"r1bqkb1r/npp1pppp/p4n2/3P4/4pB2/2N5/PPP1QPPP/R3KBNR w KQkq - 3 7",
"r2qkb1r/npp1pppp/p4n2/3P1b2/4pB2/2N5/PPP1QPPP/2KR1BNR w kq - 5 8",
"r2qkb1r/1pp1pppp/p4n2/1n1P1b2/4pB2/2N4P/PPP1QPP1/2KR1BNR w kq - 1 9",
"r2qkb1r/1pp1pppp/5n2/1p1P1b2/4pB2/7P/PPP1QPP1/2KR1BNR w kq - 0 10",
"r2qkb1r/1ppbpppp/5n2/1Q1P4/4pB2/7P/PPP2PP1/2KR1BNR w kq - 1 11",
"3qkb1r/1Qpbpppp/5n2/3P4/4pB2/7P/rPP2PP1/2KR1BNR w k - 0 12",
"q3kb1r/1Qpbpppp/5n2/3P4/4pB2/7P/rPP2PP1/1K1R1BNR w k - 2 13",
"r3kb1r/2pbpppp/5n2/3P4/4pB2/7P/1PP2PP1/1K1R1BNR w k - 0 14",
"r3kb1r/2Bb1ppp/4pn2/3P4/4p3/7P/1PP2PP1/1K1R1BNR w k - 0 15",
"r3kb1r/2Bb2pp/4pn2/8/4p3/7P/1PP2PP1/1K1R1BNR w k - 0 16",
"r3k2r/2Bb2pp/4pn2/2b5/4p3/7P/1PP1NPP1/1K1R1B1R w k - 2 17",
"r6r/2Bbk1pp/4pn2/2b5/3Np3/7P/1PP2PP1/1K1R1B1R w - - 4 18",
"r6r/b2bk1pp/4pn2/4B3/3Np3/7P/1PP2PP1/1K1R1B1R w - - 6 19",
"r1r5/b2bk1pp/4pn2/4B3/2BNp3/7P/1PP2PP1/1K1R3R w - - 8 20",
"r7/b2bk1pp/4pn2/2r1B3/2BNp3/1P5P/2P2PP1/1K1R3R w - - 1 21",
"rb6/3bk1pp/4pn2/2r1B3/2BNpP2/1P5P/2P3P1/1K1R3R w - - 1 22",
"1r6/3bk1pp/4pn2/2r5/2BNpP2/1P5P/2P3P1/1K1R3R w - - 0 23",
"1r6/3bk1p1/4pn1p/2r5/2BNpP2/1P5P/2P3P1/2KR3R w - - 0 24",
"8/3bk1p1/1r2pn1p/2r5/2BNpP1P/1P6/2P3P1/2KR3R w - - 1 25",
"8/3bk3/1r2pnpp/2r5/2BNpP1P/1P6/2P3P1/2K1R2R w - - 0 26",
"2b5/4k3/1r2pnpp/2r5/2BNpP1P/1P4P1/2P5/2K1R2R w - - 1 27",
"8/1b2k3/1r2pnpp/2r5/2BNpP1P/1P4P1/2P5/2K1R1R1 w - - 3 28",
"8/1b1nk3/1r2p1pp/2r5/2BNpPPP/1P6/2P5/2K1R1R1 w - - 1 29",
"8/1b2k3/1r2p1pp/2r1nP2/2BNp1PP/1P6/2P5/2K1R1R1 w - - 1 30",
"8/1b2k3/1r2p1p1/2r1nPp1/2BNp2P/1P6/2P5/2K1R1R1 w - - 0 31",
"8/1b2k3/1r2p1n1/2r3p1/2BNp2P/1P6/2P5/2K1R1R1 w - - 0 32",
"8/1b2k3/1r2p1n1/6r1/2BNp2P/1P6/2P5/2K1R3 w - - 0 33",
"8/1b2k3/1r2p3/4n1P1/2BNp3/1P6/2P5/2K1R3 w - - 1 34",
"8/1b2k3/1r2p3/4n1P1/2BN4/1P2p3/2P5/2K4R w - - 0 35",
"8/1b2k3/1r2p2R/6P1/2nN4/1P2p3/2P5/2K5 w - - 0 36",
"8/1b2k3/3rp2R/6P1/2PN4/4p3/2P5/2K5 w - - 1 37",
"8/4k3/3rp2R/6P1/2PN4/2P1p3/6b1/2K5 w - - 1 38",
"8/4k3/r3p2R/2P3P1/3N4/2P1p3/6b1/2K5 w - - 1 39",
"8/3k4/r3p2R/2P2NP1/8/2P1p3/6b1/2K5 w - - 3 40",
"8/3k4/4p2R/2P3P1/8/2P1N3/6b1/r1K5 w - - 1 41",
"8/3k4/4p2R/2P3P1/8/2P1N3/3K2b1/6r1 w - - 3 42",
"8/3k4/4p2R/2P3P1/8/2PKNb2/8/6r1 w - - 5 43",
"8/4k3/4p1R1/2P3P1/8/2PKNb2/8/6r1 w - - 7 44",
"8/4k3/4p1R1/2P3P1/3K4/2P1N3/8/6rb w - - 9 45",
"8/3k4/4p1R1/2P1K1P1/8/2P1N3/8/6rb w - - 11 46",
"8/3k4/4p1R1/2P3P1/5K2/2P1N3/8/4r2b w - - 13 47",
"8/3k4/2b1p2R/2P3P1/5K2/2P1N3/8/4r3 w - - 15 48",
"8/3k4/2b1p3/2P3P1/5K2/2P1N2R/8/6r1 w - - 17 49",
"2k5/7R/2b1p3/2P3P1/5K2/2P1N3/8/6r1 w - - 19 50",
"2k5/7R/4p3/2P3P1/b1P2K2/4N3/8/6r1 w - - 1 51",
"2k5/3bR3/4p3/2P3P1/2P2K2/4N3/8/6r1 w - - 3 52",
"3k4/3b2R1/4p3/2P3P1/2P2K2/4N3/8/6r1 w - - 5 53",
"3kb3/6R1/4p1P1/2P5/2P2K2/4N3/8/6r1 w - - 1 54",
"3kb3/6R1/4p1P1/2P5/2P2KN1/8/8/2r5 w - - 3 55",
"3kb3/6R1/4p1P1/2P1N3/2P2K2/8/8/5r2 w - - 5 56",
"3kb3/6R1/4p1P1/2P1N3/2P5/4K3/8/4r3 w - - 7 57",
},
{
"rnbq1rk1/ppp1npb1/4p1p1/3P3p/3PP3/2N2N2/PP2BPPP/R1BQ1RK1 b - - 0 8",
"rnbq1rk1/ppp1npb1/6p1/3pP2p/3P4/2N2N2/PP2BPPP/R1BQ1RK1 b - - 0 9",
"rn1q1rk1/ppp1npb1/6p1/3pP2p/3P2b1/2N2N2/PP2BPPP/R1BQR1K1 b - - 2 10",
"r2q1rk1/ppp1npb1/2n3p1/3pP2p/3P2bN/2N5/PP2BPPP/R1BQR1K1 b - - 4 11",
"r4rk1/pppqnpb1/2n3p1/3pP2p/3P2bN/2N4P/PP2BPP1/R1BQR1K1 b - - 0 12",
"r4rk1/pppqnpb1/2n3p1/3pP2p/3P3N/7P/PP2NPP1/R1BQR1K1 b - - 0 13",
"r4rk1/pppq1pb1/2n3p1/3pPN1p/3P4/7P/PP2NPP1/R1BQR1K1 b - - 0 14",
"r4rk1/ppp2pb1/2n3p1/3pPq1p/3P1N2/7P/PP3PP1/R1BQR1K1 b - - 1 15",
"r4rk1/pppq1pb1/2n3p1/3pP2p/P2P1N2/7P/1P3PP1/R1BQR1K1 b - - 0 16",
"r2n1rk1/pppq1pb1/6p1/3pP2p/P2P1N2/R6P/1P3PP1/2BQR1K1 b - - 2 17",
"r4rk1/pppq1pb1/4N1p1/3pP2p/P2P4/R6P/1P3PP1/2BQR1K1 b - - 0 18",
"r4rk1/ppp2pb1/4q1p1/3pP1Bp/P2P4/R6P/1P3PP1/3QR1K1 b - - 1 19",
"r3r1k1/ppp2pb1/4q1p1/3pP1Bp/P2P1P2/R6P/1P4P1/3QR1K1 b - - 0 20",
"r3r1k1/ppp3b1/4qpp1/3pP2p/P2P1P1B/R6P/1P4P1/3QR1K1 b - - 1 21",
"r3r1k1/ppp3b1/4q1p1/3pP2p/P4P1B/R6P/1P4P1/3QR1K1 b - - 0 22",
"r4rk1/ppp3b1/4q1p1/3pP1Bp/P4P2/R6P/1P4P1/3QR1K1 b - - 2 23",
"r4rk1/pp4b1/4q1p1/2ppP1Bp/P4P2/3R3P/1P4P1/3QR1K1 b - - 1 24",
"r4rk1/pp4b1/4q1p1/2p1P1Bp/P2p1PP1/3R3P/1P6/3QR1K1 b - - 0 25",
"r4rk1/pp4b1/4q1p1/2p1P1B1/P2p1PP1/3R4/1P6/3QR1K1 b - - 0 26",
"r5k1/pp3rb1/4q1p1/2p1P1B1/P2p1PP1/6R1/1P6/3QR1K1 b - - 2 27",
"5rk1/pp3rb1/4q1p1/2p1P1B1/P2pRPP1/6R1/1P6/3Q2K1 b - - 4 28",
"5rk1/1p3rb1/p3q1p1/P1p1P1B1/3pRPP1/6R1/1P6/3Q2K1 b - - 0 29",
"4r1k1/1p3rb1/p3q1p1/P1p1P1B1/3pRPP1/1P4R1/8/3Q2K1 b - - 0 30",
"4r1k1/5rb1/pP2q1p1/2p1P1B1/3pRPP1/1P4R1/8/3Q2K1 b - - 0 31",
"4r1k1/5rb1/pq4p1/2p1P1B1/3pRPP1/1P4R1/4Q3/6K1 b - - 1 32",
"4r1k1/1r4b1/pq4p1/2p1P1B1/3pRPP1/1P4R1/2Q5/6K1 b - - 3 33",
"4r1k1/1r4b1/1q4p1/p1p1P1B1/3p1PP1/1P4R1/2Q5/4R1K1 b - - 1 34",
"4r1k1/3r2b1/1q4p1/p1p1P1B1/2Qp1PP1/1P4R1/8/4R1K1 b - - 3 35",
"4r1k1/3r2b1/4q1p1/p1p1P1B1/2Qp1PP1/1P4R1/5K2/4R3 b - - 5 36",
"4r1k1/3r2b1/6p1/p1p1P1B1/2Pp1PP1/6R1/5K2/4R3 b - - 0 37",
"4r1k1/3r2b1/6p1/p1p1P1B1/2P2PP1/3p2R1/5K2/3R4 b - - 1 38",
"5rk1/3r2b1/6p1/p1p1P1B1/2P2PP1/3p2R1/8/3RK3 b - - 3 39",
"5rk1/6b1/6p1/p1p1P1B1/2Pr1PP1/3R4/8/3RK3 b - - 0 40",
"5rk1/3R2b1/6p1/p1p1P1B1/2r2PP1/8/8/3RK3 b - - 1 41",
"5rk1/3R2b1/6p1/p1p1P1B1/4rPP1/8/3K4/3R4 b - - 3 42",
"1r4k1/3R2b1/6p1/p1p1P1B1/4rPP1/2K5/8/3R4 b - - 5 43",
"1r4k1/3R2b1/6p1/p1p1P1B1/2K2PP1/4r3/8/3R4 b - - 7 44",
"1r3bk1/8/3R2p1/p1p1P1B1/2K2PP1/4r3/8/3R4 b - - 9 45",
"1r3bk1/8/6R1/2p1P1B1/p1K2PP1/4r3/8/3R4 b - - 0 46",
"1r3b2/5k2/R7/2p1P1B1/p1K2PP1/4r3/8/3R4 b - - 2 47",
"5b2/1r3k2/R7/2p1P1B1/p1K2PP1/4r3/8/7R b - - 4 48",
"5b2/5k2/R7/2pKP1B1/pr3PP1/4r3/8/7R b - - 6 49",
"5b2/5k2/R1K5/2p1P1B1/p2r1PP1/4r3/8/7R b - - 8 50",
"8/R4kb1/2K5/2p1P1B1/p2r1PP1/4r3/8/7R b - - 10 51",
"8/R5b1/2K3k1/2p1PPB1/p2r2P1/4r3/8/7R b - - 0 52",
"8/6R1/2K5/2p1PPk1/p2r2P1/4r3/8/7R b - - 0 53",
"8/6R1/2K5/2p1PP2/p2r1kP1/4r3/8/5R2 b - - 2 54",
"8/6R1/2K2P2/2p1P3/p2r2P1/4r1k1/8/5R2 b - - 0 55",
"8/5PR1/2K5/2p1P3/p2r2P1/4r3/6k1/5R2 b - - 0 56",
},
{
"rn1qkb1r/p1pbpppp/5n2/8/2pP4/2N5/1PQ1PPPP/R1B1KBNR w KQkq - 0 7",
"r2qkb1r/p1pbpppp/2n2n2/8/2pP4/2N2N2/1PQ1PPPP/R1B1KB1R w KQkq - 2 8",
"r2qkb1r/p1pbpppp/5n2/8/1npPP3/2N2N2/1PQ2PPP/R1B1KB1R w KQkq - 1 9",
"r2qkb1r/p1pb1ppp/4pn2/8/1npPP3/2N2N2/1P3PPP/R1BQKB1R w KQkq - 0 10",
"r2qk2r/p1pbbppp/4pn2/8/1nBPP3/2N2N2/1P3PPP/R1BQK2R w KQkq - 1 11",
"r2q1rk1/p1pbbppp/4pn2/8/1nBPP3/2N2N2/1P3PPP/R1BQ1RK1 w - - 3 12",
"r2q1rk1/2pbbppp/p3pn2/8/1nBPPB2/2N2N2/1P3PPP/R2Q1RK1 w - - 0 13",
"r2q1rk1/2p1bppp/p3pn2/1b6/1nBPPB2/2N2N2/1P3PPP/R2QR1K1 w - - 2 14",
"r2q1rk1/4bppp/p1p1pn2/1b6/1nBPPB2/1PN2N2/5PPP/R2QR1K1 w - - 0 15",
"r4rk1/3qbppp/p1p1pn2/1b6/1nBPPB2/1PN2N2/3Q1PPP/R3R1K1 w - - 2 16",
"r4rk1/1q2bppp/p1p1pn2/1b6/1nBPPB2/1PN2N1P/3Q1PP1/R3R1K1 w - - 1 17",
"r3r1k1/1q2bppp/p1p1pn2/1b6/1nBPPB2/1PN2N1P/4QPP1/R3R1K1 w - - 3 18",
"r3r1k1/1q1nbppp/p1p1p3/1b6/1nBPPB2/1PN2N1P/4QPP1/3RR1K1 w - - 5 19",
"r3rbk1/1q1n1ppp/p1p1p3/1b6/1nBPPB2/1PN2N1P/3RQPP1/4R1K1 w - - 7 20",
"r3rbk1/1q3ppp/pnp1p3/1b6/1nBPPB2/1PN2N1P/3RQPP1/4R2K w - - 9 21",
"2r1rbk1/1q3ppp/pnp1p3/1b6/1nBPPB2/1PN2N1P/3RQPP1/1R5K w - - 11 22",
"2r1rbk1/1q4pp/pnp1pp2/1b6/1nBPPB2/1PN2N1P/4QPP1/1R1R3K w - - 0 23",
"2r1rbk1/5qpp/pnp1pp2/1b6/1nBPP3/1PN1BN1P/4QPP1/1R1R3K w - - 2 24",
"2r1rbk1/5qp1/pnp1pp1p/1b6/1nBPP3/1PN1BN1P/4QPP1/1R1R2K1 w - - 0 25",
"2r1rbk1/5qp1/pnp1pp1p/1b6/2BPP3/1P2BN1P/n3QPP1/1R1R2K1 w - - 0 26",
"r3rbk1/5qp1/pnp1pp1p/1b6/2BPP3/1P2BN1P/Q4PP1/1R1R2K1 w - - 1 27",
"rr3bk1/5qp1/pnp1pp1p/1b6/2BPP3/1P2BN1P/Q4PP1/R2R2K1 w - - 3 28",
"rr2qbk1/6p1/pnp1pp1p/1b6/2BPP3/1P2BN1P/4QPP1/R2R2K1 w - - 5 29",
"rr2qbk1/6p1/1np1pp1p/pb6/2BPP3/1P1QBN1P/5PP1/R2R2K1 w - - 0 30",
"rr2qbk1/6p1/1n2pp1p/pp6/3PP3/1P1QBN1P/5PP1/R2R2K1 w - - 0 31",
"rr2qbk1/6p1/1n2pp1p/1p1P4/p3P3/1P1QBN1P/5PP1/R2R2K1 w - - 0 32",
"rr2qbk1/3n2p1/3Ppp1p/1p6/p3P3/1P1QBN1P/5PP1/R2R2K1 w - - 1 33",
"rr3bk1/3n2p1/3Ppp1p/1p5q/pP2P3/3QBN1P/5PP1/R2R2K1 w - - 1 34",
"rr3bk1/3n2p1/3Ppp1p/1p5q/1P2P3/p2QBN1P/5PP1/2RR2K1 w - - 0 35",
"1r3bk1/3n2p1/r2Ppp1p/1p5q/1P2P3/pQ2BN1P/5PP1/2RR2K1 w - - 2 36",
"1r2qbk1/2Rn2p1/r2Ppp1p/1p6/1P2P3/pQ2BN1P/5PP1/3R2K1 w - - 4 37",
"1r2qbk1/2Rn2p1/r2Ppp1p/1pB5/1P2P3/1Q3N1P/p4PP1/3R2K1 w - - 0 38",
"1r2q1k1/2Rn2p1/r2bpp1p/1pB5/1P2P3/1Q3N1P/p4PP1/R5K1 w - - 0 39",
"1r2q1k1/2Rn2p1/3rpp1p/1p6/1P2P3/1Q3N1P/p4PP1/R5K1 w - - 0 40",
"2r1q1k1/2Rn2p1/3rpp1p/1p6/1P2P3/5N1P/Q4PP1/R5K1 w - - 1 41",
"1r2q1k1/1R1n2p1/3rpp1p/1p6/1P2P3/5N1P/Q4PP1/R5K1 w - - 3 42",
"2r1q1k1/2Rn2p1/3rpp1p/1p6/1P2P3/5N1P/Q4PP1/R5K1 w - - 5 43",
"1r2q1k1/1R1n2p1/3rpp1p/1p6/1P2P3/5N1P/Q4PP1/R5K1 w - - 7 44",
"1rq3k1/R2n2p1/3rpp1p/1p6/1P2P3/5N1P/Q4PP1/R5K1 w - - 9 45",
"2q3k1/Rr1n2p1/3rpp1p/1p6/1P2P3/5N1P/4QPP1/R5K1 w - - 11 46",
"Rrq3k1/3n2p1/3rpp1p/1p6/1P2P3/5N1P/4QPP1/R5K1 w - - 13 47",
},
{
"rn1qkb1r/1pp2ppp/p4p2/3p1b2/5P2/1P2PN2/P1PP2PP/RN1QKB1R b KQkq - 1 6",
"r2qkb1r/1pp2ppp/p1n2p2/3p1b2/3P1P2/1P2PN2/P1P3PP/RN1QKB1R b KQkq - 0 7",
"r2qkb1r/1pp2ppp/p4p2/3p1b2/1n1P1P2/1P1BPN2/P1P3PP/RN1QK2R b KQkq - 2 8",
"r2qkb1r/1pp2ppp/p4p2/3p1b2/3P1P2/1P1PPN2/P5PP/RN1QK2R b KQkq - 0 9",
"r2qk2r/1pp2ppp/p2b1p2/3p1b2/3P1P2/1PNPPN2/P5PP/R2QK2R b KQkq - 2 10",
"r2qk2r/1p3ppp/p1pb1p2/3p1b2/3P1P2/1PNPPN2/P5PP/R2Q1RK1 b kq - 1 11",
"r2q1rk1/1p3ppp/p1pb1p2/3p1b2/3P1P2/1PNPPN2/P2Q2PP/R4RK1 b - - 3 12",
"r2qr1k1/1p3ppp/p1pb1p2/3p1b2/3P1P2/1P1PPN2/P2QN1PP/R4RK1 b - - 5 13",
"r3r1k1/1p3ppp/pqpb1p2/3p1b2/3P1P2/1P1PPNN1/P2Q2PP/R4RK1 b - - 7 14",
"r3r1k1/1p3ppp/pqp2p2/3p1b2/1b1P1P2/1P1PPNN1/P1Q3PP/R4RK1 b - - 9 15",
"r3r1k1/1p1b1ppp/pqp2p2/3p4/1b1P1P2/1P1PPNN1/P4QPP/R4RK1 b - - 11 16",
"2r1r1k1/1p1b1ppp/pqp2p2/3p4/1b1PPP2/1P1P1NN1/P4QPP/R4RK1 b - - 0 17",
"2r1r1k1/1p1b1ppp/pq3p2/2pp4/1b1PPP2/PP1P1NN1/5QPP/R4RK1 b - - 0 18",
"2r1r1k1/1p1b1ppp/pq3p2/2Pp4/4PP2/PPbP1NN1/5QPP/R4RK1 b - - 0 19",
"2r1r1k1/1p1b1ppp/p4p2/2Pp4/4PP2/PqbP1NN1/5QPP/RR4K1 b - - 1 20",
"2r1r1k1/1p1b1ppp/p4p2/2Pp4/q3PP2/P1bP1NN1/R4QPP/1R4K1 b - - 3 21",
"2r1r1k1/1p3ppp/p4p2/1bPP4/q4P2/P1bP1NN1/R4QPP/1R4K1 b - - 0 22",
"2r1r1k1/1p3ppp/p4p2/2PP4/q4P2/P1bb1NN1/R4QPP/2R3K1 b - - 1 23",
"2r1r1k1/1p3ppp/p2P1p2/2P5/2q2P2/P1bb1NN1/R4QPP/2R3K1 b - - 0 24",
"2rr2k1/1p3ppp/p2P1p2/2P5/2q2P2/P1bb1NN1/R4QPP/2R4K b - - 2 25",
"2rr2k1/1p3ppp/p2P1p2/2Q5/5P2/P1bb1NN1/R5PP/2R4K b - - 0 26",
"3r2k1/1p3ppp/p2P1p2/2r5/5P2/P1bb1N2/R3N1PP/2R4K b - - 1 27",
"3r2k1/1p3ppp/p2P1p2/2r5/5P2/P1b2N2/4R1PP/2R4K b - - 0 28",
"3r2k1/1p3ppp/p2P1p2/2r5/1b3P2/P4N2/4R1PP/3R3K b - - 2 29",
"3r2k1/1p2Rppp/p2P1p2/b1r5/5P2/P4N2/6PP/3R3K b - - 4 30",
"3r2k1/1R3ppp/p1rP1p2/b7/5P2/P4N2/6PP/3R3K b - - 0 31",
"3r2k1/1R3ppp/p2R1p2/b7/5P2/P4N2/6PP/7K b - - 0 32",
"6k1/1R3ppp/p2r1p2/b7/5P2/P4NP1/7P/7K b - - 0 33",
"6k1/1R3p1p/p2r1pp1/b7/5P1P/P4NP1/8/7K b - - 0 34",
"6k1/3R1p1p/pr3pp1/b7/5P1P/P4NP1/8/7K b - - 2 35",
"6k1/5p2/pr3pp1/b2R3p/5P1P/P4NP1/8/7K b - - 1 36",
"6k1/5p2/pr3pp1/7p/5P1P/P1bR1NP1/8/7K b - - 3 37",
"6k1/5p2/p1r2pp1/7p/5P1P/P1bR1NP1/6K1/8 b - - 5 38",
"6k1/5p2/p1r2pp1/b2R3p/5P1P/P4NP1/6K1/8 b - - 7 39",
"6k1/5p2/p4pp1/b2R3p/5P1P/P4NPK/2r5/8 b - - 9 40",
"6k1/2b2p2/p4pp1/7p/5P1P/P2R1NPK/2r5/8 b - - 11 41",
"6k1/2b2p2/5pp1/p6p/3N1P1P/P2R2PK/2r5/8 b - - 1 42",
"6k1/2b2p2/5pp1/p6p/3N1P1P/P1R3PK/r7/8 b - - 3 43",
"6k1/5p2/1b3pp1/p6p/5P1P/P1R3PK/r1N5/8 b - - 5 44",
"8/5pk1/1bR2pp1/p6p/5P1P/P5PK/r1N5/8 b - - 7 45",
"3b4/5pk1/2R2pp1/p4P1p/7P/P5PK/r1N5/8 b - - 0 46",
"8/4bpk1/2R2pp1/p4P1p/6PP/P6K/r1N5/8 b - - 0 47",
"8/5pk1/2R2pP1/p6p/6PP/b6K/r1N5/8 b - - 0 48",
"8/6k1/2R2pp1/p6P/7P/b6K/r1N5/8 b - - 0 49",
"8/6k1/2R2p2/p6p/7P/b5K1/r1N5/8 b - - 1 50",
"8/8/2R2pk1/p6p/7P/b4K2/r1N5/8 b - - 3 51",
"8/8/2R2pk1/p6p/7P/4NK2/rb6/8 b - - 5 52",
"2R5/8/5pk1/7p/p6P/4NK2/rb6/8 b - - 1 53",
"6R1/8/5pk1/7p/p6P/4NK2/1b6/r7 b - - 3 54",
"R7/5k2/5p2/7p/p6P/4NK2/1b6/r7 b - - 5 55",
"R7/5k2/5p2/7p/7P/p3N3/1b2K3/r7 b - - 1 56",
"8/R4k2/5p2/7p/7P/p3N3/1b2K3/7r b - - 3 57",
"8/8/5pk1/7p/R6P/p3N3/1b2K3/7r b - - 5 58",
"8/8/5pk1/7p/R6P/p7/4K3/2bN3r b - - 7 59",
"8/8/5pk1/7p/R6P/p7/4KN1r/2b5 b - - 9 60",
"8/8/5pk1/7p/R6P/p3K3/1b3N1r/8 b - - 11 61",
"8/8/R4pk1/7p/7P/p1b1K3/5N1r/8 b - - 13 62",
"8/8/5pk1/7p/7P/2b1K3/R4N1r/8 b - - 0 63",
"8/8/5pk1/7p/3K3P/8/R4N1r/4b3 b - - 2 64",
}
};
// clang-format on
namespace Stockfish { } // namespace
/// setup_bench() builds a list of UCI commands to be run by bench. There namespace Stockfish::Benchmark {
/// are five parameters: TT size in MB, number of search threads that
/// should be used, the limit value spent for each position, a file name
/// where to look for positions in FEN format, the type of the limit:
/// depth, perft, nodes and movetime (in millisecs), and evaluation type
/// mixed (default), classical, NNUE.
///
/// bench -> search default positions up to depth 13
/// bench 64 1 15 -> search default positions up to depth 15 (TT = 64MB)
/// bench 64 4 5000 current movetime -> search current position with 4 threads for 5 sec
/// bench 64 1 100000 default nodes -> search default positions for 100K nodes each
/// bench 16 1 5 default perft -> run a perft 5 on default positions
vector<string> setup_bench(const Position& current, istream& is) { // Builds a list of UCI commands to be run by bench. There
// are five parameters: TT size in MB, number of search threads that
// should be used, the limit value spent for each position, a file name
// where to look for positions in FEN format, and the type of the limit:
// depth, perft, nodes and movetime (in milliseconds). Examples:
//
// bench : search default positions up to depth 13
// bench 64 1 15 : search default positions up to depth 15 (TT = 64MB)
// bench 64 1 100000 default nodes : search default positions for 100K nodes each
// bench 64 4 5000 current movetime : search current position with 4 threads for 5 sec
// bench 16 1 5 blah perft : run a perft 5 on positions in file "blah"
std::vector<std::string> setup_bench(const std::string& currentFen, std::istream& is) {
vector<string> fens, list; std::vector<std::string> fens, list;
string go, token; std::string go, token;
// Assign default values to missing arguments // Assign default values to missing arguments
string ttSize = (is >> token) ? token : "16"; std::string ttSize = (is >> token) ? token : "16";
string threads = (is >> token) ? token : "1"; std::string threads = (is >> token) ? token : "1";
string limit = (is >> token) ? token : "13"; std::string limit = (is >> token) ? token : "13";
string fenFile = (is >> token) ? token : "default"; std::string fenFile = (is >> token) ? token : "default";
string limitType = (is >> token) ? token : "depth"; std::string limitType = (is >> token) ? token : "depth";
string evalType = (is >> token) ? token : "mixed";
go = limitType == "eval" ? "eval" : "go " + limitType + " " + limit; go = limitType == "eval" ? "eval" : "go " + limitType + " " + limit;
if (fenFile == "default") if (fenFile == "default")
fens = Defaults; fens = Defaults;
else if (fenFile == "current") else if (fenFile == "current")
fens.push_back(current.fen()); fens.push_back(currentFen);
else else
{ {
string fen; std::string fen;
ifstream file(fenFile); std::ifstream file(fenFile);
if (!file.is_open()) if (!file.is_open())
{ {
cerr << "Unable to open file " << fenFile << endl; std::cerr << "Unable to open file " << fenFile << std::endl;
exit(EXIT_FAILURE); exit(EXIT_FAILURE);
} }
while (getline(file, fen)) while (getline(file, fen))
if (!fen.empty()) if (!fen.empty())
fens.push_back(fen); fens.push_back(fen);
file.close(); file.close();
} }
list.emplace_back("setoption name Threads value " + threads); list.emplace_back("setoption name Threads value " + threads);
list.emplace_back("setoption name Hash value " + ttSize); list.emplace_back("setoption name Hash value " + ttSize);
list.emplace_back("ucinewgame"); list.emplace_back("ucinewgame");
size_t posCounter = 0; for (const std::string& fen : fens)
if (fen.find("setoption") != std::string::npos)
list.emplace_back(fen);
else
{
list.emplace_back("position fen " + fen);
list.emplace_back(go);
}
for (const string& fen : fens) return list;
if (fen.find("setoption") != string::npos)
list.emplace_back(fen);
else
{
if (evalType == "classical" || (evalType == "mixed" && posCounter % 2 == 0))
list.emplace_back("setoption name Use NNUE value false");
else if (evalType == "NNUE" || (evalType == "mixed" && posCounter % 2 != 0))
list.emplace_back("setoption name Use NNUE value true");
list.emplace_back("position fen " + fen);
list.emplace_back(go);
++posCounter;
}
list.emplace_back("setoption name Use NNUE value true");
return list;
} }
} // namespace Stockfish BenchmarkSetup setup_benchmark(std::istream& is) {
// TT_SIZE_PER_THREAD is chosen such that roughly half of the hash is used all positions
// for the current sequence have been searched.
static constexpr int TT_SIZE_PER_THREAD = 128;
static constexpr int DEFAULT_DURATION_S = 150;
BenchmarkSetup setup{};
// Assign default values to missing arguments
int desiredTimeS;
if (!(is >> setup.threads))
setup.threads = get_hardware_concurrency();
else
setup.originalInvocation += std::to_string(setup.threads);
if (!(is >> setup.ttSize))
setup.ttSize = TT_SIZE_PER_THREAD * setup.threads;
else
setup.originalInvocation += " " + std::to_string(setup.ttSize);
if (!(is >> desiredTimeS))
desiredTimeS = DEFAULT_DURATION_S;
else
setup.originalInvocation += " " + std::to_string(desiredTimeS);
setup.filledInvocation += std::to_string(setup.threads) + " " + std::to_string(setup.ttSize)
+ " " + std::to_string(desiredTimeS);
auto getCorrectedTime = [&](int ply) {
// time per move is fit roughly based on LTC games
// seconds = 50/{ply+15}
// ms = 50000/{ply+15}
// with this fit 10th move gets 2000ms
// adjust for desired 10th move time
return 50000.0 / (static_cast<double>(ply) + 15.0);
};
float totalTime = 0;
for (const auto& game : BenchmarkPositions)
{
setup.commands.emplace_back("ucinewgame");
int ply = 1;
for (int i = 0; i < static_cast<int>(game.size()); ++i)
{
const float correctedTime = getCorrectedTime(ply);
totalTime += correctedTime;
ply += 1;
}
}
float timeScaleFactor = static_cast<float>(desiredTimeS * 1000) / totalTime;
for (const auto& game : BenchmarkPositions)
{
setup.commands.emplace_back("ucinewgame");
int ply = 1;
for (const std::string& fen : game)
{
setup.commands.emplace_back("position fen " + fen);
const int correctedTime = static_cast<int>(getCorrectedTime(ply) * timeScaleFactor);
setup.commands.emplace_back("go movetime " + std::to_string(correctedTime));
ply += 1;
}
}
return setup;
}
} // namespace Stockfish
+14 -6
View File
@@ -1,6 +1,6 @@
/* /*
Stockfish, a UCI chess playing engine derived from Glaurung 2.1 Stockfish, a UCI chess playing engine derived from Glaurung 2.1
Copyright (C) 2004-2023 The Stockfish developers (see AUTHORS file) Copyright (C) 2004-2025 The Stockfish developers (see AUTHORS file)
Stockfish is free software: you can redistribute it and/or modify Stockfish is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by it under the terms of the GNU General Public License as published by
@@ -23,12 +23,20 @@
#include <string> #include <string>
#include <vector> #include <vector>
namespace Stockfish { namespace Stockfish::Benchmark {
class Position; std::vector<std::string> setup_bench(const std::string&, std::istream&);
std::vector<std::string> setup_bench(const Position&, std::istream&); struct BenchmarkSetup {
int ttSize;
int threads;
std::vector<std::string> commands;
std::string originalInvocation;
std::string filledInvocation;
};
} // namespace Stockfish BenchmarkSetup setup_benchmark(std::istream&);
#endif // #ifndef BENCHMARK_H_INCLUDED } // namespace Stockfish
#endif // #ifndef BENCHMARK_H_INCLUDED
-172
View File
@@ -1,172 +0,0 @@
/*
Stockfish, a UCI chess playing engine derived from Glaurung 2.1
Copyright (C) 2004-2023 The Stockfish developers (see AUTHORS file)
Stockfish is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
Stockfish is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <cassert>
#include <vector>
#include <bitset>
#include "bitboard.h"
#include "types.h"
namespace Stockfish {
namespace {
// There are 24 possible pawn squares: files A to D and ranks from 2 to 7.
// Positions with the pawn on files E to H will be mirrored before probing.
constexpr unsigned MAX_INDEX = 2*24*64*64; // stm * psq * wksq * bksq = 196608
std::bitset<MAX_INDEX> KPKBitbase;
// A KPK bitbase index is an integer in [0, IndexMax] range
//
// Information is mapped in a way that minimizes the number of iterations:
//
// bit 0- 5: white king square (from SQ_A1 to SQ_H8)
// bit 6-11: black king square (from SQ_A1 to SQ_H8)
// bit 12: side to move (WHITE or BLACK)
// bit 13-14: white pawn file (from FILE_A to FILE_D)
// bit 15-17: white pawn RANK_7 - rank (from RANK_7 - RANK_7 to RANK_7 - RANK_2)
unsigned index(Color stm, Square bksq, Square wksq, Square psq) {
return int(wksq) | (bksq << 6) | (stm << 12) | (file_of(psq) << 13) | ((RANK_7 - rank_of(psq)) << 15);
}
enum Result {
INVALID = 0,
UNKNOWN = 1,
DRAW = 2,
WIN = 4
};
Result& operator|=(Result& r, Result v) { return r = Result(r | v); }
struct KPKPosition {
KPKPosition() = default;
explicit KPKPosition(unsigned idx);
operator Result() const { return result; }
Result classify(const std::vector<KPKPosition>& db);
Color stm;
Square ksq[COLOR_NB], psq;
Result result;
};
} // namespace
bool Bitbases::probe(Square wksq, Square wpsq, Square bksq, Color stm) {
assert(file_of(wpsq) <= FILE_D);
return KPKBitbase[index(stm, bksq, wksq, wpsq)];
}
void Bitbases::init() {
std::vector<KPKPosition> db(MAX_INDEX);
unsigned idx, repeat = 1;
// Initialize db with known win / draw positions
for (idx = 0; idx < MAX_INDEX; ++idx)
db[idx] = KPKPosition(idx);
// Iterate through the positions until none of the unknown positions can be
// changed to either wins or draws (15 cycles needed).
while (repeat)
for (repeat = idx = 0; idx < MAX_INDEX; ++idx)
repeat |= (db[idx] == UNKNOWN && db[idx].classify(db) != UNKNOWN);
// Fill the bitbase with the decisive results
for (idx = 0; idx < MAX_INDEX; ++idx)
if (db[idx] == WIN)
KPKBitbase.set(idx);
}
namespace {
KPKPosition::KPKPosition(unsigned idx) {
ksq[WHITE] = Square((idx >> 0) & 0x3F);
ksq[BLACK] = Square((idx >> 6) & 0x3F);
stm = Color ((idx >> 12) & 0x01);
psq = make_square(File((idx >> 13) & 0x3), Rank(RANK_7 - ((idx >> 15) & 0x7)));
// Invalid if two pieces are on the same square or if a king can be captured
if ( distance(ksq[WHITE], ksq[BLACK]) <= 1
|| ksq[WHITE] == psq
|| ksq[BLACK] == psq
|| (stm == WHITE && (pawn_attacks_bb(WHITE, psq) & ksq[BLACK])))
result = INVALID;
// Win if the pawn can be promoted without getting captured
else if ( stm == WHITE
&& rank_of(psq) == RANK_7
&& ksq[WHITE] != psq + NORTH
&& ( distance(ksq[BLACK], psq + NORTH) > 1
|| (distance(ksq[WHITE], psq + NORTH) == 1)))
result = WIN;
// Draw if it is stalemate or the black king can capture the pawn
else if ( stm == BLACK
&& ( !(attacks_bb<KING>(ksq[BLACK]) & ~(attacks_bb<KING>(ksq[WHITE]) | pawn_attacks_bb(WHITE, psq)))
|| (attacks_bb<KING>(ksq[BLACK]) & ~attacks_bb<KING>(ksq[WHITE]) & psq)))
result = DRAW;
// Position will be classified later
else
result = UNKNOWN;
}
Result KPKPosition::classify(const std::vector<KPKPosition>& db) {
// White to move: If one move leads to a position classified as WIN, the result
// of the current position is WIN. If all moves lead to positions classified
// as DRAW, the current position is classified as DRAW, otherwise the current
// position is classified as UNKNOWN.
//
// Black to move: If one move leads to a position classified as DRAW, the result
// of the current position is DRAW. If all moves lead to positions classified
// as WIN, the position is classified as WIN, otherwise the current position is
// classified as UNKNOWN.
const Result Good = (stm == WHITE ? WIN : DRAW);
const Result Bad = (stm == WHITE ? DRAW : WIN);
Result r = INVALID;
Bitboard b = attacks_bb<KING>(ksq[stm]);
while (b)
r |= stm == WHITE ? db[index(BLACK, ksq[BLACK], pop_lsb(b), psq)]
: db[index(WHITE, pop_lsb(b), ksq[WHITE], psq)];
if (stm == WHITE)
{
if (rank_of(psq) < RANK_7) // Single push
r |= db[index(BLACK, ksq[BLACK], ksq[WHITE], psq + NORTH)];
if ( rank_of(psq) == RANK_2 // Double push
&& psq + NORTH != ksq[WHITE]
&& psq + NORTH != ksq[BLACK])
r |= db[index(BLACK, ksq[BLACK], ksq[WHITE], psq + NORTH + NORTH)];
}
return result = r & Good ? Good : r & UNKNOWN ? UNKNOWN : Bad;
}
} // namespace
} // namespace Stockfish
+97 -87
View File
@@ -1,6 +1,6 @@
/* /*
Stockfish, a UCI chess playing engine derived from Glaurung 2.1 Stockfish, a UCI chess playing engine derived from Glaurung 2.1
Copyright (C) 2004-2023 The Stockfish developers (see AUTHORS file) Copyright (C) 2004-2025 The Stockfish developers (see AUTHORS file)
Stockfish is free software: you can redistribute it and/or modify Stockfish is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by it under the terms of the GNU General Public License as published by
@@ -16,10 +16,12 @@
along with this program. If not, see <http://www.gnu.org/licenses/>. along with this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
#include "bitboard.h"
#include <algorithm> #include <algorithm>
#include <bitset> #include <bitset>
#include <initializer_list>
#include "bitboard.h"
#include "misc.h" #include "misc.h"
namespace Stockfish { namespace Stockfish {
@@ -32,145 +34,154 @@ Bitboard BetweenBB[SQUARE_NB][SQUARE_NB];
Bitboard PseudoAttacks[PIECE_TYPE_NB][SQUARE_NB]; Bitboard PseudoAttacks[PIECE_TYPE_NB][SQUARE_NB];
Bitboard PawnAttacks[COLOR_NB][SQUARE_NB]; Bitboard PawnAttacks[COLOR_NB][SQUARE_NB];
Magic RookMagics[SQUARE_NB]; alignas(64) Magic Magics[SQUARE_NB][2];
Magic BishopMagics[SQUARE_NB];
namespace { namespace {
Bitboard RookTable[0x19000]; // To store rook attacks Bitboard RookTable[0x19000]; // To store rook attacks
Bitboard BishopTable[0x1480]; // To store bishop attacks Bitboard BishopTable[0x1480]; // To store bishop attacks
void init_magics(PieceType pt, Bitboard table[], Magic magics[]); void init_magics(PieceType pt, Bitboard table[], Magic magics[][2]);
} // Returns the bitboard of target square for the given step
// from the given square. If the step is off the board, returns empty bitboard.
/// safe_destination() returns the bitboard of target square for the given step Bitboard safe_destination(Square s, int step) {
/// from the given square. If the step is off the board, returns empty bitboard.
inline Bitboard safe_destination(Square s, int step) {
Square to = Square(s + step); Square to = Square(s + step);
return is_ok(to) && distance(s, to) <= 2 ? square_bb(to) : Bitboard(0); return is_ok(to) && distance(s, to) <= 2 ? square_bb(to) : Bitboard(0);
} }
}
// Returns an ASCII representation of a bitboard suitable
/// Bitboards::pretty() returns an ASCII representation of a bitboard suitable // to be printed to standard output. Useful for debugging.
/// to be printed to standard output. Useful for debugging.
std::string Bitboards::pretty(Bitboard b) { std::string Bitboards::pretty(Bitboard b) {
std::string s = "+---+---+---+---+---+---+---+---+\n"; std::string s = "+---+---+---+---+---+---+---+---+\n";
for (Rank r = RANK_8; r >= RANK_1; --r) for (Rank r = RANK_8; r >= RANK_1; --r)
{ {
for (File f = FILE_A; f <= FILE_H; ++f) for (File f = FILE_A; f <= FILE_H; ++f)
s += b & make_square(f, r) ? "| X " : "| "; s += b & make_square(f, r) ? "| X " : "| ";
s += "| " + std::to_string(1 + r) + "\n+---+---+---+---+---+---+---+---+\n"; s += "| " + std::to_string(1 + r) + "\n+---+---+---+---+---+---+---+---+\n";
} }
s += " a b c d e f g h\n"; s += " a b c d e f g h\n";
return s; return s;
} }
/// Bitboards::init() initializes various bitboard tables. It is called at // Initializes various bitboard tables. It is called at
/// startup and relies on global objects to be already zero-initialized. // startup and relies on global objects to be already zero-initialized.
void Bitboards::init() { void Bitboards::init() {
for (unsigned i = 0; i < (1 << 16); ++i) for (unsigned i = 0; i < (1 << 16); ++i)
PopCnt16[i] = uint8_t(std::bitset<16>(i).count()); PopCnt16[i] = uint8_t(std::bitset<16>(i).count());
for (Square s1 = SQ_A1; s1 <= SQ_H8; ++s1) for (Square s1 = SQ_A1; s1 <= SQ_H8; ++s1)
for (Square s2 = SQ_A1; s2 <= SQ_H8; ++s2) for (Square s2 = SQ_A1; s2 <= SQ_H8; ++s2)
SquareDistance[s1][s2] = std::max(distance<File>(s1, s2), distance<Rank>(s1, s2)); SquareDistance[s1][s2] = std::max(distance<File>(s1, s2), distance<Rank>(s1, s2));
init_magics(ROOK, RookTable, RookMagics); init_magics(ROOK, RookTable, Magics);
init_magics(BISHOP, BishopTable, BishopMagics); init_magics(BISHOP, BishopTable, Magics);
for (Square s1 = SQ_A1; s1 <= SQ_H8; ++s1) for (Square s1 = SQ_A1; s1 <= SQ_H8; ++s1)
{ {
PawnAttacks[WHITE][s1] = pawn_attacks_bb<WHITE>(square_bb(s1)); PawnAttacks[WHITE][s1] = pawn_attacks_bb<WHITE>(square_bb(s1));
PawnAttacks[BLACK][s1] = pawn_attacks_bb<BLACK>(square_bb(s1)); PawnAttacks[BLACK][s1] = pawn_attacks_bb<BLACK>(square_bb(s1));
for (int step : {-9, -8, -7, -1, 1, 7, 8, 9} ) for (int step : {-9, -8, -7, -1, 1, 7, 8, 9})
PseudoAttacks[KING][s1] |= safe_destination(s1, step); PseudoAttacks[KING][s1] |= safe_destination(s1, step);
for (int step : {-17, -15, -10, -6, 6, 10, 15, 17} ) for (int step : {-17, -15, -10, -6, 6, 10, 15, 17})
PseudoAttacks[KNIGHT][s1] |= safe_destination(s1, step); PseudoAttacks[KNIGHT][s1] |= safe_destination(s1, step);
PseudoAttacks[QUEEN][s1] = PseudoAttacks[BISHOP][s1] = attacks_bb<BISHOP>(s1, 0); PseudoAttacks[QUEEN][s1] = PseudoAttacks[BISHOP][s1] = attacks_bb<BISHOP>(s1, 0);
PseudoAttacks[QUEEN][s1] |= PseudoAttacks[ ROOK][s1] = attacks_bb< ROOK>(s1, 0); PseudoAttacks[QUEEN][s1] |= PseudoAttacks[ROOK][s1] = attacks_bb<ROOK>(s1, 0);
for (PieceType pt : { BISHOP, ROOK }) for (PieceType pt : {BISHOP, ROOK})
for (Square s2 = SQ_A1; s2 <= SQ_H8; ++s2) for (Square s2 = SQ_A1; s2 <= SQ_H8; ++s2)
{ {
if (PseudoAttacks[pt][s1] & s2) if (PseudoAttacks[pt][s1] & s2)
{ {
LineBB[s1][s2] = (attacks_bb(pt, s1, 0) & attacks_bb(pt, s2, 0)) | s1 | s2; LineBB[s1][s2] = (attacks_bb(pt, s1, 0) & attacks_bb(pt, s2, 0)) | s1 | s2;
BetweenBB[s1][s2] = (attacks_bb(pt, s1, square_bb(s2)) & attacks_bb(pt, s2, square_bb(s1))); BetweenBB[s1][s2] =
} (attacks_bb(pt, s1, square_bb(s2)) & attacks_bb(pt, s2, square_bb(s1)));
BetweenBB[s1][s2] |= s2; }
} BetweenBB[s1][s2] |= s2;
} }
}
} }
namespace { namespace {
Bitboard sliding_attack(PieceType pt, Square sq, Bitboard occupied) { Bitboard sliding_attack(PieceType pt, Square sq, Bitboard occupied) {
Bitboard attacks = 0; Bitboard attacks = 0;
Direction RookDirections[4] = {NORTH, SOUTH, EAST, WEST}; Direction RookDirections[4] = {NORTH, SOUTH, EAST, WEST};
Direction BishopDirections[4] = {NORTH_EAST, SOUTH_EAST, SOUTH_WEST, NORTH_WEST}; Direction BishopDirections[4] = {NORTH_EAST, SOUTH_EAST, SOUTH_WEST, NORTH_WEST};
for (Direction d : (pt == ROOK ? RookDirections : BishopDirections)) for (Direction d : (pt == ROOK ? RookDirections : BishopDirections))
{ {
Square s = sq; Square s = sq;
while (safe_destination(s, d) && !(occupied & s)) while (safe_destination(s, d))
{
attacks |= (s += d); attacks |= (s += d);
if (occupied & s)
{
break;
}
}
} }
return attacks; return attacks;
} }
// init_magics() computes all rook and bishop attacks at startup. Magic // Computes all rook and bishop attacks at startup. Magic
// bitboards are used to look up attacks of sliding pieces. As a reference see // bitboards are used to look up attacks of sliding pieces. As a reference see
// www.chessprogramming.org/Magic_Bitboards. In particular, here we use the so // https://www.chessprogramming.org/Magic_Bitboards. In particular, here we use
// called "fancy" approach. // the so called "fancy" approach.
void init_magics(PieceType pt, Bitboard table[], Magic magics[][2]) {
void init_magics(PieceType pt, Bitboard table[], Magic magics[]) {
#ifndef USE_PEXT
// Optimal PRNG seeds to pick the correct magics in the shortest time // Optimal PRNG seeds to pick the correct magics in the shortest time
int seeds[][RANK_NB] = { { 8977, 44560, 54343, 38998, 5731, 95205, 104912, 17020 }, int seeds[][RANK_NB] = {{8977, 44560, 54343, 38998, 5731, 95205, 104912, 17020},
{ 728, 10316, 55013, 32803, 12281, 15100, 16645, 255 } }; {728, 10316, 55013, 32803, 12281, 15100, 16645, 255}};
Bitboard occupancy[4096], reference[4096], edges, b; Bitboard occupancy[4096];
int epoch[4096] = {}, cnt = 0, size = 0; int epoch[4096] = {}, cnt = 0;
#endif
Bitboard reference[4096];
int size = 0;
for (Square s = SQ_A1; s <= SQ_H8; ++s) for (Square s = SQ_A1; s <= SQ_H8; ++s)
{ {
// Board edges are not considered in the relevant occupancies // Board edges are not considered in the relevant occupancies
edges = ((Rank1BB | Rank8BB) & ~rank_bb(s)) | ((FileABB | FileHBB) & ~file_bb(s)); Bitboard edges = ((Rank1BB | Rank8BB) & ~rank_bb(s)) | ((FileABB | FileHBB) & ~file_bb(s));
// Given a square 's', the mask is the bitboard of sliding attacks from // Given a square 's', the mask is the bitboard of sliding attacks from
// 's' computed on an empty board. The index must be big enough to contain // 's' computed on an empty board. The index must be big enough to contain
// all the attacks for each possible subset of the mask and so is 2 power // all the attacks for each possible subset of the mask and so is 2 power
// the number of 1s of the mask. Hence we deduce the size of the shift to // the number of 1s of the mask. Hence we deduce the size of the shift to
// apply to the 64 or 32 bits word to get the index. // apply to the 64 or 32 bits word to get the index.
Magic& m = magics[s]; Magic& m = magics[s][pt - BISHOP];
m.mask = sliding_attack(pt, s, 0) & ~edges; m.mask = sliding_attack(pt, s, 0) & ~edges;
#ifndef USE_PEXT
m.shift = (Is64Bit ? 64 : 32) - popcount(m.mask); m.shift = (Is64Bit ? 64 : 32) - popcount(m.mask);
#endif
// Set the offset for the attacks table of the square. We have individual // Set the offset for the attacks table of the square. We have individual
// table sizes for each square with "Fancy Magic Bitboards". // table sizes for each square with "Fancy Magic Bitboards".
m.attacks = s == SQ_A1 ? table : magics[s - 1].attacks + size; m.attacks = s == SQ_A1 ? table : magics[s - 1][pt - BISHOP].attacks + size;
size = 0;
// Use Carry-Rippler trick to enumerate all subsets of masks[s] and // Use Carry-Rippler trick to enumerate all subsets of masks[s] and
// store the corresponding sliding attack bitboard in reference[]. // store the corresponding sliding attack bitboard in reference[].
b = size = 0; Bitboard b = 0;
do { do
{
#ifndef USE_PEXT
occupancy[size] = b; occupancy[size] = b;
#endif
reference[size] = sliding_attack(pt, s, b); reference[size] = sliding_attack(pt, s, b);
if (HasPext) if (HasPext)
@@ -180,16 +191,14 @@ namespace {
b = (b - m.mask) & m.mask; b = (b - m.mask) & m.mask;
} while (b); } while (b);
if (HasPext) #ifndef USE_PEXT
continue;
PRNG rng(seeds[Is64Bit][rank_of(s)]); PRNG rng(seeds[Is64Bit][rank_of(s)]);
// Find a magic for square 's' picking up an (almost) random number // Find a magic for square 's' picking up an (almost) random number
// until we find the one that passes the verification test. // until we find the one that passes the verification test.
for (int i = 0; i < size; ) for (int i = 0; i < size;)
{ {
for (m.magic = 0; popcount((m.magic * m.mask) >> 56) < 6; ) for (m.magic = 0; popcount((m.magic * m.mask) >> 56) < 6;)
m.magic = rng.sparse_rand<Bitboard>(); m.magic = rng.sparse_rand<Bitboard>();
// A good magic must map every possible occupancy to an index that // A good magic must map every possible occupancy to an index that
@@ -204,15 +213,16 @@ namespace {
if (epoch[idx] < cnt) if (epoch[idx] < cnt)
{ {
epoch[idx] = cnt; epoch[idx] = cnt;
m.attacks[idx] = reference[i]; m.attacks[idx] = reference[i];
} }
else if (m.attacks[idx] != reference[i]) else if (m.attacks[idx] != reference[i])
break; break;
} }
} }
#endif
} }
} }
} }
} // namespace Stockfish } // namespace Stockfish
+214 -290
View File
@@ -1,6 +1,6 @@
/* /*
Stockfish, a UCI chess playing engine derived from Glaurung 2.1 Stockfish, a UCI chess playing engine derived from Glaurung 2.1
Copyright (C) 2004-2023 The Stockfish developers (see AUTHORS file) Copyright (C) 2004-2025 The Stockfish developers (see AUTHORS file)
Stockfish is free software: you can redistribute it and/or modify Stockfish is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by it under the terms of the GNU General Public License as published by
@@ -19,28 +19,24 @@
#ifndef BITBOARD_H_INCLUDED #ifndef BITBOARD_H_INCLUDED
#define BITBOARD_H_INCLUDED #define BITBOARD_H_INCLUDED
#include <algorithm>
#include <cassert>
#include <cmath>
#include <cstring>
#include <cstdint>
#include <cstdlib>
#include <string> #include <string>
#include "types.h" #include "types.h"
namespace Stockfish { namespace Stockfish {
namespace Bitbases {
void init();
bool probe(Square wksq, Square wpsq, Square bksq, Color us);
} // namespace Stockfish::Bitbases
namespace Bitboards { namespace Bitboards {
void init(); void init();
std::string pretty(Bitboard b); std::string pretty(Bitboard b);
} // namespace Stockfish::Bitboards } // namespace Stockfish::Bitboards
constexpr Bitboard AllSquares = ~Bitboard(0);
constexpr Bitboard DarkSquares = 0xAA55AA55AA55AA55ULL;
constexpr Bitboard FileABB = 0x0101010101010101ULL; constexpr Bitboard FileABB = 0x0101010101010101ULL;
constexpr Bitboard FileBBB = FileABB << 1; constexpr Bitboard FileBBB = FileABB << 1;
@@ -60,17 +56,6 @@ constexpr Bitboard Rank6BB = Rank1BB << (8 * 5);
constexpr Bitboard Rank7BB = Rank1BB << (8 * 6); constexpr Bitboard Rank7BB = Rank1BB << (8 * 6);
constexpr Bitboard Rank8BB = Rank1BB << (8 * 7); constexpr Bitboard Rank8BB = Rank1BB << (8 * 7);
constexpr Bitboard QueenSide = FileABB | FileBBB | FileCBB | FileDBB;
constexpr Bitboard CenterFiles = FileCBB | FileDBB | FileEBB | FileFBB;
constexpr Bitboard KingSide = FileEBB | FileFBB | FileGBB | FileHBB;
constexpr Bitboard Center = (FileDBB | FileEBB) & (Rank4BB | Rank5BB);
constexpr Bitboard KingFlank[FILE_NB] = {
QueenSide ^ FileDBB, QueenSide, QueenSide,
CenterFiles, CenterFiles,
KingSide, KingSide, KingSide ^ FileEBB
};
extern uint8_t PopCnt16[1 << 16]; extern uint8_t PopCnt16[1 << 16];
extern uint8_t SquareDistance[SQUARE_NB][SQUARE_NB]; extern uint8_t SquareDistance[SQUARE_NB][SQUARE_NB];
@@ -80,371 +65,310 @@ extern Bitboard PseudoAttacks[PIECE_TYPE_NB][SQUARE_NB];
extern Bitboard PawnAttacks[COLOR_NB][SQUARE_NB]; extern Bitboard PawnAttacks[COLOR_NB][SQUARE_NB];
/// Magic holds all magic bitboards relevant data for a single square // Magic holds all magic bitboards relevant data for a single square
struct Magic { struct Magic {
Bitboard mask; Bitboard mask;
Bitboard magic; Bitboard* attacks;
Bitboard* attacks; #ifndef USE_PEXT
unsigned shift; Bitboard magic;
unsigned shift;
#endif
// Compute the attack's index using the 'magic bitboards' approach // Compute the attack's index using the 'magic bitboards' approach
unsigned index(Bitboard occupied) const { unsigned index(Bitboard occupied) const {
if (HasPext) #ifdef USE_PEXT
return unsigned(pext(occupied, mask)); return unsigned(pext(occupied, mask));
#else
if (Is64Bit)
return unsigned(((occupied & mask) * magic) >> shift);
if (Is64Bit) unsigned lo = unsigned(occupied) & unsigned(mask);
return unsigned(((occupied & mask) * magic) >> shift); unsigned hi = unsigned(occupied >> 32) & unsigned(mask >> 32);
return (lo * unsigned(magic) ^ hi * unsigned(magic >> 32)) >> shift;
#endif
}
unsigned lo = unsigned(occupied) & unsigned(mask); Bitboard attacks_bb(Bitboard occupied) const { return attacks[index(occupied)]; }
unsigned hi = unsigned(occupied >> 32) & unsigned(mask >> 32);
return (lo * unsigned(magic) ^ hi * unsigned(magic >> 32)) >> shift;
}
}; };
extern Magic RookMagics[SQUARE_NB]; extern Magic Magics[SQUARE_NB][2];
extern Magic BishopMagics[SQUARE_NB];
inline Bitboard square_bb(Square s) { constexpr Bitboard square_bb(Square s) {
assert(is_ok(s)); assert(is_ok(s));
return (1ULL << s); return (1ULL << s);
} }
/// Overloads of bitwise operators between a Bitboard and a Square for testing // Overloads of bitwise operators between a Bitboard and a Square for testing
/// whether a given bit is set in a bitboard, and for setting and clearing bits. // whether a given bit is set in a bitboard, and for setting and clearing bits.
inline Bitboard operator&( Bitboard b, Square s) { return b & square_bb(s); } inline Bitboard operator&(Bitboard b, Square s) { return b & square_bb(s); }
inline Bitboard operator|( Bitboard b, Square s) { return b | square_bb(s); } inline Bitboard operator|(Bitboard b, Square s) { return b | square_bb(s); }
inline Bitboard operator^( Bitboard b, Square s) { return b ^ square_bb(s); } inline Bitboard operator^(Bitboard b, Square s) { return b ^ square_bb(s); }
inline Bitboard& operator|=(Bitboard& b, Square s) { return b |= square_bb(s); } inline Bitboard& operator|=(Bitboard& b, Square s) { return b |= square_bb(s); }
inline Bitboard& operator^=(Bitboard& b, Square s) { return b ^= square_bb(s); } inline Bitboard& operator^=(Bitboard& b, Square s) { return b ^= square_bb(s); }
inline Bitboard operator&(Square s, Bitboard b) { return b & s; } inline Bitboard operator&(Square s, Bitboard b) { return b & s; }
inline Bitboard operator|(Square s, Bitboard b) { return b | s; } inline Bitboard operator|(Square s, Bitboard b) { return b | s; }
inline Bitboard operator^(Square s, Bitboard b) { return b ^ s; } inline Bitboard operator^(Square s, Bitboard b) { return b ^ s; }
inline Bitboard operator|(Square s1, Square s2) { return square_bb(s1) | s2; } inline Bitboard operator|(Square s1, Square s2) { return square_bb(s1) | s2; }
constexpr bool more_than_one(Bitboard b) { constexpr bool more_than_one(Bitboard b) { return b & (b - 1); }
return b & (b - 1);
}
constexpr bool opposite_colors(Square s1, Square s2) { // rank_bb() and file_bb() return a bitboard representing all the squares on
return (s1 + rank_of(s1) + s2 + rank_of(s2)) & 1; // the given file or rank.
}
constexpr Bitboard rank_bb(Rank r) { return Rank1BB << (8 * r); }
constexpr Bitboard rank_bb(Square s) { return rank_bb(rank_of(s)); }
constexpr Bitboard file_bb(File f) { return FileABB << f; }
constexpr Bitboard file_bb(Square s) { return file_bb(file_of(s)); }
/// rank_bb() and file_bb() return a bitboard representing all the squares on // Moves a bitboard one or two steps as specified by the direction D
/// the given file or rank.
constexpr Bitboard rank_bb(Rank r) {
return Rank1BB << (8 * r);
}
constexpr Bitboard rank_bb(Square s) {
return rank_bb(rank_of(s));
}
constexpr Bitboard file_bb(File f) {
return FileABB << f;
}
constexpr Bitboard file_bb(Square s) {
return file_bb(file_of(s));
}
/// shift() moves a bitboard one or two steps as specified by the direction D
template<Direction D> template<Direction D>
constexpr Bitboard shift(Bitboard b) { constexpr Bitboard shift(Bitboard b) {
return D == NORTH ? b << 8 : D == SOUTH ? b >> 8 return D == NORTH ? b << 8
: D == NORTH+NORTH? b <<16 : D == SOUTH+SOUTH? b >>16 : D == SOUTH ? b >> 8
: D == EAST ? (b & ~FileHBB) << 1 : D == WEST ? (b & ~FileABB) >> 1 : D == NORTH + NORTH ? b << 16
: D == NORTH_EAST ? (b & ~FileHBB) << 9 : D == NORTH_WEST ? (b & ~FileABB) << 7 : D == SOUTH + SOUTH ? b >> 16
: D == SOUTH_EAST ? (b & ~FileHBB) >> 7 : D == SOUTH_WEST ? (b & ~FileABB) >> 9 : D == EAST ? (b & ~FileHBB) << 1
: 0; : D == WEST ? (b & ~FileABB) >> 1
: D == NORTH_EAST ? (b & ~FileHBB) << 9
: D == NORTH_WEST ? (b & ~FileABB) << 7
: D == SOUTH_EAST ? (b & ~FileHBB) >> 7
: D == SOUTH_WEST ? (b & ~FileABB) >> 9
: 0;
} }
/// pawn_attacks_bb() returns the squares attacked by pawns of the given color // Returns the squares attacked by pawns of the given color
/// from the squares in the given bitboard. // from the squares in the given bitboard.
template<Color C> template<Color C>
constexpr Bitboard pawn_attacks_bb(Bitboard b) { constexpr Bitboard pawn_attacks_bb(Bitboard b) {
return C == WHITE ? shift<NORTH_WEST>(b) | shift<NORTH_EAST>(b) return C == WHITE ? shift<NORTH_WEST>(b) | shift<NORTH_EAST>(b)
: shift<SOUTH_WEST>(b) | shift<SOUTH_EAST>(b); : shift<SOUTH_WEST>(b) | shift<SOUTH_EAST>(b);
} }
inline Bitboard pawn_attacks_bb(Color c, Square s) { inline Bitboard pawn_attacks_bb(Color c, Square s) {
assert(is_ok(s)); assert(is_ok(s));
return PawnAttacks[c][s]; return PawnAttacks[c][s];
} }
// Returns a bitboard representing an entire line (from board edge
/// pawn_double_attacks_bb() returns the squares doubly attacked by pawns of the // to board edge) that intersects the two given squares. If the given squares
/// given color from the squares in the given bitboard. // are not on a same file/rank/diagonal, the function returns 0. For instance,
// line_bb(SQ_C4, SQ_F7) will return a bitboard with the A2-G8 diagonal.
template<Color C>
constexpr Bitboard pawn_double_attacks_bb(Bitboard b) {
return C == WHITE ? shift<NORTH_WEST>(b) & shift<NORTH_EAST>(b)
: shift<SOUTH_WEST>(b) & shift<SOUTH_EAST>(b);
}
/// adjacent_files_bb() returns a bitboard representing all the squares on the
/// adjacent files of a given square.
constexpr Bitboard adjacent_files_bb(Square s) {
return shift<EAST>(file_bb(s)) | shift<WEST>(file_bb(s));
}
/// line_bb() returns a bitboard representing an entire line (from board edge
/// to board edge) that intersects the two given squares. If the given squares
/// are not on a same file/rank/diagonal, the function returns 0. For instance,
/// line_bb(SQ_C4, SQ_F7) will return a bitboard with the A2-G8 diagonal.
inline Bitboard line_bb(Square s1, Square s2) { inline Bitboard line_bb(Square s1, Square s2) {
assert(is_ok(s1) && is_ok(s2)); assert(is_ok(s1) && is_ok(s2));
return LineBB[s1][s2];
return LineBB[s1][s2];
} }
/// between_bb(s1, s2) returns a bitboard representing the squares in the semi-open // Returns a bitboard representing the squares in the semi-open
/// segment between the squares s1 and s2 (excluding s1 but including s2). If the // segment between the squares s1 and s2 (excluding s1 but including s2). If the
/// given squares are not on a same file/rank/diagonal, it returns s2. For instance, // given squares are not on a same file/rank/diagonal, it returns s2. For instance,
/// between_bb(SQ_C4, SQ_F7) will return a bitboard with squares D5, E6 and F7, but // between_bb(SQ_C4, SQ_F7) will return a bitboard with squares D5, E6 and F7, but
/// between_bb(SQ_E6, SQ_F8) will return a bitboard with the square F8. This trick // between_bb(SQ_E6, SQ_F8) will return a bitboard with the square F8. This trick
/// allows to generate non-king evasion moves faster: the defending piece must either // allows to generate non-king evasion moves faster: the defending piece must either
/// interpose itself to cover the check or capture the checking piece. // interpose itself to cover the check or capture the checking piece.
inline Bitboard between_bb(Square s1, Square s2) { inline Bitboard between_bb(Square s1, Square s2) {
assert(is_ok(s1) && is_ok(s2)); assert(is_ok(s1) && is_ok(s2));
return BetweenBB[s1][s2];
return BetweenBB[s1][s2];
} }
// Returns true if the squares s1, s2 and s3 are aligned either on a
// straight or on a diagonal line.
inline bool aligned(Square s1, Square s2, Square s3) { return line_bb(s1, s2) & s3; }
/// forward_ranks_bb() returns a bitboard representing the squares on the ranks in
/// front of the given one, from the point of view of the given color. For instance,
/// forward_ranks_bb(BLACK, SQ_D3) will return the 16 squares on ranks 1 and 2.
constexpr Bitboard forward_ranks_bb(Color c, Square s) { // distance() functions return the distance between x and y, defined as the
return c == WHITE ? ~Rank1BB << 8 * relative_rank(WHITE, s) // number of steps for a king in x to reach y.
: ~Rank8BB >> 8 * relative_rank(BLACK, s);
template<typename T1 = Square>
inline int distance(Square x, Square y);
template<>
inline int distance<File>(Square x, Square y) {
return std::abs(file_of(x) - file_of(y));
} }
template<>
/// forward_file_bb() returns a bitboard representing all the squares along the inline int distance<Rank>(Square x, Square y) {
/// line in front of the given one, from the point of view of the given color. return std::abs(rank_of(x) - rank_of(y));
constexpr Bitboard forward_file_bb(Color c, Square s) {
return forward_ranks_bb(c, s) & file_bb(s);
} }
template<>
/// pawn_attack_span() returns a bitboard representing all the squares that can inline int distance<Square>(Square x, Square y) {
/// be attacked by a pawn of the given color when it moves along its file, starting return SquareDistance[x][y];
/// from the given square.
constexpr Bitboard pawn_attack_span(Color c, Square s) {
return forward_ranks_bb(c, s) & adjacent_files_bb(s);
} }
/// passed_pawn_span() returns a bitboard which can be used to test if a pawn of
/// the given color and on the given square is a passed pawn.
constexpr Bitboard passed_pawn_span(Color c, Square s) {
return pawn_attack_span(c, s) | forward_file_bb(c, s);
}
/// aligned() returns true if the squares s1, s2 and s3 are aligned either on a
/// straight or on a diagonal line.
inline bool aligned(Square s1, Square s2, Square s3) {
return line_bb(s1, s2) & s3;
}
/// distance() functions return the distance between x and y, defined as the
/// number of steps for a king in x to reach y.
template<typename T1 = Square> inline int distance(Square x, Square y);
template<> inline int distance<File>(Square x, Square y) { return std::abs(file_of(x) - file_of(y)); }
template<> inline int distance<Rank>(Square x, Square y) { return std::abs(rank_of(x) - rank_of(y)); }
template<> inline int distance<Square>(Square x, Square y) { return SquareDistance[x][y]; }
inline int edge_distance(File f) { return std::min(f, File(FILE_H - f)); } inline int edge_distance(File f) { return std::min(f, File(FILE_H - f)); }
inline int edge_distance(Rank r) { return std::min(r, Rank(RANK_8 - r)); }
/// attacks_bb(Square) returns the pseudo attacks of the give piece type
/// assuming an empty board.
// Returns the pseudo attacks of the given piece type
// assuming an empty board.
template<PieceType Pt> template<PieceType Pt>
inline Bitboard attacks_bb(Square s) { inline Bitboard attacks_bb(Square s) {
assert((Pt != PAWN) && (is_ok(s))); assert((Pt != PAWN) && (is_ok(s)));
return PseudoAttacks[Pt][s];
return PseudoAttacks[Pt][s];
} }
/// attacks_bb(Square, Bitboard) returns the attacks by the given piece // Returns the attacks by the given piece
/// assuming the board is occupied according to the passed Bitboard. // assuming the board is occupied according to the passed Bitboard.
/// Sliding piece attacks do not continue passed an occupied square. // Sliding piece attacks do not continue passed an occupied square.
template<PieceType Pt> template<PieceType Pt>
inline Bitboard attacks_bb(Square s, Bitboard occupied) { inline Bitboard attacks_bb(Square s, Bitboard occupied) {
assert((Pt != PAWN) && (is_ok(s))); assert((Pt != PAWN) && (is_ok(s)));
switch (Pt) switch (Pt)
{ {
case BISHOP: return BishopMagics[s].attacks[BishopMagics[s].index(occupied)]; case BISHOP :
case ROOK : return RookMagics[s].attacks[ RookMagics[s].index(occupied)]; case ROOK :
case QUEEN : return attacks_bb<BISHOP>(s, occupied) | attacks_bb<ROOK>(s, occupied); return Magics[s][Pt - BISHOP].attacks_bb(occupied);
default : return PseudoAttacks[Pt][s]; case QUEEN :
} return attacks_bb<BISHOP>(s, occupied) | attacks_bb<ROOK>(s, occupied);
default :
return PseudoAttacks[Pt][s];
}
} }
// Returns the attacks by the given piece
// assuming the board is occupied according to the passed Bitboard.
// Sliding piece attacks do not continue passed an occupied square.
inline Bitboard attacks_bb(PieceType pt, Square s, Bitboard occupied) { inline Bitboard attacks_bb(PieceType pt, Square s, Bitboard occupied) {
assert((pt != PAWN) && (is_ok(s))); assert((pt != PAWN) && (is_ok(s)));
switch (pt) switch (pt)
{ {
case BISHOP: return attacks_bb<BISHOP>(s, occupied); case BISHOP :
case ROOK : return attacks_bb< ROOK>(s, occupied); return attacks_bb<BISHOP>(s, occupied);
case QUEEN : return attacks_bb<BISHOP>(s, occupied) | attacks_bb<ROOK>(s, occupied); case ROOK :
default : return PseudoAttacks[pt][s]; return attacks_bb<ROOK>(s, occupied);
} case QUEEN :
return attacks_bb<BISHOP>(s, occupied) | attacks_bb<ROOK>(s, occupied);
default :
return PseudoAttacks[pt][s];
}
} }
/// popcount() counts the number of non-zero bits in a bitboard // Counts the number of non-zero bits in a bitboard.
inline int popcount(Bitboard b) { inline int popcount(Bitboard b) {
#ifndef USE_POPCNT #ifndef USE_POPCNT
union { Bitboard bb; uint16_t u[4]; } v = { b }; std::uint16_t indices[4];
return PopCnt16[v.u[0]] + PopCnt16[v.u[1]] + PopCnt16[v.u[2]] + PopCnt16[v.u[3]]; std::memcpy(indices, &b, sizeof(b));
return PopCnt16[indices[0]] + PopCnt16[indices[1]] + PopCnt16[indices[2]]
+ PopCnt16[indices[3]];
#elif defined(_MSC_VER) || defined(__INTEL_COMPILER) #elif defined(_MSC_VER)
return (int)_mm_popcnt_u64(b); return int(_mm_popcnt_u64(b));
#else // Assumed gcc or compatible compiler #else // Assumed gcc or compatible compiler
return __builtin_popcountll(b); return __builtin_popcountll(b);
#endif #endif
} }
// Returns the least significant bit in a non-zero bitboard.
/// lsb() and msb() return the least/most significant bit in a non-zero bitboard
#if defined(__GNUC__) // GCC, Clang, ICC
inline Square lsb(Bitboard b) { inline Square lsb(Bitboard b) {
assert(b); assert(b);
return Square(__builtin_ctzll(b));
}
inline Square msb(Bitboard b) { #if defined(__GNUC__) // GCC, Clang, ICX
assert(b);
return Square(63 ^ __builtin_clzll(b));
}
#elif defined(_MSC_VER) // MSVC return Square(__builtin_ctzll(b));
#ifdef _WIN64 // MSVC, WIN64 #elif defined(_MSC_VER)
#ifdef _WIN64 // MSVC, WIN64
inline Square lsb(Bitboard b) { unsigned long idx;
assert(b); _BitScanForward64(&idx, b);
unsigned long idx; return Square(idx);
_BitScanForward64(&idx, b);
return (Square) idx;
}
inline Square msb(Bitboard b) { #else // MSVC, WIN32
assert(b); unsigned long idx;
unsigned long idx;
_BitScanReverse64(&idx, b);
return (Square) idx;
}
#else // MSVC, WIN32
inline Square lsb(Bitboard b) {
assert(b);
unsigned long idx;
if (b & 0xffffffff) {
_BitScanForward(&idx, int32_t(b));
return Square(idx);
} else {
_BitScanForward(&idx, int32_t(b >> 32));
return Square(idx + 32);
}
}
inline Square msb(Bitboard b) {
assert(b);
unsigned long idx;
if (b >> 32) {
_BitScanReverse(&idx, int32_t(b >> 32));
return Square(idx + 32);
} else {
_BitScanReverse(&idx, int32_t(b));
return Square(idx);
}
}
#endif
if (b & 0xffffffff)
{
_BitScanForward(&idx, int32_t(b));
return Square(idx);
}
else
{
_BitScanForward(&idx, int32_t(b >> 32));
return Square(idx + 32);
}
#endif
#else // Compiler is neither GCC nor MSVC compatible #else // Compiler is neither GCC nor MSVC compatible
#error "Compiler not supported."
#error "Compiler not supported."
#endif #endif
}
/// least_significant_square_bb() returns the bitboard of the least significant // Returns the most significant bit in a non-zero bitboard.
/// square of a non-zero bitboard. It is equivalent to square_bb(lsb(bb)). inline Square msb(Bitboard b) {
assert(b);
#if defined(__GNUC__) // GCC, Clang, ICX
return Square(63 ^ __builtin_clzll(b));
#elif defined(_MSC_VER)
#ifdef _WIN64 // MSVC, WIN64
unsigned long idx;
_BitScanReverse64(&idx, b);
return Square(idx);
#else // MSVC, WIN32
unsigned long idx;
if (b >> 32)
{
_BitScanReverse(&idx, int32_t(b >> 32));
return Square(idx + 32);
}
else
{
_BitScanReverse(&idx, int32_t(b));
return Square(idx);
}
#endif
#else // Compiler is neither GCC nor MSVC compatible
#error "Compiler not supported."
#endif
}
// Returns the bitboard of the least significant
// square of a non-zero bitboard. It is equivalent to square_bb(lsb(bb)).
inline Bitboard least_significant_square_bb(Bitboard b) { inline Bitboard least_significant_square_bb(Bitboard b) {
assert(b); assert(b);
return b & -b; return b & -b;
} }
/// pop_lsb() finds and clears the least significant bit in a non-zero bitboard // Finds and clears the least significant bit in a non-zero bitboard.
inline Square pop_lsb(Bitboard& b) { inline Square pop_lsb(Bitboard& b) {
assert(b); assert(b);
const Square s = lsb(b); const Square s = lsb(b);
b &= b - 1; b &= b - 1;
return s; return s;
} }
} // namespace Stockfish
/// frontmost_sq() returns the most advanced square for the given color, #endif // #ifndef BITBOARD_H_INCLUDED
/// requires a non-zero bitboard.
inline Square frontmost_sq(Color c, Bitboard b) {
assert(b);
return c == WHITE ? msb(b) : lsb(b);
}
} // namespace Stockfish
#endif // #ifndef BITBOARD_H_INCLUDED
-747
View File
@@ -1,747 +0,0 @@
/*
Stockfish, a UCI chess playing engine derived from Glaurung 2.1
Copyright (C) 2004-2023 The Stockfish developers (see AUTHORS file)
Stockfish is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
Stockfish is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <cassert>
#include "bitboard.h"
#include "endgame.h"
#include "movegen.h"
namespace Stockfish {
namespace {
// Used to drive the king towards the edge of the board
// in KX vs K and KQ vs KR endgames.
// Values range from 27 (center squares) to 90 (in the corners)
inline int push_to_edge(Square s) {
int rd = edge_distance(rank_of(s)), fd = edge_distance(file_of(s));
return 90 - (7 * fd * fd / 2 + 7 * rd * rd / 2);
}
// Used to drive the king towards A1H8 corners in KBN vs K endgames.
// Values range from 0 on A8H1 diagonal to 7 in A1H8 corners
inline int push_to_corner(Square s) {
return abs(7 - rank_of(s) - file_of(s));
}
// Drive a piece close to or away from another piece
inline int push_close(Square s1, Square s2) { return 140 - 20 * distance(s1, s2); }
inline int push_away(Square s1, Square s2) { return 120 - push_close(s1, s2); }
#ifndef NDEBUG
bool verify_material(const Position& pos, Color c, Value npm, int pawnsCnt) {
return pos.non_pawn_material(c) == npm && pos.count<PAWN>(c) == pawnsCnt;
}
#endif
// Map the square as if strongSide is white and strongSide's only pawn
// is on the left half of the board.
Square normalize(const Position& pos, Color strongSide, Square sq) {
assert(pos.count<PAWN>(strongSide) == 1);
if (file_of(pos.square<PAWN>(strongSide)) >= FILE_E)
sq = flip_file(sq);
return strongSide == WHITE ? sq : flip_rank(sq);
}
} // namespace
namespace Endgames {
std::pair<Map<Value>, Map<ScaleFactor>> maps;
void init() {
add<KPK>("KPK");
add<KNNK>("KNNK");
add<KBNK>("KBNK");
add<KRKP>("KRKP");
add<KRKB>("KRKB");
add<KRKN>("KRKN");
add<KQKP>("KQKP");
add<KQKR>("KQKR");
add<KNNKP>("KNNKP");
add<KRPKR>("KRPKR");
add<KRPKB>("KRPKB");
add<KBPKB>("KBPKB");
add<KBPKN>("KBPKN");
add<KBPPKB>("KBPPKB");
add<KRPPKRP>("KRPPKRP");
}
}
/// Mate with KX vs K. This function is used to evaluate positions with
/// king and plenty of material vs a lone king. It simply gives the
/// attacking side a bonus for driving the defending king towards the edge
/// of the board, and for keeping the distance between the two kings small.
template<>
Value Endgame<KXK>::operator()(const Position& pos) const {
assert(verify_material(pos, weakSide, VALUE_ZERO, 0));
assert(!pos.checkers()); // Eval is never called when in check
// Stalemate detection with lone king
if (pos.side_to_move() == weakSide && !MoveList<LEGAL>(pos).size())
return VALUE_DRAW;
Square strongKing = pos.square<KING>(strongSide);
Square weakKing = pos.square<KING>(weakSide);
Value result = pos.non_pawn_material(strongSide)
+ pos.count<PAWN>(strongSide) * PawnValueEg
+ push_to_edge(weakKing)
+ push_close(strongKing, weakKing);
if ( pos.count<QUEEN>(strongSide)
|| pos.count<ROOK>(strongSide)
||(pos.count<BISHOP>(strongSide) && pos.count<KNIGHT>(strongSide))
|| ( (pos.pieces(strongSide, BISHOP) & ~DarkSquares)
&& (pos.pieces(strongSide, BISHOP) & DarkSquares)))
result = std::min(result + VALUE_KNOWN_WIN, VALUE_TB_WIN_IN_MAX_PLY - 1);
return strongSide == pos.side_to_move() ? result : -result;
}
/// Mate with KBN vs K. This is similar to KX vs K, but we have to drive the
/// defending king towards a corner square that our bishop attacks.
template<>
Value Endgame<KBNK>::operator()(const Position& pos) const {
assert(verify_material(pos, strongSide, KnightValueMg + BishopValueMg, 0));
assert(verify_material(pos, weakSide, VALUE_ZERO, 0));
Square strongKing = pos.square<KING>(strongSide);
Square strongBishop = pos.square<BISHOP>(strongSide);
Square weakKing = pos.square<KING>(weakSide);
// If our bishop does not attack A1/H8, we flip the enemy king square
// to drive to opposite corners (A8/H1).
Value result = (VALUE_KNOWN_WIN + 3520)
+ push_close(strongKing, weakKing)
+ 420 * push_to_corner(opposite_colors(strongBishop, SQ_A1) ? flip_file(weakKing) : weakKing);
assert(abs(result) < VALUE_TB_WIN_IN_MAX_PLY);
return strongSide == pos.side_to_move() ? result : -result;
}
/// KP vs K. This endgame is evaluated with the help of a bitbase
template<>
Value Endgame<KPK>::operator()(const Position& pos) const {
assert(verify_material(pos, strongSide, VALUE_ZERO, 1));
assert(verify_material(pos, weakSide, VALUE_ZERO, 0));
// Assume strongSide is white and the pawn is on files A-D
Square strongKing = normalize(pos, strongSide, pos.square<KING>(strongSide));
Square strongPawn = normalize(pos, strongSide, pos.square<PAWN>(strongSide));
Square weakKing = normalize(pos, strongSide, pos.square<KING>(weakSide));
Color us = strongSide == pos.side_to_move() ? WHITE : BLACK;
if (!Bitbases::probe(strongKing, strongPawn, weakKing, us))
return VALUE_DRAW;
Value result = VALUE_KNOWN_WIN + PawnValueEg + Value(rank_of(strongPawn));
return strongSide == pos.side_to_move() ? result : -result;
}
/// KR vs KP. This is a somewhat tricky endgame to evaluate precisely without
/// a bitbase. The function below returns drawish scores when the pawn is
/// far advanced with support of the king, while the attacking king is far
/// away.
template<>
Value Endgame<KRKP>::operator()(const Position& pos) const {
assert(verify_material(pos, strongSide, RookValueMg, 0));
assert(verify_material(pos, weakSide, VALUE_ZERO, 1));
Square strongKing = pos.square<KING>(strongSide);
Square weakKing = pos.square<KING>(weakSide);
Square strongRook = pos.square<ROOK>(strongSide);
Square weakPawn = pos.square<PAWN>(weakSide);
Square queeningSquare = make_square(file_of(weakPawn), relative_rank(weakSide, RANK_8));
Value result;
// If the stronger side's king is in front of the pawn, it's a win
if (forward_file_bb(strongSide, strongKing) & weakPawn)
result = RookValueEg - distance(strongKing, weakPawn);
// If the weaker side's king is too far from the pawn and the rook,
// it's a win.
else if ( distance(weakKing, weakPawn) >= 3 + (pos.side_to_move() == weakSide)
&& distance(weakKing, strongRook) >= 3)
result = RookValueEg - distance(strongKing, weakPawn);
// If the pawn is far advanced and supported by the defending king,
// the position is drawish
else if ( relative_rank(strongSide, weakKing) <= RANK_3
&& distance(weakKing, weakPawn) == 1
&& relative_rank(strongSide, strongKing) >= RANK_4
&& distance(strongKing, weakPawn) > 2 + (pos.side_to_move() == strongSide))
result = Value(80) - 8 * distance(strongKing, weakPawn);
else
result = Value(200) - 8 * ( distance(strongKing, weakPawn + pawn_push(weakSide))
- distance(weakKing, weakPawn + pawn_push(weakSide))
- distance(weakPawn, queeningSquare));
return strongSide == pos.side_to_move() ? result : -result;
}
/// KR vs KB. This is very simple, and always returns drawish scores. The
/// score is slightly bigger when the defending king is close to the edge.
template<>
Value Endgame<KRKB>::operator()(const Position& pos) const {
assert(verify_material(pos, strongSide, RookValueMg, 0));
assert(verify_material(pos, weakSide, BishopValueMg, 0));
Value result = Value(push_to_edge(pos.square<KING>(weakSide)));
return strongSide == pos.side_to_move() ? result : -result;
}
/// KR vs KN. The attacking side has slightly better winning chances than
/// in KR vs KB, particularly if the king and the knight are far apart.
template<>
Value Endgame<KRKN>::operator()(const Position& pos) const {
assert(verify_material(pos, strongSide, RookValueMg, 0));
assert(verify_material(pos, weakSide, KnightValueMg, 0));
Square weakKing = pos.square<KING>(weakSide);
Square weakKnight = pos.square<KNIGHT>(weakSide);
Value result = Value(push_to_edge(weakKing) + push_away(weakKing, weakKnight));
return strongSide == pos.side_to_move() ? result : -result;
}
/// KQ vs KP. In general, this is a win for the stronger side, but there are a
/// few important exceptions. A pawn on 7th rank and on the A,C,F or H files
/// with a king positioned next to it can be a draw, so in that case, we only
/// use the distance between the kings.
template<>
Value Endgame<KQKP>::operator()(const Position& pos) const {
assert(verify_material(pos, strongSide, QueenValueMg, 0));
assert(verify_material(pos, weakSide, VALUE_ZERO, 1));
Square strongKing = pos.square<KING>(strongSide);
Square weakKing = pos.square<KING>(weakSide);
Square weakPawn = pos.square<PAWN>(weakSide);
Value result = Value(push_close(strongKing, weakKing));
if ( relative_rank(weakSide, weakPawn) != RANK_7
|| distance(weakKing, weakPawn) != 1
|| ((FileBBB | FileDBB | FileEBB | FileGBB) & weakPawn))
result += QueenValueEg - PawnValueEg;
return strongSide == pos.side_to_move() ? result : -result;
}
/// KQ vs KR. This is almost identical to KX vs K: we give the attacking
/// king a bonus for having the kings close together, and for forcing the
/// defending king towards the edge. If we also take care to avoid null move for
/// the defending side in the search, this is usually sufficient to win KQ vs KR.
template<>
Value Endgame<KQKR>::operator()(const Position& pos) const {
assert(verify_material(pos, strongSide, QueenValueMg, 0));
assert(verify_material(pos, weakSide, RookValueMg, 0));
Square strongKing = pos.square<KING>(strongSide);
Square weakKing = pos.square<KING>(weakSide);
Value result = QueenValueEg
- RookValueEg
+ push_to_edge(weakKing)
+ push_close(strongKing, weakKing);
return strongSide == pos.side_to_move() ? result : -result;
}
/// KNN vs KP. Very drawish, but there are some mate opportunities if we can
/// press the weakSide King to a corner before the pawn advances too much.
template<>
Value Endgame<KNNKP>::operator()(const Position& pos) const {
assert(verify_material(pos, strongSide, 2 * KnightValueMg, 0));
assert(verify_material(pos, weakSide, VALUE_ZERO, 1));
Square weakKing = pos.square<KING>(weakSide);
Square weakPawn = pos.square<PAWN>(weakSide);
Value result = PawnValueEg
+ 2 * push_to_edge(weakKing)
- 10 * relative_rank(weakSide, weakPawn);
return strongSide == pos.side_to_move() ? result : -result;
}
/// Some cases of trivial draws
template<> Value Endgame<KNNK>::operator()(const Position&) const { return VALUE_DRAW; }
/// KB and one or more pawns vs K. It checks for draws with rook pawns and
/// a bishop of the wrong color. If such a draw is detected, SCALE_FACTOR_DRAW
/// is returned. If not, the return value is SCALE_FACTOR_NONE, i.e. no scaling
/// will be used.
template<>
ScaleFactor Endgame<KBPsK>::operator()(const Position& pos) const {
assert(pos.non_pawn_material(strongSide) == BishopValueMg);
assert(pos.count<PAWN>(strongSide) >= 1);
// No assertions about the material of weakSide, because we want draws to
// be detected even when the weaker side has some pawns.
Bitboard strongPawns = pos.pieces(strongSide, PAWN);
Bitboard allPawns = pos.pieces(PAWN);
Square strongBishop = pos.square<BISHOP>(strongSide);
Square weakKing = pos.square<KING>(weakSide);
Square strongKing = pos.square<KING>(strongSide);
// All strongSide pawns are on a single rook file?
if (!(strongPawns & ~FileABB) || !(strongPawns & ~FileHBB))
{
Square queeningSquare = relative_square(strongSide, make_square(file_of(lsb(strongPawns)), RANK_8));
if ( opposite_colors(queeningSquare, strongBishop)
&& distance(queeningSquare, weakKing) <= 1)
return SCALE_FACTOR_DRAW;
}
// If all the pawns are on the same B or G file, then it's potentially a draw
if ((!(allPawns & ~FileBBB) || !(allPawns & ~FileGBB))
&& pos.non_pawn_material(weakSide) == 0
&& pos.count<PAWN>(weakSide) >= 1)
{
// Get the least advanced weakSide pawn
Square weakPawn = frontmost_sq(strongSide, pos.pieces(weakSide, PAWN));
// There's potential for a draw if our pawn is blocked on the 7th rank,
// the bishop cannot attack it or they only have one pawn left.
if ( relative_rank(strongSide, weakPawn) == RANK_7
&& (strongPawns & (weakPawn + pawn_push(weakSide)))
&& (opposite_colors(strongBishop, weakPawn) || !more_than_one(strongPawns)))
{
int strongKingDist = distance(weakPawn, strongKing);
int weakKingDist = distance(weakPawn, weakKing);
// It's a draw if the weak king is on its back two ranks, within 2
// squares of the blocking pawn and the strong king is not
// closer. (I think this rule only fails in practically
// unreachable positions such as 5k1K/6p1/6P1/8/8/3B4/8/8 w
// and positions where qsearch will immediately correct the
// problem such as 8/4k1p1/6P1/1K6/3B4/8/8/8 w).
if ( relative_rank(strongSide, weakKing) >= RANK_7
&& weakKingDist <= 2
&& weakKingDist <= strongKingDist)
return SCALE_FACTOR_DRAW;
}
}
return SCALE_FACTOR_NONE;
}
/// KQ vs KR and one or more pawns. It tests for fortress draws with a rook on
/// the third rank defended by a pawn.
template<>
ScaleFactor Endgame<KQKRPs>::operator()(const Position& pos) const {
assert(verify_material(pos, strongSide, QueenValueMg, 0));
assert(pos.count<ROOK>(weakSide) == 1);
assert(pos.count<PAWN>(weakSide) >= 1);
Square strongKing = pos.square<KING>(strongSide);
Square weakKing = pos.square<KING>(weakSide);
Square weakRook = pos.square<ROOK>(weakSide);
if ( relative_rank(weakSide, weakKing) <= RANK_2
&& relative_rank(weakSide, strongKing) >= RANK_4
&& relative_rank(weakSide, weakRook) == RANK_3
&& ( pos.pieces(weakSide, PAWN)
& attacks_bb<KING>(weakKing)
& pawn_attacks_bb(strongSide, weakRook)))
return SCALE_FACTOR_DRAW;
return SCALE_FACTOR_NONE;
}
/// KRP vs KR. This function knows a handful of the most important classes of
/// drawn positions, but is far from perfect. It would probably be a good idea
/// to add more knowledge in the future.
///
/// It would also be nice to rewrite the actual code for this function,
/// which is mostly copied from Glaurung 1.x, and isn't very pretty.
template<>
ScaleFactor Endgame<KRPKR>::operator()(const Position& pos) const {
assert(verify_material(pos, strongSide, RookValueMg, 1));
assert(verify_material(pos, weakSide, RookValueMg, 0));
// Assume strongSide is white and the pawn is on files A-D
Square strongKing = normalize(pos, strongSide, pos.square<KING>(strongSide));
Square strongRook = normalize(pos, strongSide, pos.square<ROOK>(strongSide));
Square strongPawn = normalize(pos, strongSide, pos.square<PAWN>(strongSide));
Square weakKing = normalize(pos, strongSide, pos.square<KING>(weakSide));
Square weakRook = normalize(pos, strongSide, pos.square<ROOK>(weakSide));
File pawnFile = file_of(strongPawn);
Rank pawnRank = rank_of(strongPawn);
Square queeningSquare = make_square(pawnFile, RANK_8);
int tempo = (pos.side_to_move() == strongSide);
// If the pawn is not too far advanced and the defending king defends the
// queening square, use the third-rank defence.
if ( pawnRank <= RANK_5
&& distance(weakKing, queeningSquare) <= 1
&& strongKing <= SQ_H5
&& (rank_of(weakRook) == RANK_6 || (pawnRank <= RANK_3 && rank_of(strongRook) != RANK_6)))
return SCALE_FACTOR_DRAW;
// The defending side saves a draw by checking from behind in case the pawn
// has advanced to the 6th rank with the king behind.
if ( pawnRank == RANK_6
&& distance(weakKing, queeningSquare) <= 1
&& rank_of(strongKing) + tempo <= RANK_6
&& (rank_of(weakRook) == RANK_1 || (!tempo && distance<File>(weakRook, strongPawn) >= 3)))
return SCALE_FACTOR_DRAW;
if ( pawnRank >= RANK_6
&& weakKing == queeningSquare
&& rank_of(weakRook) == RANK_1
&& (!tempo || distance(strongKing, strongPawn) >= 2))
return SCALE_FACTOR_DRAW;
// White pawn on a7 and rook on a8 is a draw if black's king is on g7 or h7
// and the black rook is behind the pawn.
if ( strongPawn == SQ_A7
&& strongRook == SQ_A8
&& (weakKing == SQ_H7 || weakKing == SQ_G7)
&& file_of(weakRook) == FILE_A
&& (rank_of(weakRook) <= RANK_3 || file_of(strongKing) >= FILE_D || rank_of(strongKing) <= RANK_5))
return SCALE_FACTOR_DRAW;
// If the defending king blocks the pawn and the attacking king is too far
// away, it's a draw.
if ( pawnRank <= RANK_5
&& weakKing == strongPawn + NORTH
&& distance(strongKing, strongPawn) - tempo >= 2
&& distance(strongKing, weakRook) - tempo >= 2)
return SCALE_FACTOR_DRAW;
// Pawn on the 7th rank supported by the rook from behind usually wins if the
// attacking king is closer to the queening square than the defending king,
// and the defending king cannot gain tempi by threatening the attacking rook.
if ( pawnRank == RANK_7
&& pawnFile != FILE_A
&& file_of(strongRook) == pawnFile
&& strongRook != queeningSquare
&& (distance(strongKing, queeningSquare) < distance(weakKing, queeningSquare) - 2 + tempo)
&& (distance(strongKing, queeningSquare) < distance(weakKing, strongRook) + tempo))
return ScaleFactor(SCALE_FACTOR_MAX - 2 * distance(strongKing, queeningSquare));
// Similar to the above, but with the pawn further back
if ( pawnFile != FILE_A
&& file_of(strongRook) == pawnFile
&& strongRook < strongPawn
&& (distance(strongKing, queeningSquare) < distance(weakKing, queeningSquare) - 2 + tempo)
&& (distance(strongKing, strongPawn + NORTH) < distance(weakKing, strongPawn + NORTH) - 2 + tempo)
&& ( distance(weakKing, strongRook) + tempo >= 3
|| ( distance(strongKing, queeningSquare) < distance(weakKing, strongRook) + tempo
&& (distance(strongKing, strongPawn + NORTH) < distance(weakKing, strongPawn) + tempo))))
return ScaleFactor( SCALE_FACTOR_MAX
- 8 * distance(strongPawn, queeningSquare)
- 2 * distance(strongKing, queeningSquare));
// If the pawn is not far advanced and the defending king is somewhere in
// the pawn's path, it's probably a draw.
if (pawnRank <= RANK_4 && weakKing > strongPawn)
{
if (file_of(weakKing) == file_of(strongPawn))
return ScaleFactor(10);
if ( distance<File>(weakKing, strongPawn) == 1
&& distance(strongKing, weakKing) > 2)
return ScaleFactor(24 - 2 * distance(strongKing, weakKing));
}
return SCALE_FACTOR_NONE;
}
template<>
ScaleFactor Endgame<KRPKB>::operator()(const Position& pos) const {
assert(verify_material(pos, strongSide, RookValueMg, 1));
assert(verify_material(pos, weakSide, BishopValueMg, 0));
// Test for a rook pawn
if (pos.pieces(PAWN) & (FileABB | FileHBB))
{
Square weakKing = pos.square<KING>(weakSide);
Square weakBishop = pos.square<BISHOP>(weakSide);
Square strongKing = pos.square<KING>(strongSide);
Square strongPawn = pos.square<PAWN>(strongSide);
Rank pawnRank = relative_rank(strongSide, strongPawn);
Direction push = pawn_push(strongSide);
// If the pawn is on the 5th rank and the pawn (currently) is on
// the same color square as the bishop then there is a chance of
// a fortress. Depending on the king position give a moderate
// reduction or a stronger one if the defending king is near the
// corner but not trapped there.
if (pawnRank == RANK_5 && !opposite_colors(weakBishop, strongPawn))
{
int d = distance(strongPawn + 3 * push, weakKing);
if (d <= 2 && !(d == 0 && weakKing == strongKing + 2 * push))
return ScaleFactor(24);
else
return ScaleFactor(48);
}
// When the pawn has moved to the 6th rank we can be fairly sure
// it's drawn if the bishop attacks the square in front of the
// pawn from a reasonable distance and the defending king is near
// the corner
if ( pawnRank == RANK_6
&& distance(strongPawn + 2 * push, weakKing) <= 1
&& (attacks_bb<BISHOP>(weakBishop) & (strongPawn + push))
&& distance<File>(weakBishop, strongPawn) >= 2)
return ScaleFactor(8);
}
return SCALE_FACTOR_NONE;
}
/// KRPP vs KRP. There is just a single rule: if the stronger side has no passed
/// pawns and the defending king is actively placed, the position is drawish.
template<>
ScaleFactor Endgame<KRPPKRP>::operator()(const Position& pos) const {
assert(verify_material(pos, strongSide, RookValueMg, 2));
assert(verify_material(pos, weakSide, RookValueMg, 1));
Square strongPawn1 = lsb(pos.pieces(strongSide, PAWN));
Square strongPawn2 = msb(pos.pieces(strongSide, PAWN));
Square weakKing = pos.square<KING>(weakSide);
// Does the stronger side have a passed pawn?
if (pos.pawn_passed(strongSide, strongPawn1) || pos.pawn_passed(strongSide, strongPawn2))
return SCALE_FACTOR_NONE;
Rank pawnRank = std::max(relative_rank(strongSide, strongPawn1), relative_rank(strongSide, strongPawn2));
if ( distance<File>(weakKing, strongPawn1) <= 1
&& distance<File>(weakKing, strongPawn2) <= 1
&& relative_rank(strongSide, weakKing) > pawnRank)
{
assert(pawnRank > RANK_1 && pawnRank < RANK_7);
return ScaleFactor(7 * pawnRank);
}
return SCALE_FACTOR_NONE;
}
/// K and two or more pawns vs K. There is just a single rule here: if all pawns
/// are on the same rook file and are blocked by the defending king, it's a draw.
template<>
ScaleFactor Endgame<KPsK>::operator()(const Position& pos) const {
assert(pos.non_pawn_material(strongSide) == VALUE_ZERO);
assert(pos.count<PAWN>(strongSide) >= 2);
assert(verify_material(pos, weakSide, VALUE_ZERO, 0));
Square weakKing = pos.square<KING>(weakSide);
Bitboard strongPawns = pos.pieces(strongSide, PAWN);
// If all pawns are ahead of the king on a single rook file, it's a draw.
if ( !(strongPawns & ~(FileABB | FileHBB))
&& !(strongPawns & ~passed_pawn_span(weakSide, weakKing)))
return SCALE_FACTOR_DRAW;
return SCALE_FACTOR_NONE;
}
/// KBP vs KB. There are two rules: if the defending king is somewhere along the
/// path of the pawn, and the square of the king is not of the same color as the
/// stronger side's bishop, it's a draw. If the two bishops have opposite color,
/// it's almost always a draw.
template<>
ScaleFactor Endgame<KBPKB>::operator()(const Position& pos) const {
assert(verify_material(pos, strongSide, BishopValueMg, 1));
assert(verify_material(pos, weakSide, BishopValueMg, 0));
Square strongPawn = pos.square<PAWN>(strongSide);
Square strongBishop = pos.square<BISHOP>(strongSide);
Square weakBishop = pos.square<BISHOP>(weakSide);
Square weakKing = pos.square<KING>(weakSide);
// Case 1: Defending king blocks the pawn, and cannot be driven away
if ( (forward_file_bb(strongSide, strongPawn) & weakKing)
&& ( opposite_colors(weakKing, strongBishop)
|| relative_rank(strongSide, weakKing) <= RANK_6))
return SCALE_FACTOR_DRAW;
// Case 2: Opposite colored bishops
if (opposite_colors(strongBishop, weakBishop))
return SCALE_FACTOR_DRAW;
return SCALE_FACTOR_NONE;
}
/// KBPP vs KB. It detects a few basic draws with opposite-colored bishops
template<>
ScaleFactor Endgame<KBPPKB>::operator()(const Position& pos) const {
assert(verify_material(pos, strongSide, BishopValueMg, 2));
assert(verify_material(pos, weakSide, BishopValueMg, 0));
Square strongBishop = pos.square<BISHOP>(strongSide);
Square weakBishop = pos.square<BISHOP>(weakSide);
if (!opposite_colors(strongBishop, weakBishop))
return SCALE_FACTOR_NONE;
Square weakKing = pos.square<KING>(weakSide);
Square strongPawn1 = lsb(pos.pieces(strongSide, PAWN));
Square strongPawn2 = msb(pos.pieces(strongSide, PAWN));
Square blockSq1, blockSq2;
if (relative_rank(strongSide, strongPawn1) > relative_rank(strongSide, strongPawn2))
{
blockSq1 = strongPawn1 + pawn_push(strongSide);
blockSq2 = make_square(file_of(strongPawn2), rank_of(strongPawn1));
}
else
{
blockSq1 = strongPawn2 + pawn_push(strongSide);
blockSq2 = make_square(file_of(strongPawn1), rank_of(strongPawn2));
}
switch (distance<File>(strongPawn1, strongPawn2))
{
case 0:
// Both pawns are on the same file. It's an easy draw if the defender firmly
// controls some square in the frontmost pawn's path.
if ( file_of(weakKing) == file_of(blockSq1)
&& relative_rank(strongSide, weakKing) >= relative_rank(strongSide, blockSq1)
&& opposite_colors(weakKing, strongBishop))
return SCALE_FACTOR_DRAW;
else
return SCALE_FACTOR_NONE;
case 1:
// Pawns on adjacent files. It's a draw if the defender firmly controls the
// square in front of the frontmost pawn's path, and the square diagonally
// behind this square on the file of the other pawn.
if ( weakKing == blockSq1
&& opposite_colors(weakKing, strongBishop)
&& ( weakBishop == blockSq2
|| (attacks_bb<BISHOP>(blockSq2, pos.pieces()) & pos.pieces(weakSide, BISHOP))
|| distance<Rank>(strongPawn1, strongPawn2) >= 2))
return SCALE_FACTOR_DRAW;
else if ( weakKing == blockSq2
&& opposite_colors(weakKing, strongBishop)
&& ( weakBishop == blockSq1
|| (attacks_bb<BISHOP>(blockSq1, pos.pieces()) & pos.pieces(weakSide, BISHOP))))
return SCALE_FACTOR_DRAW;
else
return SCALE_FACTOR_NONE;
default:
// The pawns are not on the same file or adjacent files. No scaling.
return SCALE_FACTOR_NONE;
}
}
/// KBP vs KN. There is a single rule: if the defending king is somewhere along
/// the path of the pawn, and the square of the king is not of the same color as
/// the stronger side's bishop, it's a draw.
template<>
ScaleFactor Endgame<KBPKN>::operator()(const Position& pos) const {
assert(verify_material(pos, strongSide, BishopValueMg, 1));
assert(verify_material(pos, weakSide, KnightValueMg, 0));
Square strongPawn = pos.square<PAWN>(strongSide);
Square strongBishop = pos.square<BISHOP>(strongSide);
Square weakKing = pos.square<KING>(weakSide);
if ( file_of(weakKing) == file_of(strongPawn)
&& relative_rank(strongSide, strongPawn) < relative_rank(strongSide, weakKing)
&& ( opposite_colors(weakKing, strongBishop)
|| relative_rank(strongSide, weakKing) <= RANK_6))
return SCALE_FACTOR_DRAW;
return SCALE_FACTOR_NONE;
}
/// KP vs KP. This is done by removing the weakest side's pawn and probing the
/// KP vs K bitbase: if the weakest side has a draw without the pawn, it probably
/// has at least a draw with the pawn as well. The exception is when the stronger
/// side's pawn is far advanced and not on a rook file; in this case it is often
/// possible to win (e.g. 8/4k3/3p4/3P4/6K1/8/8/8 w - - 0 1).
template<>
ScaleFactor Endgame<KPKP>::operator()(const Position& pos) const {
assert(verify_material(pos, strongSide, VALUE_ZERO, 1));
assert(verify_material(pos, weakSide, VALUE_ZERO, 1));
// Assume strongSide is white and the pawn is on files A-D
Square strongKing = normalize(pos, strongSide, pos.square<KING>(strongSide));
Square weakKing = normalize(pos, strongSide, pos.square<KING>(weakSide));
Square strongPawn = normalize(pos, strongSide, pos.square<PAWN>(strongSide));
Color us = strongSide == pos.side_to_move() ? WHITE : BLACK;
// If the pawn has advanced to the fifth rank or further, and is not a
// rook pawn, it's too dangerous to assume that it's at least a draw.
if (rank_of(strongPawn) >= RANK_5 && file_of(strongPawn) != FILE_A)
return SCALE_FACTOR_NONE;
// Probe the KPK bitbase with the weakest side's pawn removed. If it's a draw,
// it's probably at least a draw even with the pawn.
return Bitbases::probe(strongKing, strongPawn, weakKing, us) ? SCALE_FACTOR_NONE : SCALE_FACTOR_DRAW;
}
} // namespace Stockfish
-126
View File
@@ -1,126 +0,0 @@
/*
Stockfish, a UCI chess playing engine derived from Glaurung 2.1
Copyright (C) 2004-2023 The Stockfish developers (see AUTHORS file)
Stockfish is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
Stockfish is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef ENDGAME_H_INCLUDED
#define ENDGAME_H_INCLUDED
#include <memory>
#include <string>
#include <type_traits>
#include <unordered_map>
#include <utility>
#include "position.h"
#include "types.h"
namespace Stockfish {
/// EndgameCode lists all supported endgame functions by corresponding codes
enum EndgameCode {
EVALUATION_FUNCTIONS,
KNNK, // KNN vs K
KNNKP, // KNN vs KP
KXK, // Generic "mate lone king" eval
KBNK, // KBN vs K
KPK, // KP vs K
KRKP, // KR vs KP
KRKB, // KR vs KB
KRKN, // KR vs KN
KQKP, // KQ vs KP
KQKR, // KQ vs KR
SCALING_FUNCTIONS,
KBPsK, // KB and pawns vs K
KQKRPs, // KQ vs KR and pawns
KRPKR, // KRP vs KR
KRPKB, // KRP vs KB
KRPPKRP, // KRPP vs KRP
KPsK, // K and pawns vs K
KBPKB, // KBP vs KB
KBPPKB, // KBPP vs KB
KBPKN, // KBP vs KN
KPKP // KP vs KP
};
/// Endgame functions can be of two types depending on whether they return a
/// Value or a ScaleFactor.
template<EndgameCode E> using
eg_type = typename std::conditional<(E < SCALING_FUNCTIONS), Value, ScaleFactor>::type;
/// Base and derived functors for endgame evaluation and scaling functions
template<typename T>
struct EndgameBase {
explicit EndgameBase(Color c) : strongSide(c), weakSide(~c) {}
virtual ~EndgameBase() = default;
virtual T operator()(const Position&) const = 0;
const Color strongSide, weakSide;
};
template<EndgameCode E, typename T = eg_type<E>>
struct Endgame : public EndgameBase<T> {
explicit Endgame(Color c) : EndgameBase<T>(c) {}
T operator()(const Position&) const override;
};
/// The Endgames namespace handles the pointers to endgame evaluation and scaling
/// base objects in two std::map. We use polymorphism to invoke the actual
/// endgame function by calling its virtual operator().
namespace Endgames {
template<typename T> using Ptr = std::unique_ptr<EndgameBase<T>>;
template<typename T> using Map = std::unordered_map<Key, Ptr<T>>;
extern std::pair<Map<Value>, Map<ScaleFactor>> maps;
void init();
template<typename T>
Map<T>& map() {
return std::get<std::is_same<T, ScaleFactor>::value>(maps);
}
template<EndgameCode E, typename T = eg_type<E>>
void add(const std::string& code) {
StateInfo st;
map<T>()[Position().set(code, WHITE, &st).material_key()] = Ptr<T>(new Endgame<E>(WHITE));
map<T>()[Position().set(code, BLACK, &st).material_key()] = Ptr<T>(new Endgame<E>(BLACK));
}
template<typename T>
const EndgameBase<T>* probe(Key key) {
auto it = map<T>().find(key);
return it != map<T>().end() ? it->second.get() : nullptr;
}
}
} // namespace Stockfish
#endif // #ifndef ENDGAME_H_INCLUDED
+369
View File
@@ -0,0 +1,369 @@
/*
Stockfish, a UCI chess playing engine derived from Glaurung 2.1
Copyright (C) 2004-2025 The Stockfish developers (see AUTHORS file)
Stockfish is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
Stockfish is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "engine.h"
#include <cassert>
#include <deque>
#include <iosfwd>
#include <memory>
#include <ostream>
#include <sstream>
#include <string_view>
#include <utility>
#include <vector>
#include "evaluate.h"
#include "misc.h"
#include "nnue/network.h"
#include "nnue/nnue_common.h"
#include "perft.h"
#include "position.h"
#include "search.h"
#include "syzygy/tbprobe.h"
#include "types.h"
#include "uci.h"
#include "ucioption.h"
namespace Stockfish {
namespace NN = Eval::NNUE;
constexpr auto StartFEN = "rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq - 0 1";
constexpr int MaxHashMB = Is64Bit ? 33554432 : 2048;
Engine::Engine(std::optional<std::string> path) :
binaryDirectory(path ? CommandLine::get_binary_directory(*path) : ""),
numaContext(NumaConfig::from_system()),
states(new std::deque<StateInfo>(1)),
threads(),
networks(
numaContext,
NN::Networks(
NN::NetworkBig({EvalFileDefaultNameBig, "None", ""}, NN::EmbeddedNNUEType::BIG),
NN::NetworkSmall({EvalFileDefaultNameSmall, "None", ""}, NN::EmbeddedNNUEType::SMALL))) {
pos.set(StartFEN, false, &states->back());
options.add( //
"Debug Log File", Option("", [](const Option& o) {
start_logger(o);
return std::nullopt;
}));
options.add( //
"NumaPolicy", Option("auto", [this](const Option& o) {
set_numa_config_from_option(o);
return numa_config_information_as_string() + "\n"
+ thread_allocation_information_as_string();
}));
options.add( //
"Threads", Option(1, 1, 1024, [this](const Option&) {
resize_threads();
return thread_allocation_information_as_string();
}));
options.add( //
"Hash", Option(16, 1, MaxHashMB, [this](const Option& o) {
set_tt_size(o);
return std::nullopt;
}));
options.add( //
"Clear Hash", Option([this](const Option&) {
search_clear();
return std::nullopt;
}));
options.add( //
"Ponder", Option(false));
options.add( //
"MultiPV", Option(1, 1, MAX_MOVES));
options.add("Skill Level", Option(20, 0, 20));
options.add("Move Overhead", Option(10, 0, 5000));
options.add("nodestime", Option(0, 0, 10000));
options.add("UCI_Chess960", Option(false));
options.add("UCI_LimitStrength", Option(false));
options.add("UCI_Elo",
Option(Stockfish::Search::Skill::LowestElo, Stockfish::Search::Skill::LowestElo,
Stockfish::Search::Skill::HighestElo));
options.add("UCI_ShowWDL", Option(false));
options.add( //
"SyzygyPath", Option("", [](const Option& o) {
Tablebases::init(o);
return std::nullopt;
}));
options.add("SyzygyProbeDepth", Option(1, 1, 100));
options.add("Syzygy50MoveRule", Option(true));
options.add("SyzygyProbeLimit", Option(7, 0, 7));
options.add( //
"EvalFile", Option(EvalFileDefaultNameBig, [this](const Option& o) {
load_big_network(o);
return std::nullopt;
}));
options.add( //
"EvalFileSmall", Option(EvalFileDefaultNameSmall, [this](const Option& o) {
load_small_network(o);
return std::nullopt;
}));
load_networks();
resize_threads();
}
std::uint64_t Engine::perft(const std::string& fen, Depth depth, bool isChess960) {
verify_networks();
return Benchmark::perft(fen, depth, isChess960);
}
void Engine::go(Search::LimitsType& limits) {
assert(limits.perft == 0);
verify_networks();
threads.start_thinking(options, pos, states, limits);
}
void Engine::stop() { threads.stop = true; }
void Engine::search_clear() {
wait_for_search_finished();
tt.clear(threads);
threads.clear();
// @TODO wont work with multiple instances
Tablebases::init(options["SyzygyPath"]); // Free mapped files
}
void Engine::set_on_update_no_moves(std::function<void(const Engine::InfoShort&)>&& f) {
updateContext.onUpdateNoMoves = std::move(f);
}
void Engine::set_on_update_full(std::function<void(const Engine::InfoFull&)>&& f) {
updateContext.onUpdateFull = std::move(f);
}
void Engine::set_on_iter(std::function<void(const Engine::InfoIter&)>&& f) {
updateContext.onIter = std::move(f);
}
void Engine::set_on_bestmove(std::function<void(std::string_view, std::string_view)>&& f) {
updateContext.onBestmove = std::move(f);
}
void Engine::set_on_verify_networks(std::function<void(std::string_view)>&& f) {
onVerifyNetworks = std::move(f);
}
void Engine::wait_for_search_finished() { threads.main_thread()->wait_for_search_finished(); }
void Engine::set_position(const std::string& fen, const std::vector<std::string>& moves) {
// Drop the old state and create a new one
states = StateListPtr(new std::deque<StateInfo>(1));
pos.set(fen, options["UCI_Chess960"], &states->back());
for (const auto& move : moves)
{
auto m = UCIEngine::to_move(pos, move);
if (m == Move::none())
break;
states->emplace_back();
pos.do_move(m, states->back());
}
}
// modifiers
void Engine::set_numa_config_from_option(const std::string& o) {
if (o == "auto" || o == "system")
{
numaContext.set_numa_config(NumaConfig::from_system());
}
else if (o == "hardware")
{
// Don't respect affinity set in the system.
numaContext.set_numa_config(NumaConfig::from_system(false));
}
else if (o == "none")
{
numaContext.set_numa_config(NumaConfig{});
}
else
{
numaContext.set_numa_config(NumaConfig::from_string(o));
}
// Force reallocation of threads in case affinities need to change.
resize_threads();
threads.ensure_network_replicated();
}
void Engine::resize_threads() {
threads.wait_for_search_finished();
threads.set(numaContext.get_numa_config(), {options, threads, tt, networks}, updateContext);
// Reallocate the hash with the new threadpool size
set_tt_size(options["Hash"]);
threads.ensure_network_replicated();
}
void Engine::set_tt_size(size_t mb) {
wait_for_search_finished();
tt.resize(mb, threads);
}
void Engine::set_ponderhit(bool b) { threads.main_manager()->ponder = b; }
// network related
void Engine::verify_networks() const {
networks->big.verify(options["EvalFile"], onVerifyNetworks);
networks->small.verify(options["EvalFileSmall"], onVerifyNetworks);
}
void Engine::load_networks() {
networks.modify_and_replicate([this](NN::Networks& networks_) {
networks_.big.load(binaryDirectory, options["EvalFile"]);
networks_.small.load(binaryDirectory, options["EvalFileSmall"]);
});
threads.clear();
threads.ensure_network_replicated();
}
void Engine::load_big_network(const std::string& file) {
networks.modify_and_replicate(
[this, &file](NN::Networks& networks_) { networks_.big.load(binaryDirectory, file); });
threads.clear();
threads.ensure_network_replicated();
}
void Engine::load_small_network(const std::string& file) {
networks.modify_and_replicate(
[this, &file](NN::Networks& networks_) { networks_.small.load(binaryDirectory, file); });
threads.clear();
threads.ensure_network_replicated();
}
void Engine::save_network(const std::pair<std::optional<std::string>, std::string> files[2]) {
networks.modify_and_replicate([&files](NN::Networks& networks_) {
networks_.big.save(files[0].first);
networks_.small.save(files[1].first);
});
}
// utility functions
void Engine::trace_eval() const {
StateListPtr trace_states(new std::deque<StateInfo>(1));
Position p;
p.set(pos.fen(), options["UCI_Chess960"], &trace_states->back());
verify_networks();
sync_cout << "\n" << Eval::trace(p, *networks) << sync_endl;
}
const OptionsMap& Engine::get_options() const { return options; }
OptionsMap& Engine::get_options() { return options; }
std::string Engine::fen() const { return pos.fen(); }
void Engine::flip() { pos.flip(); }
std::string Engine::visualize() const {
std::stringstream ss;
ss << pos;
return ss.str();
}
int Engine::get_hashfull(int maxAge) const { return tt.hashfull(maxAge); }
std::vector<std::pair<size_t, size_t>> Engine::get_bound_thread_count_by_numa_node() const {
auto counts = threads.get_bound_thread_count_by_numa_node();
const NumaConfig& cfg = numaContext.get_numa_config();
std::vector<std::pair<size_t, size_t>> ratios;
NumaIndex n = 0;
for (; n < counts.size(); ++n)
ratios.emplace_back(counts[n], cfg.num_cpus_in_numa_node(n));
if (!counts.empty())
for (; n < cfg.num_numa_nodes(); ++n)
ratios.emplace_back(0, cfg.num_cpus_in_numa_node(n));
return ratios;
}
std::string Engine::get_numa_config_as_string() const {
return numaContext.get_numa_config().to_string();
}
std::string Engine::numa_config_information_as_string() const {
auto cfgStr = get_numa_config_as_string();
return "Available processors: " + cfgStr;
}
std::string Engine::thread_binding_information_as_string() const {
auto boundThreadsByNode = get_bound_thread_count_by_numa_node();
std::stringstream ss;
if (boundThreadsByNode.empty())
return ss.str();
bool isFirst = true;
for (auto&& [current, total] : boundThreadsByNode)
{
if (!isFirst)
ss << ":";
ss << current << "/" << total;
isFirst = false;
}
return ss.str();
}
std::string Engine::thread_allocation_information_as_string() const {
std::stringstream ss;
size_t threadsSize = threads.size();
ss << "Using " << threadsSize << (threadsSize > 1 ? " threads" : " thread");
auto boundThreadsByNodeStr = thread_binding_information_as_string();
if (boundThreadsByNodeStr.empty())
return ss.str();
ss << " with NUMA node thread binding: ";
ss << boundThreadsByNodeStr;
return ss.str();
}
}
+130
View File
@@ -0,0 +1,130 @@
/*
Stockfish, a UCI chess playing engine derived from Glaurung 2.1
Copyright (C) 2004-2025 The Stockfish developers (see AUTHORS file)
Stockfish is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
Stockfish is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef ENGINE_H_INCLUDED
#define ENGINE_H_INCLUDED
#include <cstddef>
#include <cstdint>
#include <functional>
#include <optional>
#include <string>
#include <string_view>
#include <utility>
#include <vector>
#include "nnue/network.h"
#include "numa.h"
#include "position.h"
#include "search.h"
#include "syzygy/tbprobe.h" // for Stockfish::Depth
#include "thread.h"
#include "tt.h"
#include "ucioption.h"
namespace Stockfish {
class Engine {
public:
using InfoShort = Search::InfoShort;
using InfoFull = Search::InfoFull;
using InfoIter = Search::InfoIteration;
Engine(std::optional<std::string> path = std::nullopt);
// Cannot be movable due to components holding backreferences to fields
Engine(const Engine&) = delete;
Engine(Engine&&) = delete;
Engine& operator=(const Engine&) = delete;
Engine& operator=(Engine&&) = delete;
~Engine() { wait_for_search_finished(); }
std::uint64_t perft(const std::string& fen, Depth depth, bool isChess960);
// non blocking call to start searching
void go(Search::LimitsType&);
// non blocking call to stop searching
void stop();
// blocking call to wait for search to finish
void wait_for_search_finished();
// set a new position, moves are in UCI format
void set_position(const std::string& fen, const std::vector<std::string>& moves);
// modifiers
void set_numa_config_from_option(const std::string& o);
void resize_threads();
void set_tt_size(size_t mb);
void set_ponderhit(bool);
void search_clear();
void set_on_update_no_moves(std::function<void(const InfoShort&)>&&);
void set_on_update_full(std::function<void(const InfoFull&)>&&);
void set_on_iter(std::function<void(const InfoIter&)>&&);
void set_on_bestmove(std::function<void(std::string_view, std::string_view)>&&);
void set_on_verify_networks(std::function<void(std::string_view)>&&);
// network related
void verify_networks() const;
void load_networks();
void load_big_network(const std::string& file);
void load_small_network(const std::string& file);
void save_network(const std::pair<std::optional<std::string>, std::string> files[2]);
// utility functions
void trace_eval() const;
const OptionsMap& get_options() const;
OptionsMap& get_options();
int get_hashfull(int maxAge = 0) const;
std::string fen() const;
void flip();
std::string visualize() const;
std::vector<std::pair<size_t, size_t>> get_bound_thread_count_by_numa_node() const;
std::string get_numa_config_as_string() const;
std::string numa_config_information_as_string() const;
std::string thread_allocation_information_as_string() const;
std::string thread_binding_information_as_string() const;
private:
const std::string binaryDirectory;
NumaReplicationContext numaContext;
Position pos;
StateListPtr states;
OptionsMap options;
ThreadPool threads;
TranspositionTable tt;
LazyNumaReplicated<Eval::NNUE::Networks> networks;
Search::SearchManager::UpdateContext updateContext;
std::function<void(std::string_view)> onVerifyNetworks;
};
} // namespace Stockfish
#endif // #ifndef ENGINE_H_INCLUDED
+71 -1105
View File
File diff suppressed because it is too large Load Diff
+21 -20
View File
@@ -1,6 +1,6 @@
/* /*
Stockfish, a UCI chess playing engine derived from Glaurung 2.1 Stockfish, a UCI chess playing engine derived from Glaurung 2.1
Copyright (C) 2004-2023 The Stockfish developers (see AUTHORS file) Copyright (C) 2004-2025 The Stockfish developers (see AUTHORS file)
Stockfish is free software: you can redistribute it and/or modify Stockfish is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by it under the terms of the GNU General Public License as published by
@@ -20,7 +20,6 @@
#define EVALUATE_H_INCLUDED #define EVALUATE_H_INCLUDED
#include <string> #include <string>
#include <optional>
#include "types.h" #include "types.h"
@@ -30,26 +29,28 @@ class Position;
namespace Eval { namespace Eval {
std::string trace(Position& pos); // The default net name MUST follow the format nn-[SHA256 first 12 digits].nnue
Value evaluate(const Position& pos); // for the build process (profile-build and fishtest) to work. Do not change the
// name of the macro or the location where this macro is defined, as it is used
// in the Makefile/Fishtest.
#define EvalFileDefaultNameBig "nn-287197aae49d.nnue"
#define EvalFileDefaultNameSmall "nn-287197aae49d.nnue"
extern bool useNNUE; namespace NNUE {
extern std::string currentEvalFileName; struct Networks;
struct AccumulatorCaches;
}
// The default net name MUST follow the format nn-[SHA256 first 12 digits].nnue std::string trace(Position& pos, const Eval::NNUE::Networks& networks);
// 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.
#define EvalFileDefaultName "nn-5af11540bbfe.nnue"
namespace NNUE { int simple_eval(const Position& pos, Color c);
bool use_smallnet(const Position& pos);
Value evaluate(const NNUE::Networks& networks,
const Position& pos,
Eval::NNUE::AccumulatorCaches& caches,
int optimism);
} // namespace Eval
void init(); } // namespace Stockfish
void verify();
} // namespace NNUE #endif // #ifndef EVALUATE_H_INCLUDED
} // namespace Eval
} // namespace Stockfish
#endif // #ifndef EVALUATE_H_INCLUDED
+165
View File
@@ -0,0 +1,165 @@
/*
Stockfish, a UCI chess playing engine derived from Glaurung 2.1
Copyright (C) 2004-2025 The Stockfish developers (see AUTHORS file)
Stockfish is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
Stockfish is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef HISTORY_H_INCLUDED
#define HISTORY_H_INCLUDED
#include <algorithm>
#include <array>
#include <cassert>
#include <cmath>
#include <cstdint>
#include <cstdlib>
#include <limits>
#include <type_traits> // IWYU pragma: keep
#include "misc.h"
#include "position.h"
namespace Stockfish {
constexpr int PAWN_HISTORY_SIZE = 512; // has to be a power of 2
constexpr int CORRECTION_HISTORY_SIZE = 32768; // has to be a power of 2
constexpr int CORRECTION_HISTORY_LIMIT = 1024;
constexpr int LOW_PLY_HISTORY_SIZE = 4;
static_assert((PAWN_HISTORY_SIZE & (PAWN_HISTORY_SIZE - 1)) == 0,
"PAWN_HISTORY_SIZE has to be a power of 2");
static_assert((CORRECTION_HISTORY_SIZE & (CORRECTION_HISTORY_SIZE - 1)) == 0,
"CORRECTION_HISTORY_SIZE has to be a power of 2");
enum PawnHistoryType {
Normal,
Correction
};
template<PawnHistoryType T = Normal>
inline int pawn_structure_index(const Position& pos) {
return pos.pawn_key() & ((T == Normal ? PAWN_HISTORY_SIZE : CORRECTION_HISTORY_SIZE) - 1);
}
inline int minor_piece_index(const Position& pos) {
return pos.minor_piece_key() & (CORRECTION_HISTORY_SIZE - 1);
}
template<Color c>
inline int non_pawn_index(const Position& pos) {
return pos.non_pawn_key(c) & (CORRECTION_HISTORY_SIZE - 1);
}
// StatsEntry is the container of various numerical statistics. We use a class
// instead of a naked value to directly call history update operator<<() on
// the entry. The first template parameter T is the base type of the array,
// and the second template parameter D limits the range of updates in [-D, D]
// when we update values with the << operator
template<typename T, int D>
class StatsEntry {
static_assert(std::is_arithmetic<T>::value, "Not an arithmetic type");
static_assert(D <= std::numeric_limits<T>::max(), "D overflows T");
T entry;
public:
StatsEntry& operator=(const T& v) {
entry = v;
return *this;
}
operator const T&() const { return entry; }
void operator<<(int bonus) {
// Make sure that bonus is in range [-D, D]
int clampedBonus = std::clamp(bonus, -D, D);
entry += clampedBonus - entry * std::abs(clampedBonus) / D;
assert(std::abs(entry) <= D);
}
};
enum StatsType {
NoCaptures,
Captures
};
template<typename T, int D, std::size_t... Sizes>
using Stats = MultiArray<StatsEntry<T, D>, Sizes...>;
// ButterflyHistory records how often quiet moves have been successful or unsuccessful
// during the current search, and is used for reduction and move ordering decisions.
// It uses 2 tables (one for each color) indexed by the move's from and to squares,
// see https://www.chessprogramming.org/Butterfly_Boards (~11 elo)
using ButterflyHistory = Stats<std::int16_t, 7183, COLOR_NB, int(SQUARE_NB) * int(SQUARE_NB)>;
// LowPlyHistory is adressed by play and move's from and to squares, used
// to improve move ordering near the root
using LowPlyHistory =
Stats<std::int16_t, 7183, LOW_PLY_HISTORY_SIZE, int(SQUARE_NB) * int(SQUARE_NB)>;
// CapturePieceToHistory is addressed by a move's [piece][to][captured piece type]
using CapturePieceToHistory = Stats<std::int16_t, 10692, PIECE_NB, SQUARE_NB, PIECE_TYPE_NB>;
// PieceToHistory is like ButterflyHistory but is addressed by a move's [piece][to]
using PieceToHistory = Stats<std::int16_t, 30000, PIECE_NB, SQUARE_NB>;
// ContinuationHistory is the combined history of a given pair of moves, usually
// the current one given a previous one. The nested history table is based on
// PieceToHistory instead of ButterflyBoards.
// (~63 elo)
using ContinuationHistory = MultiArray<PieceToHistory, PIECE_NB, SQUARE_NB>;
// PawnHistory is addressed by the pawn structure and a move's [piece][to]
using PawnHistory = Stats<std::int16_t, 8192, PAWN_HISTORY_SIZE, PIECE_NB, SQUARE_NB>;
// Correction histories record differences between the static evaluation of
// positions and their search score. It is used to improve the static evaluation
// used by some search heuristics.
// see https://www.chessprogramming.org/Static_Evaluation_Correction_History
enum CorrHistType {
Pawn, // By color and pawn structure
Minor, // By color and positions of minor pieces (Knight, Bishop)
NonPawn, // By non-pawn material positions and color
PieceTo, // By [piece][to] move
Continuation, // Combined history of move pairs
};
namespace Detail {
template<CorrHistType>
struct CorrHistTypedef {
using type = Stats<std::int16_t, CORRECTION_HISTORY_LIMIT, CORRECTION_HISTORY_SIZE, COLOR_NB>;
};
template<>
struct CorrHistTypedef<PieceTo> {
using type = Stats<std::int16_t, CORRECTION_HISTORY_LIMIT, PIECE_NB, SQUARE_NB>;
};
template<>
struct CorrHistTypedef<Continuation> {
using type = MultiArray<CorrHistTypedef<PieceTo>::type, PIECE_NB, SQUARE_NB>;
};
}
template<CorrHistType T>
using CorrectionHistory = typename Detail::CorrHistTypedef<T>::type;
} // namespace Stockfish
#endif // #ifndef HISTORY_H_INCLUDED
+162 -54
View File
@@ -26,7 +26,9 @@
defined(__SSSE3__) || \ defined(__SSSE3__) || \
defined(__SSE4_1__) || \ defined(__SSE4_1__) || \
defined(__SSE4_2__) || \ defined(__SSE4_2__) || \
defined(__neon__) defined(__neon__) || \
defined(__ARM_NEON) || \
defined(__ALTIVEC__)
# define INCBIN_ALIGNMENT_INDEX 4 # define INCBIN_ALIGNMENT_INDEX 4
#elif ULONG_MAX != 0xffffffffu #elif ULONG_MAX != 0xffffffffu
# define INCBIN_ALIGNMENT_INDEX 3 # define INCBIN_ALIGNMENT_INDEX 3
@@ -64,6 +66,9 @@
X X
#define INCBIN_INVOKE(N, ...) \ #define INCBIN_INVOKE(N, ...) \
INCBIN_EVAL(N(__VA_ARGS__)) INCBIN_EVAL(N(__VA_ARGS__))
/* Variable argument count for overloading by arity */
#define INCBIN_VA_ARG_COUNTER(_1, _2, _3, N, ...) N
#define INCBIN_VA_ARGC(...) INCBIN_VA_ARG_COUNTER(__VA_ARGS__, 3, 2, 1, 0)
/* Green Hills uses a different directive for including binary data */ /* Green Hills uses a different directive for including binary data */
#if defined(__ghs__) #if defined(__ghs__)
@@ -117,28 +122,49 @@
#endif #endif
/** /**
* @brief Optionally override the linker section into which data is emitted. * @brief Optionally override the linker section into which size and data is
* * emitted.
* @warning If you use this facility, you'll have to deal with platform-specific linker output *
* section naming on your own * @warning If you use this facility, you might have to deal with
* * platform-specific linker output section naming on your own.
* Overriding the default linker output section, e.g for esp8266/Arduino:
* @code
* #define INCBIN_OUTPUT_SECTION ".irom.text"
* #include "incbin.h"
* INCBIN(Foo, "foo.txt");
* // Data is emitted into program memory that never gets copied to RAM
* @endcode
*/ */
#if !defined(INCBIN_OUTPUT_SECTION) #if !defined(INCBIN_OUTPUT_SECTION)
# if defined(__APPLE__) # if defined(__APPLE__)
# define INCBIN_OUTPUT_SECTION ".const_data" # define INCBIN_OUTPUT_SECTION ".const_data"
# else # else
# define INCBIN_OUTPUT_SECTION ".rodata" # define INCBIN_OUTPUT_SECTION ".rodata"
# endif # endif
#endif #endif
/**
* @brief Optionally override the linker section into which data is emitted.
*
* @warning If you use this facility, you might have to deal with
* platform-specific linker output section naming on your own.
*/
#if !defined(INCBIN_OUTPUT_DATA_SECTION)
# define INCBIN_OUTPUT_DATA_SECTION INCBIN_OUTPUT_SECTION
#endif
/**
* @brief Optionally override the linker section into which size is emitted.
*
* @warning If you use this facility, you might have to deal with
* platform-specific linker output section naming on your own.
*
* @note This is useful for Harvard architectures where program memory cannot
* be directly read from the program without special instructions. With this you
* can chose to put the size variable in RAM rather than ROM.
*/
#if !defined(INCBIN_OUTPUT_SIZE_SECTION)
# define INCBIN_OUTPUT_SIZE_SECTION INCBIN_OUTPUT_SECTION
#endif
#if defined(__APPLE__) #if defined(__APPLE__)
# include "TargetConditionals.h"
# if defined(TARGET_OS_IPHONE) && !defined(INCBIN_SILENCE_BITCODE_WARNING)
# warning "incbin is incompatible with bitcode. Using the library will break upload to App Store if you have bitcode enabled. Add `#define INCBIN_SILENCE_BITCODE_WARNING` before including this header to silence this warning."
# endif
/* The directives are different for Apple branded compilers */ /* The directives are different for Apple branded compilers */
# define INCBIN_SECTION INCBIN_OUTPUT_SECTION "\n" # define INCBIN_SECTION INCBIN_OUTPUT_SECTION "\n"
# define INCBIN_GLOBAL(NAME) ".globl " INCBIN_MANGLE INCBIN_STRINGIZE(INCBIN_PREFIX) #NAME "\n" # define INCBIN_GLOBAL(NAME) ".globl " INCBIN_MANGLE INCBIN_STRINGIZE(INCBIN_PREFIX) #NAME "\n"
@@ -179,27 +205,17 @@
/** /**
* @brief Specify the prefix to use for symbol names. * @brief Specify the prefix to use for symbol names.
* *
* By default this is `g', producing symbols of the form: * @note By default this is "g".
* @code
* #include "incbin.h"
* INCBIN(Foo, "foo.txt");
* *
* // Now you have the following symbols:
* // const unsigned char gFooData[];
* // const unsigned char *const gFooEnd;
* // const unsigned int gFooSize;
* @endcode
*
* If however you specify a prefix before including: e.g:
* @code * @code
* #define INCBIN_PREFIX incbin * #define INCBIN_PREFIX incbin
* #include "incbin.h" * #include "incbin.h"
* INCBIN(Foo, "foo.txt"); * INCBIN(Foo, "foo.txt");
* *
* // Now you have the following symbols instead: * // Now you have the following symbols instead:
* // const unsigned char incbinFooData[]; * // const unsigned char incbinFoo<data>[];
* // const unsigned char *const incbinFooEnd; * // const unsigned char *const incbinFoo<end>;
* // const unsigned int incbinFooSize; * // const unsigned int incbinFoo<size>;
* @endcode * @endcode
*/ */
#if !defined(INCBIN_PREFIX) #if !defined(INCBIN_PREFIX)
@@ -213,18 +229,8 @@
* - INCBIN_STYLE_CAMEL "CamelCase" * - INCBIN_STYLE_CAMEL "CamelCase"
* - INCBIN_STYLE_SNAKE "snake_case" * - INCBIN_STYLE_SNAKE "snake_case"
* *
* Default option is *INCBIN_STYLE_CAMEL* producing symbols of the form: * @note By default this is INCBIN_STYLE_CAMEL
* @code
* #include "incbin.h"
* INCBIN(Foo, "foo.txt");
* *
* // Now you have the following symbols:
* // const unsigned char <prefix>FooData[];
* // const unsigned char *const <prefix>FooEnd;
* // const unsigned int <prefix>FooSize;
* @endcode
*
* If however you specify a style before including: e.g:
* @code * @code
* #define INCBIN_STYLE INCBIN_STYLE_SNAKE * #define INCBIN_STYLE INCBIN_STYLE_SNAKE
* #include "incbin.h" * #include "incbin.h"
@@ -288,23 +294,38 @@
* The symbol names are a concatenation of `INCBIN_PREFIX' before *NAME*; with * The symbol names are a concatenation of `INCBIN_PREFIX' before *NAME*; with
* "Data", as well as "End" and "Size" after. An example is provided below. * "Data", as well as "End" and "Size" after. An example is provided below.
* *
* @param TYPE Optional array type. Omitting this picks a default of `unsigned char`.
* @param NAME The name given for the binary data * @param NAME The name given for the binary data
* *
* @code * @code
* INCBIN_EXTERN(Foo); * INCBIN_EXTERN(Foo);
* *
* // Now you have the following symbols: * // Now you have the following symbols:
* // extern const unsigned char <prefix>FooData[]; * // extern const unsigned char <prefix>Foo<data>[];
* // extern const unsigned char *const <prefix>FooEnd; * // extern const unsigned char *const <prefix>Foo<end>;
* // extern const unsigned int <prefix>FooSize; * // extern const unsigned int <prefix>Foo<size>;
* @endcode
*
* You may specify a custom optional data type as well as the first argument.
* @code
* INCBIN_EXTERN(custom_type, Foo);
*
* // Now you have the following symbols:
* // extern const custom_type <prefix>Foo<data>[];
* // extern const custom_type *const <prefix>Foo<end>;
* // extern const unsigned int <prefix>Foo<size>;
* @endcode * @endcode
*/ */
#define INCBIN_EXTERN(NAME) \ #define INCBIN_EXTERN(...) \
INCBIN_EXTERNAL const INCBIN_ALIGN unsigned char \ INCBIN_CONCATENATE(INCBIN_EXTERN_, INCBIN_VA_ARGC(__VA_ARGS__))(__VA_ARGS__)
#define INCBIN_EXTERN_1(NAME, ...) \
INCBIN_EXTERN_2(unsigned char, NAME)
#define INCBIN_EXTERN_2(TYPE, NAME) \
INCBIN_EXTERNAL const INCBIN_ALIGN TYPE \
INCBIN_CONCATENATE( \ INCBIN_CONCATENATE( \
INCBIN_CONCATENATE(INCBIN_PREFIX, NAME), \ INCBIN_CONCATENATE(INCBIN_PREFIX, NAME), \
INCBIN_STYLE_IDENT(DATA))[]; \ INCBIN_STYLE_IDENT(DATA))[]; \
INCBIN_EXTERNAL const INCBIN_ALIGN unsigned char *const \ INCBIN_EXTERNAL const INCBIN_ALIGN TYPE *const \
INCBIN_CONCATENATE( \ INCBIN_CONCATENATE( \
INCBIN_CONCATENATE(INCBIN_PREFIX, NAME), \ INCBIN_CONCATENATE(INCBIN_PREFIX, NAME), \
INCBIN_STYLE_IDENT(END)); \ INCBIN_STYLE_IDENT(END)); \
@@ -313,6 +334,29 @@
INCBIN_CONCATENATE(INCBIN_PREFIX, NAME), \ INCBIN_CONCATENATE(INCBIN_PREFIX, NAME), \
INCBIN_STYLE_IDENT(SIZE)) INCBIN_STYLE_IDENT(SIZE))
/**
* @brief Externally reference textual data included in another translation unit.
*
* Produces three external symbols that reference the textual data included in
* another translation unit.
*
* The symbol names are a concatenation of `INCBIN_PREFIX' before *NAME*; with
* "Data", as well as "End" and "Size" after. An example is provided below.
*
* @param NAME The name given for the textual data
*
* @code
* INCBIN_EXTERN(Foo);
*
* // Now you have the following symbols:
* // extern const char <prefix>Foo<data>[];
* // extern const char *const <prefix>Foo<end>;
* // extern const unsigned int <prefix>Foo<size>;
* @endcode
*/
#define INCTXT_EXTERN(NAME) \
INCBIN_EXTERN_2(char, NAME)
/** /**
* @brief Include a binary file into the current translation unit. * @brief Include a binary file into the current translation unit.
* *
@@ -322,6 +366,7 @@
* The symbol names are a concatenation of `INCBIN_PREFIX' before *NAME*; with * The symbol names are a concatenation of `INCBIN_PREFIX' before *NAME*; with
* "Data", as well as "End" and "Size" after. An example is provided below. * "Data", as well as "End" and "Size" after. An example is provided below.
* *
* @param TYPE Optional array type. Omitting this picks a default of `unsigned char`.
* @param NAME The name to associate with this binary data (as an identifier.) * @param NAME The name to associate with this binary data (as an identifier.)
* @param FILENAME The file to include (as a string literal.) * @param FILENAME The file to include (as a string literal.)
* *
@@ -329,9 +374,20 @@
* INCBIN(Icon, "icon.png"); * INCBIN(Icon, "icon.png");
* *
* // Now you have the following symbols: * // Now you have the following symbols:
* // const unsigned char <prefix>IconData[]; * // const unsigned char <prefix>Icon<data>[];
* // const unsigned char *const <prefix>IconEnd; * // const unsigned char *const <prefix>Icon<end>;
* // const unsigned int <prefix>IconSize; * // const unsigned int <prefix>Icon<size>;
* @endcode
*
* You may specify a custom optional data type as well as the first argument.
* These macros are specialized by arity.
* @code
* INCBIN(custom_type, Icon, "icon.png");
*
* // Now you have the following symbols:
* // const custom_type <prefix>Icon<data>[];
* // const custom_type *const <prefix>Icon<end>;
* // const unsigned int <prefix>Icon<size>;
* @endcode * @endcode
* *
* @warning This must be used in global scope * @warning This must be used in global scope
@@ -341,15 +397,28 @@
* please @see INCBIN_EXTERN. * please @see INCBIN_EXTERN.
*/ */
#ifdef _MSC_VER #ifdef _MSC_VER
#define INCBIN(NAME, FILENAME) \ # define INCBIN(NAME, FILENAME) \
INCBIN_EXTERN(NAME) INCBIN_EXTERN(NAME)
#else #else
#define INCBIN(NAME, FILENAME) \ # define INCBIN(...) \
INCBIN_CONCATENATE(INCBIN_, INCBIN_VA_ARGC(__VA_ARGS__))(__VA_ARGS__)
# if defined(__GNUC__)
# define INCBIN_1(...) _Pragma("GCC error \"Single argument INCBIN not allowed\"")
# elif defined(__clang__)
# define INCBIN_1(...) _Pragma("clang error \"Single argument INCBIN not allowed\"")
# else
# define INCBIN_1(...) /* Cannot do anything here */
# endif
# define INCBIN_2(NAME, FILENAME) \
INCBIN_3(unsigned char, NAME, FILENAME)
# define INCBIN_3(TYPE, NAME, FILENAME) INCBIN_COMMON(TYPE, NAME, FILENAME, /* No terminator for binary data */)
# define INCBIN_COMMON(TYPE, NAME, FILENAME, TERMINATOR) \
__asm__(INCBIN_SECTION \ __asm__(INCBIN_SECTION \
INCBIN_GLOBAL_LABELS(NAME, DATA) \ INCBIN_GLOBAL_LABELS(NAME, DATA) \
INCBIN_ALIGN_HOST \ INCBIN_ALIGN_HOST \
INCBIN_MANGLE INCBIN_STRINGIZE(INCBIN_PREFIX) #NAME INCBIN_STYLE_STRING(DATA) ":\n" \ INCBIN_MANGLE INCBIN_STRINGIZE(INCBIN_PREFIX) #NAME INCBIN_STYLE_STRING(DATA) ":\n" \
INCBIN_MACRO " \"" FILENAME "\"\n" \ INCBIN_MACRO " \"" FILENAME "\"\n" \
TERMINATOR \
INCBIN_GLOBAL_LABELS(NAME, END) \ INCBIN_GLOBAL_LABELS(NAME, END) \
INCBIN_ALIGN_BYTE \ INCBIN_ALIGN_BYTE \
INCBIN_MANGLE INCBIN_STRINGIZE(INCBIN_PREFIX) #NAME INCBIN_STYLE_STRING(END) ":\n" \ INCBIN_MANGLE INCBIN_STRINGIZE(INCBIN_PREFIX) #NAME INCBIN_STYLE_STRING(END) ":\n" \
@@ -362,7 +431,46 @@
INCBIN_ALIGN_HOST \ INCBIN_ALIGN_HOST \
".text\n" \ ".text\n" \
); \ ); \
INCBIN_EXTERN(NAME) INCBIN_EXTERN(TYPE, NAME)
#endif
/**
* @brief Include a textual file into the current translation unit.
*
* This behaves the same as INCBIN except it produces char compatible arrays
* and implicitly adds a null-terminator byte, thus the size of data included
* by this is one byte larger than that of INCBIN.
*
* Includes a textual file into the current translation unit, producing three
* symbols for objects that encode the data and size respectively.
*
* The symbol names are a concatenation of `INCBIN_PREFIX' before *NAME*; with
* "Data", as well as "End" and "Size" after. An example is provided below.
*
* @param NAME The name to associate with this binary data (as an identifier.)
* @param FILENAME The file to include (as a string literal.)
*
* @code
* INCTXT(Readme, "readme.txt");
*
* // Now you have the following symbols:
* // const char <prefix>Readme<data>[];
* // const char *const <prefix>Readme<end>;
* // const unsigned int <prefix>Readme<size>;
* @endcode
*
* @warning This must be used in global scope
* @warning The identifiers may be different if INCBIN_STYLE is not default
*
* To externally reference the data included by this in another translation unit
* please @see INCBIN_EXTERN.
*/
#if defined(_MSC_VER)
# define INCTXT(NAME, FILENAME) \
INCBIN_EXTERN(NAME)
#else
# define INCTXT(NAME, FILENAME) \
INCBIN_COMMON(char, NAME, FILENAME, INCBIN_BYTE "0\n")
#endif #endif
#endif
#endif
+13 -22
View File
@@ -1,6 +1,6 @@
/* /*
Stockfish, a UCI chess playing engine derived from Glaurung 2.1 Stockfish, a UCI chess playing engine derived from Glaurung 2.1
Copyright (C) 2004-2023 The Stockfish developers (see AUTHORS file) Copyright (C) 2004-2025 The Stockfish developers (see AUTHORS file)
Stockfish is free software: you can redistribute it and/or modify Stockfish is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by it under the terms of the GNU General Public License as published by
@@ -19,35 +19,26 @@
#include <iostream> #include <iostream>
#include "bitboard.h" #include "bitboard.h"
#include "endgame.h" #include "misc.h"
#include "position.h" #include "position.h"
#include "psqt.h" #include "types.h"
#include "search.h"
#include "syzygy/tbprobe.h"
#include "thread.h"
#include "tt.h"
#include "uci.h" #include "uci.h"
#include "tune.h"
using namespace Stockfish; using namespace Stockfish;
int main(int argc, char* argv[]) { int main(int argc, char* argv[]) {
std::cout << engine_info() << std::endl; std::cout << engine_info() << std::endl;
CommandLine::init(argc, argv); Bitboards::init();
UCI::init(Options); Position::init();
Tune::init();
PSQT::init();
Bitboards::init();
Position::init();
Bitbases::init();
Endgames::init();
Threads.set(size_t(Options["Threads"]));
Search::clear(); // After threads are up
Eval::NNUE::init();
UCI::loop(argc, argv); UCIEngine uci(argc, argv);
Threads.set(0); Tune::init(uci.engine_options());
return 0;
uci.loop();
return 0;
} }
-229
View File
@@ -1,229 +0,0 @@
/*
Stockfish, a UCI chess playing engine derived from Glaurung 2.1
Copyright (C) 2004-2023 The Stockfish developers (see AUTHORS file)
Stockfish is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
Stockfish is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <cassert>
#include <cstring> // For std::memset
#include "material.h"
#include "thread.h"
using namespace std;
namespace Stockfish {
namespace {
#define S(mg, eg) make_score(mg, eg)
// Polynomial material imbalance parameters
// One Score parameter for each pair (our piece, another of our pieces)
constexpr Score QuadraticOurs[][PIECE_TYPE_NB] = {
// OUR PIECE 2
// bishop pair pawn knight bishop rook queen
{S(1419, 1455) }, // Bishop pair
{S( 101, 28), S( 37, 39) }, // Pawn
{S( 57, 64), S(249, 187), S(-49, -62) }, // Knight OUR PIECE 1
{S( 0, 0), S(118, 137), S( 10, 27), S( 0, 0) }, // Bishop
{S( -63, -68), S( -5, 3), S(100, 81), S(132, 118), S(-246, -244) }, // Rook
{S(-210, -211), S( 37, 14), S(147, 141), S(161, 105), S(-158, -174), S(-9,-31) } // Queen
};
// One Score parameter for each pair (our piece, their piece)
constexpr Score QuadraticTheirs[][PIECE_TYPE_NB] = {
// THEIR PIECE
// bishop pair pawn knight bishop rook queen
{ }, // Bishop pair
{S( 33, 30) }, // Pawn
{S( 46, 18), S(106, 84) }, // Knight OUR PIECE
{S( 75, 35), S( 59, 44), S( 60, 15) }, // Bishop
{S( 26, 35), S( 6, 22), S( 38, 39), S(-12, -2) }, // Rook
{S( 97, 93), S(100, 163), S(-58, -91), S(112, 192), S(276, 225) } // Queen
};
#undef S
// Endgame evaluation and scaling functions are accessed directly and not through
// the function maps because they correspond to more than one material hash key.
Endgame<KXK> EvaluateKXK[] = { Endgame<KXK>(WHITE), Endgame<KXK>(BLACK) };
Endgame<KBPsK> ScaleKBPsK[] = { Endgame<KBPsK>(WHITE), Endgame<KBPsK>(BLACK) };
Endgame<KQKRPs> ScaleKQKRPs[] = { Endgame<KQKRPs>(WHITE), Endgame<KQKRPs>(BLACK) };
Endgame<KPsK> ScaleKPsK[] = { Endgame<KPsK>(WHITE), Endgame<KPsK>(BLACK) };
Endgame<KPKP> ScaleKPKP[] = { Endgame<KPKP>(WHITE), Endgame<KPKP>(BLACK) };
// Helper used to detect a given material distribution
bool is_KXK(const Position& pos, Color us) {
return !more_than_one(pos.pieces(~us))
&& pos.non_pawn_material(us) >= RookValueMg;
}
bool is_KBPsK(const Position& pos, Color us) {
return pos.non_pawn_material(us) == BishopValueMg
&& pos.count<PAWN>(us) >= 1;
}
bool is_KQKRPs(const Position& pos, Color us) {
return !pos.count<PAWN>(us)
&& pos.non_pawn_material(us) == QueenValueMg
&& pos.count<ROOK>(~us) == 1
&& pos.count<PAWN>(~us) >= 1;
}
/// imbalance() calculates the imbalance by comparing the piece count of each
/// piece type for both colors.
template<Color Us>
Score imbalance(const int pieceCount[][PIECE_TYPE_NB]) {
constexpr Color Them = ~Us;
Score bonus = SCORE_ZERO;
// Second-degree polynomial material imbalance, by Tord Romstad
for (int pt1 = NO_PIECE_TYPE; pt1 <= QUEEN; ++pt1)
{
if (!pieceCount[Us][pt1])
continue;
int v = QuadraticOurs[pt1][pt1] * pieceCount[Us][pt1];
for (int pt2 = NO_PIECE_TYPE; pt2 < pt1; ++pt2)
v += QuadraticOurs[pt1][pt2] * pieceCount[Us][pt2]
+ QuadraticTheirs[pt1][pt2] * pieceCount[Them][pt2];
bonus += pieceCount[Us][pt1] * v;
}
return bonus;
}
} // namespace
namespace Material {
/// Material::probe() looks up the current position's material configuration in
/// the material hash table. It returns a pointer to the Entry if the position
/// is found. Otherwise a new Entry is computed and stored there, so we don't
/// have to recompute all when the same material configuration occurs again.
Entry* probe(const Position& pos) {
Key key = pos.material_key();
Entry* e = pos.this_thread()->materialTable[key];
if (e->key == key)
return e;
std::memset(e, 0, sizeof(Entry));
e->key = key;
e->factor[WHITE] = e->factor[BLACK] = (uint8_t)SCALE_FACTOR_NORMAL;
Value npm_w = pos.non_pawn_material(WHITE);
Value npm_b = pos.non_pawn_material(BLACK);
Value npm = std::clamp(npm_w + npm_b, EndgameLimit, MidgameLimit);
// Map total non-pawn material into [PHASE_ENDGAME, PHASE_MIDGAME]
e->gamePhase = Phase(((npm - EndgameLimit) * PHASE_MIDGAME) / (MidgameLimit - EndgameLimit));
// Let's look if we have a specialized evaluation function for this particular
// material configuration. Firstly we look for a fixed configuration one, then
// for a generic one if the previous search failed.
if ((e->evaluationFunction = Endgames::probe<Value>(key)) != nullptr)
return e;
for (Color c : { WHITE, BLACK })
if (is_KXK(pos, c))
{
e->evaluationFunction = &EvaluateKXK[c];
return e;
}
// OK, we didn't find any special evaluation function for the current material
// configuration. Is there a suitable specialized scaling function?
const auto* sf = Endgames::probe<ScaleFactor>(key);
if (sf)
{
e->scalingFunction[sf->strongSide] = sf; // Only strong color assigned
return e;
}
// We didn't find any specialized scaling function, so fall back on generic
// ones that refer to more than one material distribution. Note that in this
// case we don't return after setting the function.
for (Color c : { WHITE, BLACK })
{
if (is_KBPsK(pos, c))
e->scalingFunction[c] = &ScaleKBPsK[c];
else if (is_KQKRPs(pos, c))
e->scalingFunction[c] = &ScaleKQKRPs[c];
}
if (npm_w + npm_b == VALUE_ZERO && pos.pieces(PAWN)) // Only pawns on the board
{
if (!pos.count<PAWN>(BLACK))
{
assert(pos.count<PAWN>(WHITE) >= 2);
e->scalingFunction[WHITE] = &ScaleKPsK[WHITE];
}
else if (!pos.count<PAWN>(WHITE))
{
assert(pos.count<PAWN>(BLACK) >= 2);
e->scalingFunction[BLACK] = &ScaleKPsK[BLACK];
}
else if (pos.count<PAWN>(WHITE) == 1 && pos.count<PAWN>(BLACK) == 1)
{
// This is a special case because we set scaling functions
// for both colors instead of only one.
e->scalingFunction[WHITE] = &ScaleKPKP[WHITE];
e->scalingFunction[BLACK] = &ScaleKPKP[BLACK];
}
}
// Zero or just one pawn makes it difficult to win, even with a small material
// advantage. This catches some trivial draws like KK, KBK and KNK and gives a
// drawish scale factor for cases such as KRKBP and KmmKm (except for KBBKN).
if (!pos.count<PAWN>(WHITE) && npm_w - npm_b <= BishopValueMg)
e->factor[WHITE] = uint8_t(npm_w < RookValueMg ? SCALE_FACTOR_DRAW :
npm_b <= BishopValueMg ? 4 : 14);
if (!pos.count<PAWN>(BLACK) && npm_b - npm_w <= BishopValueMg)
e->factor[BLACK] = uint8_t(npm_b < RookValueMg ? SCALE_FACTOR_DRAW :
npm_w <= BishopValueMg ? 4 : 14);
// Evaluate the material imbalance. We use PIECE_TYPE_NONE as a place holder
// for the bishop pair "extended piece", which allows us to be more flexible
// in defining bishop pair bonuses.
const int pieceCount[COLOR_NB][PIECE_TYPE_NB] = {
{ pos.count<BISHOP>(WHITE) > 1, pos.count<PAWN>(WHITE), pos.count<KNIGHT>(WHITE),
pos.count<BISHOP>(WHITE) , pos.count<ROOK>(WHITE), pos.count<QUEEN >(WHITE) },
{ pos.count<BISHOP>(BLACK) > 1, pos.count<PAWN>(BLACK), pos.count<KNIGHT>(BLACK),
pos.count<BISHOP>(BLACK) , pos.count<ROOK>(BLACK), pos.count<QUEEN >(BLACK) } };
e->score = (imbalance<WHITE>(pieceCount) - imbalance<BLACK>(pieceCount)) / 16;
return e;
}
} // namespace Material
} // namespace Stockfish
-71
View File
@@ -1,71 +0,0 @@
/*
Stockfish, a UCI chess playing engine derived from Glaurung 2.1
Copyright (C) 2004-2023 The Stockfish developers (see AUTHORS file)
Stockfish is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
Stockfish is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef MATERIAL_H_INCLUDED
#define MATERIAL_H_INCLUDED
#include "endgame.h"
#include "misc.h"
#include "position.h"
#include "types.h"
namespace Stockfish::Material {
/// Material::Entry contains various information about a material configuration.
/// It contains a material imbalance evaluation, a function pointer to a special
/// endgame evaluation function (which in most cases is nullptr, meaning that the
/// standard evaluation function will be used), and scale factors.
///
/// The scale factors are used to scale the evaluation score up or down. For
/// instance, in KRB vs KR endgames, the score is scaled down by a factor of 4,
/// which will result in scores of absolute value less than one pawn.
struct Entry {
Score imbalance() const { return score; }
Phase game_phase() const { return (Phase)gamePhase; }
bool specialized_eval_exists() const { return evaluationFunction != nullptr; }
Value evaluate(const Position& pos) const { return (*evaluationFunction)(pos); }
// scale_factor() takes a position and a color as input and returns a scale factor
// for the given color. We have to provide the position in addition to the color
// because the scale factor may also be a function which should be applied to
// the position. For instance, in KBP vs K endgames, the scaling function looks
// for rook pawns and wrong-colored bishops.
ScaleFactor scale_factor(const Position& pos, Color c) const {
ScaleFactor sf = scalingFunction[c] ? (*scalingFunction[c])(pos)
: SCALE_FACTOR_NONE;
return sf != SCALE_FACTOR_NONE ? sf : ScaleFactor(factor[c]);
}
Key key;
const EndgameBase<Value>* evaluationFunction;
const EndgameBase<ScaleFactor>* scalingFunction[COLOR_NB]; // Could be one for each
// side (e.g. KPKP, KBPsK)
Score score;
int16_t gamePhase;
uint8_t factor[COLOR_NB];
};
using Table = HashTable<Entry, 8192>;
Entry* probe(const Position& pos);
} // namespace Stockfish::Material
#endif // #ifndef MATERIAL_H_INCLUDED
+268
View File
@@ -0,0 +1,268 @@
/*
Stockfish, a UCI chess playing engine derived from Glaurung 2.1
Copyright (C) 2004-2025 The Stockfish developers (see AUTHORS file)
Stockfish is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
Stockfish is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "memory.h"
#include <cstdlib>
#if __has_include("features.h")
#include <features.h>
#endif
#if defined(__linux__) && !defined(__ANDROID__)
#include <sys/mman.h>
#endif
#if defined(__APPLE__) || defined(__ANDROID__) || defined(__OpenBSD__) \
|| (defined(__GLIBCXX__) && !defined(_GLIBCXX_HAVE_ALIGNED_ALLOC) && !defined(_WIN32)) \
|| defined(__e2k__)
#define POSIXALIGNEDALLOC
#include <stdlib.h>
#endif
#ifdef _WIN32
#if _WIN32_WINNT < 0x0601
#undef _WIN32_WINNT
#define _WIN32_WINNT 0x0601 // Force to include needed API prototypes
#endif
#ifndef NOMINMAX
#define NOMINMAX
#endif
#include <ios> // std::hex, std::dec
#include <iostream> // std::cerr
#include <ostream> // std::endl
#include <windows.h>
// The needed Windows API for processor groups could be missed from old Windows
// versions, so instead of calling them directly (forcing the linker to resolve
// the calls at compile time), try to load them at runtime. To do this we need
// first to define the corresponding function pointers.
extern "C" {
using OpenProcessToken_t = bool (*)(HANDLE, DWORD, PHANDLE);
using LookupPrivilegeValueA_t = bool (*)(LPCSTR, LPCSTR, PLUID);
using AdjustTokenPrivileges_t =
bool (*)(HANDLE, BOOL, PTOKEN_PRIVILEGES, DWORD, PTOKEN_PRIVILEGES, PDWORD);
}
#endif
namespace Stockfish {
// Wrappers for systems where the c++17 implementation does not guarantee the
// availability of aligned_alloc(). Memory allocated with std_aligned_alloc()
// must be freed with std_aligned_free().
void* std_aligned_alloc(size_t alignment, size_t size) {
#if defined(_ISOC11_SOURCE)
return aligned_alloc(alignment, size);
#elif defined(POSIXALIGNEDALLOC)
void* mem = nullptr;
posix_memalign(&mem, alignment, size);
return mem;
#elif defined(_WIN32) && !defined(_M_ARM) && !defined(_M_ARM64)
return _mm_malloc(size, alignment);
#elif defined(_WIN32)
return _aligned_malloc(size, alignment);
#else
return std::aligned_alloc(alignment, size);
#endif
}
void std_aligned_free(void* ptr) {
#if defined(POSIXALIGNEDALLOC)
free(ptr);
#elif defined(_WIN32) && !defined(_M_ARM) && !defined(_M_ARM64)
_mm_free(ptr);
#elif defined(_WIN32)
_aligned_free(ptr);
#else
free(ptr);
#endif
}
// aligned_large_pages_alloc() will return suitably aligned memory,
// if possible using large pages.
#if defined(_WIN32)
static void* aligned_large_pages_alloc_windows([[maybe_unused]] size_t allocSize) {
#if !defined(_WIN64)
return nullptr;
#else
HANDLE hProcessToken{};
LUID luid{};
void* mem = nullptr;
const size_t largePageSize = GetLargePageMinimum();
if (!largePageSize)
return nullptr;
// Dynamically link OpenProcessToken, LookupPrivilegeValue and AdjustTokenPrivileges
HMODULE hAdvapi32 = GetModuleHandle(TEXT("advapi32.dll"));
if (!hAdvapi32)
hAdvapi32 = LoadLibrary(TEXT("advapi32.dll"));
auto OpenProcessToken_f =
OpenProcessToken_t((void (*)()) GetProcAddress(hAdvapi32, "OpenProcessToken"));
if (!OpenProcessToken_f)
return nullptr;
auto LookupPrivilegeValueA_f =
LookupPrivilegeValueA_t((void (*)()) GetProcAddress(hAdvapi32, "LookupPrivilegeValueA"));
if (!LookupPrivilegeValueA_f)
return nullptr;
auto AdjustTokenPrivileges_f =
AdjustTokenPrivileges_t((void (*)()) GetProcAddress(hAdvapi32, "AdjustTokenPrivileges"));
if (!AdjustTokenPrivileges_f)
return nullptr;
// We need SeLockMemoryPrivilege, so try to enable it for the process
if (!OpenProcessToken_f( // OpenProcessToken()
GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &hProcessToken))
return nullptr;
if (LookupPrivilegeValueA_f(nullptr, "SeLockMemoryPrivilege", &luid))
{
TOKEN_PRIVILEGES tp{};
TOKEN_PRIVILEGES prevTp{};
DWORD prevTpLen = 0;
tp.PrivilegeCount = 1;
tp.Privileges[0].Luid = luid;
tp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
// Try to enable SeLockMemoryPrivilege. Note that even if AdjustTokenPrivileges()
// succeeds, we still need to query GetLastError() to ensure that the privileges
// were actually obtained.
if (AdjustTokenPrivileges_f(hProcessToken, FALSE, &tp, sizeof(TOKEN_PRIVILEGES), &prevTp,
&prevTpLen)
&& GetLastError() == ERROR_SUCCESS)
{
// Round up size to full pages and allocate
allocSize = (allocSize + largePageSize - 1) & ~size_t(largePageSize - 1);
mem = VirtualAlloc(nullptr, allocSize, MEM_RESERVE | MEM_COMMIT | MEM_LARGE_PAGES,
PAGE_READWRITE);
// Privilege no longer needed, restore previous state
AdjustTokenPrivileges_f(hProcessToken, FALSE, &prevTp, 0, nullptr, nullptr);
}
}
CloseHandle(hProcessToken);
return mem;
#endif
}
void* aligned_large_pages_alloc(size_t allocSize) {
// Try to allocate large pages
void* mem = aligned_large_pages_alloc_windows(allocSize);
// Fall back to regular, page-aligned, allocation if necessary
if (!mem)
mem = VirtualAlloc(nullptr, allocSize, MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE);
return mem;
}
#else
void* aligned_large_pages_alloc(size_t allocSize) {
#if defined(__linux__)
constexpr size_t alignment = 2 * 1024 * 1024; // 2MB page size assumed
#else
constexpr size_t alignment = 4096; // small page size assumed
#endif
// Round up to multiples of alignment
size_t size = ((allocSize + alignment - 1) / alignment) * alignment;
void* mem = std_aligned_alloc(alignment, size);
#if defined(MADV_HUGEPAGE)
madvise(mem, size, MADV_HUGEPAGE);
#endif
return mem;
}
#endif
bool has_large_pages() {
#if defined(_WIN32)
constexpr size_t page_size = 2 * 1024 * 1024; // 2MB page size assumed
void* mem = aligned_large_pages_alloc_windows(page_size);
if (mem == nullptr)
{
return false;
}
else
{
aligned_large_pages_free(mem);
return true;
}
#elif defined(__linux__)
#if defined(MADV_HUGEPAGE)
return true;
#else
return false;
#endif
#else
return false;
#endif
}
// aligned_large_pages_free() will free the previously memory allocated
// by aligned_large_pages_alloc(). The effect is a nop if mem == nullptr.
#if defined(_WIN32)
void aligned_large_pages_free(void* mem) {
if (mem && !VirtualFree(mem, 0, MEM_RELEASE))
{
DWORD err = GetLastError();
std::cerr << "Failed to free large page memory. Error code: 0x" << std::hex << err
<< std::dec << std::endl;
exit(EXIT_FAILURE);
}
}
#else
void aligned_large_pages_free(void* mem) { std_aligned_free(mem); }
#endif
} // namespace Stockfish
+218
View File
@@ -0,0 +1,218 @@
/*
Stockfish, a UCI chess playing engine derived from Glaurung 2.1
Copyright (C) 2004-2025 The Stockfish developers (see AUTHORS file)
Stockfish is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
Stockfish is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef MEMORY_H_INCLUDED
#define MEMORY_H_INCLUDED
#include <algorithm>
#include <cstddef>
#include <cstdint>
#include <memory>
#include <new>
#include <type_traits>
#include <utility>
#include "types.h"
namespace Stockfish {
void* std_aligned_alloc(size_t alignment, size_t size);
void std_aligned_free(void* ptr);
// Memory aligned by page size, min alignment: 4096 bytes
void* aligned_large_pages_alloc(size_t size);
void aligned_large_pages_free(void* mem);
bool has_large_pages();
// Frees memory which was placed there with placement new.
// Works for both single objects and arrays of unknown bound.
template<typename T, typename FREE_FUNC>
void memory_deleter(T* ptr, FREE_FUNC free_func) {
if (!ptr)
return;
// Explicitly needed to call the destructor
if constexpr (!std::is_trivially_destructible_v<T>)
ptr->~T();
free_func(ptr);
return;
}
// Frees memory which was placed there with placement new.
// Works for both single objects and arrays of unknown bound.
template<typename T, typename FREE_FUNC>
void memory_deleter_array(T* ptr, FREE_FUNC free_func) {
if (!ptr)
return;
// Move back on the pointer to where the size is allocated
const size_t array_offset = std::max(sizeof(size_t), alignof(T));
char* raw_memory = reinterpret_cast<char*>(ptr) - array_offset;
if constexpr (!std::is_trivially_destructible_v<T>)
{
const size_t size = *reinterpret_cast<size_t*>(raw_memory);
// Explicitly call the destructor for each element in reverse order
for (size_t i = size; i-- > 0;)
ptr[i].~T();
}
free_func(raw_memory);
}
// Allocates memory for a single object and places it there with placement new
template<typename T, typename ALLOC_FUNC, typename... Args>
inline std::enable_if_t<!std::is_array_v<T>, T*> memory_allocator(ALLOC_FUNC alloc_func,
Args&&... args) {
void* raw_memory = alloc_func(sizeof(T));
ASSERT_ALIGNED(raw_memory, alignof(T));
return new (raw_memory) T(std::forward<Args>(args)...);
}
// Allocates memory for an array of unknown bound and places it there with placement new
template<typename T, typename ALLOC_FUNC>
inline std::enable_if_t<std::is_array_v<T>, std::remove_extent_t<T>*>
memory_allocator(ALLOC_FUNC alloc_func, size_t num) {
using ElementType = std::remove_extent_t<T>;
const size_t array_offset = std::max(sizeof(size_t), alignof(ElementType));
// Save the array size in the memory location
char* raw_memory =
reinterpret_cast<char*>(alloc_func(array_offset + num * sizeof(ElementType)));
ASSERT_ALIGNED(raw_memory, alignof(T));
new (raw_memory) size_t(num);
for (size_t i = 0; i < num; ++i)
new (raw_memory + array_offset + i * sizeof(ElementType)) ElementType();
// Need to return the pointer at the start of the array so that
// the indexing in unique_ptr<T[]> works.
return reinterpret_cast<ElementType*>(raw_memory + array_offset);
}
//
//
// aligned large page unique ptr
//
//
template<typename T>
struct LargePageDeleter {
void operator()(T* ptr) const { return memory_deleter<T>(ptr, aligned_large_pages_free); }
};
template<typename T>
struct LargePageArrayDeleter {
void operator()(T* ptr) const { return memory_deleter_array<T>(ptr, aligned_large_pages_free); }
};
template<typename T>
using LargePagePtr =
std::conditional_t<std::is_array_v<T>,
std::unique_ptr<T, LargePageArrayDeleter<std::remove_extent_t<T>>>,
std::unique_ptr<T, LargePageDeleter<T>>>;
// make_unique_large_page for single objects
template<typename T, typename... Args>
std::enable_if_t<!std::is_array_v<T>, LargePagePtr<T>> make_unique_large_page(Args&&... args) {
static_assert(alignof(T) <= 4096,
"aligned_large_pages_alloc() may fail for such a big alignment requirement of T");
T* obj = memory_allocator<T>(aligned_large_pages_alloc, std::forward<Args>(args)...);
return LargePagePtr<T>(obj);
}
// make_unique_large_page for arrays of unknown bound
template<typename T>
std::enable_if_t<std::is_array_v<T>, LargePagePtr<T>> make_unique_large_page(size_t num) {
using ElementType = std::remove_extent_t<T>;
static_assert(alignof(ElementType) <= 4096,
"aligned_large_pages_alloc() may fail for such a big alignment requirement of T");
ElementType* memory = memory_allocator<T>(aligned_large_pages_alloc, num);
return LargePagePtr<T>(memory);
}
//
//
// aligned unique ptr
//
//
template<typename T>
struct AlignedDeleter {
void operator()(T* ptr) const { return memory_deleter<T>(ptr, std_aligned_free); }
};
template<typename T>
struct AlignedArrayDeleter {
void operator()(T* ptr) const { return memory_deleter_array<T>(ptr, std_aligned_free); }
};
template<typename T>
using AlignedPtr =
std::conditional_t<std::is_array_v<T>,
std::unique_ptr<T, AlignedArrayDeleter<std::remove_extent_t<T>>>,
std::unique_ptr<T, AlignedDeleter<T>>>;
// make_unique_aligned for single objects
template<typename T, typename... Args>
std::enable_if_t<!std::is_array_v<T>, AlignedPtr<T>> make_unique_aligned(Args&&... args) {
const auto func = [](size_t size) { return std_aligned_alloc(alignof(T), size); };
T* obj = memory_allocator<T>(func, std::forward<Args>(args)...);
return AlignedPtr<T>(obj);
}
// make_unique_aligned for arrays of unknown bound
template<typename T>
std::enable_if_t<std::is_array_v<T>, AlignedPtr<T>> make_unique_aligned(size_t num) {
using ElementType = std::remove_extent_t<T>;
const auto func = [](size_t size) { return std_aligned_alloc(alignof(ElementType), size); };
ElementType* memory = memory_allocator<T>(func, num);
return AlignedPtr<T>(memory);
}
// Get the first aligned element of an array.
// ptr must point to an array of size at least `sizeof(T) * N + alignment` bytes,
// where N is the number of elements in the array.
template<uintptr_t Alignment, typename T>
T* align_ptr_up(T* ptr) {
static_assert(alignof(T) < Alignment);
const uintptr_t ptrint = reinterpret_cast<uintptr_t>(reinterpret_cast<char*>(ptr));
return reinterpret_cast<T*>(
reinterpret_cast<char*>((ptrint + (Alignment - 1)) / Alignment * Alignment));
}
} // namespace Stockfish
#endif // #ifndef MEMORY_H_INCLUDED
+318 -594
View File
File diff suppressed because it is too large Load Diff
+233 -93
View File
@@ -1,6 +1,6 @@
/* /*
Stockfish, a UCI chess playing engine derived from Glaurung 2.1 Stockfish, a UCI chess playing engine derived from Glaurung 2.1
Copyright (C) 2004-2023 The Stockfish developers (see AUTHORS file) Copyright (C) 2004-2025 The Stockfish developers (see AUTHORS file)
Stockfish is free software: you can redistribute it and/or modify Stockfish is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by it under the terms of the GNU General Public License as published by
@@ -19,158 +19,298 @@
#ifndef MISC_H_INCLUDED #ifndef MISC_H_INCLUDED
#define MISC_H_INCLUDED #define MISC_H_INCLUDED
#include <algorithm>
#include <array>
#include <cassert> #include <cassert>
#include <chrono> #include <chrono>
#include <ostream> #include <cstddef>
#include <string>
#include <vector>
#include <cstdint> #include <cstdint>
#include <cstdio>
#include "types.h" #include <iosfwd>
#include <optional>
#include <string>
#include <string_view>
#include <vector>
#define stringify2(x) #x #define stringify2(x) #x
#define stringify(x) stringify2(x) #define stringify(x) stringify2(x)
namespace Stockfish { namespace Stockfish {
std::string engine_version_info();
std::string engine_info(bool to_uci = false); std::string engine_info(bool to_uci = false);
std::string compiler_info(); std::string compiler_info();
void prefetch(void* addr);
// Preloads the given address in L1/L2 cache. This is a non-blocking
// function that doesn't stall the CPU waiting for data to be loaded from memory,
// which can be quite slow.
void prefetch(const void* addr);
void start_logger(const std::string& fname); void start_logger(const std::string& fname);
void* std_aligned_alloc(size_t alignment, size_t size);
void std_aligned_free(void* ptr); size_t str_to_size_t(const std::string& s);
void* aligned_large_pages_alloc(size_t size); // memory aligned by page size, min alignment: 4096 bytes
void aligned_large_pages_free(void* mem); // nop if mem == nullptr #if defined(__linux__)
struct PipeDeleter {
void operator()(FILE* file) const {
if (file != nullptr)
{
pclose(file);
}
}
};
#endif
// Reads the file as bytes.
// Returns std::nullopt if the file does not exist.
std::optional<std::string> read_file_to_string(const std::string& path);
void dbg_hit_on(bool cond, int slot = 0); void dbg_hit_on(bool cond, int slot = 0);
void dbg_mean_of(int64_t value, int slot = 0); void dbg_mean_of(int64_t value, int slot = 0);
void dbg_stdev_of(int64_t value, int slot = 0); void dbg_stdev_of(int64_t value, int slot = 0);
void dbg_extremes_of(int64_t value, int slot = 0);
void dbg_correl_of(int64_t value1, int64_t value2, int slot = 0); void dbg_correl_of(int64_t value1, int64_t value2, int slot = 0);
void dbg_print(); void dbg_print();
using TimePoint = std::chrono::milliseconds::rep; // A value in milliseconds using TimePoint = std::chrono::milliseconds::rep; // A value in milliseconds
static_assert(sizeof(TimePoint) == sizeof(int64_t), "TimePoint should be 64 bits"); static_assert(sizeof(TimePoint) == sizeof(int64_t), "TimePoint should be 64 bits");
inline TimePoint now() { inline TimePoint now() {
return std::chrono::duration_cast<std::chrono::milliseconds> return std::chrono::duration_cast<std::chrono::milliseconds>(
(std::chrono::steady_clock::now().time_since_epoch()).count(); std::chrono::steady_clock::now().time_since_epoch())
.count();
} }
template<class Entry, int Size> inline std::vector<std::string_view> split(std::string_view s, std::string_view delimiter) {
struct HashTable { std::vector<std::string_view> res;
Entry* operator[](Key key) { return &table[(uint32_t)key & (Size - 1)]; }
private: if (s.empty())
std::vector<Entry> table = std::vector<Entry>(Size); // Allocate on the heap return res;
size_t begin = 0;
for (;;)
{
const size_t end = s.find(delimiter, begin);
if (end == std::string::npos)
break;
res.emplace_back(s.substr(begin, end - begin));
begin = end + delimiter.size();
}
res.emplace_back(s.substr(begin));
return res;
}
void remove_whitespace(std::string& s);
bool is_whitespace(std::string_view s);
enum SyncCout {
IO_LOCK,
IO_UNLOCK
}; };
enum SyncCout { IO_LOCK, IO_UNLOCK };
std::ostream& operator<<(std::ostream&, SyncCout); std::ostream& operator<<(std::ostream&, SyncCout);
#define sync_cout std::cout << IO_LOCK #define sync_cout std::cout << IO_LOCK
#define sync_endl std::endl << IO_UNLOCK #define sync_endl std::endl << IO_UNLOCK
void sync_cout_start();
void sync_cout_end();
// align_ptr_up() : get the first aligned element of an array. // True if and only if the binary is compiled on a little-endian machine
// ptr must point to an array of size at least `sizeof(T) * N + alignment` bytes, static inline const std::uint16_t Le = 1;
// where N is the number of elements in the array. static inline const bool IsLittleEndian = *reinterpret_cast<const char*>(&Le) == 1;
template <uintptr_t Alignment, typename T>
T* align_ptr_up(T* ptr)
{
static_assert(alignof(T) < Alignment);
const uintptr_t ptrint = reinterpret_cast<uintptr_t>(reinterpret_cast<char*>(ptr));
return reinterpret_cast<T*>(reinterpret_cast<char*>((ptrint + (Alignment - 1)) / Alignment * Alignment));
}
// IsLittleEndian : true if and only if the binary is compiled on a little endian machine template<typename T, std::size_t MaxSize>
static inline const union { uint32_t i; char c[4]; } Le = { 0x01020304 };
static inline const bool IsLittleEndian = (Le.c[0] == 4);
template <typename T, std::size_t MaxSize>
class ValueList { class ValueList {
public: public:
std::size_t size() const { return size_; } std::size_t size() const { return size_; }
void push_back(const T& value) { values_[size_++] = value; } void push_back(const T& value) { values_[size_++] = value; }
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_; }
const T& operator[](int index) const { return values_[index]; }
private: private:
T values_[MaxSize]; T values_[MaxSize];
std::size_t size_ = 0; std::size_t size_ = 0;
}; };
/// xorshift64star Pseudo-Random Number Generator template<typename T, std::size_t Size, std::size_t... Sizes>
/// This class is based on original code written and dedicated class MultiArray;
/// to the public domain by Sebastiano Vigna (2014).
/// It has the following characteristics: namespace Detail {
///
/// - Outputs 64-bit numbers template<typename T, std::size_t Size, std::size_t... Sizes>
/// - Passes Dieharder and SmallCrush test batteries struct MultiArrayHelper {
/// - Does not require warm-up, no zeroland to escape using ChildType = MultiArray<T, Sizes...>;
/// - Internal state is a single 64-bit integer };
/// - Period is 2^64 - 1
/// - Speed: 1.60 ns/call (Core i7 @3.40GHz) template<typename T, std::size_t Size>
/// struct MultiArrayHelper<T, Size> {
/// For further analysis see using ChildType = T;
/// <http://vigna.di.unimi.it/ftp/papers/xorshift.pdf> };
}
// MultiArray is a generic N-dimensional array.
// The template parameters (Size and Sizes) encode the dimensions of the array.
template<typename T, std::size_t Size, std::size_t... Sizes>
class MultiArray {
using ChildType = typename Detail::MultiArrayHelper<T, Size, Sizes...>::ChildType;
using ArrayType = std::array<ChildType, Size>;
ArrayType data_;
public:
using value_type = typename ArrayType::value_type;
using size_type = typename ArrayType::size_type;
using difference_type = typename ArrayType::difference_type;
using reference = typename ArrayType::reference;
using const_reference = typename ArrayType::const_reference;
using pointer = typename ArrayType::pointer;
using const_pointer = typename ArrayType::const_pointer;
using iterator = typename ArrayType::iterator;
using const_iterator = typename ArrayType::const_iterator;
using reverse_iterator = typename ArrayType::reverse_iterator;
using const_reverse_iterator = typename ArrayType::const_reverse_iterator;
constexpr auto& at(size_type index) noexcept { return data_.at(index); }
constexpr const auto& at(size_type index) const noexcept { return data_.at(index); }
constexpr auto& operator[](size_type index) noexcept { return data_[index]; }
constexpr const auto& operator[](size_type index) const noexcept { return data_[index]; }
constexpr auto& front() noexcept { return data_.front(); }
constexpr const auto& front() const noexcept { return data_.front(); }
constexpr auto& back() noexcept { return data_.back(); }
constexpr const auto& back() const noexcept { return data_.back(); }
auto* data() { return data_.data(); }
const auto* data() const { return data_.data(); }
constexpr auto begin() noexcept { return data_.begin(); }
constexpr auto end() noexcept { return data_.end(); }
constexpr auto begin() const noexcept { return data_.begin(); }
constexpr auto end() const noexcept { return data_.end(); }
constexpr auto cbegin() const noexcept { return data_.cbegin(); }
constexpr auto cend() const noexcept { return data_.cend(); }
constexpr auto rbegin() noexcept { return data_.rbegin(); }
constexpr auto rend() noexcept { return data_.rend(); }
constexpr auto rbegin() const noexcept { return data_.rbegin(); }
constexpr auto rend() const noexcept { return data_.rend(); }
constexpr auto crbegin() const noexcept { return data_.crbegin(); }
constexpr auto crend() const noexcept { return data_.crend(); }
constexpr bool empty() const noexcept { return data_.empty(); }
constexpr size_type size() const noexcept { return data_.size(); }
constexpr size_type max_size() const noexcept { return data_.max_size(); }
template<typename U>
void fill(const U& v) {
static_assert(std::is_assignable_v<T, U>, "Cannot assign fill value to entry type");
for (auto& ele : data_)
{
if constexpr (sizeof...(Sizes) == 0)
ele = v;
else
ele.fill(v);
}
}
constexpr void swap(MultiArray<T, Size, Sizes...>& other) noexcept { data_.swap(other.data_); }
};
// xorshift64star Pseudo-Random Number Generator
// This class is based on original code written and dedicated
// to the public domain by Sebastiano Vigna (2014).
// It has the following characteristics:
//
// - Outputs 64-bit numbers
// - Passes Dieharder and SmallCrush test batteries
// - Does not require warm-up, no zeroland to escape
// - Internal state is a single 64-bit integer
// - Period is 2^64 - 1
// - Speed: 1.60 ns/call (Core i7 @3.40GHz)
//
// For further analysis see
// <http://vigna.di.unimi.it/ftp/papers/xorshift.pdf>
class PRNG { class PRNG {
uint64_t s; uint64_t s;
uint64_t rand64() { uint64_t rand64() {
s ^= s >> 12, s ^= s << 25, s ^= s >> 27; s ^= s >> 12, s ^= s << 25, s ^= s >> 27;
return s * 2685821657736338717LL; return s * 2685821657736338717LL;
} }
public: public:
PRNG(uint64_t seed) : s(seed) { assert(seed); } PRNG(uint64_t seed) :
s(seed) {
assert(seed);
}
template<typename T> T rand() { return T(rand64()); } template<typename T>
T rand() {
return T(rand64());
}
/// Special generator used to fast init magic numbers. // Special generator used to fast init magic numbers.
/// Output values only have 1/8th of their bits set on average. // Output values only have 1/8th of their bits set on average.
template<typename T> T sparse_rand() template<typename T>
{ return T(rand64() & rand64() & rand64()); } T sparse_rand() {
return T(rand64() & rand64() & rand64());
}
}; };
inline uint64_t mul_hi64(uint64_t a, uint64_t b) { inline uint64_t mul_hi64(uint64_t a, uint64_t b) {
#if defined(__GNUC__) && defined(IS_64BIT) #if defined(__GNUC__) && defined(IS_64BIT)
__extension__ using uint128 = unsigned __int128; __extension__ using uint128 = unsigned __int128;
return ((uint128)a * (uint128)b) >> 64; return (uint128(a) * uint128(b)) >> 64;
#else #else
uint64_t aL = (uint32_t)a, aH = a >> 32; uint64_t aL = uint32_t(a), aH = a >> 32;
uint64_t bL = (uint32_t)b, bH = b >> 32; uint64_t bL = uint32_t(b), bH = b >> 32;
uint64_t c1 = (aL * bL) >> 32; uint64_t c1 = (aL * bL) >> 32;
uint64_t c2 = aH * bL + c1; uint64_t c2 = aH * bL + c1;
uint64_t c3 = aL * bH + (uint32_t)c2; uint64_t c3 = aL * bH + uint32_t(c2);
return aH * bH + (c2 >> 32) + (c3 >> 32); return aH * bH + (c2 >> 32) + (c3 >> 32);
#endif #endif
} }
/// Under Windows it is not possible for a process to run on more than one
/// logical processor group. This usually means to be limited to use max 64
/// cores. To overcome this, some special platform specific API should be
/// called to set group affinity for each thread. Original code from Texel by
/// Peter Österlund.
namespace WinProcGroup { struct CommandLine {
void bindThisThread(size_t idx); public:
CommandLine(int _argc, char** _argv) :
argc(_argc),
argv(_argv) {}
static std::string get_binary_directory(std::string argv0);
static std::string get_working_directory();
int argc;
char** argv;
};
namespace Utility {
template<typename T, typename Predicate>
void move_to_front(std::vector<T>& vec, Predicate pred) {
auto it = std::find_if(vec.begin(), vec.end(), pred);
if (it != vec.end())
{
std::rotate(vec.begin(), it, it + 1);
}
}
} }
namespace CommandLine { } // namespace Stockfish
void init(int argc, char* argv[]);
extern std::string binaryDirectory; // path of the executable directory #endif // #ifndef MISC_H_INCLUDED
extern std::string workingDirectory; // path of the working directory
}
} // namespace Stockfish
#endif // #ifndef MISC_H_INCLUDED
+91 -119
View File
@@ -1,6 +1,6 @@
/* /*
Stockfish, a UCI chess playing engine derived from Glaurung 2.1 Stockfish, a UCI chess playing engine derived from Glaurung 2.1
Copyright (C) 2004-2023 The Stockfish developers (see AUTHORS file) Copyright (C) 2004-2025 The Stockfish developers (see AUTHORS file)
Stockfish is free software: you can redistribute it and/or modify Stockfish is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by it under the terms of the GNU General Public License as published by
@@ -16,90 +16,75 @@
along with this program. If not, see <http://www.gnu.org/licenses/>. along with this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
#include <cassert>
#include "movegen.h" #include "movegen.h"
#include <cassert>
#include <initializer_list>
#include "bitboard.h"
#include "position.h" #include "position.h"
namespace Stockfish { namespace Stockfish {
namespace { namespace {
template<GenType Type, Direction D, bool Enemy> template<GenType Type, Direction D, bool Enemy>
ExtMove* make_promotions(ExtMove* moveList, [[maybe_unused]] Square to) { ExtMove* make_promotions(ExtMove* moveList, [[maybe_unused]] Square to) {
if constexpr (Type == CAPTURES || Type == EVASIONS || Type == NON_EVASIONS) constexpr bool all = Type == EVASIONS || Type == NON_EVASIONS;
{
*moveList++ = make<PROMOTION>(to - D, to, QUEEN);
if constexpr (Enemy && Type == CAPTURES)
{
*moveList++ = make<PROMOTION>(to - D, to, ROOK);
*moveList++ = make<PROMOTION>(to - D, to, BISHOP);
*moveList++ = make<PROMOTION>(to - D, to, KNIGHT);
}
}
if constexpr ((Type == QUIETS && !Enemy) || Type == EVASIONS || Type == NON_EVASIONS) if constexpr (Type == CAPTURES || all)
*moveList++ = Move::make<PROMOTION>(to - D, to, QUEEN);
if constexpr ((Type == CAPTURES && Enemy) || (Type == QUIETS && !Enemy) || all)
{ {
*moveList++ = make<PROMOTION>(to - D, to, ROOK); *moveList++ = Move::make<PROMOTION>(to - D, to, ROOK);
*moveList++ = make<PROMOTION>(to - D, to, BISHOP); *moveList++ = Move::make<PROMOTION>(to - D, to, BISHOP);
*moveList++ = make<PROMOTION>(to - D, to, KNIGHT); *moveList++ = Move::make<PROMOTION>(to - D, to, KNIGHT);
} }
return moveList; return moveList;
} }
template<Color Us, GenType Type> template<Color Us, GenType Type>
ExtMove* generate_pawn_moves(const Position& pos, ExtMove* moveList, Bitboard target) { ExtMove* generate_pawn_moves(const Position& pos, ExtMove* moveList, Bitboard target) {
constexpr Color Them = ~Us; constexpr Color Them = ~Us;
constexpr Bitboard TRank7BB = (Us == WHITE ? Rank7BB : Rank2BB); constexpr Bitboard TRank7BB = (Us == WHITE ? Rank7BB : Rank2BB);
constexpr Bitboard TRank3BB = (Us == WHITE ? Rank3BB : Rank6BB); constexpr Bitboard TRank3BB = (Us == WHITE ? Rank3BB : Rank6BB);
constexpr Direction Up = pawn_push(Us); constexpr Direction Up = pawn_push(Us);
constexpr Direction UpRight = (Us == WHITE ? NORTH_EAST : SOUTH_WEST); constexpr Direction UpRight = (Us == WHITE ? NORTH_EAST : SOUTH_WEST);
constexpr Direction UpLeft = (Us == WHITE ? NORTH_WEST : SOUTH_EAST); constexpr Direction UpLeft = (Us == WHITE ? NORTH_WEST : SOUTH_EAST);
const Bitboard emptySquares = ~pos.pieces(); const Bitboard emptySquares = ~pos.pieces();
const Bitboard enemies = Type == EVASIONS ? pos.checkers() const Bitboard enemies = Type == EVASIONS ? pos.checkers() : pos.pieces(Them);
: pos.pieces(Them);
Bitboard pawnsOn7 = pos.pieces(Us, PAWN) & TRank7BB; Bitboard pawnsOn7 = pos.pieces(Us, PAWN) & TRank7BB;
Bitboard pawnsNotOn7 = pos.pieces(Us, PAWN) & ~TRank7BB; Bitboard pawnsNotOn7 = pos.pieces(Us, PAWN) & ~TRank7BB;
// Single and double pawn pushes, no promotions // Single and double pawn pushes, no promotions
if constexpr (Type != CAPTURES) if constexpr (Type != CAPTURES)
{ {
Bitboard b1 = shift<Up>(pawnsNotOn7) & emptySquares; Bitboard b1 = shift<Up>(pawnsNotOn7) & emptySquares;
Bitboard b2 = shift<Up>(b1 & TRank3BB) & emptySquares; Bitboard b2 = shift<Up>(b1 & TRank3BB) & emptySquares;
if constexpr (Type == EVASIONS) // Consider only blocking squares if constexpr (Type == EVASIONS) // Consider only blocking squares
{ {
b1 &= target; b1 &= target;
b2 &= target; b2 &= target;
} }
if constexpr (Type == QUIET_CHECKS)
{
// To make a quiet check, you either make a direct check by pushing a pawn
// or push a blocker pawn that is not on the same file as the enemy king.
// Discovered check promotion has been already generated amongst the captures.
Square ksq = pos.square<KING>(Them);
Bitboard dcCandidatePawns = pos.blockers_for_king(Them) & ~file_bb(ksq);
b1 &= pawn_attacks_bb(Them, ksq) | shift< Up>(dcCandidatePawns);
b2 &= pawn_attacks_bb(Them, ksq) | shift<Up+Up>(dcCandidatePawns);
}
while (b1) while (b1)
{ {
Square to = pop_lsb(b1); Square to = pop_lsb(b1);
*moveList++ = make_move(to - Up, to); *moveList++ = Move(to - Up, to);
} }
while (b2) while (b2)
{ {
Square to = pop_lsb(b2); Square to = pop_lsb(b2);
*moveList++ = make_move(to - Up - Up, to); *moveList++ = Move(to - Up - Up, to);
} }
} }
@@ -107,8 +92,8 @@ namespace {
if (pawnsOn7) if (pawnsOn7)
{ {
Bitboard b1 = shift<UpRight>(pawnsOn7) & enemies; Bitboard b1 = shift<UpRight>(pawnsOn7) & enemies;
Bitboard b2 = shift<UpLeft >(pawnsOn7) & enemies; Bitboard b2 = shift<UpLeft>(pawnsOn7) & enemies;
Bitboard b3 = shift<Up >(pawnsOn7) & emptySquares; Bitboard b3 = shift<Up>(pawnsOn7) & emptySquares;
if constexpr (Type == EVASIONS) if constexpr (Type == EVASIONS)
b3 &= target; b3 &= target;
@@ -120,25 +105,25 @@ namespace {
moveList = make_promotions<Type, UpLeft, true>(moveList, pop_lsb(b2)); moveList = make_promotions<Type, UpLeft, true>(moveList, pop_lsb(b2));
while (b3) while (b3)
moveList = make_promotions<Type, Up, false>(moveList, pop_lsb(b3)); moveList = make_promotions<Type, Up, false>(moveList, pop_lsb(b3));
} }
// Standard and en passant captures // Standard and en passant captures
if constexpr (Type == CAPTURES || Type == EVASIONS || Type == NON_EVASIONS) if constexpr (Type == CAPTURES || Type == EVASIONS || Type == NON_EVASIONS)
{ {
Bitboard b1 = shift<UpRight>(pawnsNotOn7) & enemies; Bitboard b1 = shift<UpRight>(pawnsNotOn7) & enemies;
Bitboard b2 = shift<UpLeft >(pawnsNotOn7) & enemies; Bitboard b2 = shift<UpLeft>(pawnsNotOn7) & enemies;
while (b1) while (b1)
{ {
Square to = pop_lsb(b1); Square to = pop_lsb(b1);
*moveList++ = make_move(to - UpRight, to); *moveList++ = Move(to - UpRight, to);
} }
while (b2) while (b2)
{ {
Square to = pop_lsb(b2); Square to = pop_lsb(b2);
*moveList++ = make_move(to - UpLeft, to); *moveList++ = Move(to - UpLeft, to);
} }
if (pos.ep_square() != SQ_NONE) if (pos.ep_square() != SQ_NONE)
@@ -154,16 +139,16 @@ namespace {
assert(b1); assert(b1);
while (b1) while (b1)
*moveList++ = make<EN_PASSANT>(pop_lsb(b1), pos.ep_square()); *moveList++ = Move::make<EN_PASSANT>(pop_lsb(b1), pos.ep_square());
} }
} }
return moveList; return moveList;
} }
template<Color Us, PieceType Pt, bool Checks> template<Color Us, PieceType Pt>
ExtMove* generate_moves(const Position& pos, ExtMove* moveList, Bitboard target) { ExtMove* generate_moves(const Position& pos, ExtMove* moveList, Bitboard target) {
static_assert(Pt != KING && Pt != PAWN, "Unsupported piece type in generate_moves()"); static_assert(Pt != KING && Pt != PAWN, "Unsupported piece type in generate_moves()");
@@ -171,114 +156,101 @@ namespace {
while (bb) while (bb)
{ {
Square from = pop_lsb(bb); Square from = pop_lsb(bb);
Bitboard b = attacks_bb<Pt>(from, pos.pieces()) & target; Bitboard b = attacks_bb<Pt>(from, pos.pieces()) & target;
// To check, you either move freely a blocker or make a direct check.
if (Checks && (Pt == QUEEN || !(pos.blockers_for_king(~Us) & from)))
b &= pos.check_squares(Pt);
while (b) while (b)
*moveList++ = make_move(from, pop_lsb(b)); *moveList++ = Move(from, pop_lsb(b));
} }
return moveList; return moveList;
} }
template<Color Us, GenType Type> template<Color Us, GenType Type>
ExtMove* generate_all(const Position& pos, ExtMove* moveList) { ExtMove* generate_all(const Position& pos, ExtMove* moveList) {
static_assert(Type != LEGAL, "Unsupported type in generate_all()"); static_assert(Type != LEGAL, "Unsupported type in generate_all()");
constexpr bool Checks = Type == QUIET_CHECKS; // Reduce template instantiations
const Square ksq = pos.square<KING>(Us); const Square ksq = pos.square<KING>(Us);
Bitboard target; Bitboard target;
// Skip generating non-king moves when in double check // Skip generating non-king moves when in double check
if (Type != EVASIONS || !more_than_one(pos.checkers())) if (Type != EVASIONS || !more_than_one(pos.checkers()))
{ {
target = Type == EVASIONS ? between_bb(ksq, lsb(pos.checkers())) target = Type == EVASIONS ? between_bb(ksq, lsb(pos.checkers()))
: Type == NON_EVASIONS ? ~pos.pieces( Us) : Type == NON_EVASIONS ? ~pos.pieces(Us)
: Type == CAPTURES ? pos.pieces(~Us) : Type == CAPTURES ? pos.pieces(~Us)
: ~pos.pieces( ); // QUIETS || QUIET_CHECKS : ~pos.pieces(); // QUIETS
moveList = generate_pawn_moves<Us, Type>(pos, moveList, target); moveList = generate_pawn_moves<Us, Type>(pos, moveList, target);
moveList = generate_moves<Us, KNIGHT, Checks>(pos, moveList, target); moveList = generate_moves<Us, KNIGHT>(pos, moveList, target);
moveList = generate_moves<Us, BISHOP, Checks>(pos, moveList, target); moveList = generate_moves<Us, BISHOP>(pos, moveList, target);
moveList = generate_moves<Us, ROOK, Checks>(pos, moveList, target); moveList = generate_moves<Us, ROOK>(pos, moveList, target);
moveList = generate_moves<Us, QUEEN, Checks>(pos, moveList, target); moveList = generate_moves<Us, QUEEN>(pos, moveList, target);
} }
if (!Checks || pos.blockers_for_king(~Us) & ksq) Bitboard b = attacks_bb<KING>(ksq) & (Type == EVASIONS ? ~pos.pieces(Us) : target);
{
Bitboard b = attacks_bb<KING>(ksq) & (Type == EVASIONS ? ~pos.pieces(Us) : target);
if (Checks)
b &= ~attacks_bb<QUEEN>(pos.square<KING>(~Us));
while (b) while (b)
*moveList++ = make_move(ksq, pop_lsb(b)); *moveList++ = Move(ksq, pop_lsb(b));
if ((Type == QUIETS || Type == NON_EVASIONS) && pos.can_castle(Us & ANY_CASTLING)) if ((Type == QUIETS || Type == NON_EVASIONS) && pos.can_castle(Us & ANY_CASTLING))
for (CastlingRights cr : { Us & KING_SIDE, Us & QUEEN_SIDE } ) for (CastlingRights cr : {Us & KING_SIDE, Us & QUEEN_SIDE})
if (!pos.castling_impeded(cr) && pos.can_castle(cr)) if (!pos.castling_impeded(cr) && pos.can_castle(cr))
*moveList++ = make<CASTLING>(ksq, pos.castling_rook_square(cr)); *moveList++ = Move::make<CASTLING>(ksq, pos.castling_rook_square(cr));
}
return moveList; return moveList;
} }
} // namespace } // namespace
/// <CAPTURES> Generates all pseudo-legal captures plus queen promotions // <CAPTURES> Generates all pseudo-legal captures plus queen promotions
/// <QUIETS> Generates all pseudo-legal non-captures and underpromotions // <QUIETS> Generates all pseudo-legal non-captures and underpromotions
/// <EVASIONS> Generates all pseudo-legal check evasions when the side to move is in check // <EVASIONS> Generates all pseudo-legal check evasions
/// <QUIET_CHECKS> Generates all pseudo-legal non-captures giving check, except castling and promotions // <NON_EVASIONS> Generates all pseudo-legal captures and non-captures
/// <NON_EVASIONS> Generates all pseudo-legal captures and non-captures //
/// // Returns a pointer to the end of the move list.
/// Returns a pointer to the end of the move list.
template<GenType Type> template<GenType Type>
ExtMove* generate(const Position& pos, ExtMove* moveList) { ExtMove* generate(const Position& pos, ExtMove* moveList) {
static_assert(Type != LEGAL, "Unsupported type in generate()"); static_assert(Type != LEGAL, "Unsupported type in generate()");
assert((Type == EVASIONS) == (bool)pos.checkers()); assert((Type == EVASIONS) == bool(pos.checkers()));
Color us = pos.side_to_move(); Color us = pos.side_to_move();
return us == WHITE ? generate_all<WHITE, Type>(pos, moveList) return us == WHITE ? generate_all<WHITE, Type>(pos, moveList)
: generate_all<BLACK, Type>(pos, moveList); : generate_all<BLACK, Type>(pos, moveList);
} }
// Explicit template instantiations // Explicit template instantiations
template ExtMove* generate<CAPTURES>(const Position&, ExtMove*); template ExtMove* generate<CAPTURES>(const Position&, ExtMove*);
template ExtMove* generate<QUIETS>(const Position&, ExtMove*); template ExtMove* generate<QUIETS>(const Position&, ExtMove*);
template ExtMove* generate<EVASIONS>(const Position&, ExtMove*); template ExtMove* generate<EVASIONS>(const Position&, ExtMove*);
template ExtMove* generate<QUIET_CHECKS>(const Position&, ExtMove*);
template ExtMove* generate<NON_EVASIONS>(const Position&, ExtMove*); template ExtMove* generate<NON_EVASIONS>(const Position&, ExtMove*);
/// generate<LEGAL> generates all the legal moves in the given position // generate<LEGAL> generates all the legal moves in the given position
template<> template<>
ExtMove* generate<LEGAL>(const Position& pos, ExtMove* moveList) { ExtMove* generate<LEGAL>(const Position& pos, ExtMove* moveList) {
Color us = pos.side_to_move(); Color us = pos.side_to_move();
Bitboard pinned = pos.blockers_for_king(us) & pos.pieces(us); Bitboard pinned = pos.blockers_for_king(us) & pos.pieces(us);
Square ksq = pos.square<KING>(us); Square ksq = pos.square<KING>(us);
ExtMove* cur = moveList; ExtMove* cur = moveList;
moveList = pos.checkers() ? generate<EVASIONS >(pos, moveList) moveList =
: generate<NON_EVASIONS>(pos, moveList); pos.checkers() ? generate<EVASIONS>(pos, moveList) : generate<NON_EVASIONS>(pos, moveList);
while (cur != moveList) while (cur != moveList)
if ( ((pinned & from_sq(*cur)) || from_sq(*cur) == ksq || type_of(*cur) == EN_PASSANT) if (((pinned & cur->from_sq()) || cur->from_sq() == ksq || cur->type_of() == EN_PASSANT)
&& !pos.legal(*cur)) && !pos.legal(*cur))
*cur = (--moveList)->move; *cur = *(--moveList);
else else
++cur; ++cur;
return moveList; return moveList;
} }
} // namespace Stockfish } // namespace Stockfish
+28 -32
View File
@@ -1,6 +1,6 @@
/* /*
Stockfish, a UCI chess playing engine derived from Glaurung 2.1 Stockfish, a UCI chess playing engine derived from Glaurung 2.1
Copyright (C) 2004-2023 The Stockfish developers (see AUTHORS file) Copyright (C) 2004-2025 The Stockfish developers (see AUTHORS file)
Stockfish is free software: you can redistribute it and/or modify Stockfish is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by it under the terms of the GNU General Public License as published by
@@ -19,7 +19,8 @@
#ifndef MOVEGEN_H_INCLUDED #ifndef MOVEGEN_H_INCLUDED
#define MOVEGEN_H_INCLUDED #define MOVEGEN_H_INCLUDED
#include <algorithm> #include <algorithm> // IWYU pragma: keep
#include <cstddef>
#include "types.h" #include "types.h"
@@ -28,50 +29,45 @@ namespace Stockfish {
class Position; class Position;
enum GenType { enum GenType {
CAPTURES, CAPTURES,
QUIETS, QUIETS,
QUIET_CHECKS, EVASIONS,
EVASIONS, NON_EVASIONS,
NON_EVASIONS, LEGAL
LEGAL
}; };
struct ExtMove { struct ExtMove: public Move {
Move move; int value;
int value;
operator Move() const { return move; } void operator=(Move m) { data = m.raw(); }
void operator=(Move m) { move = m; }
// Inhibit unwanted implicit conversions to Move // Inhibit unwanted implicit conversions to Move
// with an ambiguity that yields to a compile error. // with an ambiguity that yields to a compile error.
operator float() const = delete; operator float() const = delete;
}; };
inline bool operator<(const ExtMove& f, const ExtMove& s) { inline bool operator<(const ExtMove& f, const ExtMove& s) { return f.value < s.value; }
return f.value < s.value;
}
template<GenType> template<GenType>
ExtMove* generate(const Position& pos, ExtMove* moveList); ExtMove* generate(const Position& pos, ExtMove* moveList);
/// The MoveList struct is a simple wrapper around generate(). It sometimes comes // The MoveList struct wraps the generate() function and returns a convenient
/// in handy to use this class instead of the low level generate() function. // list of moves. Using MoveList is sometimes preferable to directly calling
// the lower level generate() function.
template<GenType T> template<GenType T>
struct MoveList { struct MoveList {
explicit MoveList(const Position& pos) : last(generate<T>(pos, moveList)) {} explicit MoveList(const Position& pos) :
const ExtMove* begin() const { return moveList; } last(generate<T>(pos, moveList)) {}
const ExtMove* end() const { return last; } const ExtMove* begin() const { return moveList; }
size_t size() const { return last - moveList; } const ExtMove* end() const { return last; }
bool contains(Move move) const { size_t size() const { return last - moveList; }
return std::find(begin(), end(), move) != end(); bool contains(Move move) const { return std::find(begin(), end(), move) != end(); }
}
private: private:
ExtMove moveList[MAX_MOVES], *last; ExtMove moveList[MAX_MOVES], *last;
}; };
} // namespace Stockfish } // namespace Stockfish
#endif // #ifndef MOVEGEN_H_INCLUDED #endif // #ifndef MOVEGEN_H_INCLUDED
+236 -211
View File
@@ -1,6 +1,6 @@
/* /*
Stockfish, a UCI chess playing engine derived from Glaurung 2.1 Stockfish, a UCI chess playing engine derived from Glaurung 2.1
Copyright (C) 2004-2023 The Stockfish developers (see AUTHORS file) Copyright (C) 2004-2025 The Stockfish developers (see AUTHORS file)
Stockfish is free software: you can redistribute it and/or modify Stockfish is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by it under the terms of the GNU General Public License as published by
@@ -16,280 +16,305 @@
along with this program. If not, see <http://www.gnu.org/licenses/>. along with this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
#include "movepick.h"
#include <cassert> #include <cassert>
#include <limits>
#include "bitboard.h" #include "bitboard.h"
#include "movepick.h" #include "misc.h"
#include "position.h"
namespace Stockfish { namespace Stockfish {
namespace { namespace {
enum Stages { enum Stages {
MAIN_TT, CAPTURE_INIT, GOOD_CAPTURE, REFUTATION, QUIET_INIT, QUIET, BAD_CAPTURE, // generate main search moves
EVASION_TT, EVASION_INIT, EVASION, MAIN_TT,
PROBCUT_TT, PROBCUT_INIT, PROBCUT, CAPTURE_INIT,
QSEARCH_TT, QCAPTURE_INIT, QCAPTURE, QCHECK_INIT, QCHECK GOOD_CAPTURE,
}; QUIET_INIT,
GOOD_QUIET,
BAD_CAPTURE,
BAD_QUIET,
// partial_insertion_sort() sorts moves in descending order up to and including // generate evasion moves
// a given limit. The order of moves smaller than the limit is left unspecified. EVASION_TT,
void partial_insertion_sort(ExtMove* begin, ExtMove* end, int limit) { EVASION_INIT,
EVASION,
// generate probcut moves
PROBCUT_TT,
PROBCUT_INIT,
PROBCUT,
// generate qsearch moves
QSEARCH_TT,
QCAPTURE_INIT,
QCAPTURE
};
// Sort moves in descending order up to and including a given limit.
// The order of moves smaller than the limit is left unspecified.
void partial_insertion_sort(ExtMove* begin, ExtMove* end, int limit) {
for (ExtMove *sortedEnd = begin, *p = begin + 1; p < end; ++p) for (ExtMove *sortedEnd = begin, *p = begin + 1; p < end; ++p)
if (p->value >= limit) if (p->value >= limit)
{ {
ExtMove tmp = *p, *q; ExtMove tmp = *p, *q;
*p = *++sortedEnd; *p = *++sortedEnd;
for (q = sortedEnd; q != begin && *(q - 1) < tmp; --q) for (q = sortedEnd; q != begin && *(q - 1) < tmp; --q)
*q = *(q - 1); *q = *(q - 1);
*q = tmp; *q = tmp;
} }
}
} // namespace
/// Constructors of the MovePicker class. As arguments we pass information
/// to help it to return the (presumably) good moves first, to decide which
/// moves to return (in the quiescence search, for instance, we only want to
/// search captures, promotions, and some checks) and how important good move
/// ordering is at the current node.
/// MovePicker constructor for the main search
MovePicker::MovePicker(const Position& p, Move ttm, Depth d, const ButterflyHistory* mh,
const CapturePieceToHistory* cph,
const PieceToHistory** ch,
Move cm,
const Move* killers)
: pos(p), mainHistory(mh), captureHistory(cph), continuationHistory(ch),
ttMove(ttm), refutations{{killers[0], 0}, {killers[1], 0}, {cm, 0}}, depth(d)
{
assert(d > 0);
stage = (pos.checkers() ? EVASION_TT : MAIN_TT) +
!(ttm && pos.pseudo_legal(ttm));
} }
/// MovePicker constructor for quiescence search } // namespace
MovePicker::MovePicker(const Position& p, Move ttm, Depth d, const ButterflyHistory* mh,
const CapturePieceToHistory* cph,
const PieceToHistory** ch,
Square rs)
: pos(p), mainHistory(mh), captureHistory(cph), continuationHistory(ch), ttMove(ttm), recaptureSquare(rs), depth(d)
{
assert(d <= 0);
stage = (pos.checkers() ? EVASION_TT : QSEARCH_TT) +
!( ttm // Constructors of the MovePicker class. As arguments, we pass information
&& pos.pseudo_legal(ttm)); // to decide which class of moves to emit, to help sorting the (presumably)
// good moves first, and how important move ordering is at the current node.
// MovePicker constructor for the main search and for the quiescence search
MovePicker::MovePicker(const Position& p,
Move ttm,
Depth d,
const ButterflyHistory* mh,
const LowPlyHistory* lph,
const CapturePieceToHistory* cph,
const PieceToHistory** ch,
const PawnHistory* ph,
int pl) :
pos(p),
mainHistory(mh),
lowPlyHistory(lph),
captureHistory(cph),
continuationHistory(ch),
pawnHistory(ph),
ttMove(ttm),
depth(d),
ply(pl) {
if (pos.checkers())
stage = EVASION_TT + !(ttm && pos.pseudo_legal(ttm));
else
stage = (depth > 0 ? MAIN_TT : QSEARCH_TT) + !(ttm && pos.pseudo_legal(ttm));
} }
/// MovePicker constructor for ProbCut: we generate captures with SEE greater // MovePicker constructor for ProbCut: we generate captures with Static Exchange
/// than or equal to the given threshold. // Evaluation (SEE) greater than or equal to the given threshold.
MovePicker::MovePicker(const Position& p, Move ttm, Value th, const CapturePieceToHistory* cph) MovePicker::MovePicker(const Position& p, Move ttm, int th, const CapturePieceToHistory* cph) :
: pos(p), captureHistory(cph), ttMove(ttm), threshold(th) pos(p),
{ captureHistory(cph),
assert(!pos.checkers()); ttMove(ttm),
threshold(th) {
assert(!pos.checkers());
stage = PROBCUT_TT + !(ttm && pos.capture_stage(ttm) stage = PROBCUT_TT
&& pos.pseudo_legal(ttm) + !(ttm && pos.capture_stage(ttm) && pos.pseudo_legal(ttm) && pos.see_ge(ttm, threshold));
&& pos.see_ge(ttm, threshold));
} }
/// MovePicker::score() assigns a numerical value to each move in a list, used // Assigns a numerical value to each move in a list, used for sorting.
/// for sorting. Captures are ordered by Most Valuable Victim (MVV), preferring // Captures are ordered by Most Valuable Victim (MVV), preferring captures
/// captures with a good history. Quiets moves are ordered using the history tables. // with a good history. Quiets moves are ordered using the history tables.
template<GenType Type> template<GenType Type>
void MovePicker::score() { void MovePicker::score() {
static_assert(Type == CAPTURES || Type == QUIETS || Type == EVASIONS, "Wrong type"); static_assert(Type == CAPTURES || Type == QUIETS || Type == EVASIONS, "Wrong type");
[[maybe_unused]] Bitboard threatenedByPawn, threatenedByMinor, threatenedByRook, threatenedPieces; [[maybe_unused]] Bitboard threatenedByPawn, threatenedByMinor, threatenedByRook,
if constexpr (Type == QUIETS) threatenedPieces;
{ if constexpr (Type == QUIETS)
Color us = pos.side_to_move(); {
Color us = pos.side_to_move();
threatenedByPawn = pos.attacks_by<PAWN>(~us); threatenedByPawn = pos.attacks_by<PAWN>(~us);
threatenedByMinor = pos.attacks_by<KNIGHT>(~us) | pos.attacks_by<BISHOP>(~us) | threatenedByPawn; threatenedByMinor =
threatenedByRook = pos.attacks_by<ROOK>(~us) | threatenedByMinor; pos.attacks_by<KNIGHT>(~us) | pos.attacks_by<BISHOP>(~us) | threatenedByPawn;
threatenedByRook = pos.attacks_by<ROOK>(~us) | threatenedByMinor;
// Pieces threatened by pieces of lesser material value // Pieces threatened by pieces of lesser material value
threatenedPieces = (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);
} }
for (auto& m : *this) for (auto& m : *this)
if constexpr (Type == CAPTURES) if constexpr (Type == CAPTURES)
m.value = (7 * int(PieceValue[MG][pos.piece_on(to_sq(m))]) m.value =
+ (*captureHistory)[pos.moved_piece(m)][to_sq(m)][type_of(pos.piece_on(to_sq(m)))]) / 16; 7 * int(PieceValue[pos.piece_on(m.to_sq())])
+ (*captureHistory)[pos.moved_piece(m)][m.to_sq()][type_of(pos.piece_on(m.to_sq()))];
else if constexpr (Type == QUIETS) else if constexpr (Type == QUIETS)
m.value = 2 * (*mainHistory)[pos.side_to_move()][from_to(m)] {
+ 2 * (*continuationHistory[0])[pos.moved_piece(m)][to_sq(m)] Piece pc = pos.moved_piece(m);
+ (*continuationHistory[1])[pos.moved_piece(m)][to_sq(m)] PieceType pt = type_of(pc);
+ (*continuationHistory[3])[pos.moved_piece(m)][to_sq(m)] Square from = m.from_sq();
+ (*continuationHistory[5])[pos.moved_piece(m)][to_sq(m)] Square to = m.to_sq();
+ (threatenedPieces & from_sq(m) ?
(type_of(pos.moved_piece(m)) == QUEEN && !(to_sq(m) & threatenedByRook) ? 50000 // histories
: type_of(pos.moved_piece(m)) == ROOK && !(to_sq(m) & threatenedByMinor) ? 25000 m.value = 2 * (*mainHistory)[pos.side_to_move()][m.from_to()];
: !(to_sq(m) & threatenedByPawn) ? 15000 m.value += 2 * (*pawnHistory)[pawn_structure_index(pos)][pc][to];
: 0) m.value += (*continuationHistory[0])[pc][to];
: 0) m.value += (*continuationHistory[1])[pc][to];
+ bool(pos.check_squares(type_of(pos.moved_piece(m))) & to_sq(m)) * 16384; m.value += (*continuationHistory[2])[pc][to];
else // Type == EVASIONS m.value += (*continuationHistory[3])[pc][to];
{ m.value += (*continuationHistory[4])[pc][to] / 3;
if (pos.capture_stage(m)) m.value += (*continuationHistory[5])[pc][to];
m.value = PieceValue[MG][pos.piece_on(to_sq(m))]
- Value(type_of(pos.moved_piece(m))) // bonus for checks
+ (1 << 28); m.value += bool(pos.check_squares(pt) & to) * 16384;
else
m.value = (*mainHistory)[pos.side_to_move()][from_to(m)] // bonus for escaping from capture
+ (*continuationHistory[0])[pos.moved_piece(m)][to_sq(m)]; m.value += threatenedPieces & from ? (pt == QUEEN && !(to & threatenedByRook) ? 51700
} : pt == ROOK && !(to & threatenedByMinor) ? 25600
: !(to & threatenedByPawn) ? 14450
: 0)
: 0;
// malus for putting piece en prise
m.value -= (pt == QUEEN ? bool(to & threatenedByRook) * 49000
: pt == ROOK && bool(to & threatenedByMinor) ? 24335
: 0);
if (ply < LOW_PLY_HISTORY_SIZE)
m.value += 8 * (*lowPlyHistory)[ply][m.from_to()] / (1 + 2 * ply);
}
else // Type == EVASIONS
{
if (pos.capture_stage(m))
m.value = PieceValue[pos.piece_on(m.to_sq())] + (1 << 28);
else
m.value = (*mainHistory)[pos.side_to_move()][m.from_to()]
+ (*continuationHistory[0])[pos.moved_piece(m)][m.to_sq()]
+ (*pawnHistory)[pawn_structure_index(pos)][pos.moved_piece(m)][m.to_sq()];
}
} }
/// MovePicker::select() returns the next move satisfying a predicate function. // Returns the next move satisfying a predicate function.
/// It never returns the TT move. // This never returns the TT move, as it was emitted before.
template<MovePicker::PickType T, typename Pred> template<typename Pred>
Move MovePicker::select(Pred filter) { Move MovePicker::select(Pred filter) {
while (cur < endMoves) for (; cur < endMoves; ++cur)
{ if (*cur != ttMove && filter())
if constexpr (T == Best) return *cur++;
std::swap(*cur, *std::max_element(cur, endMoves));
if (*cur != ttMove && filter()) return Move::none();
return *cur++;
cur++;
}
return MOVE_NONE;
} }
/// MovePicker::next_move() is the most important method of the MovePicker class. It // This is the most important method of the MovePicker class. We emit one
/// returns a new pseudo-legal move every time it is called until there are no more // new pseudo-legal move on every call until there are no more moves left,
/// moves left, picking the move with the highest score from a list of generated moves. // picking the move with the highest score from a list of generated moves.
Move MovePicker::next_move(bool skipQuiets) { Move MovePicker::next_move() {
auto quiet_threshold = [](Depth d) { return -3560 * d; };
top: top:
switch (stage) { switch (stage)
{
case MAIN_TT: case MAIN_TT :
case EVASION_TT: case EVASION_TT :
case QSEARCH_TT: case QSEARCH_TT :
case PROBCUT_TT: case PROBCUT_TT :
++stage; ++stage;
return ttMove; return ttMove;
case CAPTURE_INIT: case CAPTURE_INIT :
case PROBCUT_INIT: case PROBCUT_INIT :
case QCAPTURE_INIT: case QCAPTURE_INIT :
cur = endBadCaptures = moves; cur = endBadCaptures = moves;
endMoves = generate<CAPTURES>(pos, cur); endMoves = generate<CAPTURES>(pos, cur);
score<CAPTURES>(); score<CAPTURES>();
partial_insertion_sort(cur, endMoves, std::numeric_limits<int>::min()); partial_insertion_sort(cur, endMoves, std::numeric_limits<int>::min());
++stage; ++stage;
goto top; goto top;
case GOOD_CAPTURE: case GOOD_CAPTURE :
if (select<Next>([&](){ if (select([&]() {
return pos.see_ge(*cur, Value(-cur->value)) ? // Move losing capture to endBadCaptures to be tried later
// Move losing capture to endBadCaptures to be tried later return pos.see_ge(*cur, -cur->value / 18) ? true
true : (*endBadCaptures++ = *cur, false); })) : (*endBadCaptures++ = *cur, false);
return *(cur - 1); }))
return *(cur - 1);
// Prepare the pointers to loop over the refutations array ++stage;
cur = std::begin(refutations); [[fallthrough]];
endMoves = std::end(refutations);
// If the countermove is the same as a killer, skip it case QUIET_INIT :
if ( refutations[0].move == refutations[2].move if (!skipQuiets)
|| refutations[1].move == refutations[2].move) {
--endMoves; cur = endBadCaptures;
endMoves = beginBadQuiets = endBadQuiets = generate<QUIETS>(pos, cur);
++stage; score<QUIETS>();
[[fallthrough]]; partial_insertion_sort(cur, endMoves, quiet_threshold(depth));
}
case REFUTATION: ++stage;
if (select<Next>([&](){ return *cur != MOVE_NONE [[fallthrough]];
&& !pos.capture_stage(*cur)
&& pos.pseudo_legal(*cur); }))
return *(cur - 1);
++stage;
[[fallthrough]];
case QUIET_INIT: case GOOD_QUIET :
if (!skipQuiets) if (!skipQuiets && select([]() { return true; }))
{ {
cur = endBadCaptures; if ((cur - 1)->value > -7998 || (cur - 1)->value <= quiet_threshold(depth))
endMoves = generate<QUIETS>(pos, cur); return *(cur - 1);
score<QUIETS>(); // Remaining quiets are bad
partial_insertion_sort(cur, endMoves, -3000 * depth); beginBadQuiets = cur - 1;
} }
++stage; // Prepare the pointers to loop over the bad captures
[[fallthrough]]; cur = moves;
endMoves = endBadCaptures;
case QUIET: ++stage;
if ( !skipQuiets [[fallthrough]];
&& select<Next>([&](){return *cur != refutations[0].move
&& *cur != refutations[1].move
&& *cur != refutations[2].move;}))
return *(cur - 1);
// Prepare the pointers to loop over the bad captures case BAD_CAPTURE :
cur = moves; if (select([]() { return true; }))
endMoves = endBadCaptures; return *(cur - 1);
++stage; // Prepare the pointers to loop over the bad quiets
[[fallthrough]]; cur = beginBadQuiets;
endMoves = endBadQuiets;
case BAD_CAPTURE: ++stage;
return select<Next>([](){ return true; }); [[fallthrough]];
case EVASION_INIT: case BAD_QUIET :
cur = moves; if (!skipQuiets)
endMoves = generate<EVASIONS>(pos, cur); return select([]() { return true; });
score<EVASIONS>(); return Move::none();
++stage;
[[fallthrough]];
case EVASION: case EVASION_INIT :
return select<Best>([](){ return true; }); cur = moves;
endMoves = generate<EVASIONS>(pos, cur);
case PROBCUT: score<EVASIONS>();
return select<Next>([&](){ return pos.see_ge(*cur, threshold); }); partial_insertion_sort(cur, endMoves, std::numeric_limits<int>::min());
++stage;
[[fallthrough]];
case QCAPTURE: case EVASION :
if (select<Next>([&](){ return depth > DEPTH_QS_RECAPTURES case QCAPTURE :
|| to_sq(*cur) == recaptureSquare; })) return select([]() { return true; });
return *(cur - 1);
// If we did not find any move and we do not try checks, we have finished case PROBCUT :
if (depth != DEPTH_QS_CHECKS) return select([&]() { return pos.see_ge(*cur, threshold); });
return MOVE_NONE; }
++stage; assert(false);
[[fallthrough]]; return Move::none(); // Silence warning
case QCHECK_INIT:
cur = moves;
endMoves = generate<QUIET_CHECKS>(pos, cur);
++stage;
[[fallthrough]];
case QCHECK:
return select<Next>([](){ return true; });
}
assert(false);
return MOVE_NONE; // Silence warning
} }
} // namespace Stockfish void MovePicker::skip_quiet_moves() { skipQuiets = true; }
} // namespace Stockfish
+47 -122
View File
@@ -1,6 +1,6 @@
/* /*
Stockfish, a UCI chess playing engine derived from Glaurung 2.1 Stockfish, a UCI chess playing engine derived from Glaurung 2.1
Copyright (C) 2004-2023 The Stockfish developers (see AUTHORS file) Copyright (C) 2004-2025 The Stockfish developers (see AUTHORS file)
Stockfish is free software: you can redistribute it and/or modify Stockfish is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by it under the terms of the GNU General Public License as published by
@@ -19,137 +19,62 @@
#ifndef MOVEPICK_H_INCLUDED #ifndef MOVEPICK_H_INCLUDED
#define MOVEPICK_H_INCLUDED #define MOVEPICK_H_INCLUDED
#include <array> #include "history.h"
#include <limits>
#include <type_traits>
#include "movegen.h" #include "movegen.h"
#include "position.h"
#include "types.h" #include "types.h"
namespace Stockfish { namespace Stockfish {
/// StatsEntry stores the stat table value. It is usually a number but could class Position;
/// be a move or even a nested history. We use a class instead of naked value
/// to directly call history update operator<<() on the entry so to use stats
/// tables at caller sites as simple multi-dim arrays.
template<typename T, int D>
class StatsEntry {
T entry; // The MovePicker class is used to pick one pseudo-legal move at a time from the
// current position. The most important method is next_move(), which emits one
public: // new pseudo-legal move on every call, until there are no moves left, when
void operator=(const T& v) { entry = v; } // Move::none() is returned. In order to improve the efficiency of the alpha-beta
T* operator&() { return &entry; } // algorithm, MovePicker attempts to return the moves which are most likely to get
T* operator->() { return &entry; } // a cut-off first.
operator const T&() const { return entry; }
void operator<<(int bonus) {
assert(abs(bonus) <= D); // Ensure range is [-D, D]
static_assert(D <= std::numeric_limits<T>::max(), "D overflows T");
entry += bonus - entry * abs(bonus) / D;
assert(abs(entry) <= D);
}
};
/// Stats is a generic N-dimensional array used to store various statistics.
/// The first template parameter T is the base type of the array, the second
/// template parameter D limits the range of updates in [-D, D] when we update
/// values with the << operator, while the last parameters (Size and Sizes)
/// encode the dimensions of the array.
template <typename T, int D, int Size, int... Sizes>
struct Stats : public std::array<Stats<T, D, Sizes...>, Size>
{
using stats = Stats<T, D, Size, Sizes...>;
void fill(const T& v) {
// For standard-layout 'this' points to first struct member
assert(std::is_standard_layout<stats>::value);
using entry = StatsEntry<T, D>;
entry* p = reinterpret_cast<entry*>(this);
std::fill(p, p + sizeof(*this) / sizeof(entry), v);
}
};
template <typename T, int D, int Size>
struct Stats<T, D, Size> : public std::array<StatsEntry<T, D>, Size> {};
/// In stats table, D=0 means that the template parameter is not used
enum StatsParams { NOT_USED = 0 };
enum StatsType { NoCaptures, Captures };
/// ButterflyHistory records how often quiet moves have been successful or
/// unsuccessful during the current search, and is used for reduction and move
/// ordering decisions. It uses 2 tables (one for each color) indexed by
/// the move's from and to squares, see www.chessprogramming.org/Butterfly_Boards
/// (~11 elo)
using ButterflyHistory = Stats<int16_t, 7183, COLOR_NB, int(SQUARE_NB) * int(SQUARE_NB)>;
/// CounterMoveHistory stores counter moves indexed by [piece][to] of the previous
/// move, see www.chessprogramming.org/Countermove_Heuristic
using CounterMoveHistory = Stats<Move, NOT_USED, PIECE_NB, SQUARE_NB>;
/// CapturePieceToHistory is addressed by a move's [piece][to][captured piece type]
using CapturePieceToHistory = Stats<int16_t, 10692, PIECE_NB, SQUARE_NB, PIECE_TYPE_NB>;
/// PieceToHistory is like ButterflyHistory but is addressed by a move's [piece][to]
using PieceToHistory = Stats<int16_t, 29952, PIECE_NB, SQUARE_NB>;
/// ContinuationHistory is the combined history of a given pair of moves, usually
/// the current one given a previous one. The nested history table is based on
/// PieceToHistory instead of ButterflyBoards.
/// (~63 elo)
using ContinuationHistory = Stats<PieceToHistory, NOT_USED, PIECE_NB, SQUARE_NB>;
/// MovePicker class is used to pick one pseudo-legal move at a time from the
/// current position. The most important method is next_move(), which returns a
/// new pseudo-legal move each time it is called, until there are no moves left,
/// when MOVE_NONE is returned. In order to improve the efficiency of the
/// alpha-beta algorithm, MovePicker attempts to return the moves which are most
/// likely to get a cut-off first.
class MovePicker { class MovePicker {
enum PickType { Next, Best }; public:
MovePicker(const MovePicker&) = delete;
MovePicker& operator=(const MovePicker&) = delete;
MovePicker(const Position&,
Move,
Depth,
const ButterflyHistory*,
const LowPlyHistory*,
const CapturePieceToHistory*,
const PieceToHistory**,
const PawnHistory*,
int);
MovePicker(const Position&, Move, int, const CapturePieceToHistory*);
Move next_move();
void skip_quiet_moves();
public: private:
MovePicker(const MovePicker&) = delete; template<typename Pred>
MovePicker& operator=(const MovePicker&) = delete; Move select(Pred);
MovePicker(const Position&, Move, Depth, const ButterflyHistory*, template<GenType>
const CapturePieceToHistory*, void score();
const PieceToHistory**, ExtMove* begin() { return cur; }
Move, ExtMove* end() { return endMoves; }
const Move*);
MovePicker(const Position&, Move, Depth, const ButterflyHistory*,
const CapturePieceToHistory*,
const PieceToHistory**,
Square);
MovePicker(const Position&, Move, Value, const CapturePieceToHistory*);
Move next_move(bool skipQuiets = false);
private: const Position& pos;
template<PickType T, typename Pred> Move select(Pred); const ButterflyHistory* mainHistory;
template<GenType> void score(); const LowPlyHistory* lowPlyHistory;
ExtMove* begin() { return cur; } const CapturePieceToHistory* captureHistory;
ExtMove* end() { return endMoves; } const PieceToHistory** continuationHistory;
const PawnHistory* pawnHistory;
const Position& pos; Move ttMove;
const ButterflyHistory* mainHistory; ExtMove * cur, *endMoves, *endBadCaptures, *beginBadQuiets, *endBadQuiets;
const CapturePieceToHistory* captureHistory; int stage;
const PieceToHistory** continuationHistory; int threshold;
Move ttMove; Depth depth;
ExtMove refutations[3], *cur, *endMoves, *endBadCaptures; int ply;
int stage; bool skipQuiets = false;
Square recaptureSquare; ExtMove moves[MAX_MOVES];
Value threshold;
Depth depth;
ExtMove moves[MAX_MOVES];
}; };
} // namespace Stockfish } // namespace Stockfish
#endif // #ifndef MOVEPICK_H_INCLUDED #endif // #ifndef MOVEPICK_H_INCLUDED
-405
View File
@@ -1,405 +0,0 @@
/*
Stockfish, a UCI chess playing engine derived from Glaurung 2.1
Copyright (C) 2004-2023 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/>.
*/
// Code for calculating NNUE evaluation function
#include <fstream>
#include <iomanip>
#include <iostream>
#include <set>
#include <sstream>
#include <string_view>
#include "../evaluate.h"
#include "../position.h"
#include "../uci.h"
#include "../types.h"
#include "evaluate_nnue.h"
namespace Stockfish::Eval::NNUE {
// Input feature converter
LargePagePtr<FeatureTransformer> featureTransformer;
// Evaluation function
AlignedPtr<Network> network[LayerStacks];
// Evaluation function file name
std::string fileName;
std::string netDescription;
namespace Detail {
// Initialize the evaluation function parameters
template <typename T>
void initialize(AlignedPtr<T>& pointer) {
pointer.reset(reinterpret_cast<T*>(std_aligned_alloc(alignof(T), sizeof(T))));
std::memset(pointer.get(), 0, sizeof(T));
}
template <typename T>
void initialize(LargePagePtr<T>& pointer) {
static_assert(alignof(T) <= 4096, "aligned_large_pages_alloc() may fail for such a big alignment requirement of T");
pointer.reset(reinterpret_cast<T*>(aligned_large_pages_alloc(sizeof(T))));
std::memset(pointer.get(), 0, sizeof(T));
}
// Read evaluation function parameters
template <typename T>
bool read_parameters(std::istream& stream, T& reference) {
std::uint32_t header;
header = read_little_endian<std::uint32_t>(stream);
if (!stream || header != T::get_hash_value()) return false;
return reference.read_parameters(stream);
}
// Write evaluation function parameters
template <typename T>
bool write_parameters(std::ostream& stream, const T& reference) {
write_little_endian<std::uint32_t>(stream, T::get_hash_value());
return reference.write_parameters(stream);
}
} // namespace Detail
// Initialize the evaluation function parameters
static void initialize() {
Detail::initialize(featureTransformer);
for (std::size_t i = 0; i < LayerStacks; ++i)
Detail::initialize(network[i]);
}
// Read network header
static bool read_header(std::istream& stream, std::uint32_t* hashValue, std::string* desc)
{
std::uint32_t version, size;
version = read_little_endian<std::uint32_t>(stream);
*hashValue = read_little_endian<std::uint32_t>(stream);
size = read_little_endian<std::uint32_t>(stream);
if (!stream || version != Version) return false;
desc->resize(size);
stream.read(&(*desc)[0], size);
return !stream.fail();
}
// Write network header
static bool write_header(std::ostream& stream, std::uint32_t hashValue, const std::string& desc)
{
write_little_endian<std::uint32_t>(stream, Version);
write_little_endian<std::uint32_t>(stream, hashValue);
write_little_endian<std::uint32_t>(stream, (std::uint32_t)desc.size());
stream.write(&desc[0], desc.size());
return !stream.fail();
}
// Read network parameters
static bool read_parameters(std::istream& stream) {
std::uint32_t hashValue;
if (!read_header(stream, &hashValue, &netDescription)) return false;
if (hashValue != HashValue) return false;
if (!Detail::read_parameters(stream, *featureTransformer)) return false;
for (std::size_t i = 0; i < LayerStacks; ++i)
if (!Detail::read_parameters(stream, *(network[i]))) return false;
return stream && stream.peek() == std::ios::traits_type::eof();
}
// Write network parameters
static bool write_parameters(std::ostream& stream) {
if (!write_header(stream, HashValue, netDescription)) return false;
if (!Detail::write_parameters(stream, *featureTransformer)) return false;
for (std::size_t i = 0; i < LayerStacks; ++i)
if (!Detail::write_parameters(stream, *(network[i]))) return false;
return (bool)stream;
}
void hint_common_parent_position(const Position& pos) {
if (Eval::useNNUE)
featureTransformer->hint_common_access(pos);
}
// Evaluation function. Perform differential calculation.
Value evaluate(const Position& pos, bool adjusted, int* complexity) {
// We manually align the arrays on the stack because with gcc < 9.3
// overaligning stack variables with alignas() doesn't work correctly.
constexpr uint64_t alignment = CacheLineSize;
constexpr int delta = 24;
#if defined(ALIGNAS_ON_STACK_VARIABLES_BROKEN)
TransformedFeatureType transformedFeaturesUnaligned[
FeatureTransformer::BufferSize + alignment / sizeof(TransformedFeatureType)];
auto* transformedFeatures = align_ptr_up<alignment>(&transformedFeaturesUnaligned[0]);
#else
alignas(alignment)
TransformedFeatureType transformedFeatures[FeatureTransformer::BufferSize];
#endif
ASSERT_ALIGNED(transformedFeatures, alignment);
const int bucket = (pos.count<ALL_PIECES>() - 1) / 4;
const auto psqt = featureTransformer->transform(pos, transformedFeatures, bucket);
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
if (adjusted)
return static_cast<Value>(((1024 - delta) * psqt + (1024 + delta) * positional) / (1024 * OutputScale));
else
return static_cast<Value>((psqt + positional) / OutputScale);
}
struct NnueEvalTrace {
static_assert(LayerStacks == PSQTBuckets);
Value psqt[LayerStacks];
Value positional[LayerStacks];
std::size_t correctBucket;
};
static NnueEvalTrace trace_evaluate(const Position& pos) {
// We manually align the arrays on the stack because with gcc < 9.3
// overaligning stack variables with alignas() doesn't work correctly.
constexpr uint64_t alignment = CacheLineSize;
#if defined(ALIGNAS_ON_STACK_VARIABLES_BROKEN)
TransformedFeatureType transformedFeaturesUnaligned[
FeatureTransformer::BufferSize + alignment / sizeof(TransformedFeatureType)];
auto* transformedFeatures = align_ptr_up<alignment>(&transformedFeaturesUnaligned[0]);
#else
alignas(alignment)
TransformedFeatureType transformedFeatures[FeatureTransformer::BufferSize];
#endif
ASSERT_ALIGNED(transformedFeatures, alignment);
NnueEvalTrace t{};
t.correctBucket = (pos.count<ALL_PIECES>() - 1) / 4;
for (IndexType bucket = 0; bucket < LayerStacks; ++bucket) {
const auto materialist = featureTransformer->transform(pos, transformedFeatures, bucket);
const auto positional = network[bucket]->propagate(transformedFeatures);
t.psqt[bucket] = static_cast<Value>( materialist / OutputScale );
t.positional[bucket] = static_cast<Value>( positional / OutputScale );
}
return t;
}
constexpr std::string_view PieceToChar(" PNBRQK pnbrqk");
// format_cp_compact() converts a Value into (centi)pawns and writes it in a buffer.
// The buffer must have capacity for at least 5 chars.
static void format_cp_compact(Value v, char* buffer) {
buffer[0] = (v < 0 ? '-' : v > 0 ? '+' : ' ');
int cp = std::abs(100 * v / UCI::NormalizeToPawnValue);
if (cp >= 10000)
{
buffer[1] = '0' + cp / 10000; cp %= 10000;
buffer[2] = '0' + cp / 1000; cp %= 1000;
buffer[3] = '0' + cp / 100;
buffer[4] = ' ';
}
else if (cp >= 1000)
{
buffer[1] = '0' + cp / 1000; cp %= 1000;
buffer[2] = '0' + cp / 100; cp %= 100;
buffer[3] = '.';
buffer[4] = '0' + cp / 10;
}
else
{
buffer[1] = '0' + cp / 100; cp %= 100;
buffer[2] = '.';
buffer[3] = '0' + cp / 10; cp %= 10;
buffer[4] = '0' + cp / 1;
}
}
// format_cp_aligned_dot() converts a Value into (centi)pawns, always keeping two decimals.
static void format_cp_aligned_dot(Value v, std::stringstream &stream) {
const double cp = 1.0 * std::abs(int(v)) / UCI::NormalizeToPawnValue;
stream << (v < 0 ? '-' : v > 0 ? '+' : ' ')
<< std::setiosflags(std::ios::fixed)
<< std::setw(6)
<< std::setprecision(2)
<< cp;
}
// trace() returns a string with the value of each piece on a board,
// and a table for (PSQT, Layers) values bucket by bucket.
std::string trace(Position& pos) {
std::stringstream ss;
char board[3*8+1][8*8+2];
std::memset(board, ' ', sizeof(board));
for (int row = 0; row < 3*8+1; ++row)
board[row][8*8+1] = '\0';
// A lambda to output one box of the board
auto writeSquare = [&board](File file, Rank rank, Piece pc, Value value) {
const int x = ((int)file) * 8;
const int y = (7 - (int)rank) * 3;
for (int i = 1; i < 8; ++i)
board[y][x+i] = board[y+3][x+i] = '-';
for (int i = 1; i < 3; ++i)
board[y+i][x] = board[y+i][x+8] = '|';
board[y][x] = board[y][x+8] = board[y+3][x+8] = board[y+3][x] = '+';
if (pc != NO_PIECE)
board[y+1][x+4] = PieceToChar[pc];
if (value != VALUE_NONE)
format_cp_compact(value, &board[y+2][x+2]);
};
// We estimate the value of each piece by doing a differential evaluation from
// the current base eval, simulating the removal of the piece from its square.
Value base = evaluate(pos);
base = pos.side_to_move() == WHITE ? base : -base;
for (File f = FILE_A; f <= FILE_H; ++f)
for (Rank r = RANK_1; r <= RANK_8; ++r)
{
Square sq = make_square(f, r);
Piece pc = pos.piece_on(sq);
Value v = VALUE_NONE;
if (pc != NO_PIECE && type_of(pc) != KING)
{
auto st = pos.state();
pos.remove_piece(sq);
st->accumulator.computed[WHITE] = false;
st->accumulator.computed[BLACK] = false;
Value eval = evaluate(pos);
eval = pos.side_to_move() == WHITE ? eval : -eval;
v = base - eval;
pos.put_piece(pc, sq);
st->accumulator.computed[WHITE] = false;
st->accumulator.computed[BLACK] = false;
}
writeSquare(f, r, pc, v);
}
ss << " NNUE derived piece values:\n";
for (int row = 0; row < 3*8+1; ++row)
ss << board[row] << '\n';
ss << '\n';
auto t = trace_evaluate(pos);
ss << " NNUE network contributions "
<< (pos.side_to_move() == WHITE ? "(White to move)" : "(Black to move)") << std::endl
<< "+------------+------------+------------+------------+\n"
<< "| Bucket | Material | Positional | Total |\n"
<< "| | (PSQT) | (Layers) | |\n"
<< "+------------+------------+------------+------------+\n";
for (std::size_t bucket = 0; bucket < LayerStacks; ++bucket)
{
ss << "| " << bucket << " ";
ss << " | "; format_cp_aligned_dot(t.psqt[bucket], ss); ss << " "
<< " | "; format_cp_aligned_dot(t.positional[bucket], ss); ss << " "
<< " | "; format_cp_aligned_dot(t.psqt[bucket] + t.positional[bucket], ss); ss << " "
<< " |";
if (bucket == t.correctBucket)
ss << " <-- this bucket is used";
ss << '\n';
}
ss << "+------------+------------+------------+------------+\n";
return ss.str();
}
// Load eval, from a file stream or a memory stream
bool load_eval(std::string name, std::istream& stream) {
initialize();
fileName = name;
return read_parameters(stream);
}
// Save eval, to a file stream or a memory stream
bool save_eval(std::ostream& stream) {
if (fileName.empty())
return false;
return write_parameters(stream);
}
/// Save eval, to a file given by its name
bool save_eval(const std::optional<std::string>& filename) {
std::string actualFilename;
std::string msg;
if (filename.has_value())
actualFilename = filename.value();
else
{
if (currentEvalFileName != EvalFileDefaultName)
{
msg = "Failed to export a net. A non-embedded net can only be saved if the filename is specified";
sync_cout << msg << sync_endl;
return false;
}
actualFilename = EvalFileDefaultName;
}
std::ofstream stream(actualFilename, std::ios_base::binary);
bool saved = save_eval(stream);
msg = saved ? "Network saved successfully to " + actualFilename
: "Failed to export a net";
sync_cout << msg << sync_endl;
return saved;
}
} // namespace Stockfish::Eval::NNUE
-68
View File
@@ -1,68 +0,0 @@
/*
Stockfish, a UCI chess playing engine derived from Glaurung 2.1
Copyright (C) 2004-2023 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/>.
*/
// header used in NNUE evaluation function
#ifndef NNUE_EVALUATE_NNUE_H_INCLUDED
#define NNUE_EVALUATE_NNUE_H_INCLUDED
#include "nnue_feature_transformer.h"
#include <memory>
namespace Stockfish::Eval::NNUE {
// Hash value of evaluation function structure
constexpr std::uint32_t HashValue =
FeatureTransformer::get_hash_value() ^ Network::get_hash_value();
// Deleter for automating release of memory area
template <typename T>
struct AlignedDeleter {
void operator()(T* ptr) const {
ptr->~T();
std_aligned_free(ptr);
}
};
template <typename T>
struct LargePageDeleter {
void operator()(T* ptr) const {
ptr->~T();
aligned_large_pages_free(ptr);
}
};
template <typename T>
using AlignedPtr = std::unique_ptr<T, AlignedDeleter<T>>;
template <typename T>
using LargePagePtr = std::unique_ptr<T, LargePageDeleter<T>>;
std::string trace(Position& pos);
Value evaluate(const Position& pos, bool adjusted = false, int* complexity = nullptr);
void hint_common_parent_position(const Position& pos);
bool load_eval(std::string name, std::istream& stream);
bool save_eval(std::ostream& stream);
bool save_eval(const std::optional<std::string>& filename);
} // namespace Stockfish::Eval::NNUE
#endif // #ifndef NNUE_EVALUATE_NNUE_H_INCLUDED
+49 -45
View File
@@ -1,6 +1,6 @@
/* /*
Stockfish, a UCI chess playing engine derived from Glaurung 2.1 Stockfish, a UCI chess playing engine derived from Glaurung 2.1
Copyright (C) 2004-2023 The Stockfish developers (see AUTHORS file) Copyright (C) 2004-2025 The Stockfish developers (see AUTHORS file)
Stockfish is free software: you can redistribute it and/or modify Stockfish is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by it under the terms of the GNU General Public License as published by
@@ -20,65 +20,69 @@
#include "half_ka_v2_hm.h" #include "half_ka_v2_hm.h"
#include "../../bitboard.h"
#include "../../position.h" #include "../../position.h"
#include "../../types.h"
#include "../nnue_accumulator.h"
namespace Stockfish::Eval::NNUE::Features { namespace Stockfish::Eval::NNUE::Features {
// 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
template<Color Perspective> template<Color Perspective>
inline IndexType HalfKAv2_hm::make_index(Square s, Piece pc, Square ksq) { inline IndexType HalfKAv2_hm::make_index(Square s, Piece pc, Square ksq) {
return IndexType((int(s) ^ OrientTBL[Perspective][ksq]) + PieceSquareIndex[Perspective][pc] + KingBuckets[Perspective][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> template<Color Perspective>
void HalfKAv2_hm::append_active_indices( void HalfKAv2_hm::append_active_indices(const Position& pos, IndexList& active) {
const Position& pos, Square ksq = pos.square<KING>(Perspective);
IndexList& active Bitboard bb = pos.pieces();
) {
Square ksq = pos.square<KING>(Perspective);
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 // Explicit template instantiations
template void HalfKAv2_hm::append_active_indices<WHITE>(const Position& pos, IndexList& active); 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); template void HalfKAv2_hm::append_active_indices<BLACK>(const Position& pos, IndexList& active);
template IndexType HalfKAv2_hm::make_index<WHITE>(Square s, Piece pc, Square ksq);
template IndexType HalfKAv2_hm::make_index<BLACK>(Square s, Piece pc, Square ksq);
// append_changed_indices() : get a list of indices for recently changed features // Get a list of indices for recently changed features
template<Color Perspective> 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, 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 // 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<WHITE>(Square ksq,
template void HalfKAv2_hm::append_changed_indices<BLACK>(Square ksq, const DirtyPiece& dp, IndexList& removed, IndexList& added); 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;
}
int HalfKAv2_hm::refresh_cost(const Position& pos) { int HalfKAv2_hm::refresh_cost(const Position& pos) { return pos.count<ALL_PIECES>(); }
return pos.count<ALL_PIECES>();
}
bool HalfKAv2_hm::requires_refresh(const StateInfo* st, Color perspective) { bool HalfKAv2_hm::requires_refresh(const StateInfo* st, Color perspective) {
return st->dirtyPiece.piece[0] == make_piece(perspective, KING); return st->dirtyPiece.piece[0] == make_piece(perspective, KING);
} }
} // namespace Stockfish::Eval::NNUE::Features } // namespace Stockfish::Eval::NNUE::Features
+47 -49
View File
@@ -1,6 +1,6 @@
/* /*
Stockfish, a UCI chess playing engine derived from Glaurung 2.1 Stockfish, a UCI chess playing engine derived from Glaurung 2.1
Copyright (C) 2004-2023 The Stockfish developers (see AUTHORS file) Copyright (C) 2004-2025 The Stockfish developers (see AUTHORS file)
Stockfish is free software: you can redistribute it and/or modify Stockfish is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by it under the terms of the GNU General Public License as published by
@@ -21,50 +21,47 @@
#ifndef NNUE_FEATURES_HALF_KA_V2_HM_H_INCLUDED #ifndef NNUE_FEATURES_HALF_KA_V2_HM_H_INCLUDED
#define NNUE_FEATURES_HALF_KA_V2_HM_H_INCLUDED #define NNUE_FEATURES_HALF_KA_V2_HM_H_INCLUDED
#include <cstdint>
#include "../../misc.h"
#include "../../types.h"
#include "../nnue_common.h" #include "../nnue_common.h"
#include "../../evaluate.h"
#include "../../misc.h"
namespace Stockfish { namespace Stockfish {
struct StateInfo; struct StateInfo;
class Position;
} }
namespace Stockfish::Eval::NNUE::Features { namespace Stockfish::Eval::NNUE::Features {
// Feature HalfKAv2_hm: Combination of the position of own king // Feature HalfKAv2_hm: Combination of the position of own king and the
// and the position of pieces. Position mirrored such that king always on e..h files. // position of pieces. Position mirrored such that king is always on e..h files.
class HalfKAv2_hm { class HalfKAv2_hm {
// unique number for each piece type on each square // Unique number for each piece type on each square
enum { enum {
PS_NONE = 0, PS_NONE = 0,
PS_W_PAWN = 0, PS_W_PAWN = 0,
PS_B_PAWN = 1 * SQUARE_NB, PS_B_PAWN = 1 * SQUARE_NB,
PS_W_KNIGHT = 2 * SQUARE_NB, PS_W_KNIGHT = 2 * SQUARE_NB,
PS_B_KNIGHT = 3 * SQUARE_NB, PS_B_KNIGHT = 3 * SQUARE_NB,
PS_W_BISHOP = 4 * SQUARE_NB, PS_W_BISHOP = 4 * SQUARE_NB,
PS_B_BISHOP = 5 * SQUARE_NB, PS_B_BISHOP = 5 * SQUARE_NB,
PS_W_ROOK = 6 * SQUARE_NB, PS_W_ROOK = 6 * SQUARE_NB,
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] = {
// convention: W - us, B - them // Convention: W - us, B - them
// viewed from other side, W and B are reversed // Viewed from other side, W and B are reversed
{ 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,
PS_NONE, PS_B_PAWN, PS_B_KNIGHT, PS_B_BISHOP, PS_B_ROOK, PS_B_QUEEN, PS_KING, PS_NONE }, PS_NONE, PS_B_PAWN, PS_B_KNIGHT, PS_B_BISHOP, PS_B_ROOK, PS_B_QUEEN, PS_KING, PS_NONE},
{ PS_NONE, PS_B_PAWN, PS_B_KNIGHT, PS_B_BISHOP, PS_B_ROOK, PS_B_QUEEN, PS_KING, PS_NONE, {PS_NONE, PS_B_PAWN, PS_B_KNIGHT, PS_B_BISHOP, PS_B_ROOK, PS_B_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 } PS_NONE, PS_W_PAWN, PS_W_KNIGHT, PS_W_BISHOP, PS_W_ROOK, PS_W_QUEEN, PS_KING, PS_NONE}};
};
// Index of a feature for a given king position and another piece on some square
template<Color Perspective>
static IndexType make_index(Square s, Piece pc, Square ksq);
public: public:
// Feature name // Feature name
@@ -75,9 +72,10 @@ namespace Stockfish::Eval::NNUE::Features {
// Number of feature dimensions // Number of feature dimensions
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;
#define B(v) (v * PS_NB) #define B(v) (v * PS_NB)
// clang-format off
static constexpr int KingBuckets[COLOR_NB][SQUARE_NB] = { static constexpr int KingBuckets[COLOR_NB][SQUARE_NB] = {
{ B(28), B(29), B(30), B(31), B(31), B(30), B(29), B(28), { B(28), B(29), B(30), B(31), B(31), B(30), B(29), B(28),
B(24), B(25), B(26), B(27), B(27), B(26), B(25), B(24), B(24), B(25), B(26), B(27), B(27), B(26), B(25), B(24),
@@ -96,8 +94,9 @@ namespace Stockfish::Eval::NNUE::Features {
B(24), B(25), B(26), B(27), B(27), B(26), B(25), B(24), 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) } B(28), B(29), B(30), B(31), B(31), B(30), B(29), B(28) }
}; };
// clang-format on
#undef B #undef B
// clang-format off
// Orient a square according to perspective (rotates by 180 for black) // Orient a square according to perspective (rotates by 180 for black)
static constexpr int OrientTBL[COLOR_NB][SQUARE_NB] = { 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,
@@ -117,36 +116,35 @@ namespace Stockfish::Eval::NNUE::Features {
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 }
}; };
// clang-format on
// Maximum number of simultaneously active features. // Maximum number of simultaneously active features.
static constexpr IndexType MaxActiveDimensions = 32; static constexpr IndexType MaxActiveDimensions = 32;
using IndexList = ValueList<IndexType, MaxActiveDimensions>; using IndexList = ValueList<IndexType, MaxActiveDimensions>;
// Index of a feature for a given king position and another piece on some square
template<Color Perspective>
static IndexType make_index(Square s, Piece pc, Square ksq);
// Get a list of indices for active features // Get a list of indices for active features
template<Color Perspective> template<Color Perspective>
static void append_active_indices( static void append_active_indices(const Position& pos, IndexList& active);
const Position& pos,
IndexList& active);
// Get a list of indices for recently changed features // Get a list of indices for recently changed features
template<Color Perspective> template<Color Perspective>
static void append_changed_indices( static void
Square ksq, append_changed_indices(Square ksq, const DirtyPiece& dp, IndexList& removed, IndexList& added);
const DirtyPiece& dp,
IndexList& removed,
IndexList& added
);
// Returns the cost of updating one perspective, the most costly one. // Returns the cost of updating one perspective, the most costly one.
// Assumes no refresh needed. // Assumes no refresh needed.
static int update_cost(const StateInfo* st); static int update_cost(const StateInfo* st);
static int refresh_cost(const Position& pos); static int refresh_cost(const Position& pos);
// Returns whether the change stored in this StateInfo means that // Returns whether the change stored in this StateInfo means
// a full accumulator refresh is required. // that a full accumulator refresh is required.
static bool requires_refresh(const StateInfo* st, Color perspective); static bool requires_refresh(const StateInfo* st, Color perspective);
}; };
} // namespace Stockfish::Eval::NNUE::Features } // namespace Stockfish::Eval::NNUE::Features
#endif // #ifndef NNUE_FEATURES_HALF_KA_V2_HM_H_INCLUDED #endif // #ifndef NNUE_FEATURES_HALF_KA_V2_HM_H_INCLUDED
+203 -460
View File
@@ -1,6 +1,6 @@
/* /*
Stockfish, a UCI chess playing engine derived from Glaurung 2.1 Stockfish, a UCI chess playing engine derived from Glaurung 2.1
Copyright (C) 2004-2023 The Stockfish developers (see AUTHORS file) Copyright (C) 2004-2025 The Stockfish developers (see AUTHORS file)
Stockfish is free software: you can redistribute it and/or modify Stockfish is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by it under the terms of the GNU General Public License as published by
@@ -21,163 +21,117 @@
#ifndef NNUE_LAYERS_AFFINE_TRANSFORM_H_INCLUDED #ifndef NNUE_LAYERS_AFFINE_TRANSFORM_H_INCLUDED
#define NNUE_LAYERS_AFFINE_TRANSFORM_H_INCLUDED #define NNUE_LAYERS_AFFINE_TRANSFORM_H_INCLUDED
#include <cstdint>
#include <iostream> #include <iostream>
#include <algorithm>
#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).
Two approaches are employed, depending on the sizes of the transform.
Approach 1 (a specialization for large inputs):
- used when the PaddedInputDimensions >= 128
- uses AVX512 if possible
- processes inputs in batches of 2*InputSimdWidth
- so in batches of 128 for AVX512
- the weight blocks of size InputSimdWidth are transposed such that
access is sequential
- N columns of the weight matrix are processed a time, where N
depends on the architecture (the amount of registers)
- accumulate + hadd is used
Approach 2 (a specialization for small inputs):
- used when the PaddedInputDimensions < 128
- expected use-case is for when PaddedInputDimensions == 32 and InputDimensions <= 32. - expected use-case is for when PaddedInputDimensions == 32 and InputDimensions <= 32.
- that's why AVX512 is hard to implement - that's why AVX512 is hard to implement
- expected use-case is small layers - expected use-case is small layers
- not optimized as well as the approach 1
- inputs are processed in chunks of 4, weights are respectively transposed - inputs are processed in chunks of 4, weights are respectively transposed
- accumulation happens directly to int32s - accumulation happens directly to int32s
*/ */
namespace Stockfish::Eval::NNUE::Layers { namespace Stockfish::Eval::NNUE::Layers {
#if defined(USE_SSSE3) || defined(USE_NEON_DOTPROD)
#define ENABLE_SEQ_OPT
#endif
// Fallback implementation for older/other architectures. // Fallback implementation for older/other architectures.
// Identical for both approaches. Requires the input to be padded to at least 16 values. // Requires the input to be padded to at least 16 values.
#if !defined(USE_SSSE3) #ifndef ENABLE_SEQ_OPT
template <IndexType InputDimensions, IndexType PaddedInputDimensions, IndexType OutputDimensions>
static void affine_transform_non_ssse3(std::int32_t* output, const std::int8_t* weights, const std::int32_t* biases, const std::uint8_t* input) template<IndexType InputDimensions, IndexType PaddedInputDimensions, IndexType OutputDimensions>
{ static void affine_transform_non_ssse3(std::int32_t* output,
# if defined(USE_SSE2) const std::int8_t* weights,
const std::int32_t* biases,
const std::uint8_t* input) {
#if defined(USE_SSE2) || defined(USE_NEON)
#if defined(USE_SSE2)
// At least a multiple of 16, with SSE2. // At least a multiple of 16, with SSE2.
constexpr IndexType NumChunks = ceil_to_multiple<IndexType>(InputDimensions, 16) / 16; constexpr IndexType NumChunks = ceil_to_multiple<IndexType>(InputDimensions, 16) / 16;
const __m128i Zeros = _mm_setzero_si128(); const __m128i Zeros = _mm_setzero_si128();
const auto inputVector = reinterpret_cast<const __m128i*>(input); const auto inputVector = reinterpret_cast<const __m128i*>(input);
# elif defined(USE_MMX) #elif defined(USE_NEON)
constexpr IndexType NumChunks = ceil_to_multiple<IndexType>(InputDimensions, 8) / 8; constexpr IndexType NumChunks = ceil_to_multiple<IndexType>(InputDimensions, 16) / 16;
const __m64 Zeros = _mm_setzero_si64(); const auto inputVector = reinterpret_cast<const int8x8_t*>(input);
const auto inputVector = reinterpret_cast<const __m64*>(input); #endif
# elif defined(USE_NEON_DOTPROD) for (IndexType i = 0; i < OutputDimensions; ++i)
constexpr IndexType NumChunks = ceil_to_multiple<IndexType>(InputDimensions, 16) / 16; {
const auto inputVector = reinterpret_cast<const int8x16_t*>(input); const IndexType offset = i * PaddedInputDimensions;
# elif defined(USE_NEON) #if defined(USE_SSE2)
constexpr IndexType NumChunks = ceil_to_multiple<IndexType>(InputDimensions, 16) / 16; __m128i sumLo = _mm_cvtsi32_si128(biases[i]);
const auto inputVector = reinterpret_cast<const int8x8_t*>(input); __m128i sumHi = Zeros;
# endif const auto row = reinterpret_cast<const __m128i*>(&weights[offset]);
for (IndexType j = 0; j < NumChunks; ++j)
{
__m128i row_j = _mm_load_si128(&row[j]);
__m128i input_j = _mm_load_si128(&inputVector[j]);
__m128i extendedRowLo = _mm_srai_epi16(_mm_unpacklo_epi8(row_j, row_j), 8);
__m128i extendedRowHi = _mm_srai_epi16(_mm_unpackhi_epi8(row_j, row_j), 8);
__m128i extendedInputLo = _mm_unpacklo_epi8(input_j, Zeros);
__m128i extendedInputHi = _mm_unpackhi_epi8(input_j, Zeros);
__m128i productLo = _mm_madd_epi16(extendedRowLo, extendedInputLo);
__m128i productHi = _mm_madd_epi16(extendedRowHi, extendedInputHi);
sumLo = _mm_add_epi32(sumLo, productLo);
sumHi = _mm_add_epi32(sumHi, productHi);
}
__m128i sum = _mm_add_epi32(sumLo, sumHi);
__m128i sumHigh_64 = _mm_shuffle_epi32(sum, _MM_SHUFFLE(1, 0, 3, 2));
sum = _mm_add_epi32(sum, sumHigh_64);
__m128i sum_second_32 = _mm_shufflelo_epi16(sum, _MM_SHUFFLE(1, 0, 3, 2));
sum = _mm_add_epi32(sum, sum_second_32);
output[i] = _mm_cvtsi128_si32(sum);
for (IndexType i = 0; i < OutputDimensions; ++i) { #elif defined(USE_NEON)
const IndexType offset = i * PaddedInputDimensions;
# if defined(USE_SSE2) int32x4_t sum = {biases[i]};
__m128i sumLo = _mm_cvtsi32_si128(biases[i]); const auto row = reinterpret_cast<const int8x8_t*>(&weights[offset]);
__m128i sumHi = Zeros; for (IndexType j = 0; j < NumChunks; ++j)
const auto row = reinterpret_cast<const __m128i*>(&weights[offset]); {
for (IndexType j = 0; j < NumChunks; ++j) { int16x8_t product = vmull_s8(inputVector[j * 2], row[j * 2]);
__m128i row_j = _mm_load_si128(&row[j]); product = vmlal_s8(product, inputVector[j * 2 + 1], row[j * 2 + 1]);
__m128i input_j = _mm_load_si128(&inputVector[j]); sum = vpadalq_s16(sum, product);
__m128i extendedRowLo = _mm_srai_epi16(_mm_unpacklo_epi8(row_j, row_j), 8); }
__m128i extendedRowHi = _mm_srai_epi16(_mm_unpackhi_epi8(row_j, row_j), 8); output[i] = sum[0] + sum[1] + sum[2] + sum[3];
__m128i extendedInputLo = _mm_unpacklo_epi8(input_j, Zeros);
__m128i extendedInputHi = _mm_unpackhi_epi8(input_j, Zeros);
__m128i productLo = _mm_madd_epi16(extendedRowLo, extendedInputLo);
__m128i productHi = _mm_madd_epi16(extendedRowHi, extendedInputHi);
sumLo = _mm_add_epi32(sumLo, productLo);
sumHi = _mm_add_epi32(sumHi, productHi);
}
__m128i sum = _mm_add_epi32(sumLo, sumHi);
__m128i sumHigh_64 = _mm_shuffle_epi32(sum, _MM_SHUFFLE(1, 0, 3, 2));
sum = _mm_add_epi32(sum, sumHigh_64);
__m128i sum_second_32 = _mm_shufflelo_epi16(sum, _MM_SHUFFLE(1, 0, 3, 2));
sum = _mm_add_epi32(sum, sum_second_32);
output[i] = _mm_cvtsi128_si32(sum);
# elif defined(USE_MMX) #endif
__m64 sumLo = _mm_cvtsi32_si64(biases[i]);
__m64 sumHi = Zeros;
const auto row = reinterpret_cast<const __m64*>(&weights[offset]);
for (IndexType j = 0; j < NumChunks; ++j) {
__m64 row_j = row[j];
__m64 input_j = inputVector[j];
__m64 extendedRowLo = _mm_srai_pi16(_mm_unpacklo_pi8(row_j, row_j), 8);
__m64 extendedRowHi = _mm_srai_pi16(_mm_unpackhi_pi8(row_j, row_j), 8);
__m64 extendedInputLo = _mm_unpacklo_pi8(input_j, Zeros);
__m64 extendedInputHi = _mm_unpackhi_pi8(input_j, Zeros);
__m64 productLo = _mm_madd_pi16(extendedRowLo, extendedInputLo);
__m64 productHi = _mm_madd_pi16(extendedRowHi, extendedInputHi);
sumLo = _mm_add_pi32(sumLo, productLo);
sumHi = _mm_add_pi32(sumHi, productHi);
}
__m64 sum = _mm_add_pi32(sumLo, sumHi);
sum = _mm_add_pi32(sum, _mm_unpackhi_pi32(sum, sum));
output[i] = _mm_cvtsi64_si32(sum);
# elif defined(USE_NEON_DOTPROD)
int32x4_t sum = {biases[i]};
const auto row = reinterpret_cast<const int8x16_t*>(&weights[offset]);
for (IndexType j = 0; j < NumChunks; ++j) {
sum = vdotq_s32(sum, inputVector[j], row[j]);
}
output[i] = vaddvq_s32(sum);
# elif defined(USE_NEON)
int32x4_t sum = {biases[i]};
const auto row = reinterpret_cast<const int8x8_t*>(&weights[offset]);
for (IndexType j = 0; j < NumChunks; ++j) {
int16x8_t product = vmull_s8(inputVector[j * 2], row[j * 2]);
product = vmlal_s8(product, inputVector[j * 2 + 1], row[j * 2 + 1]);
sum = vpadalq_s16(sum, product);
}
output[i] = sum[0] + sum[1] + sum[2] + sum[3];
# else
std::int32_t sum = biases[i];
for (IndexType j = 0; j < InputDimensions; ++j) {
sum += weights[offset + j] * input[j];
}
output[i] = sum;
# endif
} }
#else
std::memcpy(output, biases, sizeof(std::int32_t) * OutputDimensions);
# if defined(USE_MMX) // Traverse weights in transpose order to take advantage of input sparsity
_mm_empty(); for (IndexType i = 0; i < InputDimensions; ++i)
# endif if (input[i])
} {
#endif const std::int8_t* w = &weights[i];
const int in = input[i];
for (IndexType j = 0; j < OutputDimensions; ++j)
output[j] += w[j * PaddedInputDimensions] * in;
}
#endif
}
template <IndexType InDims, IndexType OutDims, typename Enabled = void> #endif // !ENABLE_SEQ_OPT
class AffineTransform;
#if defined (USE_AVX512) template<IndexType InDims, IndexType OutDims>
constexpr IndexType LargeInputSize = 2 * 64; class AffineTransform {
#else
constexpr IndexType LargeInputSize = std::numeric_limits<IndexType>::max();
#endif
// A specialization for large inputs
template <IndexType InDims, IndexType OutDims>
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;
using OutputType = std::int32_t; using OutputType = std::int32_t;
// Number of input/output dimensions // Number of input/output dimensions
static constexpr IndexType InputDimensions = InDims; static constexpr IndexType InputDimensions = InDims;
static constexpr IndexType OutputDimensions = OutDims; static constexpr IndexType OutputDimensions = OutDims;
static constexpr IndexType PaddedInputDimensions = static constexpr IndexType PaddedInputDimensions =
@@ -187,377 +141,166 @@ namespace Stockfish::Eval::NNUE::Layers {
using OutputBuffer = OutputType[PaddedOutputDimensions]; using OutputBuffer = OutputType[PaddedOutputDimensions];
static_assert(PaddedInputDimensions >= LargeInputSize, "Something went wrong. This specialization (for large inputs) should not have been chosen.");
#if defined (USE_AVX512)
static constexpr IndexType InputSimdWidth = 64;
static constexpr IndexType MaxNumOutputRegs = 16;
#elif defined (USE_AVX2)
static constexpr IndexType InputSimdWidth = 32;
static constexpr IndexType MaxNumOutputRegs = 8;
#elif defined (USE_SSSE3)
static constexpr IndexType InputSimdWidth = 16;
static constexpr IndexType MaxNumOutputRegs = 8;
#elif defined (USE_NEON_DOTPROD)
static constexpr IndexType InputSimdWidth = 16;
static constexpr IndexType MaxNumOutputRegs = 8;
#elif defined (USE_NEON)
static constexpr IndexType InputSimdWidth = 8;
static constexpr IndexType MaxNumOutputRegs = 8;
#else
// The fallback implementation will not have permuted weights.
// We define these to avoid a lot of ifdefs later.
static constexpr IndexType InputSimdWidth = 1;
static constexpr IndexType MaxNumOutputRegs = 1;
#endif
// A big block is a region in the weight matrix of the size [PaddedInputDimensions, NumOutputRegs].
// A small block is a region of size [InputSimdWidth, 1]
static constexpr IndexType NumOutputRegs = std::min(MaxNumOutputRegs, OutputDimensions);
static constexpr IndexType SmallBlockSize = InputSimdWidth;
static constexpr IndexType BigBlockSize = NumOutputRegs * PaddedInputDimensions;
static constexpr IndexType NumSmallBlocksInBigBlock = BigBlockSize / SmallBlockSize;
static constexpr IndexType NumSmallBlocksPerOutput = PaddedInputDimensions / SmallBlockSize;
static constexpr IndexType NumBigBlocks = OutputDimensions / NumOutputRegs;
static_assert(OutputDimensions % NumOutputRegs == 0);
// Hash value embedded in the evaluation file // Hash value embedded in the evaluation file
static constexpr std::uint32_t get_hash_value(std::uint32_t prevHash) { static constexpr std::uint32_t get_hash_value(std::uint32_t prevHash) {
std::uint32_t hashValue = 0xCC03DAE4u; std::uint32_t hashValue = 0xCC03DAE4u;
hashValue += OutputDimensions; hashValue += OutputDimensions;
hashValue ^= prevHash >> 1; hashValue ^= prevHash >> 1;
hashValue ^= prevHash << 31; hashValue ^= prevHash << 31;
return hashValue; return hashValue;
} }
/* static constexpr IndexType get_weight_index_scrambled(IndexType i) {
Transposes the small blocks within a block. return (i / 4) % (PaddedInputDimensions / 4) * OutputDimensions * 4
Effectively means that weights can be traversed sequentially during inference. + i / PaddedInputDimensions * 4 + i % 4;
*/
static IndexType get_weight_index(IndexType i)
{
const IndexType smallBlock = (i / SmallBlockSize) % NumSmallBlocksInBigBlock;
const IndexType smallBlockCol = smallBlock / NumSmallBlocksPerOutput;
const IndexType smallBlockRow = smallBlock % NumSmallBlocksPerOutput;
const IndexType bigBlock = i / BigBlockSize;
const IndexType rest = i % SmallBlockSize;
const IndexType idx =
bigBlock * BigBlockSize
+ smallBlockRow * SmallBlockSize * NumOutputRegs
+ smallBlockCol * SmallBlockSize
+ rest;
return idx;
} }
// Read network parameters static constexpr IndexType get_weight_index(IndexType i) {
bool read_parameters(std::istream& stream) { #ifdef ENABLE_SEQ_OPT
read_little_endian<BiasType>(stream, biases, OutputDimensions); return get_weight_index_scrambled(i);
for (IndexType i = 0; i < OutputDimensions * PaddedInputDimensions; ++i)
weights[get_weight_index(i)] = read_little_endian<WeightType>(stream);
return !stream.fail();
}
// Write network parameters
bool write_parameters(std::ostream& stream) const {
write_little_endian<BiasType>(stream, biases, OutputDimensions);
for (IndexType i = 0; i < OutputDimensions * PaddedInputDimensions; ++i)
write_little_endian<WeightType>(stream, weights[get_weight_index(i)]);
return !stream.fail();
}
// Forward propagation
const OutputType* propagate(
const InputType* input, OutputType* output) const {
#if defined (USE_AVX512)
using acc_vec_t = __m512i;
using bias_vec_t = __m128i;
using weight_vec_t = __m512i;
using in_vec_t = __m512i;
#define vec_zero _mm512_setzero_si512()
#define vec_add_dpbusd_32x2 Simd::m512_add_dpbusd_epi32x2
#define vec_hadd Simd::m512_hadd
#define vec_haddx4 Simd::m512_haddx4
#elif defined (USE_AVX2)
using acc_vec_t = __m256i;
using bias_vec_t = __m128i;
using weight_vec_t = __m256i;
using in_vec_t = __m256i;
#define vec_zero _mm256_setzero_si256()
#define vec_add_dpbusd_32x2 Simd::m256_add_dpbusd_epi32x2
#define vec_hadd Simd::m256_hadd
#define vec_haddx4 Simd::m256_haddx4
#elif defined (USE_SSSE3)
using acc_vec_t = __m128i;
using bias_vec_t = __m128i;
using weight_vec_t = __m128i;
using in_vec_t = __m128i;
#define vec_zero _mm_setzero_si128()
#define vec_add_dpbusd_32x2 Simd::m128_add_dpbusd_epi32x2
#define vec_hadd Simd::m128_hadd
#define vec_haddx4 Simd::m128_haddx4
#elif defined (USE_NEON_DOTPROD)
using acc_vec_t = int32x4_t;
using bias_vec_t = int32x4_t;
using weight_vec_t = int8x16_t;
using in_vec_t = int8x16_t;
#define vec_zero {0}
#define vec_add_dpbusd_32x2 Simd::dotprod_m128_add_dpbusd_epi32x2
#define vec_hadd Simd::neon_m128_hadd
#define vec_haddx4 Simd::neon_m128_haddx4
#elif defined (USE_NEON)
using acc_vec_t = int32x4_t;
using bias_vec_t = int32x4_t;
using weight_vec_t = int8x8_t;
using in_vec_t = int8x8_t;
#define vec_zero {0}
#define vec_add_dpbusd_32x2 Simd::neon_m128_add_dpbusd_epi32x2
#define vec_hadd Simd::neon_m128_hadd
#define vec_haddx4 Simd::neon_m128_haddx4
#endif
#if defined (USE_SSSE3) || defined (USE_NEON)
const in_vec_t* invec = reinterpret_cast<const in_vec_t*>(input);
// Perform accumulation to registers for each big block
for (IndexType bigBlock = 0; bigBlock < NumBigBlocks; ++bigBlock)
{
acc_vec_t acc[NumOutputRegs] = { vec_zero };
// Each big block has NumOutputRegs small blocks in each "row", one per register.
// We process two small blocks at a time to save on one addition without VNNI.
for (IndexType smallBlock = 0; smallBlock < NumSmallBlocksPerOutput; smallBlock += 2)
{
const weight_vec_t* weightvec =
reinterpret_cast<const weight_vec_t*>(
weights
+ bigBlock * BigBlockSize
+ smallBlock * SmallBlockSize * NumOutputRegs);
const in_vec_t in0 = invec[smallBlock + 0];
const in_vec_t in1 = invec[smallBlock + 1];
for (IndexType k = 0; k < NumOutputRegs; ++k)
vec_add_dpbusd_32x2(acc[k], in0, weightvec[k], in1, weightvec[k + NumOutputRegs]);
}
// Horizontally add all accumulators.
if constexpr (NumOutputRegs % 4 == 0)
{
bias_vec_t* outputvec = reinterpret_cast<bias_vec_t*>(output);
const bias_vec_t* biasvec = reinterpret_cast<const bias_vec_t*>(biases);
for (IndexType k = 0; k < NumOutputRegs; k += 4)
{
const IndexType idx = (bigBlock * NumOutputRegs + k) / 4;
outputvec[idx] = vec_haddx4(acc[k+0], acc[k+1], acc[k+2], acc[k+3], biasvec[idx]);
}
}
else
{
for (IndexType k = 0; k < NumOutputRegs; ++k)
{
const IndexType idx = (bigBlock * NumOutputRegs + k);
output[idx] = vec_hadd(acc[k], biases[idx]);
}
}
}
# undef vec_zero
# undef vec_add_dpbusd_32x2
# undef vec_hadd
# undef vec_haddx4
#else #else
// Use old implementation for the other architectures. return i;
affine_transform_non_ssse3<
InputDimensions,
PaddedInputDimensions,
OutputDimensions>(output, weights, biases, input);
#endif
return output;
}
private:
using BiasType = OutputType;
using WeightType = std::int8_t;
alignas(CacheLineSize) BiasType biases[OutputDimensions];
alignas(CacheLineSize) WeightType weights[OutputDimensions * PaddedInputDimensions];
};
// A specialization for small inputs
template <IndexType InDims, IndexType OutDims>
class AffineTransform<InDims, OutDims, std::enable_if_t<(ceil_to_multiple<IndexType>(InDims, MaxSimdWidth) < LargeInputSize)>> {
public:
// Input/output type
// Input/output type
using InputType = std::uint8_t;
using OutputType = std::int32_t;
// Number of input/output dimensions
static constexpr IndexType InputDimensions = InDims;
static constexpr IndexType OutputDimensions = OutDims;
static constexpr IndexType PaddedInputDimensions =
ceil_to_multiple<IndexType>(InputDimensions, MaxSimdWidth);
static constexpr IndexType PaddedOutputDimensions =
ceil_to_multiple<IndexType>(OutputDimensions, MaxSimdWidth);
using OutputBuffer = OutputType[PaddedOutputDimensions];
static_assert(PaddedInputDimensions < LargeInputSize, "Something went wrong. This specialization (for small inputs) should not have been chosen.");
// Hash value embedded in the evaluation file
static constexpr std::uint32_t get_hash_value(std::uint32_t prevHash) {
std::uint32_t hashValue = 0xCC03DAE4u;
hashValue += OutputDimensions;
hashValue ^= prevHash >> 1;
hashValue ^= prevHash << 31;
return hashValue;
}
static IndexType get_weight_index_scrambled(IndexType i)
{
return
(i / 4) % (PaddedInputDimensions / 4) * OutputDimensions * 4 +
i / PaddedInputDimensions * 4 +
i % 4;
}
static IndexType get_weight_index(IndexType i)
{
#if defined (USE_SSSE3)
return get_weight_index_scrambled(i);
#else
return i;
#endif #endif
} }
// Read network parameters // Read network parameters
bool read_parameters(std::istream& stream) { bool read_parameters(std::istream& stream) {
read_little_endian<BiasType>(stream, biases, OutputDimensions); read_little_endian<BiasType>(stream, biases, OutputDimensions);
for (IndexType i = 0; i < OutputDimensions * PaddedInputDimensions; ++i) for (IndexType i = 0; i < OutputDimensions * PaddedInputDimensions; ++i)
weights[get_weight_index(i)] = read_little_endian<WeightType>(stream); weights[get_weight_index(i)] = read_little_endian<WeightType>(stream);
return !stream.fail(); return !stream.fail();
} }
// Write network parameters // Write network parameters
bool write_parameters(std::ostream& stream) const { bool write_parameters(std::ostream& stream) const {
write_little_endian<BiasType>(stream, biases, OutputDimensions); write_little_endian<BiasType>(stream, biases, OutputDimensions);
for (IndexType i = 0; i < OutputDimensions * PaddedInputDimensions; ++i) for (IndexType i = 0; i < OutputDimensions * PaddedInputDimensions; ++i)
write_little_endian<WeightType>(stream, weights[get_weight_index(i)]); write_little_endian<WeightType>(stream, weights[get_weight_index(i)]);
return !stream.fail(); return !stream.fail();
} }
// Forward propagation // Forward propagation
const OutputType* propagate( void propagate(const InputType* input, OutputType* output) const {
const InputType* input, OutputType* output) const {
#if defined (USE_AVX512) #ifdef ENABLE_SEQ_OPT
using vec_t = __m512i;
#define vec_setzero _mm512_setzero_si512
#define vec_set_32 _mm512_set1_epi32
#define vec_add_dpbusd_32 Simd::m512_add_dpbusd_epi32
#define vec_add_dpbusd_32x2 Simd::m512_add_dpbusd_epi32x2
#define vec_hadd Simd::m512_hadd
#elif defined (USE_AVX2)
using vec_t = __m256i;
#define vec_setzero _mm256_setzero_si256
#define vec_set_32 _mm256_set1_epi32
#define vec_add_dpbusd_32 Simd::m256_add_dpbusd_epi32
#define vec_add_dpbusd_32x2 Simd::m256_add_dpbusd_epi32x2
#define vec_hadd Simd::m256_hadd
#elif defined (USE_SSSE3)
using vec_t = __m128i;
#define vec_setzero _mm_setzero_si128
#define vec_set_32 _mm_set1_epi32
#define vec_add_dpbusd_32 Simd::m128_add_dpbusd_epi32
#define vec_add_dpbusd_32x2 Simd::m128_add_dpbusd_epi32x2
#define vec_hadd Simd::m128_hadd
#endif
#if defined (USE_SSSE3) if constexpr (OutputDimensions > 1)
const auto inputVector = reinterpret_cast<const vec_t*>(input);
static constexpr IndexType OutputSimdWidth = sizeof(vec_t) / sizeof(OutputType);
static_assert(OutputDimensions % OutputSimdWidth == 0 || OutputDimensions == 1);
if constexpr (OutputDimensions % OutputSimdWidth == 0)
{
constexpr IndexType NumChunks = ceil_to_multiple<IndexType>(InputDimensions, 8) / 4;
constexpr IndexType NumRegs = OutputDimensions / OutputSimdWidth;
const auto input32 = reinterpret_cast<const std::int32_t*>(input);
const vec_t* biasvec = reinterpret_cast<const vec_t*>(biases);
vec_t acc[NumRegs];
for (IndexType k = 0; k < NumRegs; ++k)
acc[k] = biasvec[k];
for (IndexType i = 0; i < NumChunks; i += 2)
{ {
const vec_t in0 = vec_set_32(input32[i + 0]); #if defined(USE_AVX512)
const vec_t in1 = vec_set_32(input32[i + 1]); using vec_t = __m512i;
const auto col0 = reinterpret_cast<const vec_t*>(&weights[(i + 0) * OutputDimensions * 4]); #define vec_set_32 _mm512_set1_epi32
const auto col1 = reinterpret_cast<const vec_t*>(&weights[(i + 1) * OutputDimensions * 4]); #define vec_add_dpbusd_32 Simd::m512_add_dpbusd_epi32
for (IndexType k = 0; k < NumRegs; ++k) #elif defined(USE_AVX2)
vec_add_dpbusd_32x2(acc[k], in0, col0[k], in1, col1[k]); using vec_t = __m256i;
#define vec_set_32 _mm256_set1_epi32
#define vec_add_dpbusd_32 Simd::m256_add_dpbusd_epi32
#elif defined(USE_SSSE3)
using vec_t = __m128i;
#define vec_set_32 _mm_set1_epi32
#define vec_add_dpbusd_32 Simd::m128_add_dpbusd_epi32
#elif defined(USE_NEON_DOTPROD)
using vec_t = int32x4_t;
#define vec_set_32 vdupq_n_s32
#define vec_add_dpbusd_32(acc, a, b) \
Simd::dotprod_m128_add_dpbusd_epi32(acc, vreinterpretq_s8_s32(a), \
vreinterpretq_s8_s32(b))
#endif
static constexpr IndexType OutputSimdWidth = sizeof(vec_t) / sizeof(OutputType);
static_assert(OutputDimensions % OutputSimdWidth == 0);
constexpr IndexType NumChunks = ceil_to_multiple<IndexType>(InputDimensions, 8) / 4;
constexpr IndexType NumRegs = OutputDimensions / OutputSimdWidth;
const auto input32 = reinterpret_cast<const std::int32_t*>(input);
const vec_t* biasvec = reinterpret_cast<const vec_t*>(biases);
vec_t acc[NumRegs];
for (IndexType k = 0; k < NumRegs; ++k)
acc[k] = biasvec[k];
for (IndexType i = 0; i < NumChunks; ++i)
{
const vec_t in0 = vec_set_32(input32[i]);
const auto col0 =
reinterpret_cast<const vec_t*>(&weights[i * OutputDimensions * 4]);
for (IndexType k = 0; k < NumRegs; ++k)
vec_add_dpbusd_32(acc[k], in0, col0[k]);
}
vec_t* outptr = reinterpret_cast<vec_t*>(output);
for (IndexType k = 0; k < NumRegs; ++k)
outptr[k] = acc[k];
#undef vec_set_32
#undef vec_add_dpbusd_32
} }
else if constexpr (OutputDimensions == 1)
vec_t* outptr = reinterpret_cast<vec_t*>(output);
for (IndexType k = 0; k < NumRegs; ++k)
outptr[k] = acc[k];
}
else if constexpr (OutputDimensions == 1)
{
constexpr IndexType NumChunks = PaddedInputDimensions / SimdWidth;
vec_t sum0 = vec_setzero();
const auto row0 = reinterpret_cast<const vec_t*>(&weights[0]);
for (int j = 0; j < (int)NumChunks; ++j)
{ {
const vec_t in = inputVector[j]; // We cannot use AVX512 for the last layer because there are only 32 inputs
vec_add_dpbusd_32(sum0, in, row0[j]); // and the buffer is not padded to 64 elements.
} #if defined(USE_AVX2)
output[0] = vec_hadd(sum0, biases[0]); using vec_t = __m256i;
} #define vec_setzero() _mm256_setzero_si256()
#define vec_set_32 _mm256_set1_epi32
#define vec_add_dpbusd_32 Simd::m256_add_dpbusd_epi32
#define vec_hadd Simd::m256_hadd
#elif defined(USE_SSSE3)
using vec_t = __m128i;
#define vec_setzero() _mm_setzero_si128()
#define vec_set_32 _mm_set1_epi32
#define vec_add_dpbusd_32 Simd::m128_add_dpbusd_epi32
#define vec_hadd Simd::m128_hadd
#elif defined(USE_NEON_DOTPROD)
using vec_t = int32x4_t;
#define vec_setzero() vdupq_n_s32(0)
#define vec_set_32 vdupq_n_s32
#define vec_add_dpbusd_32(acc, a, b) \
Simd::dotprod_m128_add_dpbusd_epi32(acc, vreinterpretq_s8_s32(a), \
vreinterpretq_s8_s32(b))
#define vec_hadd Simd::neon_m128_hadd
#endif
# undef vec_setzero const auto inputVector = reinterpret_cast<const vec_t*>(input);
# undef vec_set_32
# undef vec_add_dpbusd_32 static constexpr IndexType InputSimdWidth = sizeof(vec_t) / sizeof(InputType);
# undef vec_add_dpbusd_32x2
# undef vec_hadd static_assert(PaddedInputDimensions % InputSimdWidth == 0);
constexpr IndexType NumChunks = PaddedInputDimensions / InputSimdWidth;
vec_t sum0 = vec_setzero();
const auto row0 = reinterpret_cast<const vec_t*>(&weights[0]);
for (int j = 0; j < int(NumChunks); ++j)
{
const vec_t in = inputVector[j];
vec_add_dpbusd_32(sum0, in, row0[j]);
}
output[0] = vec_hadd(sum0, biases[0]);
#undef vec_setzero
#undef vec_set_32
#undef vec_add_dpbusd_32
#undef vec_hadd
}
#else #else
// Use old implementation for the other architectures. // Use old implementation for the other architectures.
affine_transform_non_ssse3< affine_transform_non_ssse3<InputDimensions, PaddedInputDimensions, OutputDimensions>(
InputDimensions, output, weights, biases, input);
PaddedInputDimensions,
OutputDimensions>(output, weights, biases, input);
#endif #endif
return output;
} }
private: private:
using BiasType = OutputType; using BiasType = OutputType;
using WeightType = std::int8_t; using WeightType = std::int8_t;
alignas(CacheLineSize) BiasType biases[OutputDimensions]; alignas(CacheLineSize) BiasType biases[OutputDimensions];
alignas(CacheLineSize) WeightType weights[OutputDimensions * PaddedInputDimensions]; alignas(CacheLineSize) WeightType weights[OutputDimensions * PaddedInputDimensions];
}; };
} // namespace Stockfish::Eval::NNUE::Layers } // namespace Stockfish::Eval::NNUE::Layers
#endif // #ifndef NNUE_LAYERS_AFFINE_TRANSFORM_H_INCLUDED #endif // #ifndef NNUE_LAYERS_AFFINE_TRANSFORM_H_INCLUDED
+193 -173
View File
@@ -1,6 +1,6 @@
/* /*
Stockfish, a UCI chess playing engine derived from Glaurung 2.1 Stockfish, a UCI chess playing engine derived from Glaurung 2.1
Copyright (C) 2004-2023 The Stockfish developers (see AUTHORS file) Copyright (C) 2004-2025 The Stockfish developers (see AUTHORS file)
Stockfish is free software: you can redistribute it and/or modify Stockfish is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by it under the terms of the GNU General Public License as published by
@@ -21,10 +21,12 @@
#ifndef NNUE_LAYERS_AFFINE_TRANSFORM_SPARSE_INPUT_H_INCLUDED #ifndef NNUE_LAYERS_AFFINE_TRANSFORM_SPARSE_INPUT_H_INCLUDED
#define NNUE_LAYERS_AFFINE_TRANSFORM_SPARSE_INPUT_H_INCLUDED #define NNUE_LAYERS_AFFINE_TRANSFORM_SPARSE_INPUT_H_INCLUDED
#include <iostream>
#include <algorithm> #include <algorithm>
#include <array> #include <array>
#include <type_traits> #include <cstdint>
#include <iostream>
#include "../../bitboard.h"
#include "../nnue_common.h" #include "../nnue_common.h"
#include "affine_transform.h" #include "affine_transform.h"
#include "simd.h" #include "simd.h"
@@ -34,130 +36,147 @@
*/ */
namespace Stockfish::Eval::NNUE::Layers { namespace Stockfish::Eval::NNUE::Layers {
#if defined(__GNUC__) // GCC, Clang, ICC
static inline IndexType lsb_(std::uint32_t b) { #if (USE_SSSE3 | (USE_NEON >= 8))
assert(b); static constexpr int lsb_index64[64] = {
return IndexType(__builtin_ctzl(b)); 0, 47, 1, 56, 48, 27, 2, 60, 57, 49, 41, 37, 28, 16, 3, 61, 54, 58, 35, 52, 50, 42,
} 21, 44, 38, 32, 29, 23, 17, 11, 4, 62, 46, 55, 26, 59, 40, 36, 15, 53, 34, 51, 20, 43,
31, 22, 10, 45, 25, 39, 14, 33, 19, 30, 9, 24, 13, 18, 8, 12, 7, 6, 5, 63};
#elif defined(_MSC_VER) // MSVC constexpr int constexpr_lsb(uint64_t bb) {
assert(bb != 0);
constexpr uint64_t debruijn64 = 0x03F79D71B4CB0A89ULL;
return lsb_index64[((bb ^ (bb - 1)) * debruijn64) >> 58];
}
static inline IndexType lsb_(std::uint32_t b) { alignas(CacheLineSize) static constexpr struct OffsetIndices {
assert(b);
unsigned long idx;
_BitScanForward(&idx, b);
return (IndexType) idx;
}
#else // Compiler is neither GCC nor MSVC compatible #if (USE_SSE41)
std::uint8_t offset_indices[256][8];
#else
std::uint16_t offset_indices[256][8];
#endif
#error "Compiler not supported." constexpr OffsetIndices() :
offset_indices() {
#endif for (int i = 0; i < 256; ++i)
{
std::uint64_t j = i, k = 0;
#if defined(USE_SSSE3) while (j)
alignas(CacheLineSize) static inline const std::array<std::array<std::uint16_t, 8>, 256> lookup_indices = [](){ {
std::array<std::array<std::uint16_t, 8>, 256> v{}; offset_indices[i][k++] = constexpr_lsb(j);
for (int i = 0; i < 256; ++i) j &= j - 1;
{ }
int j = i; while (k < 8)
int k = 0; offset_indices[i][k++] = 0;
while(j) }
{
const IndexType lsbIndex = lsb_(std::uint32_t(j));
j &= j - 1;
v[i][k] = lsbIndex;
++k;
}
} }
return v;
}();
alignas(CacheLineSize) static inline const std::array<unsigned, 256> lookup_count = [](){
std::array<unsigned, 256> v;
for (int i = 0; i < 256; ++i)
{
int j = i;
int k = 0;
while(j)
{
j &= j - 1;
++k;
}
v[i] = k;
}
return v;
}();
// Find indices of nonzero numbers in an int32_t array } Lookup;
template<const IndexType InputDimensions>
void find_nnz(const std::int32_t* input, std::uint16_t* out, IndexType& count_out) { // Find indices of nonzero numbers in an int32_t array
#if defined (USE_AVX512) template<const IndexType InputDimensions>
void find_nnz(const std::int32_t* input, std::uint16_t* out, IndexType& count_out) {
#if defined(USE_SSSE3)
#if defined(USE_AVX512)
using vec_t = __m512i; using vec_t = __m512i;
#define vec_nnz(a) _mm512_cmpgt_epi32_mask(a, _mm512_setzero_si512()) #define vec_nnz(a) _mm512_cmpgt_epi32_mask(a, _mm512_setzero_si512())
#elif defined (USE_AVX2) #elif defined(USE_AVX2)
using vec_t = __m256i; using vec_t = __m256i;
#define vec_nnz(a) _mm256_movemask_ps(_mm256_castsi256_ps(_mm256_cmpgt_epi32(a, _mm256_setzero_si256()))) #if defined(USE_VNNI) && !defined(USE_AVXVNNI)
#elif defined (USE_SSSE3) #define vec_nnz(a) _mm256_cmpgt_epi32_mask(a, _mm256_setzero_si256())
#else
#define vec_nnz(a) \
_mm256_movemask_ps( \
_mm256_castsi256_ps(_mm256_cmpgt_epi32(a, _mm256_setzero_si256())))
#endif
#elif defined(USE_SSSE3)
using vec_t = __m128i; using vec_t = __m128i;
#define vec_nnz(a) _mm_movemask_ps(_mm_castsi128_ps(_mm_cmpgt_epi32(a, _mm_setzero_si128()))) #define vec_nnz(a) \
#endif _mm_movemask_ps(_mm_castsi128_ps(_mm_cmpgt_epi32(a, _mm_setzero_si128())))
#endif
using vec128_t = __m128i;
#define vec128_zero _mm_setzero_si128()
#define vec128_set_16(a) _mm_set1_epi16(a)
#if (USE_SSE41)
#define vec128_load(a) _mm_cvtepu8_epi16(_mm_loadl_epi64(a))
#else
#define vec128_load(a) _mm_load_si128(a)
#endif
#define vec128_storeu(a, b) _mm_storeu_si128(a, b)
#define vec128_add(a, b) _mm_add_epi16(a, b)
#elif defined(USE_NEON)
using vec_t = uint32x4_t;
static const std::uint32_t Mask[4] = {1, 2, 4, 8};
#define vec_nnz(a) vaddvq_u32(vandq_u32(vtstq_u32(a, a), vld1q_u32(Mask)))
using vec128_t = uint16x8_t;
#define vec128_zero vdupq_n_u16(0)
#define vec128_set_16(a) vdupq_n_u16(a)
#define vec128_load(a) vld1q_u16(reinterpret_cast<const std::uint16_t*>(a))
#define vec128_storeu(a, b) vst1q_u16(reinterpret_cast<std::uint16_t*>(a), b)
#define vec128_add(a, b) vaddq_u16(a, b)
#endif
constexpr IndexType InputSimdWidth = sizeof(vec_t) / sizeof(std::int32_t); constexpr IndexType InputSimdWidth = sizeof(vec_t) / sizeof(std::int32_t);
// Inputs are processed InputSimdWidth at a time and outputs are processed 8 at a time so we process in chunks of max(InputSimdWidth, 8) // Inputs are processed InputSimdWidth at a time and outputs are processed 8 at a time so we process in chunks of max(InputSimdWidth, 8)
constexpr IndexType ChunkSize = std::max<IndexType>(InputSimdWidth, 8); constexpr IndexType ChunkSize = std::max<IndexType>(InputSimdWidth, 8);
constexpr IndexType NumChunks = InputDimensions / ChunkSize; constexpr IndexType NumChunks = InputDimensions / ChunkSize;
constexpr IndexType InputsPerChunk = ChunkSize / InputSimdWidth; constexpr IndexType InputsPerChunk = ChunkSize / InputSimdWidth;
constexpr IndexType OutputsPerChunk = ChunkSize / 8; constexpr IndexType OutputsPerChunk = ChunkSize / 8;
const auto inputVector = reinterpret_cast<const vec_t*>(input); const auto inputVector = reinterpret_cast<const vec_t*>(input);
IndexType count = 0; IndexType count = 0;
__m128i base = _mm_set1_epi16(0); vec128_t base = vec128_zero;
__m128i increment = _mm_set1_epi16(8); const vec128_t increment = vec128_set_16(8);
for (IndexType i = 0; i < NumChunks; ++i) for (IndexType i = 0; i < NumChunks; ++i)
{ {
// bitmask of nonzero values in this chunk // bitmask of nonzero values in this chunk
unsigned nnz = 0; unsigned nnz = 0;
for (IndexType j = 0; j < InputsPerChunk; ++j) for (IndexType j = 0; j < InputsPerChunk; ++j)
{ {
const vec_t inputChunk = inputVector[i * InputsPerChunk + j]; const vec_t inputChunk = inputVector[i * InputsPerChunk + j];
nnz |= (unsigned)vec_nnz(inputChunk) << (j * InputSimdWidth); nnz |= unsigned(vec_nnz(inputChunk)) << (j * InputSimdWidth);
} }
for (IndexType j = 0; j < OutputsPerChunk; ++j) for (IndexType j = 0; j < OutputsPerChunk; ++j)
{ {
const auto lookup = (nnz >> (j * 8)) & 0xFF; const unsigned lookup = (nnz >> (j * 8)) & 0xFF;
const auto offsets = _mm_loadu_si128(reinterpret_cast<const __m128i*>(&lookup_indices[lookup])); const vec128_t offsets =
_mm_storeu_si128(reinterpret_cast<__m128i*>(out + count), _mm_add_epi16(base, offsets)); vec128_load(reinterpret_cast<const vec128_t*>(&Lookup.offset_indices[lookup]));
count += lookup_count[lookup]; vec128_storeu(reinterpret_cast<vec128_t*>(out + count), vec128_add(base, offsets));
base = _mm_add_epi16(base, increment); count += popcount(lookup);
} base = vec128_add(base, increment);
}
} }
count_out = count; count_out = count;
} }
# undef vec_nnz #undef vec_nnz
#undef vec128_zero
#undef vec128_set_16
#undef vec128_load
#undef vec128_storeu
#undef vec128_add
#endif #endif
// Sparse input implementation // Sparse input implementation
template <IndexType InDims, IndexType OutDims> template<IndexType InDims, IndexType OutDims>
class AffineTransformSparseInput { class AffineTransformSparseInput {
public: public:
// Input/output type // Input/output type
// Input/output type using InputType = std::uint8_t;
using InputType = std::uint8_t;
using OutputType = std::int32_t; using OutputType = std::int32_t;
// Number of input/output dimensions // Number of input/output dimensions
static constexpr IndexType InputDimensions = InDims; static constexpr IndexType InputDimensions = InDims;
static constexpr IndexType OutputDimensions = OutDims; static constexpr IndexType OutputDimensions = OutDims;
static_assert(OutputDimensions % 16 == 0, "Only implemented for OutputDimensions divisible by 16."); static_assert(OutputDimensions % 16 == 0,
"Only implemented for OutputDimensions divisible by 16.");
static constexpr IndexType PaddedInputDimensions = static constexpr IndexType PaddedInputDimensions =
ceil_to_multiple<IndexType>(InputDimensions, MaxSimdWidth); ceil_to_multiple<IndexType>(InputDimensions, MaxSimdWidth);
static constexpr IndexType PaddedOutputDimensions = static constexpr IndexType PaddedOutputDimensions =
ceil_to_multiple<IndexType>(OutputDimensions, MaxSimdWidth); ceil_to_multiple<IndexType>(OutputDimensions, MaxSimdWidth);
#if defined (USE_SSSE3) #if (USE_SSSE3 | (USE_NEON >= 8))
static constexpr IndexType ChunkSize = 4; static constexpr IndexType ChunkSize = 4;
#else #else
static constexpr IndexType ChunkSize = 1; static constexpr IndexType ChunkSize = 1;
@@ -167,120 +186,121 @@ namespace Stockfish::Eval::NNUE::Layers {
// Hash value embedded in the evaluation file // Hash value embedded in the evaluation file
static constexpr std::uint32_t get_hash_value(std::uint32_t prevHash) { static constexpr std::uint32_t get_hash_value(std::uint32_t prevHash) {
std::uint32_t hashValue = 0xCC03DAE4u; std::uint32_t hashValue = 0xCC03DAE4u;
hashValue += OutputDimensions; hashValue += OutputDimensions;
hashValue ^= prevHash >> 1; hashValue ^= prevHash >> 1;
hashValue ^= prevHash << 31; hashValue ^= prevHash << 31;
return hashValue; return hashValue;
} }
static IndexType get_weight_index_scrambled(IndexType i) static constexpr IndexType get_weight_index_scrambled(IndexType i) {
{ return (i / ChunkSize) % (PaddedInputDimensions / ChunkSize) * OutputDimensions * ChunkSize
return + i / PaddedInputDimensions * ChunkSize + i % ChunkSize;
(i / ChunkSize) % (PaddedInputDimensions / ChunkSize) * OutputDimensions * ChunkSize +
i / PaddedInputDimensions * ChunkSize +
i % ChunkSize;
} }
static IndexType get_weight_index(IndexType i) static constexpr IndexType get_weight_index(IndexType i) {
{ #if (USE_SSSE3 | (USE_NEON >= 8))
#if defined (USE_SSSE3) return get_weight_index_scrambled(i);
return get_weight_index_scrambled(i);
#else #else
return i; return i;
#endif #endif
} }
// Read network parameters // Read network parameters
bool read_parameters(std::istream& stream) { bool read_parameters(std::istream& stream) {
read_little_endian<BiasType>(stream, biases, OutputDimensions); read_little_endian<BiasType>(stream, biases, OutputDimensions);
for (IndexType i = 0; i < OutputDimensions * PaddedInputDimensions; ++i) for (IndexType i = 0; i < OutputDimensions * PaddedInputDimensions; ++i)
weights[get_weight_index(i)] = read_little_endian<WeightType>(stream); weights[get_weight_index(i)] = read_little_endian<WeightType>(stream);
return !stream.fail(); return !stream.fail();
} }
// Write network parameters // Write network parameters
bool write_parameters(std::ostream& stream) const { bool write_parameters(std::ostream& stream) const {
write_little_endian<BiasType>(stream, biases, OutputDimensions); write_little_endian<BiasType>(stream, biases, OutputDimensions);
for (IndexType i = 0; i < OutputDimensions * PaddedInputDimensions; ++i) for (IndexType i = 0; i < OutputDimensions * PaddedInputDimensions; ++i)
write_little_endian<WeightType>(stream, weights[get_weight_index(i)]); write_little_endian<WeightType>(stream, weights[get_weight_index(i)]);
return !stream.fail(); return !stream.fail();
} }
// Forward propagation // Forward propagation
const OutputType* propagate( void propagate(const InputType* input, OutputType* output) const {
const InputType* input, OutputType* output) const {
#if defined (USE_SSSE3) #if (USE_SSSE3 | (USE_NEON >= 8))
#if defined (USE_AVX512) #if defined(USE_AVX512)
using vec_t = __m512i; using invec_t = __m512i;
#define vec_setzero _mm512_setzero_si512 using outvec_t = __m512i;
#define vec_set_32 _mm512_set1_epi32 #define vec_set_32 _mm512_set1_epi32
#define vec_add_dpbusd_32 Simd::m512_add_dpbusd_epi32 #define vec_add_dpbusd_32 Simd::m512_add_dpbusd_epi32
#elif defined (USE_AVX2) #elif defined(USE_AVX2)
using vec_t = __m256i; using invec_t = __m256i;
#define vec_setzero _mm256_setzero_si256 using outvec_t = __m256i;
#define vec_set_32 _mm256_set1_epi32 #define vec_set_32 _mm256_set1_epi32
#define vec_add_dpbusd_32 Simd::m256_add_dpbusd_epi32 #define vec_add_dpbusd_32 Simd::m256_add_dpbusd_epi32
#elif defined (USE_SSSE3) #elif defined(USE_SSSE3)
using vec_t = __m128i; using invec_t = __m128i;
#define vec_setzero _mm_setzero_si128 using outvec_t = __m128i;
#define vec_set_32 _mm_set1_epi32 #define vec_set_32 _mm_set1_epi32
#define vec_add_dpbusd_32 Simd::m128_add_dpbusd_epi32 #define vec_add_dpbusd_32 Simd::m128_add_dpbusd_epi32
#endif #elif defined(USE_NEON_DOTPROD)
static constexpr IndexType OutputSimdWidth = sizeof(vec_t) / sizeof(OutputType); using invec_t = int8x16_t;
using outvec_t = int32x4_t;
#define vec_set_32(a) vreinterpretq_s8_u32(vdupq_n_u32(a))
#define vec_add_dpbusd_32 Simd::dotprod_m128_add_dpbusd_epi32
#elif defined(USE_NEON)
using invec_t = int8x16_t;
using outvec_t = int32x4_t;
#define vec_set_32(a) vreinterpretq_s8_u32(vdupq_n_u32(a))
#define vec_add_dpbusd_32 Simd::neon_m128_add_dpbusd_epi32
#endif
static constexpr IndexType OutputSimdWidth = sizeof(outvec_t) / sizeof(OutputType);
constexpr IndexType NumChunks = ceil_to_multiple<IndexType>(InputDimensions, 8) / ChunkSize; constexpr IndexType NumChunks = ceil_to_multiple<IndexType>(InputDimensions, 8) / ChunkSize;
constexpr IndexType NumRegs = OutputDimensions / OutputSimdWidth; constexpr IndexType NumRegs = OutputDimensions / OutputSimdWidth;
std::uint16_t nnz[NumChunks]; std::uint16_t nnz[NumChunks];
IndexType count; IndexType count;
const auto input32 = reinterpret_cast<const std::int32_t*>(input); const auto input32 = reinterpret_cast<const std::int32_t*>(input);
// Find indices of nonzero 32bit blocks // Find indices of nonzero 32-bit blocks
find_nnz<NumChunks>(input32, nnz, count); find_nnz<NumChunks>(input32, nnz, count);
const vec_t* biasvec = reinterpret_cast<const vec_t*>(biases); const outvec_t* biasvec = reinterpret_cast<const outvec_t*>(biases);
vec_t acc[NumRegs]; outvec_t acc[NumRegs];
for (IndexType k = 0; k < NumRegs; ++k)
acc[k] = biasvec[k];
for (IndexType j = 0; j < count; ++j)
{
const auto i = nnz[j];
const vec_t in = vec_set_32(input32[i]);
const auto col = reinterpret_cast<const vec_t*>(&weights[i * OutputDimensions * ChunkSize]);
for (IndexType k = 0; k < NumRegs; ++k) for (IndexType k = 0; k < NumRegs; ++k)
vec_add_dpbusd_32(acc[k], in, col[k]); acc[k] = biasvec[k];
}
vec_t* outptr = reinterpret_cast<vec_t*>(output); for (IndexType j = 0; j < count; ++j)
for (IndexType k = 0; k < NumRegs; ++k) {
outptr[k] = acc[k]; const auto i = nnz[j];
# undef vec_setzero const invec_t in = vec_set_32(input32[i]);
# undef vec_set_32 const auto col =
# undef vec_add_dpbusd_32 reinterpret_cast<const invec_t*>(&weights[i * OutputDimensions * ChunkSize]);
for (IndexType k = 0; k < NumRegs; ++k)
vec_add_dpbusd_32(acc[k], in, col[k]);
}
outvec_t* outptr = reinterpret_cast<outvec_t*>(output);
for (IndexType k = 0; k < NumRegs; ++k)
outptr[k] = acc[k];
#undef vec_set_32
#undef vec_add_dpbusd_32
#else #else
// Use dense implementation for the other architectures. // Use dense implementation for the other architectures.
affine_transform_non_ssse3< affine_transform_non_ssse3<InputDimensions, PaddedInputDimensions, OutputDimensions>(
InputDimensions, output, weights, biases, input);
PaddedInputDimensions,
OutputDimensions>(output, weights, biases, input);
#endif #endif
return output;
} }
private: private:
using BiasType = OutputType; using BiasType = OutputType;
using WeightType = std::int8_t; using WeightType = std::int8_t;
alignas(CacheLineSize) BiasType biases[OutputDimensions]; alignas(CacheLineSize) BiasType biases[OutputDimensions];
alignas(CacheLineSize) WeightType weights[OutputDimensions * PaddedInputDimensions]; alignas(CacheLineSize) WeightType weights[OutputDimensions * PaddedInputDimensions];
}; };
} // namespace Stockfish::Eval::NNUE::Layers } // namespace Stockfish::Eval::NNUE::Layers
#endif // #ifndef NNUE_LAYERS_AFFINE_TRANSFORM_SPARSE_INPUT_H_INCLUDED #endif // #ifndef NNUE_LAYERS_AFFINE_TRANSFORM_SPARSE_INPUT_H_INCLUDED
+109 -125
View File
@@ -1,6 +1,6 @@
/* /*
Stockfish, a UCI chess playing engine derived from Glaurung 2.1 Stockfish, a UCI chess playing engine derived from Glaurung 2.1
Copyright (C) 2004-2023 The Stockfish developers (see AUTHORS file) Copyright (C) 2004-2025 The Stockfish developers (see AUTHORS file)
Stockfish is free software: you can redistribute it and/or modify Stockfish is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by it under the terms of the GNU General Public License as published by
@@ -21,160 +21,144 @@
#ifndef NNUE_LAYERS_CLIPPED_RELU_H_INCLUDED #ifndef NNUE_LAYERS_CLIPPED_RELU_H_INCLUDED
#define NNUE_LAYERS_CLIPPED_RELU_H_INCLUDED #define NNUE_LAYERS_CLIPPED_RELU_H_INCLUDED
#include <algorithm>
#include <cstdint>
#include <iosfwd>
#include "../nnue_common.h" #include "../nnue_common.h"
namespace Stockfish::Eval::NNUE::Layers { namespace Stockfish::Eval::NNUE::Layers {
// Clipped ReLU // Clipped ReLU
template <IndexType InDims> template<IndexType InDims>
class ClippedReLU { class ClippedReLU {
public: public:
// Input/output type // Input/output type
using InputType = std::int32_t; using InputType = std::int32_t;
using OutputType = std::uint8_t; using OutputType = std::uint8_t;
// Number of input/output dimensions // Number of input/output dimensions
static constexpr IndexType InputDimensions = InDims; static constexpr IndexType InputDimensions = InDims;
static constexpr IndexType OutputDimensions = InputDimensions; static constexpr IndexType OutputDimensions = InputDimensions;
static constexpr IndexType PaddedOutputDimensions = static constexpr IndexType PaddedOutputDimensions =
ceil_to_multiple<IndexType>(OutputDimensions, 32); ceil_to_multiple<IndexType>(OutputDimensions, 32);
using OutputBuffer = OutputType[PaddedOutputDimensions]; using OutputBuffer = OutputType[PaddedOutputDimensions];
// Hash value embedded in the evaluation file // Hash value embedded in the evaluation file
static constexpr std::uint32_t get_hash_value(std::uint32_t prevHash) { static constexpr std::uint32_t get_hash_value(std::uint32_t prevHash) {
std::uint32_t hashValue = 0x538D24C7u; std::uint32_t hashValue = 0x538D24C7u;
hashValue += prevHash; hashValue += prevHash;
return hashValue; return hashValue;
} }
// Read network parameters // Read network parameters
bool read_parameters(std::istream&) { bool read_parameters(std::istream&) { return true; }
return true;
}
// Write network parameters // Write network parameters
bool write_parameters(std::ostream&) const { bool write_parameters(std::ostream&) const { return true; }
return true;
}
// Forward propagation // Forward propagation
const OutputType* propagate( void propagate(const InputType* input, OutputType* output) const {
const InputType* input, OutputType* output) const {
#if defined(USE_AVX2) #if defined(USE_AVX2)
if constexpr (InputDimensions % SimdWidth == 0) { if constexpr (InputDimensions % SimdWidth == 0)
{
constexpr IndexType NumChunks = InputDimensions / SimdWidth;
const __m256i Offsets = _mm256_set_epi32(7, 3, 6, 2, 5, 1, 4, 0);
const auto in = reinterpret_cast<const __m256i*>(input);
const auto out = reinterpret_cast<__m256i*>(output);
for (IndexType i = 0; i < NumChunks; ++i)
{
const __m256i words0 =
_mm256_srli_epi16(_mm256_packus_epi32(_mm256_load_si256(&in[i * 4 + 0]),
_mm256_load_si256(&in[i * 4 + 1])),
WeightScaleBits);
const __m256i words1 =
_mm256_srli_epi16(_mm256_packus_epi32(_mm256_load_si256(&in[i * 4 + 2]),
_mm256_load_si256(&in[i * 4 + 3])),
WeightScaleBits);
_mm256_store_si256(&out[i], _mm256_permutevar8x32_epi32(
_mm256_packs_epi16(words0, words1), Offsets));
}
}
else
{
constexpr IndexType NumChunks = InputDimensions / (SimdWidth / 2);
const auto in = reinterpret_cast<const __m128i*>(input);
const auto out = reinterpret_cast<__m128i*>(output);
for (IndexType i = 0; i < NumChunks; ++i)
{
const __m128i words0 = _mm_srli_epi16(
_mm_packus_epi32(_mm_load_si128(&in[i * 4 + 0]), _mm_load_si128(&in[i * 4 + 1])),
WeightScaleBits);
const __m128i words1 = _mm_srli_epi16(
_mm_packus_epi32(_mm_load_si128(&in[i * 4 + 2]), _mm_load_si128(&in[i * 4 + 3])),
WeightScaleBits);
_mm_store_si128(&out[i], _mm_packs_epi16(words0, words1));
}
}
constexpr IndexType Start = InputDimensions % SimdWidth == 0
? InputDimensions / SimdWidth * SimdWidth
: InputDimensions / (SimdWidth / 2) * (SimdWidth / 2);
#elif defined(USE_SSE2)
constexpr IndexType NumChunks = InputDimensions / SimdWidth; constexpr IndexType NumChunks = InputDimensions / SimdWidth;
const __m256i Zero = _mm256_setzero_si256();
const __m256i Offsets = _mm256_set_epi32(7, 3, 6, 2, 5, 1, 4, 0); #ifndef USE_SSE41
const auto in = reinterpret_cast<const __m256i*>(input); const __m128i k0x80s = _mm_set1_epi8(-128);
const auto out = reinterpret_cast<__m256i*>(output); #endif
for (IndexType i = 0; i < NumChunks; ++i) {
const __m256i words0 = _mm256_srai_epi16(_mm256_packs_epi32( const auto in = reinterpret_cast<const __m128i*>(input);
_mm256_load_si256(&in[i * 4 + 0]),
_mm256_load_si256(&in[i * 4 + 1])), WeightScaleBits);
const __m256i words1 = _mm256_srai_epi16(_mm256_packs_epi32(
_mm256_load_si256(&in[i * 4 + 2]),
_mm256_load_si256(&in[i * 4 + 3])), WeightScaleBits);
_mm256_store_si256(&out[i], _mm256_permutevar8x32_epi32(_mm256_max_epi8(
_mm256_packs_epi16(words0, words1), Zero), Offsets));
}
} else {
constexpr IndexType NumChunks = InputDimensions / (SimdWidth / 2);
const __m128i Zero = _mm_setzero_si128();
const auto in = reinterpret_cast<const __m128i*>(input);
const auto out = reinterpret_cast<__m128i*>(output); const auto out = reinterpret_cast<__m128i*>(output);
for (IndexType i = 0; i < NumChunks; ++i) { for (IndexType i = 0; i < NumChunks; ++i)
const __m128i words0 = _mm_srai_epi16(_mm_packs_epi32( {
_mm_load_si128(&in[i * 4 + 0]), #if defined(USE_SSE41)
_mm_load_si128(&in[i * 4 + 1])), WeightScaleBits); const __m128i words0 = _mm_srli_epi16(
const __m128i words1 = _mm_srai_epi16(_mm_packs_epi32( _mm_packus_epi32(_mm_load_si128(&in[i * 4 + 0]), _mm_load_si128(&in[i * 4 + 1])),
_mm_load_si128(&in[i * 4 + 2]), WeightScaleBits);
_mm_load_si128(&in[i * 4 + 3])), WeightScaleBits); const __m128i words1 = _mm_srli_epi16(
const __m128i packedbytes = _mm_packs_epi16(words0, words1); _mm_packus_epi32(_mm_load_si128(&in[i * 4 + 2]), _mm_load_si128(&in[i * 4 + 3])),
_mm_store_si128(&out[i], _mm_max_epi8(packedbytes, Zero)); WeightScaleBits);
_mm_store_si128(&out[i], _mm_packs_epi16(words0, words1));
#else
const __m128i words0 = _mm_srai_epi16(
_mm_packs_epi32(_mm_load_si128(&in[i * 4 + 0]), _mm_load_si128(&in[i * 4 + 1])),
WeightScaleBits);
const __m128i words1 = _mm_srai_epi16(
_mm_packs_epi32(_mm_load_si128(&in[i * 4 + 2]), _mm_load_si128(&in[i * 4 + 3])),
WeightScaleBits);
const __m128i packedbytes = _mm_packs_epi16(words0, words1);
_mm_store_si128(&out[i], _mm_subs_epi8(_mm_adds_epi8(packedbytes, k0x80s), k0x80s));
#endif
} }
} constexpr IndexType Start = NumChunks * SimdWidth;
constexpr IndexType Start =
InputDimensions % SimdWidth == 0
? InputDimensions / SimdWidth * SimdWidth
: InputDimensions / (SimdWidth / 2) * (SimdWidth / 2);
#elif defined(USE_SSE2) #elif defined(USE_NEON)
constexpr IndexType NumChunks = InputDimensions / SimdWidth; constexpr IndexType NumChunks = InputDimensions / (SimdWidth / 2);
const int8x8_t Zero = {0};
const auto in = reinterpret_cast<const int32x4_t*>(input);
const auto out = reinterpret_cast<int8x8_t*>(output);
for (IndexType i = 0; i < NumChunks; ++i)
{
int16x8_t shifted;
const auto pack = reinterpret_cast<int16x4_t*>(&shifted);
pack[0] = vqshrn_n_s32(in[i * 2 + 0], WeightScaleBits);
pack[1] = vqshrn_n_s32(in[i * 2 + 1], WeightScaleBits);
out[i] = vmax_s8(vqmovn_s16(shifted), Zero);
}
constexpr IndexType Start = NumChunks * (SimdWidth / 2);
#else
constexpr IndexType Start = 0;
#endif
#ifdef USE_SSE41 for (IndexType i = Start; i < InputDimensions; ++i)
const __m128i Zero = _mm_setzero_si128(); {
#else output[i] = static_cast<OutputType>(std::clamp(input[i] >> WeightScaleBits, 0, 127));
const __m128i k0x80s = _mm_set1_epi8(-128); }
#endif
const auto in = reinterpret_cast<const __m128i*>(input);
const auto out = reinterpret_cast<__m128i*>(output);
for (IndexType i = 0; i < NumChunks; ++i) {
const __m128i words0 = _mm_srai_epi16(_mm_packs_epi32(
_mm_load_si128(&in[i * 4 + 0]),
_mm_load_si128(&in[i * 4 + 1])), WeightScaleBits);
const __m128i words1 = _mm_srai_epi16(_mm_packs_epi32(
_mm_load_si128(&in[i * 4 + 2]),
_mm_load_si128(&in[i * 4 + 3])), WeightScaleBits);
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 * SimdWidth;
#elif defined(USE_MMX)
constexpr IndexType NumChunks = InputDimensions / SimdWidth;
const __m64 k0x80s = _mm_set1_pi8(-128);
const auto in = reinterpret_cast<const __m64*>(input);
const auto out = reinterpret_cast<__m64*>(output);
for (IndexType i = 0; i < NumChunks; ++i) {
const __m64 words0 = _mm_srai_pi16(
_mm_packs_pi32(in[i * 4 + 0], in[i * 4 + 1]),
WeightScaleBits);
const __m64 words1 = _mm_srai_pi16(
_mm_packs_pi32(in[i * 4 + 2], in[i * 4 + 3]),
WeightScaleBits);
const __m64 packedbytes = _mm_packs_pi16(words0, words1);
out[i] = _mm_subs_pi8(_mm_adds_pi8(packedbytes, k0x80s), k0x80s);
}
_mm_empty();
constexpr IndexType Start = NumChunks * SimdWidth;
#elif defined(USE_NEON)
constexpr IndexType NumChunks = InputDimensions / (SimdWidth / 2);
const int8x8_t Zero = {0};
const auto in = reinterpret_cast<const int32x4_t*>(input);
const auto out = reinterpret_cast<int8x8_t*>(output);
for (IndexType i = 0; i < NumChunks; ++i) {
int16x8_t shifted;
const auto pack = reinterpret_cast<int16x4_t*>(&shifted);
pack[0] = vqshrn_n_s32(in[i * 2 + 0], WeightScaleBits);
pack[1] = vqshrn_n_s32(in[i * 2 + 1], WeightScaleBits);
out[i] = vmax_s8(vqmovn_s16(shifted), Zero);
}
constexpr IndexType Start = NumChunks * (SimdWidth / 2);
#else
constexpr IndexType Start = 0;
#endif
for (IndexType i = Start; i < InputDimensions; ++i) {
output[i] = static_cast<OutputType>(
std::max(0, std::min(127, input[i] >> WeightScaleBits)));
}
return output;
} }
}; };
} // namespace Stockfish::Eval::NNUE::Layers } // namespace Stockfish::Eval::NNUE::Layers
#endif // NNUE_LAYERS_CLIPPED_RELU_H_INCLUDED #endif // NNUE_LAYERS_CLIPPED_RELU_H_INCLUDED
+98 -367
View File
@@ -1,6 +1,6 @@
/* /*
Stockfish, a UCI chess playing engine derived from Glaurung 2.1 Stockfish, a UCI chess playing engine derived from Glaurung 2.1
Copyright (C) 2004-2023 The Stockfish developers (see AUTHORS file) Copyright (C) 2004-2025 The Stockfish developers (see AUTHORS file)
Stockfish is free software: you can redistribute it and/or modify Stockfish is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by it under the terms of the GNU General Public License as published by
@@ -20,384 +20,115 @@
#define STOCKFISH_SIMD_H_INCLUDED #define STOCKFISH_SIMD_H_INCLUDED
#if defined(USE_AVX2) #if defined(USE_AVX2)
# include <immintrin.h> #include <immintrin.h>
#elif defined(USE_SSE41) #elif defined(USE_SSE41)
# include <smmintrin.h> #include <smmintrin.h>
#elif defined(USE_SSSE3) #elif defined(USE_SSSE3)
# include <tmmintrin.h> #include <tmmintrin.h>
#elif defined(USE_SSE2) #elif defined(USE_SSE2)
# include <emmintrin.h> #include <emmintrin.h>
#elif defined(USE_MMX)
# include <mmintrin.h>
#elif defined(USE_NEON) #elif defined(USE_NEON)
# include <arm_neon.h> #include <arm_neon.h>
#endif
// The inline asm is only safe for GCC, where it is necessary to get good codegen.
// See https://gcc.gnu.org/bugzilla/show_bug.cgi?id=101693
// Clang does fine without it.
// Play around here: https://godbolt.org/z/7EWqrYq51
#if (defined(__GNUC__) && !defined(__clang__) && !defined(__INTEL_COMPILER))
#define USE_INLINE_ASM
#endif
// Use either the AVX512 or AVX-VNNI version of the VNNI instructions.
#if defined(USE_AVXVNNI)
#define VNNI_PREFIX "%{vex%} "
#else
#define VNNI_PREFIX ""
#endif #endif
namespace Stockfish::Simd { namespace Stockfish::Simd {
#if defined (USE_AVX512) #if defined(USE_AVX512)
[[maybe_unused]] static int m512_hadd(__m512i sum, int bias) {
return _mm512_reduce_add_epi32(sum) + bias;
}
/*
Parameters:
sum0 = [zmm0.i128[0], zmm0.i128[1], zmm0.i128[2], zmm0.i128[3]]
sum1 = [zmm1.i128[0], zmm1.i128[1], zmm1.i128[2], zmm1.i128[3]]
sum2 = [zmm2.i128[0], zmm2.i128[1], zmm2.i128[2], zmm2.i128[3]]
sum3 = [zmm3.i128[0], zmm3.i128[1], zmm3.i128[2], zmm3.i128[3]]
Returns:
ret = [
reduce_add_epi32(zmm0.i128[0]), reduce_add_epi32(zmm1.i128[0]), reduce_add_epi32(zmm2.i128[0]), reduce_add_epi32(zmm3.i128[0]),
reduce_add_epi32(zmm0.i128[1]), reduce_add_epi32(zmm1.i128[1]), reduce_add_epi32(zmm2.i128[1]), reduce_add_epi32(zmm3.i128[1]),
reduce_add_epi32(zmm0.i128[2]), reduce_add_epi32(zmm1.i128[2]), reduce_add_epi32(zmm2.i128[2]), reduce_add_epi32(zmm3.i128[2]),
reduce_add_epi32(zmm0.i128[3]), reduce_add_epi32(zmm1.i128[3]), reduce_add_epi32(zmm2.i128[3]), reduce_add_epi32(zmm3.i128[3])
]
*/
[[maybe_unused]] static __m512i m512_hadd128x16_interleave(
__m512i sum0, __m512i sum1, __m512i sum2, __m512i sum3) {
__m512i sum01a = _mm512_unpacklo_epi32(sum0, sum1);
__m512i sum01b = _mm512_unpackhi_epi32(sum0, sum1);
__m512i sum23a = _mm512_unpacklo_epi32(sum2, sum3);
__m512i sum23b = _mm512_unpackhi_epi32(sum2, sum3);
__m512i sum01 = _mm512_add_epi32(sum01a, sum01b);
__m512i sum23 = _mm512_add_epi32(sum23a, sum23b);
__m512i sum0123a = _mm512_unpacklo_epi64(sum01, sum23);
__m512i sum0123b = _mm512_unpackhi_epi64(sum01, sum23);
return _mm512_add_epi32(sum0123a, sum0123b);
}
[[maybe_unused]] static __m128i m512_haddx4(
__m512i sum0, __m512i sum1, __m512i sum2, __m512i sum3,
__m128i bias) {
__m512i sum = m512_hadd128x16_interleave(sum0, sum1, sum2, sum3);
__m256i sum256lo = _mm512_castsi512_si256(sum);
__m256i sum256hi = _mm512_extracti64x4_epi64(sum, 1);
sum256lo = _mm256_add_epi32(sum256lo, sum256hi);
__m128i sum128lo = _mm256_castsi256_si128(sum256lo);
__m128i sum128hi = _mm256_extracti128_si256(sum256lo, 1);
return _mm_add_epi32(_mm_add_epi32(sum128lo, sum128hi), bias);
}
[[maybe_unused]] static void m512_add_dpbusd_epi32(
__m512i& acc,
__m512i a,
__m512i b) {
# if defined (USE_VNNI)
# if defined (USE_INLINE_ASM)
asm(
"vpdpbusd %[b], %[a], %[acc]\n\t"
: [acc]"+v"(acc)
: [a]"v"(a), [b]"vm"(b)
);
# else
acc = _mm512_dpbusd_epi32(acc, a, b);
# endif
# else
# if defined (USE_INLINE_ASM)
__m512i tmp = _mm512_maddubs_epi16(a, b);
asm(
"vpmaddwd %[tmp], %[ones], %[tmp]\n\t"
"vpaddd %[acc], %[tmp], %[acc]\n\t"
: [acc]"+v"(acc), [tmp]"+&v"(tmp)
: [ones]"v"(_mm512_set1_epi16(1))
);
# else
__m512i product0 = _mm512_maddubs_epi16(a, b);
product0 = _mm512_madd_epi16(product0, _mm512_set1_epi16(1));
acc = _mm512_add_epi32(acc, product0);
# endif
# endif
}
[[maybe_unused]] static void m512_add_dpbusd_epi32x2(
__m512i& acc,
__m512i a0, __m512i b0,
__m512i a1, __m512i b1) {
# if defined (USE_VNNI)
# if defined (USE_INLINE_ASM)
asm(
"vpdpbusd %[b0], %[a0], %[acc]\n\t"
"vpdpbusd %[b1], %[a1], %[acc]\n\t"
: [acc]"+&v"(acc)
: [a0]"v"(a0), [b0]"vm"(b0), [a1]"v"(a1), [b1]"vm"(b1)
);
# else
acc = _mm512_dpbusd_epi32(acc, a0, b0);
acc = _mm512_dpbusd_epi32(acc, a1, b1);
# endif
# else
# if defined (USE_INLINE_ASM)
__m512i tmp0 = _mm512_maddubs_epi16(a0, b0);
__m512i tmp1 = _mm512_maddubs_epi16(a1, b1);
asm(
"vpmaddwd %[tmp0], %[ones], %[tmp0]\n\t"
"vpmaddwd %[tmp1], %[ones], %[tmp1]\n\t"
"vpaddd %[tmp0], %[tmp1], %[tmp0]\n\t"
"vpaddd %[acc], %[tmp0], %[acc]\n\t"
: [acc]"+v"(acc), [tmp0]"+&v"(tmp0), [tmp1]"+&v"(tmp1)
: [ones]"v"(_mm512_set1_epi16(1))
);
# else
__m512i product0 = _mm512_maddubs_epi16(a0, b0);
__m512i product1 = _mm512_maddubs_epi16(a1, b1);
product0 = _mm512_madd_epi16(product0, _mm512_set1_epi16(1));
product1 = _mm512_madd_epi16(product1, _mm512_set1_epi16(1));
acc = _mm512_add_epi32(acc, _mm512_add_epi32(product0, product1));
# endif
# endif
}
#endif
#if defined (USE_AVX2)
[[maybe_unused]] static int m256_hadd(__m256i sum, int bias) {
__m128i sum128 = _mm_add_epi32(_mm256_castsi256_si128(sum), _mm256_extracti128_si256(sum, 1));
sum128 = _mm_add_epi32(sum128, _mm_shuffle_epi32(sum128, _MM_PERM_BADC));
sum128 = _mm_add_epi32(sum128, _mm_shuffle_epi32(sum128, _MM_PERM_CDAB));
return _mm_cvtsi128_si32(sum128) + bias;
}
[[maybe_unused]] static __m128i m256_haddx4(
__m256i sum0, __m256i sum1, __m256i sum2, __m256i sum3,
__m128i bias) {
sum0 = _mm256_hadd_epi32(sum0, sum1);
sum2 = _mm256_hadd_epi32(sum2, sum3);
sum0 = _mm256_hadd_epi32(sum0, sum2);
__m128i sum128lo = _mm256_castsi256_si128(sum0);
__m128i sum128hi = _mm256_extracti128_si256(sum0, 1);
return _mm_add_epi32(_mm_add_epi32(sum128lo, sum128hi), bias);
}
[[maybe_unused]] static void m256_add_dpbusd_epi32(
__m256i& acc,
__m256i a,
__m256i b) {
# if defined (USE_VNNI)
# if defined (USE_INLINE_ASM)
asm(
VNNI_PREFIX "vpdpbusd %[b], %[a], %[acc]\n\t"
: [acc]"+v"(acc)
: [a]"v"(a), [b]"vm"(b)
);
# else
acc = _mm256_dpbusd_epi32(acc, a, b);
# endif
# else
# if defined (USE_INLINE_ASM)
__m256i tmp = _mm256_maddubs_epi16(a, b);
asm(
"vpmaddwd %[tmp], %[ones], %[tmp]\n\t"
"vpaddd %[acc], %[tmp], %[acc]\n\t"
: [acc]"+v"(acc), [tmp]"+&v"(tmp)
: [ones]"v"(_mm256_set1_epi16(1))
);
# else
__m256i product0 = _mm256_maddubs_epi16(a, b);
product0 = _mm256_madd_epi16(product0, _mm256_set1_epi16(1));
acc = _mm256_add_epi32(acc, product0);
# endif
# endif
}
[[maybe_unused]] static void m256_add_dpbusd_epi32x2(
__m256i& acc,
__m256i a0, __m256i b0,
__m256i a1, __m256i b1) {
# if defined (USE_VNNI)
# if defined (USE_INLINE_ASM)
asm(
VNNI_PREFIX "vpdpbusd %[b0], %[a0], %[acc]\n\t"
VNNI_PREFIX "vpdpbusd %[b1], %[a1], %[acc]\n\t"
: [acc]"+&v"(acc)
: [a0]"v"(a0), [b0]"vm"(b0), [a1]"v"(a1), [b1]"vm"(b1)
);
# else
acc = _mm256_dpbusd_epi32(acc, a0, b0);
acc = _mm256_dpbusd_epi32(acc, a1, b1);
# endif
# else
# if defined (USE_INLINE_ASM)
__m256i tmp0 = _mm256_maddubs_epi16(a0, b0);
__m256i tmp1 = _mm256_maddubs_epi16(a1, b1);
asm(
"vpmaddwd %[tmp0], %[ones], %[tmp0]\n\t"
"vpmaddwd %[tmp1], %[ones], %[tmp1]\n\t"
"vpaddd %[tmp0], %[tmp1], %[tmp0]\n\t"
"vpaddd %[acc], %[tmp0], %[acc]\n\t"
: [acc]"+v"(acc), [tmp0]"+&v"(tmp0), [tmp1]"+&v"(tmp1)
: [ones]"v"(_mm256_set1_epi16(1))
);
# else
__m256i product0 = _mm256_maddubs_epi16(a0, b0);
__m256i product1 = _mm256_maddubs_epi16(a1, b1);
product0 = _mm256_madd_epi16(product0, _mm256_set1_epi16(1));
product1 = _mm256_madd_epi16(product1, _mm256_set1_epi16(1));
acc = _mm256_add_epi32(acc, _mm256_add_epi32(product0, product1));
# endif
# endif
}
#endif
#if defined (USE_SSSE3)
[[maybe_unused]] static int m128_hadd(__m128i sum, int bias) {
sum = _mm_add_epi32(sum, _mm_shuffle_epi32(sum, 0x4E)); //_MM_PERM_BADC
sum = _mm_add_epi32(sum, _mm_shuffle_epi32(sum, 0xB1)); //_MM_PERM_CDAB
return _mm_cvtsi128_si32(sum) + bias;
}
[[maybe_unused]] static __m128i m128_haddx4(
__m128i sum0, __m128i sum1, __m128i sum2, __m128i sum3,
__m128i bias) {
sum0 = _mm_hadd_epi32(sum0, sum1);
sum2 = _mm_hadd_epi32(sum2, sum3);
sum0 = _mm_hadd_epi32(sum0, sum2);
return _mm_add_epi32(sum0, bias);
}
[[maybe_unused]] static void m128_add_dpbusd_epi32(
__m128i& acc,
__m128i a,
__m128i b) {
# if defined (USE_INLINE_ASM)
__m128i tmp = _mm_maddubs_epi16(a, b);
asm(
"pmaddwd %[ones], %[tmp]\n\t"
"paddd %[tmp], %[acc]\n\t"
: [acc]"+v"(acc), [tmp]"+&v"(tmp)
: [ones]"v"(_mm_set1_epi16(1))
);
# else
__m128i product0 = _mm_maddubs_epi16(a, b);
product0 = _mm_madd_epi16(product0, _mm_set1_epi16(1));
acc = _mm_add_epi32(acc, product0);
# endif
}
[[maybe_unused]] static void m128_add_dpbusd_epi32x2(
__m128i& acc,
__m128i a0, __m128i b0,
__m128i a1, __m128i b1) {
# if defined (USE_INLINE_ASM)
__m128i tmp0 = _mm_maddubs_epi16(a0, b0);
__m128i tmp1 = _mm_maddubs_epi16(a1, b1);
asm(
"pmaddwd %[ones], %[tmp0]\n\t"
"pmaddwd %[ones], %[tmp1]\n\t"
"paddd %[tmp1], %[tmp0]\n\t"
"paddd %[tmp0], %[acc]\n\t"
: [acc]"+v"(acc), [tmp0]"+&v"(tmp0), [tmp1]"+&v"(tmp1)
: [ones]"v"(_mm_set1_epi16(1))
);
# else
__m128i product0 = _mm_maddubs_epi16(a0, b0);
__m128i product1 = _mm_maddubs_epi16(a1, b1);
product0 = _mm_madd_epi16(product0, _mm_set1_epi16(1));
product1 = _mm_madd_epi16(product1, _mm_set1_epi16(1));
acc = _mm_add_epi32(acc, _mm_add_epi32(product0, product1));
# endif
}
#endif
#if defined (USE_NEON_DOTPROD)
[[maybe_unused]] static void dotprod_m128_add_dpbusd_epi32x2(
int32x4_t& acc,
int8x16_t a0, int8x16_t b0,
int8x16_t a1, int8x16_t b1) {
acc = vdotq_s32(acc, a0, b0);
acc = vdotq_s32(acc, a1, b1);
}
#endif
#if defined (USE_NEON)
[[maybe_unused]] static int neon_m128_reduce_add_epi32(int32x4_t s) {
# if USE_NEON >= 8
return vaddvq_s32(s);
# else
return s[0] + s[1] + s[2] + s[3];
# endif
}
[[maybe_unused]] static int neon_m128_hadd(int32x4_t sum, int bias) {
return neon_m128_reduce_add_epi32(sum) + bias;
}
[[maybe_unused]] static int32x4_t neon_m128_haddx4(
int32x4_t sum0, int32x4_t sum1, int32x4_t sum2, int32x4_t sum3,
int32x4_t bias) {
int32x4_t hsums {
neon_m128_reduce_add_epi32(sum0),
neon_m128_reduce_add_epi32(sum1),
neon_m128_reduce_add_epi32(sum2),
neon_m128_reduce_add_epi32(sum3)
};
return vaddq_s32(hsums, bias);
}
[[maybe_unused]] static void neon_m128_add_dpbusd_epi32x2(
int32x4_t& acc,
int8x8_t a0, int8x8_t b0,
int8x8_t a1, int8x8_t b1) {
int16x8_t product = vmull_s8(a0, b0);
product = vmlal_s8(product, a1, b1);
acc = vpadalq_s16(acc, product);
}
#endif
[[maybe_unused]] static int m512_hadd(__m512i sum, int bias) {
return _mm512_reduce_add_epi32(sum) + bias;
} }
#endif // STOCKFISH_SIMD_H_INCLUDED [[maybe_unused]] static void m512_add_dpbusd_epi32(__m512i& acc, __m512i a, __m512i b) {
#if defined(USE_VNNI)
acc = _mm512_dpbusd_epi32(acc, a, b);
#else
__m512i product0 = _mm512_maddubs_epi16(a, b);
product0 = _mm512_madd_epi16(product0, _mm512_set1_epi16(1));
acc = _mm512_add_epi32(acc, product0);
#endif
}
#endif
#if defined(USE_AVX2)
[[maybe_unused]] static int m256_hadd(__m256i sum, int bias) {
__m128i sum128 = _mm_add_epi32(_mm256_castsi256_si128(sum), _mm256_extracti128_si256(sum, 1));
sum128 = _mm_add_epi32(sum128, _mm_shuffle_epi32(sum128, _MM_PERM_BADC));
sum128 = _mm_add_epi32(sum128, _mm_shuffle_epi32(sum128, _MM_PERM_CDAB));
return _mm_cvtsi128_si32(sum128) + bias;
}
[[maybe_unused]] static void m256_add_dpbusd_epi32(__m256i& acc, __m256i a, __m256i b) {
#if defined(USE_VNNI)
acc = _mm256_dpbusd_epi32(acc, a, b);
#else
__m256i product0 = _mm256_maddubs_epi16(a, b);
product0 = _mm256_madd_epi16(product0, _mm256_set1_epi16(1));
acc = _mm256_add_epi32(acc, product0);
#endif
}
#endif
#if defined(USE_SSSE3)
[[maybe_unused]] static int m128_hadd(__m128i sum, int bias) {
sum = _mm_add_epi32(sum, _mm_shuffle_epi32(sum, 0x4E)); //_MM_PERM_BADC
sum = _mm_add_epi32(sum, _mm_shuffle_epi32(sum, 0xB1)); //_MM_PERM_CDAB
return _mm_cvtsi128_si32(sum) + bias;
}
[[maybe_unused]] static void m128_add_dpbusd_epi32(__m128i& acc, __m128i a, __m128i b) {
__m128i product0 = _mm_maddubs_epi16(a, b);
product0 = _mm_madd_epi16(product0, _mm_set1_epi16(1));
acc = _mm_add_epi32(acc, product0);
}
#endif
#if defined(USE_NEON_DOTPROD)
[[maybe_unused]] static void
dotprod_m128_add_dpbusd_epi32(int32x4_t& acc, int8x16_t a, int8x16_t b) {
acc = vdotq_s32(acc, a, b);
}
#endif
#if defined(USE_NEON)
[[maybe_unused]] static int neon_m128_reduce_add_epi32(int32x4_t s) {
#if USE_NEON >= 8
return vaddvq_s32(s);
#else
return s[0] + s[1] + s[2] + s[3];
#endif
}
[[maybe_unused]] static int neon_m128_hadd(int32x4_t sum, int bias) {
return neon_m128_reduce_add_epi32(sum) + bias;
}
#endif
#if USE_NEON >= 8
[[maybe_unused]] static void neon_m128_add_dpbusd_epi32(int32x4_t& acc, int8x16_t a, int8x16_t b) {
int16x8_t product0 = vmull_s8(vget_low_s8(a), vget_low_s8(b));
int16x8_t product1 = vmull_high_s8(a, b);
int16x8_t sum = vpaddq_s16(product0, product1);
acc = vpadalq_s16(acc, sum);
}
#endif
}
#endif // STOCKFISH_SIMD_H_INCLUDED
+48 -65
View File
@@ -1,6 +1,6 @@
/* /*
Stockfish, a UCI chess playing engine derived from Glaurung 2.1 Stockfish, a UCI chess playing engine derived from Glaurung 2.1
Copyright (C) 2004-2023 The Stockfish developers (see AUTHORS file) Copyright (C) 2004-2025 The Stockfish developers (see AUTHORS file)
Stockfish is free software: you can redistribute it and/or modify Stockfish is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by it under the terms of the GNU General Public License as published by
@@ -21,100 +21,83 @@
#ifndef NNUE_LAYERS_SQR_CLIPPED_RELU_H_INCLUDED #ifndef NNUE_LAYERS_SQR_CLIPPED_RELU_H_INCLUDED
#define NNUE_LAYERS_SQR_CLIPPED_RELU_H_INCLUDED #define NNUE_LAYERS_SQR_CLIPPED_RELU_H_INCLUDED
#include <algorithm>
#include <cstdint>
#include <iosfwd>
#include "../nnue_common.h" #include "../nnue_common.h"
namespace Stockfish::Eval::NNUE::Layers { namespace Stockfish::Eval::NNUE::Layers {
// Clipped ReLU // Clipped ReLU
template <IndexType InDims> template<IndexType InDims>
class SqrClippedReLU { class SqrClippedReLU {
public: public:
// Input/output type // Input/output type
using InputType = std::int32_t; using InputType = std::int32_t;
using OutputType = std::uint8_t; using OutputType = std::uint8_t;
// Number of input/output dimensions // Number of input/output dimensions
static constexpr IndexType InputDimensions = InDims; static constexpr IndexType InputDimensions = InDims;
static constexpr IndexType OutputDimensions = InputDimensions; static constexpr IndexType OutputDimensions = InputDimensions;
static constexpr IndexType PaddedOutputDimensions = static constexpr IndexType PaddedOutputDimensions =
ceil_to_multiple<IndexType>(OutputDimensions, 32); ceil_to_multiple<IndexType>(OutputDimensions, 32);
using OutputBuffer = OutputType[PaddedOutputDimensions]; using OutputBuffer = OutputType[PaddedOutputDimensions];
// Hash value embedded in the evaluation file // Hash value embedded in the evaluation file
static constexpr std::uint32_t get_hash_value(std::uint32_t prevHash) { static constexpr std::uint32_t get_hash_value(std::uint32_t prevHash) {
std::uint32_t hashValue = 0x538D24C7u; std::uint32_t hashValue = 0x538D24C7u;
hashValue += prevHash; hashValue += prevHash;
return hashValue; return hashValue;
} }
// Read network parameters // Read network parameters
bool read_parameters(std::istream&) { bool read_parameters(std::istream&) { return true; }
return true;
}
// Write network parameters // Write network parameters
bool write_parameters(std::ostream&) const { bool write_parameters(std::ostream&) const { return true; }
return true;
}
// Forward propagation // Forward propagation
const OutputType* propagate( void propagate(const InputType* input, OutputType* output) const {
const InputType* input, OutputType* output) const {
#if defined(USE_SSE2) #if defined(USE_SSE2)
constexpr IndexType NumChunks = InputDimensions / 16; constexpr IndexType NumChunks = InputDimensions / 16;
#ifdef USE_SSE41 static_assert(WeightScaleBits == 6);
const __m128i Zero = _mm_setzero_si128(); const auto in = reinterpret_cast<const __m128i*>(input);
#else const auto out = reinterpret_cast<__m128i*>(output);
const __m128i k0x80s = _mm_set1_epi8(-128); for (IndexType i = 0; i < NumChunks; ++i)
#endif {
__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]));
static_assert(WeightScaleBits == 6); // We shift by WeightScaleBits * 2 = 12 and divide by 128
const auto in = reinterpret_cast<const __m128i*>(input); // which is an additional shift-right of 7, meaning 19 in total.
const auto out = reinterpret_cast<__m128i*>(output); // MulHi strips the lower 16 bits so we need to shift out 3 more to match.
for (IndexType i = 0; i < NumChunks; ++i) { words0 = _mm_srli_epi16(_mm_mulhi_epi16(words0, words0), 3);
__m128i words0 = _mm_packs_epi32( words1 = _mm_srli_epi16(_mm_mulhi_epi16(words1, words1), 3);
_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 _mm_store_si128(&out[i], _mm_packs_epi16(words0, words1));
words0 = _mm_srli_epi16(_mm_mulhi_epi16(words0, words0), 3); }
words1 = _mm_srli_epi16(_mm_mulhi_epi16(words1, words1), 3); constexpr IndexType Start = NumChunks * 16;
const __m128i packedbytes = _mm_packs_epi16(words0, words1); #else
constexpr IndexType Start = 0;
#endif
_mm_store_si128(&out[i], for (IndexType i = Start; i < InputDimensions; ++i)
{
#ifdef USE_SSE41 output[i] = static_cast<OutputType>(
_mm_max_epi8(packedbytes, Zero) // Really should be /127 but we need to make it fast so we right-shift
#else // by an extra 7 bits instead. Needs to be accounted for in the trainer.
_mm_subs_epi8(_mm_adds_epi8(packedbytes, k0x80s), k0x80s) std::min(127ll, ((long long) (input[i]) * input[i]) >> (2 * WeightScaleBits + 7)));
#endif }
);
}
constexpr IndexType Start = NumChunks * 16;
#else
constexpr IndexType Start = 0;
#endif
for (IndexType i = Start; i < InputDimensions; ++i) {
output[i] = static_cast<OutputType>(
// really 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 } // namespace Stockfish::Eval::NNUE::Layers
#endif // NNUE_LAYERS_SQR_CLIPPED_RELU_H_INCLUDED #endif // NNUE_LAYERS_SQR_CLIPPED_RELU_H_INCLUDED
+467
View File
@@ -0,0 +1,467 @@
/*
Stockfish, a UCI chess playing engine derived from Glaurung 2.1
Copyright (C) 2004-2025 The Stockfish developers (see AUTHORS file)
Stockfish is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
Stockfish is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "network.h"
#include <cstdlib>
#include <fstream>
#include <iostream>
#include <memory>
#include <optional>
#include <type_traits>
#include <vector>
#define INCBIN_SILENCE_BITCODE_WARNING
#include "../incbin/incbin.h"
#include "../evaluate.h"
#include "../memory.h"
#include "../misc.h"
#include "../position.h"
#include "../types.h"
#include "nnue_architecture.h"
#include "nnue_common.h"
#include "nnue_misc.h"
// Macro to embed the default efficiently updatable neural network (NNUE) file
// data in the engine binary (using incbin.h, by Dale Weiler).
// This macro invocation will declare the following three variables
// const unsigned char gEmbeddedNNUEData[]; // a pointer to the embedded data
// const unsigned char *const gEmbeddedNNUEEnd; // a marker to the end
// const unsigned int gEmbeddedNNUESize; // the size of the embedded file
// Note that this does not work in Microsoft Visual Studio.
#if !defined(_MSC_VER) && !defined(NNUE_EMBEDDING_OFF)
INCBIN(EmbeddedNNUEBig, EvalFileDefaultNameBig);
INCBIN(EmbeddedNNUESmall, EvalFileDefaultNameSmall);
#else
const unsigned char gEmbeddedNNUEBigData[1] = {0x0};
const unsigned char* const gEmbeddedNNUEBigEnd = &gEmbeddedNNUEBigData[1];
const unsigned int gEmbeddedNNUEBigSize = 1;
const unsigned char gEmbeddedNNUESmallData[1] = {0x0};
const unsigned char* const gEmbeddedNNUESmallEnd = &gEmbeddedNNUESmallData[1];
const unsigned int gEmbeddedNNUESmallSize = 1;
#endif
namespace {
struct EmbeddedNNUE {
EmbeddedNNUE(const unsigned char* embeddedData,
const unsigned char* embeddedEnd,
const unsigned int embeddedSize) :
data(embeddedData),
end(embeddedEnd),
size(embeddedSize) {}
const unsigned char* data;
const unsigned char* end;
const unsigned int size;
};
using namespace Stockfish::Eval::NNUE;
EmbeddedNNUE get_embedded(EmbeddedNNUEType type) {
if (type == EmbeddedNNUEType::BIG)
return EmbeddedNNUE(gEmbeddedNNUEBigData, gEmbeddedNNUEBigEnd, gEmbeddedNNUEBigSize);
else
return EmbeddedNNUE(gEmbeddedNNUESmallData, gEmbeddedNNUESmallEnd, gEmbeddedNNUESmallSize);
}
}
namespace Stockfish::Eval::NNUE {
namespace Detail {
// Read evaluation function parameters
template<typename T>
bool read_parameters(std::istream& stream, T& reference) {
std::uint32_t header;
header = read_little_endian<std::uint32_t>(stream);
if (!stream || header != T::get_hash_value())
return false;
return reference.read_parameters(stream);
}
// Write evaluation function parameters
template<typename T>
bool write_parameters(std::ostream& stream, T& reference) {
write_little_endian<std::uint32_t>(stream, T::get_hash_value());
return reference.write_parameters(stream);
}
} // namespace Detail
template<typename Arch, typename Transformer>
Network<Arch, Transformer>::Network(const Network<Arch, Transformer>& other) :
evalFile(other.evalFile),
embeddedType(other.embeddedType) {
if (other.featureTransformer)
featureTransformer = make_unique_large_page<Transformer>(*other.featureTransformer);
network = make_unique_aligned<Arch[]>(LayerStacks);
if (!other.network)
return;
for (std::size_t i = 0; i < LayerStacks; ++i)
network[i] = other.network[i];
}
template<typename Arch, typename Transformer>
Network<Arch, Transformer>&
Network<Arch, Transformer>::operator=(const Network<Arch, Transformer>& other) {
evalFile = other.evalFile;
embeddedType = other.embeddedType;
if (other.featureTransformer)
featureTransformer = make_unique_large_page<Transformer>(*other.featureTransformer);
network = make_unique_aligned<Arch[]>(LayerStacks);
if (!other.network)
return *this;
for (std::size_t i = 0; i < LayerStacks; ++i)
network[i] = other.network[i];
return *this;
}
template<typename Arch, typename Transformer>
void Network<Arch, Transformer>::load(const std::string& rootDirectory, std::string evalfilePath) {
#if defined(DEFAULT_NNUE_DIRECTORY)
std::vector<std::string> dirs = {"<internal>", "", rootDirectory,
stringify(DEFAULT_NNUE_DIRECTORY)};
#else
std::vector<std::string> dirs = {"<internal>", "", rootDirectory};
#endif
if (evalfilePath.empty())
evalfilePath = evalFile.defaultName;
for (const auto& directory : dirs)
{
if (evalFile.current != evalfilePath)
{
if (directory != "<internal>")
{
load_user_net(directory, evalfilePath);
}
if (directory == "<internal>" && evalfilePath == evalFile.defaultName)
{
load_internal();
}
}
}
}
template<typename Arch, typename Transformer>
bool Network<Arch, Transformer>::save(const std::optional<std::string>& filename) const {
std::string actualFilename;
std::string msg;
if (filename.has_value())
actualFilename = filename.value();
else
{
if (evalFile.current != evalFile.defaultName)
{
msg = "Failed to export a net. "
"A non-embedded net can only be saved if the filename is specified";
sync_cout << msg << sync_endl;
return false;
}
actualFilename = evalFile.defaultName;
}
std::ofstream stream(actualFilename, std::ios_base::binary);
bool saved = save(stream, evalFile.current, evalFile.netDescription);
msg = saved ? "Network saved successfully to " + actualFilename : "Failed to export a net";
sync_cout << msg << sync_endl;
return saved;
}
template<typename Arch, typename Transformer>
NetworkOutput
Network<Arch, Transformer>::evaluate(const Position& pos,
AccumulatorCaches::Cache<FTDimensions>* cache) const {
// We manually align the arrays on the stack because with gcc < 9.3
// overaligning stack variables with alignas() doesn't work correctly.
constexpr uint64_t alignment = CacheLineSize;
#if defined(ALIGNAS_ON_STACK_VARIABLES_BROKEN)
TransformedFeatureType
transformedFeaturesUnaligned[FeatureTransformer<FTDimensions, nullptr>::BufferSize
+ alignment / sizeof(TransformedFeatureType)];
auto* transformedFeatures = align_ptr_up<alignment>(&transformedFeaturesUnaligned[0]);
#else
alignas(alignment) TransformedFeatureType
transformedFeatures[FeatureTransformer<FTDimensions, nullptr>::BufferSize];
#endif
ASSERT_ALIGNED(transformedFeatures, alignment);
const int bucket = (pos.count<ALL_PIECES>() - 1) / 4;
const auto psqt = featureTransformer->transform(pos, cache, transformedFeatures, bucket);
const auto positional = network[bucket].propagate(transformedFeatures);
return {static_cast<Value>(psqt / OutputScale), static_cast<Value>(positional / OutputScale)};
}
template<typename Arch, typename Transformer>
void Network<Arch, Transformer>::verify(std::string evalfilePath,
const std::function<void(std::string_view)>& f) const {
if (evalfilePath.empty())
evalfilePath = evalFile.defaultName;
if (evalFile.current != evalfilePath)
{
if (f)
{
std::string msg1 =
"Network evaluation parameters compatible with the engine must be available.";
std::string msg2 = "The network file " + evalfilePath + " was not loaded successfully.";
std::string msg3 = "The UCI option EvalFile might need to specify the full path, "
"including the directory name, to the network file.";
std::string msg4 = "The default net can be downloaded from: "
"https://tests.stockfishchess.org/api/nn/"
+ evalFile.defaultName;
std::string msg5 = "The engine will be terminated now.";
std::string msg = "ERROR: " + msg1 + '\n' + "ERROR: " + msg2 + '\n' + "ERROR: " + msg3
+ '\n' + "ERROR: " + msg4 + '\n' + "ERROR: " + msg5 + '\n';
f(msg);
}
exit(EXIT_FAILURE);
}
if (f)
{
size_t size = sizeof(*featureTransformer) + sizeof(Arch) * LayerStacks;
f("info string NNUE evaluation using " + evalfilePath + " ("
+ std::to_string(size / (1024 * 1024)) + "MiB, ("
+ std::to_string(featureTransformer->InputDimensions) + ", "
+ std::to_string(network[0].TransformedFeatureDimensions) + ", "
+ std::to_string(network[0].FC_0_OUTPUTS) + ", " + std::to_string(network[0].FC_1_OUTPUTS)
+ ", 1))");
}
}
template<typename Arch, typename Transformer>
void Network<Arch, Transformer>::hint_common_access(
const Position& pos, AccumulatorCaches::Cache<FTDimensions>* cache) const {
featureTransformer->hint_common_access(pos, cache);
}
template<typename Arch, typename Transformer>
NnueEvalTrace
Network<Arch, Transformer>::trace_evaluate(const Position& pos,
AccumulatorCaches::Cache<FTDimensions>* cache) const {
// We manually align the arrays on the stack because with gcc < 9.3
// overaligning stack variables with alignas() doesn't work correctly.
constexpr uint64_t alignment = CacheLineSize;
#if defined(ALIGNAS_ON_STACK_VARIABLES_BROKEN)
TransformedFeatureType
transformedFeaturesUnaligned[FeatureTransformer<FTDimensions, nullptr>::BufferSize
+ alignment / sizeof(TransformedFeatureType)];
auto* transformedFeatures = align_ptr_up<alignment>(&transformedFeaturesUnaligned[0]);
#else
alignas(alignment) TransformedFeatureType
transformedFeatures[FeatureTransformer<FTDimensions, nullptr>::BufferSize];
#endif
ASSERT_ALIGNED(transformedFeatures, alignment);
NnueEvalTrace t{};
t.correctBucket = (pos.count<ALL_PIECES>() - 1) / 4;
for (IndexType bucket = 0; bucket < LayerStacks; ++bucket)
{
const auto materialist =
featureTransformer->transform(pos, cache, transformedFeatures, bucket);
const auto positional = network[bucket].propagate(transformedFeatures);
t.psqt[bucket] = static_cast<Value>(materialist / OutputScale);
t.positional[bucket] = static_cast<Value>(positional / OutputScale);
}
return t;
}
template<typename Arch, typename Transformer>
void Network<Arch, Transformer>::load_user_net(const std::string& dir,
const std::string& evalfilePath) {
std::ifstream stream(dir + evalfilePath, std::ios::binary);
auto description = load(stream);
if (description.has_value())
{
evalFile.current = evalfilePath;
evalFile.netDescription = description.value();
}
}
template<typename Arch, typename Transformer>
void Network<Arch, Transformer>::load_internal() {
// C++ way to prepare a buffer for a memory stream
class MemoryBuffer: public std::basic_streambuf<char> {
public:
MemoryBuffer(char* p, size_t n) {
setg(p, p, p + n);
setp(p, p + n);
}
};
const auto embedded = get_embedded(embeddedType);
MemoryBuffer buffer(const_cast<char*>(reinterpret_cast<const char*>(embedded.data)),
size_t(embedded.size));
std::istream stream(&buffer);
auto description = load(stream);
if (description.has_value())
{
evalFile.current = evalFile.defaultName;
evalFile.netDescription = description.value();
}
}
template<typename Arch, typename Transformer>
void Network<Arch, Transformer>::initialize() {
featureTransformer = make_unique_large_page<Transformer>();
network = make_unique_aligned<Arch[]>(LayerStacks);
}
template<typename Arch, typename Transformer>
bool Network<Arch, Transformer>::save(std::ostream& stream,
const std::string& name,
const std::string& netDescription) const {
if (name.empty() || name == "None")
return false;
return write_parameters(stream, netDescription);
}
template<typename Arch, typename Transformer>
std::optional<std::string> Network<Arch, Transformer>::load(std::istream& stream) {
initialize();
std::string description;
return read_parameters(stream, description) ? std::make_optional(description) : std::nullopt;
}
// Read network header
template<typename Arch, typename Transformer>
bool Network<Arch, Transformer>::read_header(std::istream& stream,
std::uint32_t* hashValue,
std::string* desc) const {
std::uint32_t version, size;
version = read_little_endian<std::uint32_t>(stream);
*hashValue = read_little_endian<std::uint32_t>(stream);
size = read_little_endian<std::uint32_t>(stream);
if (!stream || version != Version)
return false;
desc->resize(size);
stream.read(&(*desc)[0], size);
return !stream.fail();
}
// Write network header
template<typename Arch, typename Transformer>
bool Network<Arch, Transformer>::write_header(std::ostream& stream,
std::uint32_t hashValue,
const std::string& desc) const {
write_little_endian<std::uint32_t>(stream, Version);
write_little_endian<std::uint32_t>(stream, hashValue);
write_little_endian<std::uint32_t>(stream, std::uint32_t(desc.size()));
stream.write(&desc[0], desc.size());
return !stream.fail();
}
template<typename Arch, typename Transformer>
bool Network<Arch, Transformer>::read_parameters(std::istream& stream,
std::string& netDescription) const {
std::uint32_t hashValue;
if (!read_header(stream, &hashValue, &netDescription))
return false;
if (hashValue != Network::hash)
return false;
if (!Detail::read_parameters(stream, *featureTransformer))
return false;
for (std::size_t i = 0; i < LayerStacks; ++i)
{
if (!Detail::read_parameters(stream, network[i]))
return false;
}
return stream && stream.peek() == std::ios::traits_type::eof();
}
template<typename Arch, typename Transformer>
bool Network<Arch, Transformer>::write_parameters(std::ostream& stream,
const std::string& netDescription) const {
if (!write_header(stream, Network::hash, netDescription))
return false;
if (!Detail::write_parameters(stream, *featureTransformer))
return false;
for (std::size_t i = 0; i < LayerStacks; ++i)
{
if (!Detail::write_parameters(stream, network[i]))
return false;
}
return bool(stream);
}
// Explicit template instantiation
template class Network<
NetworkArchitecture<TransformedFeatureDimensionsBig, L2Big, L3Big>,
FeatureTransformer<TransformedFeatureDimensionsBig, &StateInfo::accumulatorBig>>;
template class Network<
NetworkArchitecture<TransformedFeatureDimensionsSmall, L2Small, L3Small>,
FeatureTransformer<TransformedFeatureDimensionsSmall, &StateInfo::accumulatorSmall>>;
} // namespace Stockfish::Eval::NNUE
+134
View File
@@ -0,0 +1,134 @@
/*
Stockfish, a UCI chess playing engine derived from Glaurung 2.1
Copyright (C) 2004-2025 The Stockfish developers (see AUTHORS file)
Stockfish is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
Stockfish is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef NETWORK_H_INCLUDED
#define NETWORK_H_INCLUDED
#include <cstdint>
#include <functional>
#include <iostream>
#include <optional>
#include <string>
#include <string_view>
#include <tuple>
#include <utility>
#include "../memory.h"
#include "../position.h"
#include "../types.h"
#include "nnue_accumulator.h"
#include "nnue_architecture.h"
#include "nnue_feature_transformer.h"
#include "nnue_misc.h"
namespace Stockfish::Eval::NNUE {
enum class EmbeddedNNUEType {
BIG,
SMALL,
};
using NetworkOutput = std::tuple<Value, Value>;
template<typename Arch, typename Transformer>
class Network {
static constexpr IndexType FTDimensions = Arch::TransformedFeatureDimensions;
public:
Network(EvalFile file, EmbeddedNNUEType type) :
evalFile(file),
embeddedType(type) {}
Network(const Network& other);
Network(Network&& other) = default;
Network& operator=(const Network& other);
Network& operator=(Network&& other) = default;
void load(const std::string& rootDirectory, std::string evalfilePath);
bool save(const std::optional<std::string>& filename) const;
NetworkOutput evaluate(const Position& pos,
AccumulatorCaches::Cache<FTDimensions>* cache) const;
void hint_common_access(const Position& pos,
AccumulatorCaches::Cache<FTDimensions>* cache) const;
void verify(std::string evalfilePath, const std::function<void(std::string_view)>&) const;
NnueEvalTrace trace_evaluate(const Position& pos,
AccumulatorCaches::Cache<FTDimensions>* cache) const;
private:
void load_user_net(const std::string&, const std::string&);
void load_internal();
void initialize();
bool save(std::ostream&, const std::string&, const std::string&) const;
std::optional<std::string> load(std::istream&);
bool read_header(std::istream&, std::uint32_t*, std::string*) const;
bool write_header(std::ostream&, std::uint32_t, const std::string&) const;
bool read_parameters(std::istream&, std::string&) const;
bool write_parameters(std::ostream&, const std::string&) const;
// Input feature converter
LargePagePtr<Transformer> featureTransformer;
// Evaluation function
AlignedPtr<Arch[]> network;
EvalFile evalFile;
EmbeddedNNUEType embeddedType;
// Hash value of evaluation function structure
static constexpr std::uint32_t hash = Transformer::get_hash_value() ^ Arch::get_hash_value();
template<IndexType Size>
friend struct AccumulatorCaches::Cache;
};
// Definitions of the network types
using SmallFeatureTransformer =
FeatureTransformer<TransformedFeatureDimensionsSmall, &StateInfo::accumulatorSmall>;
using SmallNetworkArchitecture =
NetworkArchitecture<TransformedFeatureDimensionsSmall, L2Small, L3Small>;
using BigFeatureTransformer =
FeatureTransformer<TransformedFeatureDimensionsBig, &StateInfo::accumulatorBig>;
using BigNetworkArchitecture = NetworkArchitecture<TransformedFeatureDimensionsBig, L2Big, L3Big>;
using NetworkBig = Network<BigNetworkArchitecture, BigFeatureTransformer>;
using NetworkSmall = Network<SmallNetworkArchitecture, SmallFeatureTransformer>;
struct Networks {
Networks(NetworkBig&& nB, NetworkSmall&& nS) :
big(std::move(nB)),
small(std::move(nS)) {}
NetworkBig big;
NetworkSmall small;
};
} // namespace Stockfish
#endif
+71 -8
View File
@@ -1,6 +1,6 @@
/* /*
Stockfish, a UCI chess playing engine derived from Glaurung 2.1 Stockfish, a UCI chess playing engine derived from Glaurung 2.1
Copyright (C) 2004-2023 The Stockfish developers (see AUTHORS file) Copyright (C) 2004-2025 The Stockfish developers (see AUTHORS file)
Stockfish is free software: you can redistribute it and/or modify Stockfish is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by it under the terms of the GNU General Public License as published by
@@ -21,17 +21,80 @@
#ifndef NNUE_ACCUMULATOR_H_INCLUDED #ifndef NNUE_ACCUMULATOR_H_INCLUDED
#define NNUE_ACCUMULATOR_H_INCLUDED #define NNUE_ACCUMULATOR_H_INCLUDED
#include <cstdint>
#include "nnue_architecture.h" #include "nnue_architecture.h"
#include "nnue_common.h"
namespace Stockfish::Eval::NNUE { namespace Stockfish::Eval::NNUE {
// Class that holds the result of affine transformation of input features using BiasType = std::int16_t;
struct alignas(CacheLineSize) Accumulator { using PSQTWeightType = std::int32_t;
std::int16_t accumulation[2][TransformedFeatureDimensions]; using IndexType = std::uint32_t;
std::int32_t psqtAccumulation[2][PSQTBuckets];
bool computed[2]; // Class that holds the result of affine transformation of input features
}; template<IndexType Size>
struct alignas(CacheLineSize) Accumulator {
std::int16_t accumulation[COLOR_NB][Size];
std::int32_t psqtAccumulation[COLOR_NB][PSQTBuckets];
bool computed[COLOR_NB];
};
// AccumulatorCaches struct provides per-thread accumulator caches, where each
// cache contains multiple entries for each of the possible king squares.
// When the accumulator needs to be refreshed, the cached entry is used to more
// efficiently update the accumulator, instead of rebuilding it from scratch.
// This idea, was first described by Luecx (author of Koivisto) and
// is commonly referred to as "Finny Tables".
struct AccumulatorCaches {
template<typename Networks>
AccumulatorCaches(const Networks& networks) {
clear(networks);
}
template<IndexType Size>
struct alignas(CacheLineSize) Cache {
struct alignas(CacheLineSize) Entry {
BiasType accumulation[Size];
PSQTWeightType psqtAccumulation[PSQTBuckets];
Bitboard byColorBB[COLOR_NB];
Bitboard byTypeBB[PIECE_TYPE_NB];
// To initialize a refresh entry, we set all its bitboards empty,
// so we put the biases in the accumulation, without any weights on top
void clear(const BiasType* biases) {
std::memcpy(accumulation, biases, sizeof(accumulation));
std::memset((uint8_t*) this + offsetof(Entry, psqtAccumulation), 0,
sizeof(Entry) - offsetof(Entry, psqtAccumulation));
}
};
template<typename Network>
void clear(const Network& network) {
for (auto& entries1D : entries)
for (auto& entry : entries1D)
entry.clear(network.featureTransformer->biases);
}
std::array<Entry, COLOR_NB>& operator[](Square sq) { return entries[sq]; }
std::array<std::array<Entry, COLOR_NB>, SQUARE_NB> entries;
};
template<typename Networks>
void clear(const Networks& networks) {
big.clear(networks.big);
small.clear(networks.small);
}
Cache<TransformedFeatureDimensionsBig> big;
Cache<TransformedFeatureDimensionsSmall> small;
};
} // namespace Stockfish::Eval::NNUE } // namespace Stockfish::Eval::NNUE
#endif // NNUE_ACCUMULATOR_H_INCLUDED #endif // NNUE_ACCUMULATOR_H_INCLUDED
+81 -81
View File
@@ -1,6 +1,6 @@
/* /*
Stockfish, a UCI chess playing engine derived from Glaurung 2.1 Stockfish, a UCI chess playing engine derived from Glaurung 2.1
Copyright (C) 2004-2023 The Stockfish developers (see AUTHORS file) Copyright (C) 2004-2025 The Stockfish developers (see AUTHORS file)
Stockfish is free software: you can redistribute it and/or modify Stockfish is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by it under the terms of the GNU General Public License as published by
@@ -21,18 +21,16 @@
#ifndef NNUE_ARCHITECTURE_H_INCLUDED #ifndef NNUE_ARCHITECTURE_H_INCLUDED
#define NNUE_ARCHITECTURE_H_INCLUDED #define NNUE_ARCHITECTURE_H_INCLUDED
#include <memory> #include <cstdint>
#include <cstring>
#include "nnue_common.h" #include <iosfwd>
#include "features/half_ka_v2_hm.h" #include "features/half_ka_v2_hm.h"
#include "layers/affine_transform_sparse_input.h"
#include "layers/affine_transform.h" #include "layers/affine_transform.h"
#include "layers/affine_transform_sparse_input.h"
#include "layers/clipped_relu.h" #include "layers/clipped_relu.h"
#include "layers/sqr_clipped_relu.h" #include "layers/sqr_clipped_relu.h"
#include "nnue_common.h"
#include "../misc.h"
namespace Stockfish::Eval::NNUE { namespace Stockfish::Eval::NNUE {
@@ -40,98 +38,100 @@ namespace Stockfish::Eval::NNUE {
using FeatureSet = Features::HalfKAv2_hm; using FeatureSet = Features::HalfKAv2_hm;
// Number of input feature dimensions after conversion // Number of input feature dimensions after conversion
constexpr IndexType TransformedFeatureDimensions = 1536; constexpr IndexType TransformedFeatureDimensionsBig = 3072;
constexpr int L2Big = 15;
constexpr int L3Big = 32;
constexpr IndexType TransformedFeatureDimensionsSmall = 128;
constexpr int L2Small = 15;
constexpr int L3Small = 32;
constexpr IndexType PSQTBuckets = 8; constexpr IndexType PSQTBuckets = 8;
constexpr IndexType LayerStacks = 8; constexpr IndexType LayerStacks = 8;
struct Network template<IndexType L1, int L2, int L3>
{ struct NetworkArchitecture {
static constexpr int FC_0_OUTPUTS = 15; static constexpr IndexType TransformedFeatureDimensions = L1;
static constexpr int FC_1_OUTPUTS = 32; static constexpr int FC_0_OUTPUTS = L2;
static constexpr int FC_1_OUTPUTS = L3;
Layers::AffineTransformSparseInput<TransformedFeatureDimensions, FC_0_OUTPUTS + 1> fc_0; Layers::AffineTransformSparseInput<TransformedFeatureDimensions, FC_0_OUTPUTS + 1> fc_0;
Layers::SqrClippedReLU<FC_0_OUTPUTS + 1> ac_sqr_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 * 2, 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;
// Hash value embedded in the evaluation file // Hash value embedded in the evaluation file
static constexpr std::uint32_t get_hash_value() { static constexpr std::uint32_t get_hash_value() {
// input slice hash // input slice hash
std::uint32_t hashValue = 0xEC42E90Du; std::uint32_t hashValue = 0xEC42E90Du;
hashValue ^= TransformedFeatureDimensions * 2; hashValue ^= TransformedFeatureDimensions * 2;
hashValue = decltype(fc_0)::get_hash_value(hashValue); hashValue = decltype(fc_0)::get_hash_value(hashValue);
hashValue = decltype(ac_0)::get_hash_value(hashValue); hashValue = decltype(ac_0)::get_hash_value(hashValue);
hashValue = decltype(fc_1)::get_hash_value(hashValue); hashValue = decltype(fc_1)::get_hash_value(hashValue);
hashValue = decltype(ac_1)::get_hash_value(hashValue); hashValue = decltype(ac_1)::get_hash_value(hashValue);
hashValue = decltype(fc_2)::get_hash_value(hashValue); hashValue = decltype(fc_2)::get_hash_value(hashValue);
return hashValue; return hashValue;
} }
// Read network parameters // Read network parameters
bool read_parameters(std::istream& stream) { bool read_parameters(std::istream& stream) {
return fc_0.read_parameters(stream) return fc_0.read_parameters(stream) && ac_0.read_parameters(stream)
&& ac_0.read_parameters(stream) && fc_1.read_parameters(stream) && ac_1.read_parameters(stream)
&& fc_1.read_parameters(stream) && fc_2.read_parameters(stream);
&& ac_1.read_parameters(stream) }
&& fc_2.read_parameters(stream);
}
// Write network parameters // Write network parameters
bool write_parameters(std::ostream& stream) const { bool write_parameters(std::ostream& stream) const {
return fc_0.write_parameters(stream) return fc_0.write_parameters(stream) && ac_0.write_parameters(stream)
&& ac_0.write_parameters(stream) && fc_1.write_parameters(stream) && ac_1.write_parameters(stream)
&& fc_1.write_parameters(stream) && fc_2.write_parameters(stream);
&& ac_1.write_parameters(stream) }
&& fc_2.write_parameters(stream);
}
std::int32_t propagate(const TransformedFeatureType* transformedFeatures) std::int32_t propagate(const TransformedFeatureType* transformedFeatures) {
{ struct alignas(CacheLineSize) Buffer {
struct alignas(CacheLineSize) Buffer alignas(CacheLineSize) typename decltype(fc_0)::OutputBuffer fc_0_out;
{ alignas(CacheLineSize) typename decltype(ac_sqr_0)::OutputType
alignas(CacheLineSize) decltype(fc_0)::OutputBuffer fc_0_out; ac_sqr_0_out[ceil_to_multiple<IndexType>(FC_0_OUTPUTS * 2, 32)];
alignas(CacheLineSize) decltype(ac_sqr_0)::OutputType ac_sqr_0_out[ceil_to_multiple<IndexType>(FC_0_OUTPUTS * 2, 32)]; alignas(CacheLineSize) typename decltype(ac_0)::OutputBuffer ac_0_out;
alignas(CacheLineSize) decltype(ac_0)::OutputBuffer ac_0_out; alignas(CacheLineSize) typename decltype(fc_1)::OutputBuffer fc_1_out;
alignas(CacheLineSize) decltype(fc_1)::OutputBuffer fc_1_out; alignas(CacheLineSize) typename decltype(ac_1)::OutputBuffer ac_1_out;
alignas(CacheLineSize) decltype(ac_1)::OutputBuffer ac_1_out; alignas(CacheLineSize) typename decltype(fc_2)::OutputBuffer fc_2_out;
alignas(CacheLineSize) decltype(fc_2)::OutputBuffer fc_2_out;
Buffer() Buffer() { std::memset(this, 0, sizeof(*this)); }
{ };
std::memset(this, 0, sizeof(*this));
}
};
#if defined(__clang__) && (__APPLE__) #if defined(__clang__) && (__APPLE__)
// workaround for a bug reported with xcode 12 // workaround for a bug reported with xcode 12
static thread_local auto tlsBuffer = std::make_unique<Buffer>(); static thread_local auto tlsBuffer = std::make_unique<Buffer>();
// Access TLS only once, cache result. // Access TLS only once, cache result.
Buffer& buffer = *tlsBuffer; Buffer& buffer = *tlsBuffer;
#else #else
alignas(CacheLineSize) static thread_local Buffer buffer; alignas(CacheLineSize) static thread_local Buffer buffer;
#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_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);
std::memcpy(buffer.ac_sqr_0_out + FC_0_OUTPUTS, buffer.ac_0_out, FC_0_OUTPUTS * sizeof(decltype(ac_0)::OutputType)); std::memcpy(buffer.ac_sqr_0_out + FC_0_OUTPUTS, buffer.ac_0_out,
fc_1.propagate(buffer.ac_sqr_0_out, buffer.fc_1_out); FC_0_OUTPUTS * sizeof(typename decltype(ac_0)::OutputType));
ac_1.propagate(buffer.fc_1_out, buffer.ac_1_out); fc_1.propagate(buffer.ac_sqr_0_out, buffer.fc_1_out);
fc_2.propagate(buffer.ac_1_out, buffer.fc_2_out); ac_1.propagate(buffer.fc_1_out, buffer.ac_1_out);
fc_2.propagate(buffer.ac_1_out, buffer.fc_2_out);
// buffer.fc_0_out[FC_0_OUTPUTS] is such that 1.0 is equal to 127*(1<<WeightScaleBits) in quantized form // buffer.fc_0_out[FC_0_OUTPUTS] is such that 1.0 is equal to 127*(1<<WeightScaleBits) in
// but we want 1.0 to be equal to 600*OutputScale // quantized form, but we want 1.0 to be equal to 600*OutputScale
std::int32_t fwdOut = int(buffer.fc_0_out[FC_0_OUTPUTS]) * (600*OutputScale) / (127*(1<<WeightScaleBits)); std::int32_t fwdOut =
std::int32_t outputValue = buffer.fc_2_out[0] + fwdOut; (buffer.fc_0_out[FC_0_OUTPUTS]) * (600 * OutputScale) / (127 * (1 << WeightScaleBits));
std::int32_t outputValue = buffer.fc_2_out[0] + fwdOut;
return outputValue; return outputValue;
} }
}; };
} // namespace Stockfish::Eval::NNUE } // namespace Stockfish::Eval::NNUE
#endif // #ifndef NNUE_ARCHITECTURE_H_INCLUDED #endif // #ifndef NNUE_ARCHITECTURE_H_INCLUDED
+215 -172
View File
@@ -1,6 +1,6 @@
/* /*
Stockfish, a UCI chess playing engine derived from Glaurung 2.1 Stockfish, a UCI chess playing engine derived from Glaurung 2.1
Copyright (C) 2004-2023 The Stockfish developers (see AUTHORS file) Copyright (C) 2004-2025 The Stockfish developers (see AUTHORS file)
Stockfish is free software: you can redistribute it and/or modify Stockfish is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by it under the terms of the GNU General Public License as published by
@@ -21,221 +21,264 @@
#ifndef NNUE_COMMON_H_INCLUDED #ifndef NNUE_COMMON_H_INCLUDED
#define NNUE_COMMON_H_INCLUDED #define NNUE_COMMON_H_INCLUDED
#include <algorithm>
#include <cassert>
#include <cstdint>
#include <cstring> #include <cstring>
#include <iostream> #include <iostream>
#include <type_traits>
#include "../misc.h" // for IsLittleEndian #include "../misc.h"
#if defined(USE_AVX2) #if defined(USE_AVX2)
#include <immintrin.h> #include <immintrin.h>
#elif defined(USE_SSE41) #elif defined(USE_SSE41)
#include <smmintrin.h> #include <smmintrin.h>
#elif defined(USE_SSSE3) #elif defined(USE_SSSE3)
#include <tmmintrin.h> #include <tmmintrin.h>
#elif defined(USE_SSE2) #elif defined(USE_SSE2)
#include <emmintrin.h> #include <emmintrin.h>
#elif defined(USE_MMX)
#include <mmintrin.h>
#elif defined(USE_NEON) #elif defined(USE_NEON)
#include <arm_neon.h> #include <arm_neon.h>
#endif #endif
namespace Stockfish::Eval::NNUE { namespace Stockfish::Eval::NNUE {
// Version of the evaluation file // Version of the evaluation file
constexpr std::uint32_t Version = 0x7AF32F20u; constexpr std::uint32_t Version = 0x7AF32F20u;
// Constant used in evaluation value calculation // Constant used in evaluation value calculation
constexpr int OutputScale = 16; constexpr int OutputScale = 16;
constexpr int WeightScaleBits = 6; constexpr int WeightScaleBits = 6;
// Size of cache line (in bytes) // Size of cache line (in bytes)
constexpr std::size_t CacheLineSize = 64; constexpr std::size_t CacheLineSize = 64;
constexpr const char Leb128MagicString[] = "COMPRESSED_LEB128"; constexpr const char Leb128MagicString[] = "COMPRESSED_LEB128";
constexpr const std::size_t Leb128MagicStringSize = sizeof(Leb128MagicString) - 1; constexpr const std::size_t Leb128MagicStringSize = sizeof(Leb128MagicString) - 1;
// SIMD width (in bytes) // SIMD width (in bytes)
#if defined(USE_AVX2) #if defined(USE_AVX2)
constexpr std::size_t SimdWidth = 32; constexpr std::size_t SimdWidth = 32;
#elif defined(USE_SSE2) #elif defined(USE_SSE2)
constexpr std::size_t SimdWidth = 16; constexpr std::size_t SimdWidth = 16;
#elif defined(USE_MMX) #elif defined(USE_NEON)
constexpr std::size_t SimdWidth = 8; constexpr std::size_t SimdWidth = 16;
#endif
#elif defined(USE_NEON) constexpr std::size_t MaxSimdWidth = 32;
constexpr std::size_t SimdWidth = 16;
#endif
constexpr std::size_t MaxSimdWidth = 32; // Type of input feature after conversion
using TransformedFeatureType = std::uint8_t;
using IndexType = std::uint32_t;
// Type of input feature after conversion // Round n up to be a multiple of base
using TransformedFeatureType = std::uint8_t; template<typename IntType>
using IndexType = std::uint32_t; constexpr IntType ceil_to_multiple(IntType n, IntType base) {
return (n + base - 1) / base * base;
}
// Round n up to be a multiple of base
template <typename IntType>
constexpr IntType ceil_to_multiple(IntType n, IntType base) {
return (n + base - 1) / base * base;
}
// read_little_endian() is our utility to read an integer (signed or unsigned, any size) // Utility to read an integer (signed or unsigned, any size)
// from a stream in little-endian order. We swap the byte order after the read if // from a stream in little-endian order. We swap the byte order after the read if
// necessary to return a result with the byte ordering of the compiling machine. // necessary to return a result with the byte ordering of the compiling machine.
template <typename IntType> template<typename IntType>
inline IntType read_little_endian(std::istream& stream) { inline IntType read_little_endian(std::istream& stream) {
IntType result; IntType result;
if (IsLittleEndian) if (IsLittleEndian)
stream.read(reinterpret_cast<char*>(&result), sizeof(IntType)); stream.read(reinterpret_cast<char*>(&result), sizeof(IntType));
else else
{ {
std::uint8_t u[sizeof(IntType)]; std::uint8_t u[sizeof(IntType)];
typename std::make_unsigned<IntType>::type v = 0; std::make_unsigned_t<IntType> v = 0;
stream.read(reinterpret_cast<char*>(u), sizeof(IntType)); stream.read(reinterpret_cast<char*>(u), sizeof(IntType));
for (std::size_t i = 0; i < sizeof(IntType); ++i) for (std::size_t i = 0; i < sizeof(IntType); ++i)
v = (v << 8) | u[sizeof(IntType) - i - 1]; v = (v << 8) | u[sizeof(IntType) - i - 1];
std::memcpy(&result, &v, sizeof(IntType)); std::memcpy(&result, &v, sizeof(IntType));
} }
return result; return result;
} }
// write_little_endian() is our utility to write an integer (signed or unsigned, any size)
// to a stream in little-endian order. We swap the byte order before the write if
// necessary to always write in little endian order, independently of the byte
// ordering of the compiling machine.
template <typename IntType>
inline void write_little_endian(std::ostream& stream, IntType value) {
if (IsLittleEndian) // Utility to write an integer (signed or unsigned, any size)
stream.write(reinterpret_cast<const char*>(&value), sizeof(IntType)); // to a stream in little-endian order. We swap the byte order before the write if
else // necessary to always write in little-endian order, independently of the byte
{ // ordering of the compiling machine.
std::uint8_t u[sizeof(IntType)]; template<typename IntType>
typename std::make_unsigned<IntType>::type v = value; inline void write_little_endian(std::ostream& stream, IntType value) {
std::size_t i = 0; if (IsLittleEndian)
// if constexpr to silence the warning about shift by 8 stream.write(reinterpret_cast<const char*>(&value), sizeof(IntType));
if constexpr (sizeof(IntType) > 1) else
{ {
std::uint8_t u[sizeof(IntType)];
std::make_unsigned_t<IntType> v = value;
std::size_t i = 0;
// if constexpr to silence the warning about shift by 8
if constexpr (sizeof(IntType) > 1)
{
for (; i + 1 < sizeof(IntType); ++i) for (; i + 1 < sizeof(IntType); ++i)
{ {
u[i] = (std::uint8_t)v; u[i] = std::uint8_t(v);
v >>= 8; v >>= 8;
} }
} }
u[i] = (std::uint8_t)v; u[i] = std::uint8_t(v);
stream.write(reinterpret_cast<char*>(u), sizeof(IntType)); stream.write(reinterpret_cast<char*>(u), sizeof(IntType));
} }
} }
// read_little_endian(s, out, N) : read integers in bulk from a little indian stream.
// This reads N integers from stream s and put them in array out.
template <typename IntType>
inline void read_little_endian(std::istream& stream, IntType* out, std::size_t count) {
if (IsLittleEndian)
stream.read(reinterpret_cast<char*>(out), sizeof(IntType) * count);
else
for (std::size_t i = 0; i < count; ++i)
out[i] = read_little_endian<IntType>(stream);
}
// write_little_endian(s, values, N) : write integers in bulk to a little indian stream. // Read integers in bulk from a little-endian stream.
// This takes N integers from array values and writes them on stream s. // This reads N integers from stream s and puts them in array out.
template <typename IntType> template<typename IntType>
inline void write_little_endian(std::ostream& stream, const IntType* values, std::size_t count) { inline void read_little_endian(std::istream& stream, IntType* out, std::size_t count) {
if (IsLittleEndian) if (IsLittleEndian)
stream.write(reinterpret_cast<const char*>(values), sizeof(IntType) * count); stream.read(reinterpret_cast<char*>(out), sizeof(IntType) * count);
else else
for (std::size_t i = 0; i < count; ++i) for (std::size_t i = 0; i < count; ++i)
write_little_endian<IntType>(stream, values[i]); out[i] = read_little_endian<IntType>(stream);
} }
template <typename IntType>
inline void read_leb_128(std::istream& stream, IntType* out, std::size_t count) {
static_assert(std::is_signed_v<IntType>, "Not implemented for unsigned types");
char leb128MagicString[Leb128MagicStringSize];
stream.read(leb128MagicString, Leb128MagicStringSize);
assert(strncmp(Leb128MagicString, leb128MagicString, Leb128MagicStringSize) == 0);
const std::uint32_t BUF_SIZE = 4096;
std::uint8_t buf[BUF_SIZE];
auto bytes_left = read_little_endian<std::uint32_t>(stream);
std::uint32_t buf_pos = BUF_SIZE;
for (std::size_t i = 0; i < count; ++i) {
IntType result = 0;
size_t shift = 0;
do {
if (buf_pos == BUF_SIZE) {
stream.read(reinterpret_cast<char*>(buf), std::min(bytes_left, BUF_SIZE));
buf_pos = 0;
}
std::uint8_t byte = buf[buf_pos++];
--bytes_left;
result |= (byte & 0x7f) << shift;
shift += 7;
if ((byte & 0x80) == 0) {
out[i] = sizeof(IntType) * 8 <= shift || (byte & 0x40) == 0 ? result : result | ~((1 << shift) - 1);
break;
}
} while (shift < sizeof(IntType) * 8);
}
assert(bytes_left == 0);
}
template <typename IntType> // Write integers in bulk to a little-endian stream.
inline void write_leb_128(std::ostream& stream, const IntType* values, std::size_t count) { // This takes N integers from array values and writes them on stream s.
static_assert(std::is_signed_v<IntType>, "Not implemented for unsigned types"); template<typename IntType>
stream.write(Leb128MagicString, Leb128MagicStringSize); inline void write_little_endian(std::ostream& stream, const IntType* values, std::size_t count) {
std::uint32_t byte_count = 0; if (IsLittleEndian)
for (std::size_t i = 0; i < count; ++i) { stream.write(reinterpret_cast<const char*>(values), sizeof(IntType) * count);
IntType value = values[i]; else
std::uint8_t byte; for (std::size_t i = 0; i < count; ++i)
do { write_little_endian<IntType>(stream, values[i]);
byte = value & 0x7f; }
value >>= 7;
++byte_count;
} while ((byte & 0x40) == 0 ? value != 0 : value != -1); // Read N signed integers from the stream s, putting them in the array out.
} // The stream is assumed to be compressed using the signed LEB128 format.
write_little_endian(stream, byte_count); // See https://en.wikipedia.org/wiki/LEB128 for a description of the compression scheme.
const std::uint32_t BUF_SIZE = 4096; template<typename IntType>
std::uint8_t buf[BUF_SIZE]; inline void read_leb_128(std::istream& stream, IntType* out, std::size_t count) {
std::uint32_t buf_pos = 0;
auto flush = [&]() { // Check the presence of our LEB128 magic string
if (buf_pos > 0) { char leb128MagicString[Leb128MagicStringSize];
stream.write(reinterpret_cast<char*>(buf), buf_pos); stream.read(leb128MagicString, Leb128MagicStringSize);
buf_pos = 0; assert(strncmp(Leb128MagicString, leb128MagicString, Leb128MagicStringSize) == 0);
}
}; static_assert(std::is_signed_v<IntType>, "Not implemented for unsigned types");
auto write = [&](std::uint8_t byte) {
buf[buf_pos++] = byte; const std::uint32_t BUF_SIZE = 4096;
if (buf_pos == BUF_SIZE) flush(); std::uint8_t buf[BUF_SIZE];
};
for (std::size_t i = 0; i < count; ++i) { auto bytes_left = read_little_endian<std::uint32_t>(stream);
IntType value = values[i];
while (true) { std::uint32_t buf_pos = BUF_SIZE;
std::uint8_t byte = value & 0x7f; for (std::size_t i = 0; i < count; ++i)
value >>= 7; {
if ((byte & 0x40) == 0 ? value == 0 : value == -1) { IntType result = 0;
write(byte); size_t shift = 0;
break; do
} {
write(byte | 0x80); if (buf_pos == BUF_SIZE)
} {
} stream.read(reinterpret_cast<char*>(buf), std::min(bytes_left, BUF_SIZE));
flush(); buf_pos = 0;
} }
std::uint8_t byte = buf[buf_pos++];
--bytes_left;
result |= (byte & 0x7f) << shift;
shift += 7;
if ((byte & 0x80) == 0)
{
out[i] = (sizeof(IntType) * 8 <= shift || (byte & 0x40) == 0)
? result
: result | ~((1 << shift) - 1);
break;
}
} while (shift < sizeof(IntType) * 8);
}
assert(bytes_left == 0);
}
// Write signed integers to a stream with LEB128 compression.
// This takes N integers from array values, compresses them with
// the LEB128 algorithm and writes the result on the stream s.
// See https://en.wikipedia.org/wiki/LEB128 for a description of the compression scheme.
template<typename IntType>
inline void write_leb_128(std::ostream& stream, const IntType* values, std::size_t count) {
// Write our LEB128 magic string
stream.write(Leb128MagicString, Leb128MagicStringSize);
static_assert(std::is_signed_v<IntType>, "Not implemented for unsigned types");
std::uint32_t byte_count = 0;
for (std::size_t i = 0; i < count; ++i)
{
IntType value = values[i];
std::uint8_t byte;
do
{
byte = value & 0x7f;
value >>= 7;
++byte_count;
} while ((byte & 0x40) == 0 ? value != 0 : value != -1);
}
write_little_endian(stream, byte_count);
const std::uint32_t BUF_SIZE = 4096;
std::uint8_t buf[BUF_SIZE];
std::uint32_t buf_pos = 0;
auto flush = [&]() {
if (buf_pos > 0)
{
stream.write(reinterpret_cast<char*>(buf), buf_pos);
buf_pos = 0;
}
};
auto write = [&](std::uint8_t byte) {
buf[buf_pos++] = byte;
if (buf_pos == BUF_SIZE)
flush();
};
for (std::size_t i = 0; i < count; ++i)
{
IntType value = values[i];
while (true)
{
std::uint8_t byte = value & 0x7f;
value >>= 7;
if ((byte & 0x40) == 0 ? value == 0 : value == -1)
{
write(byte);
break;
}
write(byte | 0x80);
}
}
flush();
}
} // namespace Stockfish::Eval::NNUE } // namespace Stockfish::Eval::NNUE
#endif // #ifndef NNUE_COMMON_H_INCLUDED #endif // #ifndef NNUE_COMMON_H_INCLUDED
File diff suppressed because it is too large Load Diff
+203
View File
@@ -0,0 +1,203 @@
/*
Stockfish, a UCI chess playing engine derived from Glaurung 2.1
Copyright (C) 2004-2025 The Stockfish developers (see AUTHORS file)
Stockfish is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
Stockfish is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
// Code for calculating NNUE evaluation function
#include "nnue_misc.h"
#include <cmath>
#include <cstdlib>
#include <cstring>
#include <iomanip>
#include <iosfwd>
#include <iostream>
#include <sstream>
#include <string_view>
#include <tuple>
#include "../evaluate.h"
#include "../position.h"
#include "../types.h"
#include "../uci.h"
#include "network.h"
#include "nnue_accumulator.h"
namespace Stockfish::Eval::NNUE {
constexpr std::string_view PieceToChar(" PNBRQK pnbrqk");
void hint_common_parent_position(const Position& pos,
const Networks& networks,
AccumulatorCaches& caches) {
if (Eval::use_smallnet(pos))
networks.small.hint_common_access(pos, &caches.small);
else
networks.big.hint_common_access(pos, &caches.big);
}
namespace {
// Converts a Value into (centi)pawns and writes it in a buffer.
// The buffer must have capacity for at least 5 chars.
void format_cp_compact(Value v, char* buffer, const Position& pos) {
buffer[0] = (v < 0 ? '-' : v > 0 ? '+' : ' ');
int cp = std::abs(UCIEngine::to_cp(v, pos));
if (cp >= 10000)
{
buffer[1] = '0' + cp / 10000;
cp %= 10000;
buffer[2] = '0' + cp / 1000;
cp %= 1000;
buffer[3] = '0' + cp / 100;
buffer[4] = ' ';
}
else if (cp >= 1000)
{
buffer[1] = '0' + cp / 1000;
cp %= 1000;
buffer[2] = '0' + cp / 100;
cp %= 100;
buffer[3] = '.';
buffer[4] = '0' + cp / 10;
}
else
{
buffer[1] = '0' + cp / 100;
cp %= 100;
buffer[2] = '.';
buffer[3] = '0' + cp / 10;
cp %= 10;
buffer[4] = '0' + cp / 1;
}
}
// Converts a Value into pawns, always keeping two decimals
void format_cp_aligned_dot(Value v, std::stringstream& stream, const Position& pos) {
const double pawns = std::abs(0.01 * UCIEngine::to_cp(v, pos));
stream << (v < 0 ? '-'
: v > 0 ? '+'
: ' ')
<< std::setiosflags(std::ios::fixed) << std::setw(6) << std::setprecision(2) << pawns;
}
}
// Returns a string with the value of each piece on a board,
// and a table for (PSQT, Layers) values bucket by bucket.
std::string
trace(Position& pos, const Eval::NNUE::Networks& networks, Eval::NNUE::AccumulatorCaches& caches) {
std::stringstream ss;
char board[3 * 8 + 1][8 * 8 + 2];
std::memset(board, ' ', sizeof(board));
for (int row = 0; row < 3 * 8 + 1; ++row)
board[row][8 * 8 + 1] = '\0';
// A lambda to output one box of the board
auto writeSquare = [&board, &pos](File file, Rank rank, Piece pc, Value value) {
const int x = int(file) * 8;
const int y = (7 - int(rank)) * 3;
for (int i = 1; i < 8; ++i)
board[y][x + i] = board[y + 3][x + i] = '-';
for (int i = 1; i < 3; ++i)
board[y + i][x] = board[y + i][x + 8] = '|';
board[y][x] = board[y][x + 8] = board[y + 3][x + 8] = board[y + 3][x] = '+';
if (pc != NO_PIECE)
board[y + 1][x + 4] = PieceToChar[pc];
if (is_valid(value))
format_cp_compact(value, &board[y + 2][x + 2], pos);
};
// We estimate the value of each piece by doing a differential evaluation from
// the current base eval, simulating the removal of the piece from its square.
auto [psqt, positional] = networks.big.evaluate(pos, &caches.big);
Value base = psqt + positional;
base = pos.side_to_move() == WHITE ? base : -base;
for (File f = FILE_A; f <= FILE_H; ++f)
for (Rank r = RANK_1; r <= RANK_8; ++r)
{
Square sq = make_square(f, r);
Piece pc = pos.piece_on(sq);
Value v = VALUE_NONE;
if (pc != NO_PIECE && type_of(pc) != KING)
{
auto st = pos.state();
pos.remove_piece(sq);
st->accumulatorBig.computed[WHITE] = st->accumulatorBig.computed[BLACK] = false;
std::tie(psqt, positional) = networks.big.evaluate(pos, &caches.big);
Value eval = psqt + positional;
eval = pos.side_to_move() == WHITE ? eval : -eval;
v = base - eval;
pos.put_piece(pc, sq);
st->accumulatorBig.computed[WHITE] = st->accumulatorBig.computed[BLACK] = false;
}
writeSquare(f, r, pc, v);
}
ss << " NNUE derived piece values:\n";
for (int row = 0; row < 3 * 8 + 1; ++row)
ss << board[row] << '\n';
ss << '\n';
auto t = networks.big.trace_evaluate(pos, &caches.big);
ss << " NNUE network contributions "
<< (pos.side_to_move() == WHITE ? "(White to move)" : "(Black to move)") << std::endl
<< "+------------+------------+------------+------------+\n"
<< "| Bucket | Material | Positional | Total |\n"
<< "| | (PSQT) | (Layers) | |\n"
<< "+------------+------------+------------+------------+\n";
for (std::size_t bucket = 0; bucket < LayerStacks; ++bucket)
{
ss << "| " << bucket << " " //
<< " | ";
format_cp_aligned_dot(t.psqt[bucket], ss, pos);
ss << " " //
<< " | ";
format_cp_aligned_dot(t.positional[bucket], ss, pos);
ss << " " //
<< " | ";
format_cp_aligned_dot(t.psqt[bucket] + t.positional[bucket], ss, pos);
ss << " " //
<< " |";
if (bucket == t.correctBucket)
ss << " <-- this bucket is used";
ss << '\n';
}
ss << "+------------+------------+------------+------------+\n";
return ss.str();
}
} // namespace Stockfish::Eval::NNUE
+64
View File
@@ -0,0 +1,64 @@
/*
Stockfish, a UCI chess playing engine derived from Glaurung 2.1
Copyright (C) 2004-2025 The Stockfish developers (see AUTHORS file)
Stockfish is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
Stockfish is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef NNUE_MISC_H_INCLUDED
#define NNUE_MISC_H_INCLUDED
#include <cstddef>
#include <string>
#include "../types.h"
#include "nnue_architecture.h"
namespace Stockfish {
class Position;
namespace Eval::NNUE {
struct EvalFile {
// Default net name, will use one of the EvalFileDefaultName* macros defined
// in evaluate.h
std::string defaultName;
// Selected net name, either via uci option or default
std::string current;
// Net description extracted from the net file
std::string netDescription;
};
struct NnueEvalTrace {
static_assert(LayerStacks == PSQTBuckets);
Value psqt[LayerStacks];
Value positional[LayerStacks];
std::size_t correctBucket;
};
struct Networks;
struct AccumulatorCaches;
std::string trace(Position& pos, const Networks& networks, AccumulatorCaches& caches);
void hint_common_parent_position(const Position& pos,
const Networks& networks,
AccumulatorCaches& caches);
} // namespace Stockfish::Eval::NNUE
} // namespace Stockfish
#endif // #ifndef NNUE_MISC_H_INCLUDED
+1346
View File
File diff suppressed because it is too large Load Diff
-305
View File
@@ -1,305 +0,0 @@
/*
Stockfish, a UCI chess playing engine derived from Glaurung 2.1
Copyright (C) 2004-2023 The Stockfish developers (see AUTHORS file)
Stockfish is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
Stockfish is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <algorithm>
#include <cassert>
#include "bitboard.h"
#include "pawns.h"
#include "position.h"
#include "thread.h"
namespace Stockfish {
namespace {
#define V Value
#define S(mg, eg) make_score(mg, eg)
// Pawn penalties
constexpr Score Backward = S( 6, 19);
constexpr Score Doubled = S(11, 51);
constexpr Score DoubledEarly = S(17, 7);
constexpr Score Isolated = S( 1, 20);
constexpr Score WeakLever = S( 2, 57);
constexpr Score WeakUnopposed = S(15, 18);
// Bonus for blocked pawns at 5th or 6th rank
constexpr Score BlockedPawn[2] = { S(-19, -8), S(-7, 3) };
constexpr Score BlockedStorm[RANK_NB] = {
S(0, 0), S(0, 0), S(64, 75), S(-3, 14), S(-12, 19), S(-7, 4), S(-10, 5)
};
// Connected pawn bonus
constexpr int Connected[RANK_NB] = { 0, 3, 7, 7, 15, 54, 86 };
// Strength of pawn shelter for our king by [distance from edge][rank].
// RANK_1 = 0 is used for files where we have no pawn, or pawn is behind our king.
constexpr Value ShelterStrength[int(FILE_NB) / 2][RANK_NB] = {
{ V(-2), V(85), V(95), V(53), V(39), V(23), V(25) },
{ V(-55), V(64), V(32), V(-55), V(-30), V(-11), V(-61) },
{ V(-11), V(75), V(19), V(-6), V(26), V(9), V(-47) },
{ V(-41), V(-11), V(-27), V(-58), V(-42), V(-66), V(-163) }
};
// Danger of enemy pawns moving toward our king by [distance from edge][rank].
// RANK_1 = 0 is used for files where the enemy has no pawn, or their pawn
// is behind our king. Note that UnblockedStorm[0][1-2] accommodate opponent pawn
// on edge, likely blocked by our king.
constexpr Value UnblockedStorm[int(FILE_NB) / 2][RANK_NB] = {
{ V(94), V(-280), V(-170), V(90), V(59), V(47), V(53) },
{ V(43), V(-17), V(128), V(39), V(26), V(-17), V(15) },
{ V(-9), V(62), V(170), V(34), V(-5), V(-20), V(-11) },
{ V(-27), V(-19), V(106), V(10), V(2), V(-13), V(-24) }
};
// KingOnFile[semi-open Us][semi-open Them] contains bonuses/penalties
// for king when the king is on a semi-open or open file.
constexpr Score KingOnFile[2][2] = {{ S(-18,11), S(-6,-3) },
{ S( 0, 0), S( 5,-4) }};
#undef S
#undef V
/// evaluate() calculates a score for the static pawn structure of the given position.
/// We cannot use the location of pieces or king in this function, as the evaluation
/// of the pawn structure will be stored in a small cache for speed reasons, and will
/// be re-used even when the pieces have moved.
template<Color Us>
Score evaluate(const Position& pos, Pawns::Entry* e) {
constexpr Color Them = ~Us;
constexpr Direction Up = pawn_push(Us);
constexpr Direction Down = -Up;
Bitboard neighbours, stoppers, support, phalanx, opposed;
Bitboard lever, leverPush, blocked;
Square s;
bool backward, passed, doubled;
Score score = SCORE_ZERO;
Bitboard b = pos.pieces(Us, PAWN);
Bitboard ourPawns = pos.pieces( Us, PAWN);
Bitboard theirPawns = pos.pieces(Them, PAWN);
Bitboard doubleAttackThem = pawn_double_attacks_bb<Them>(theirPawns);
e->passedPawns[Us] = 0;
e->kingSquares[Us] = SQ_NONE;
e->pawnAttacks[Us] = e->pawnAttacksSpan[Us] = pawn_attacks_bb<Us>(ourPawns);
e->blockedCount += popcount(shift<Up>(ourPawns) & (theirPawns | doubleAttackThem));
// Loop through all pawns of the current color and score each pawn
while (b)
{
s = pop_lsb(b);
assert(pos.piece_on(s) == make_piece(Us, PAWN));
Rank r = relative_rank(Us, s);
// Flag the pawn
opposed = theirPawns & forward_file_bb(Us, s);
blocked = theirPawns & (s + Up);
stoppers = theirPawns & passed_pawn_span(Us, s);
lever = theirPawns & pawn_attacks_bb(Us, s);
leverPush = theirPawns & pawn_attacks_bb(Us, s + Up);
doubled = ourPawns & (s - Up);
neighbours = ourPawns & adjacent_files_bb(s);
phalanx = neighbours & rank_bb(s);
support = neighbours & rank_bb(s - Up);
if (doubled)
{
// Additional doubled penalty if none of their pawns is fixed
if (!(ourPawns & shift<Down>(theirPawns | pawn_attacks_bb<Them>(theirPawns))))
score -= DoubledEarly;
}
// A pawn is backward when it is behind all pawns of the same color on
// the adjacent files and cannot safely advance.
backward = !(neighbours & forward_ranks_bb(Them, s + Up))
&& (leverPush | blocked);
// Compute additional span if pawn is not backward nor blocked
if (!backward && !blocked)
e->pawnAttacksSpan[Us] |= pawn_attack_span(Us, s);
// A pawn is passed if one of the three following conditions is true:
// (a) there is no stoppers except some levers
// (b) the only stoppers are the leverPush, but we outnumber them
// (c) there is only one front stopper which can be levered.
// (Refined in Evaluation::passed)
passed = !(stoppers ^ lever)
|| ( !(stoppers ^ leverPush)
&& popcount(phalanx) >= popcount(leverPush))
|| ( stoppers == blocked && r >= RANK_5
&& (shift<Up>(support) & ~(theirPawns | doubleAttackThem)));
passed &= !(forward_file_bb(Us, s) & ourPawns);
// Passed pawns will be properly scored later in evaluation when we have
// full attack info.
if (passed)
e->passedPawns[Us] |= s;
// Score this pawn
if (support | phalanx)
{
int v = Connected[r] * (2 + bool(phalanx) - bool(opposed))
+ 22 * popcount(support);
score += make_score(v, v * (r - 2) / 4);
}
else if (!neighbours)
{
if ( opposed
&& (ourPawns & forward_file_bb(Them, s))
&& !(theirPawns & adjacent_files_bb(s)))
score -= Doubled;
else
score -= Isolated
+ WeakUnopposed * !opposed;
}
else if (backward)
score -= Backward
+ WeakUnopposed * !opposed * bool(~(FileABB | FileHBB) & s);
if (!support)
score -= Doubled * doubled
+ WeakLever * more_than_one(lever);
if (blocked && r >= RANK_5)
score += BlockedPawn[r - RANK_5];
}
return score;
}
} // namespace
namespace Pawns {
/// Pawns::probe() looks up the current position's pawns configuration in
/// the pawns hash table. It returns a pointer to the Entry if the position
/// is found. Otherwise a new Entry is computed and stored there, so we don't
/// have to recompute all when the same pawns configuration occurs again.
Entry* probe(const Position& pos) {
Key key = pos.pawn_key();
Entry* e = pos.this_thread()->pawnsTable[key];
if (e->key == key)
return e;
e->key = key;
e->blockedCount = 0;
e->scores[WHITE] = evaluate<WHITE>(pos, e);
e->scores[BLACK] = evaluate<BLACK>(pos, e);
return e;
}
/// Entry::evaluate_shelter() calculates the shelter bonus and the storm
/// penalty for a king, looking at the king file and the two closest files.
template<Color Us>
Score Entry::evaluate_shelter(const Position& pos, Square ksq) const {
constexpr Color Them = ~Us;
Bitboard b = pos.pieces(PAWN) & ~forward_ranks_bb(Them, ksq);
Bitboard ourPawns = b & pos.pieces(Us) & ~pawnAttacks[Them];
Bitboard theirPawns = b & pos.pieces(Them);
Score bonus = make_score(5, 5);
File center = std::clamp(file_of(ksq), FILE_B, FILE_G);
for (File f = File(center - 1); f <= File(center + 1); ++f)
{
b = ourPawns & file_bb(f);
int ourRank = b ? relative_rank(Us, frontmost_sq(Them, b)) : 0;
b = theirPawns & file_bb(f);
int theirRank = b ? relative_rank(Us, frontmost_sq(Them, b)) : 0;
int d = edge_distance(f);
bonus += make_score(ShelterStrength[d][ourRank], 0);
if (ourRank && (ourRank == theirRank - 1))
bonus -= BlockedStorm[theirRank];
else
bonus -= make_score(UnblockedStorm[d][theirRank], 0);
}
// King On File
bonus -= KingOnFile[pos.is_on_semiopen_file(Us, ksq)][pos.is_on_semiopen_file(Them, ksq)];
return bonus;
}
/// Entry::do_king_safety() calculates a bonus for king safety. It is called only
/// when king square changes, which is about 20% of total king_safety() calls.
template<Color Us>
Score Entry::do_king_safety(const Position& pos) {
Square ksq = pos.square<KING>(Us);
kingSquares[Us] = ksq;
castlingRights[Us] = pos.castling_rights(Us);
auto compare = [](Score a, Score b) { return mg_value(a) < mg_value(b); };
Score shelter = evaluate_shelter<Us>(pos, ksq);
// If we can castle use the bonus after castling if it is bigger
if (pos.can_castle(Us & KING_SIDE))
shelter = std::max(shelter, evaluate_shelter<Us>(pos, relative_square(Us, SQ_G1)), compare);
if (pos.can_castle(Us & QUEEN_SIDE))
shelter = std::max(shelter, evaluate_shelter<Us>(pos, relative_square(Us, SQ_C1)), compare);
// In endgame we like to bring our king near our closest pawn
Bitboard pawns = pos.pieces(Us, PAWN);
int minPawnDist = 6;
if (pawns & attacks_bb<KING>(ksq))
minPawnDist = 1;
else while (pawns)
minPawnDist = std::min(minPawnDist, distance(ksq, pop_lsb(pawns)));
return shelter - make_score(0, 16 * minPawnDist);
}
// Explicit template instantiation
template Score Entry::do_king_safety<WHITE>(const Position& pos);
template Score Entry::do_king_safety<BLACK>(const Position& pos);
} // namespace Pawns
} // namespace Stockfish
-70
View File
@@ -1,70 +0,0 @@
/*
Stockfish, a UCI chess playing engine derived from Glaurung 2.1
Copyright (C) 2004-2023 The Stockfish developers (see AUTHORS file)
Stockfish is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
Stockfish is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef PAWNS_H_INCLUDED
#define PAWNS_H_INCLUDED
#include "misc.h"
#include "position.h"
#include "types.h"
namespace Stockfish::Pawns {
/// Pawns::Entry contains various information about a pawn structure. A lookup
/// to the pawn hash table (performed by calling the probe function) returns a
/// pointer to an Entry object.
struct Entry {
Score pawn_score(Color c) const { return scores[c]; }
Bitboard pawn_attacks(Color c) const { return pawnAttacks[c]; }
Bitboard passed_pawns(Color c) const { return passedPawns[c]; }
Bitboard pawn_attacks_span(Color c) const { return pawnAttacksSpan[c]; }
int passed_count() const { return popcount(passedPawns[WHITE] | passedPawns[BLACK]); }
int blocked_count() const { return blockedCount; }
template<Color Us>
Score king_safety(const Position& pos) {
return kingSquares[Us] == pos.square<KING>(Us) && castlingRights[Us] == pos.castling_rights(Us)
? kingSafety[Us] : (kingSafety[Us] = do_king_safety<Us>(pos));
}
template<Color Us>
Score do_king_safety(const Position& pos);
template<Color Us>
Score evaluate_shelter(const Position& pos, Square ksq) const;
Key key;
Score scores[COLOR_NB];
Bitboard passedPawns[COLOR_NB];
Bitboard pawnAttacks[COLOR_NB];
Bitboard pawnAttacksSpan[COLOR_NB];
Square kingSquares[COLOR_NB];
Score kingSafety[COLOR_NB];
int castlingRights[COLOR_NB];
int blockedCount;
};
using Table = HashTable<Entry, 131072>;
Entry* probe(const Position& pos);
} // namespace Stockfish::Pawns
#endif // #ifndef PAWNS_H_INCLUDED
+68
View File
@@ -0,0 +1,68 @@
/*
Stockfish, a UCI chess playing engine derived from Glaurung 2.1
Copyright (C) 2004-2025 The Stockfish developers (see AUTHORS file)
Stockfish is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
Stockfish is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef PERFT_H_INCLUDED
#define PERFT_H_INCLUDED
#include <cstdint>
#include "movegen.h"
#include "position.h"
#include "types.h"
#include "uci.h"
namespace Stockfish::Benchmark {
// Utility to verify move generation. All the leaf nodes up
// to the given depth are generated and counted, and the sum is returned.
template<bool Root>
uint64_t perft(Position& pos, Depth depth) {
StateInfo st;
ASSERT_ALIGNED(&st, Eval::NNUE::CacheLineSize);
uint64_t cnt, nodes = 0;
const bool leaf = (depth == 2);
for (const auto& m : MoveList<LEGAL>(pos))
{
if (Root && depth <= 1)
cnt = 1, nodes++;
else
{
pos.do_move(m, st);
cnt = leaf ? MoveList<LEGAL>(pos).size() : perft<false>(pos, depth - 1);
nodes += cnt;
pos.undo_move(m);
}
if (Root)
sync_cout << UCIEngine::move(m, pos.is_chess960()) << ": " << cnt << sync_endl;
}
return nodes;
}
inline uint64_t perft(const std::string& fen, Depth depth, bool isChess960) {
StateListPtr states(new std::deque<StateInfo>(1));
Position p;
p.set(fen, isChess960, &states->back());
return perft<true>(p, depth);
}
}
#endif // PERFT_H_INCLUDED
+949 -971
View File
File diff suppressed because it is too large Load Diff
+235 -309
View File
@@ -1,6 +1,6 @@
/* /*
Stockfish, a UCI chess playing engine derived from Glaurung 2.1 Stockfish, a UCI chess playing engine derived from Glaurung 2.1
Copyright (C) 2004-2023 The Stockfish developers (see AUTHORS file) Copyright (C) 2004-2025 The Stockfish developers (see AUTHORS file)
Stockfish is free software: you can redistribute it and/or modify Stockfish is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by it under the terms of the GNU General Public License as published by
@@ -21,430 +21,356 @@
#include <cassert> #include <cassert>
#include <deque> #include <deque>
#include <memory> // For std::unique_ptr #include <iosfwd>
#include <memory>
#include <string> #include <string>
#include "bitboard.h" #include "bitboard.h"
#include "evaluate.h"
#include "psqt.h"
#include "types.h"
#include "nnue/nnue_accumulator.h" #include "nnue/nnue_accumulator.h"
#include "nnue/nnue_architecture.h"
#include "types.h"
namespace Stockfish { namespace Stockfish {
/// StateInfo struct stores information needed to restore a Position object to class TranspositionTable;
/// its previous state when we retract a move. Whenever a move is made on the
/// board (by calling Position::do_move), a StateInfo object must be passed. // StateInfo struct stores information needed to restore a Position object to
// its previous state when we retract a move. Whenever a move is made on the
// board (by calling Position::do_move), a StateInfo object must be passed.
struct StateInfo { struct StateInfo {
// Copied when making a move // Copied when making a move
Key pawnKey; Key materialKey;
Key materialKey; Key pawnKey;
Value nonPawnMaterial[COLOR_NB]; Key minorPieceKey;
int castlingRights; Key nonPawnKey[COLOR_NB];
int rule50; Value nonPawnMaterial[COLOR_NB];
int pliesFromNull; int castlingRights;
Square epSquare; int rule50;
int pliesFromNull;
Square epSquare;
// Not copied when making a move (will be recomputed anyhow) // Not copied when making a move (will be recomputed anyhow)
Key key; Key key;
Bitboard checkersBB; Bitboard checkersBB;
StateInfo* previous; StateInfo* previous;
Bitboard blockersForKing[COLOR_NB]; StateInfo* next;
Bitboard pinners[COLOR_NB]; Bitboard blockersForKing[COLOR_NB];
Bitboard checkSquares[PIECE_TYPE_NB]; Bitboard pinners[COLOR_NB];
Piece capturedPiece; Bitboard checkSquares[PIECE_TYPE_NB];
int repetition; Piece capturedPiece;
int repetition;
// Used by NNUE // Used by NNUE
Eval::NNUE::Accumulator accumulator; Eval::NNUE::Accumulator<Eval::NNUE::TransformedFeatureDimensionsBig> accumulatorBig;
DirtyPiece dirtyPiece; Eval::NNUE::Accumulator<Eval::NNUE::TransformedFeatureDimensionsSmall> accumulatorSmall;
DirtyPiece dirtyPiece;
}; };
/// A list to keep track of the position states along the setup moves (from the // A list to keep track of the position states along the setup moves (from the
/// start position to the position just before the search starts). Needed by // start position to the position just before the search starts). Needed by
/// 'draw by repetition' detection. Use a std::deque because pointers to // 'draw by repetition' detection. Use a std::deque because pointers to
/// elements are not invalidated upon list resizing. // elements are not invalidated upon list resizing.
using StateListPtr = std::unique_ptr<std::deque<StateInfo>>; using StateListPtr = std::unique_ptr<std::deque<StateInfo>>;
/// Position class stores information regarding the board representation as // Position class stores information regarding the board representation as
/// pieces, side to move, hash keys, castling info, etc. Important methods are // pieces, side to move, hash keys, castling info, etc. Important methods are
/// do_move() and undo_move(), used by the search to update node info when // do_move() and undo_move(), used by the search to update node info when
/// traversing the search tree. // traversing the search tree.
class Thread;
class Position { class Position {
public: public:
static void init(); static void init();
Position() = default; Position() = default;
Position(const Position&) = delete; Position(const Position&) = delete;
Position& operator=(const Position&) = delete; Position& operator=(const Position&) = delete;
// FEN string input/output // FEN string input/output
Position& set(const std::string& fenStr, bool isChess960, StateInfo* si, Thread* th); Position& set(const std::string& fenStr, bool isChess960, StateInfo* si);
Position& set(const std::string& code, Color c, StateInfo* si); Position& set(const std::string& code, Color c, StateInfo* si);
std::string fen() const; std::string fen() const;
// Position representation // Position representation
Bitboard pieces(PieceType pt) const; Bitboard pieces(PieceType pt = ALL_PIECES) const;
template<typename ...PieceTypes> Bitboard pieces(PieceType pt, PieceTypes... pts) const; template<typename... PieceTypes>
Bitboard pieces(Color c) const; Bitboard pieces(PieceType pt, PieceTypes... pts) const;
template<typename ...PieceTypes> Bitboard pieces(Color c, PieceTypes... pts) const; Bitboard pieces(Color c) const;
Piece piece_on(Square s) const; template<typename... PieceTypes>
Square ep_square() const; Bitboard pieces(Color c, PieceTypes... pts) const;
bool empty(Square s) const; Piece piece_on(Square s) const;
template<PieceType Pt> int count(Color c) const; Square ep_square() const;
template<PieceType Pt> int count() const; bool empty(Square s) const;
template<PieceType Pt> Square square(Color c) const; template<PieceType Pt>
bool is_on_semiopen_file(Color c, Square s) const; int count(Color c) const;
template<PieceType Pt>
int count() const;
template<PieceType Pt>
Square square(Color c) const;
// Castling // Castling
CastlingRights castling_rights(Color c) const; CastlingRights castling_rights(Color c) const;
bool can_castle(CastlingRights cr) const; bool can_castle(CastlingRights cr) const;
bool castling_impeded(CastlingRights cr) const; bool castling_impeded(CastlingRights cr) const;
Square castling_rook_square(CastlingRights cr) const; Square castling_rook_square(CastlingRights cr) const;
// Checking // Checking
Bitboard checkers() const; Bitboard checkers() const;
Bitboard blockers_for_king(Color c) const; Bitboard blockers_for_king(Color c) const;
Bitboard check_squares(PieceType pt) const; Bitboard check_squares(PieceType pt) const;
Bitboard pinners(Color c) const; Bitboard pinners(Color c) const;
// Attacks to/from a given square // Attacks to/from a given square
Bitboard attackers_to(Square s) const; Bitboard attackers_to(Square s) const;
Bitboard attackers_to(Square s, Bitboard occupied) const; Bitboard attackers_to(Square s, Bitboard occupied) const;
Bitboard slider_blockers(Bitboard sliders, Square s, Bitboard& pinners) const; bool attackers_to_exist(Square s, Bitboard occupied, Color c) const;
template<PieceType Pt> Bitboard attacks_by(Color c) const; void update_slider_blockers(Color c) const;
template<PieceType Pt>
Bitboard attacks_by(Color c) const;
// Properties of moves // Properties of moves
bool legal(Move m) const; bool legal(Move m) const;
bool pseudo_legal(const Move m) const; bool pseudo_legal(const Move m) const;
bool capture(Move m) const; bool capture(Move m) const;
bool capture_stage(Move m) const; bool capture_stage(Move m) const;
bool gives_check(Move m) const; bool gives_check(Move m) const;
Piece moved_piece(Move m) const; Piece moved_piece(Move m) const;
Piece captured_piece() const; Piece captured_piece() const;
// Piece specific // Doing and undoing moves
bool pawn_passed(Color c, Square s) const; void do_move(Move m, StateInfo& newSt, const TranspositionTable* tt);
bool opposite_bishops() const; void do_move(Move m, StateInfo& newSt, bool givesCheck, const TranspositionTable* tt);
int pawns_on_same_color_squares(Color c, Square s) const; void undo_move(Move m);
void do_null_move(StateInfo& newSt, const TranspositionTable& tt);
void undo_null_move();
// Doing and undoing moves // Static Exchange Evaluation
void do_move(Move m, StateInfo& newSt); bool see_ge(Move m, int threshold = 0) const;
void do_move(Move m, StateInfo& newSt, bool givesCheck);
void undo_move(Move m);
void do_null_move(StateInfo& newSt);
void undo_null_move();
// Static Exchange Evaluation // Accessing hash keys
bool see_ge(Move m, Value threshold = VALUE_ZERO) const; Key key() const;
bool see_ge(Move m, Bitboard& occupied, Value threshold = VALUE_ZERO) const; Key material_key() const;
Key pawn_key() const;
Key minor_piece_key() const;
Key non_pawn_key(Color c) const;
// Accessing hash keys // Other properties of the position
Key key() const; Color side_to_move() const;
Key key_after(Move m) const; int game_ply() const;
Key material_key() const; bool is_chess960() const;
Key pawn_key() const; bool is_draw(int ply) const;
bool is_repetition(int ply) const;
bool upcoming_repetition(int ply) const;
bool has_repeated() const;
int rule50_count() const;
Value non_pawn_material(Color c) const;
Value non_pawn_material() const;
// Other properties of the position // Position consistency check, for debugging
Color side_to_move() const; bool pos_is_ok() const;
int game_ply() const; void flip();
bool is_chess960() const;
Thread* this_thread() const;
bool is_draw(int ply) const;
bool has_game_cycle(int ply) const;
bool has_repeated() const;
int rule50_count() const;
Score psq_score() const;
Value psq_eg_stm() const;
Value non_pawn_material(Color c) const;
Value non_pawn_material() const;
// Position consistency check, for debugging // Used by NNUE
bool pos_is_ok() const; StateInfo* state() const;
void flip();
// Used by NNUE void put_piece(Piece pc, Square s);
StateInfo* state() const; void remove_piece(Square s);
void put_piece(Piece pc, Square s); private:
void remove_piece(Square s); // Initialization helpers (used while setting up a position)
void set_castling_right(Color c, Square rfrom);
void set_state() const;
void set_check_info() const;
private: // Other helpers
// Initialization helpers (used while setting up a position) void move_piece(Square from, Square to);
void set_castling_right(Color c, Square rfrom); template<bool Do>
void set_state() const; void do_castling(Color us, Square from, Square& to, Square& rfrom, Square& rto);
void set_check_info() const; template<bool AfterMove>
Key adjust_key50(Key k) const;
// Other helpers // Data members
void move_piece(Square from, Square to); Piece board[SQUARE_NB];
template<bool Do> Bitboard byTypeBB[PIECE_TYPE_NB];
void do_castling(Color us, Square from, Square& to, Square& rfrom, Square& rto); Bitboard byColorBB[COLOR_NB];
template<bool AfterMove> int pieceCount[PIECE_NB];
Key adjust_key50(Key k) const; int castlingRightsMask[SQUARE_NB];
Square castlingRookSquare[CASTLING_RIGHT_NB];
// Data members Bitboard castlingPath[CASTLING_RIGHT_NB];
Piece board[SQUARE_NB]; StateInfo* st;
Bitboard byTypeBB[PIECE_TYPE_NB]; int gamePly;
Bitboard byColorBB[COLOR_NB]; Color sideToMove;
int pieceCount[PIECE_NB]; bool chess960;
int castlingRightsMask[SQUARE_NB];
Square castlingRookSquare[CASTLING_RIGHT_NB];
Bitboard castlingPath[CASTLING_RIGHT_NB];
Thread* thisThread;
StateInfo* st;
int gamePly;
Color sideToMove;
Score psq;
bool chess960;
}; };
std::ostream& operator<<(std::ostream& os, const Position& pos); std::ostream& operator<<(std::ostream& os, const Position& pos);
inline Color Position::side_to_move() const { inline Color Position::side_to_move() const { return sideToMove; }
return sideToMove;
}
inline Piece Position::piece_on(Square s) const { inline Piece Position::piece_on(Square s) const {
assert(is_ok(s)); assert(is_ok(s));
return board[s]; return board[s];
} }
inline bool Position::empty(Square s) const { inline bool Position::empty(Square s) const { return piece_on(s) == NO_PIECE; }
return piece_on(s) == NO_PIECE;
}
inline Piece Position::moved_piece(Move m) const { inline Piece Position::moved_piece(Move m) const { return piece_on(m.from_sq()); }
return piece_on(from_sq(m));
}
inline Bitboard Position::pieces(PieceType pt = ALL_PIECES) const { inline Bitboard Position::pieces(PieceType pt) const { return byTypeBB[pt]; }
return byTypeBB[pt];
}
template<typename ...PieceTypes> template<typename... PieceTypes>
inline Bitboard Position::pieces(PieceType pt, PieceTypes... pts) const { inline Bitboard Position::pieces(PieceType pt, PieceTypes... pts) const {
return pieces(pt) | pieces(pts...); return pieces(pt) | pieces(pts...);
} }
inline Bitboard Position::pieces(Color c) const { inline Bitboard Position::pieces(Color c) const { return byColorBB[c]; }
return byColorBB[c];
}
template<typename ...PieceTypes> template<typename... PieceTypes>
inline Bitboard Position::pieces(Color c, PieceTypes... pts) const { inline Bitboard Position::pieces(Color c, PieceTypes... pts) const {
return pieces(c) & pieces(pts...); return pieces(c) & pieces(pts...);
} }
template<PieceType Pt> inline int Position::count(Color c) const { template<PieceType Pt>
return pieceCount[make_piece(c, Pt)]; inline int Position::count(Color c) const {
return pieceCount[make_piece(c, Pt)];
} }
template<PieceType Pt> inline int Position::count() const { template<PieceType Pt>
return count<Pt>(WHITE) + count<Pt>(BLACK); inline int Position::count() const {
return count<Pt>(WHITE) + count<Pt>(BLACK);
} }
template<PieceType Pt> inline Square Position::square(Color c) const { template<PieceType Pt>
assert(count<Pt>(c) == 1); inline Square Position::square(Color c) const {
return lsb(pieces(c, Pt)); assert(count<Pt>(c) == 1);
return lsb(pieces(c, Pt));
} }
inline Square Position::ep_square() const { inline Square Position::ep_square() const { return st->epSquare; }
return st->epSquare;
}
inline bool Position::is_on_semiopen_file(Color c, Square s) const { inline bool Position::can_castle(CastlingRights cr) const { return st->castlingRights & cr; }
return !(pieces(c, PAWN) & file_bb(s));
}
inline bool Position::can_castle(CastlingRights cr) const {
return st->castlingRights & cr;
}
inline CastlingRights Position::castling_rights(Color c) const { inline CastlingRights Position::castling_rights(Color c) const {
return c & CastlingRights(st->castlingRights); return c & CastlingRights(st->castlingRights);
} }
inline bool Position::castling_impeded(CastlingRights cr) const { inline bool Position::castling_impeded(CastlingRights cr) const {
assert(cr == WHITE_OO || cr == WHITE_OOO || cr == BLACK_OO || cr == BLACK_OOO); assert(cr == WHITE_OO || cr == WHITE_OOO || cr == BLACK_OO || cr == BLACK_OOO);
return pieces() & castlingPath[cr];
return pieces() & castlingPath[cr];
} }
inline Square Position::castling_rook_square(CastlingRights cr) const { inline Square Position::castling_rook_square(CastlingRights cr) const {
assert(cr == WHITE_OO || cr == WHITE_OOO || cr == BLACK_OO || cr == BLACK_OOO); assert(cr == WHITE_OO || cr == WHITE_OOO || cr == BLACK_OO || cr == BLACK_OOO);
return castlingRookSquare[cr];
return castlingRookSquare[cr];
} }
inline Bitboard Position::attackers_to(Square s) const { inline Bitboard Position::attackers_to(Square s) const { return attackers_to(s, pieces()); }
return attackers_to(s, pieces());
}
template<PieceType Pt> template<PieceType Pt>
inline Bitboard Position::attacks_by(Color c) const { inline Bitboard Position::attacks_by(Color c) const {
if constexpr (Pt == PAWN) if constexpr (Pt == PAWN)
return c == WHITE ? pawn_attacks_bb<WHITE>(pieces(WHITE, PAWN)) return c == WHITE ? pawn_attacks_bb<WHITE>(pieces(WHITE, PAWN))
: pawn_attacks_bb<BLACK>(pieces(BLACK, PAWN)); : pawn_attacks_bb<BLACK>(pieces(BLACK, PAWN));
else else
{ {
Bitboard threats = 0; Bitboard threats = 0;
Bitboard attackers = pieces(c, Pt); Bitboard attackers = pieces(c, Pt);
while (attackers) while (attackers)
threats |= attacks_bb<Pt>(pop_lsb(attackers), pieces()); threats |= attacks_bb<Pt>(pop_lsb(attackers), pieces());
return threats; return threats;
} }
} }
inline Bitboard Position::checkers() const { inline Bitboard Position::checkers() const { return st->checkersBB; }
return st->checkersBB;
}
inline Bitboard Position::blockers_for_king(Color c) const { inline Bitboard Position::blockers_for_king(Color c) const { return st->blockersForKing[c]; }
return st->blockersForKing[c];
}
inline Bitboard Position::pinners(Color c) const { inline Bitboard Position::pinners(Color c) const { return st->pinners[c]; }
return st->pinners[c];
}
inline Bitboard Position::check_squares(PieceType pt) const { inline Bitboard Position::check_squares(PieceType pt) const { return st->checkSquares[pt]; }
return st->checkSquares[pt];
}
inline bool Position::pawn_passed(Color c, Square s) const { inline Key Position::key() const { return adjust_key50<false>(st->key); }
return !(pieces(~c, PAWN) & passed_pawn_span(c, s));
}
inline int Position::pawns_on_same_color_squares(Color c, Square s) const {
return popcount(pieces(c, PAWN) & ((DarkSquares & s) ? DarkSquares : ~DarkSquares));
}
inline Key Position::key() const {
return adjust_key50<false>(st->key);
}
template<bool AfterMove> template<bool AfterMove>
inline Key Position::adjust_key50(Key k) const inline Key Position::adjust_key50(Key k) const {
{ return st->rule50 < 14 - AfterMove ? k : k ^ make_key((st->rule50 - (14 - AfterMove)) / 8);
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 { return st->pawnKey; }
return st->pawnKey;
}
inline Key Position::material_key() const { inline Key Position::material_key() const { return st->materialKey; }
return st->materialKey;
}
inline Score Position::psq_score() const { inline Key Position::minor_piece_key() const { return st->minorPieceKey; }
return psq;
}
inline Value Position::psq_eg_stm() const { inline Key Position::non_pawn_key(Color c) const { return st->nonPawnKey[c]; }
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];
}
inline Value Position::non_pawn_material() const { inline Value Position::non_pawn_material() const {
return non_pawn_material(WHITE) + non_pawn_material(BLACK); return non_pawn_material(WHITE) + non_pawn_material(BLACK);
} }
inline int Position::game_ply() const { inline int Position::game_ply() const { return gamePly; }
return gamePly;
}
inline int Position::rule50_count() const { inline int Position::rule50_count() const { return st->rule50; }
return st->rule50;
}
inline bool Position::opposite_bishops() const { inline bool Position::is_chess960() const { return chess960; }
return count<BISHOP>(WHITE) == 1
&& count<BISHOP>(BLACK) == 1
&& opposite_colors(square<BISHOP>(WHITE), square<BISHOP>(BLACK));
}
inline bool Position::is_chess960() const {
return chess960;
}
inline bool Position::capture(Move m) const { inline bool Position::capture(Move m) const {
assert(is_ok(m)); assert(m.is_ok());
return (!empty(to_sq(m)) && type_of(m) != CASTLING) return (!empty(m.to_sq()) && m.type_of() != CASTLING) || m.type_of() == EN_PASSANT;
|| type_of(m) == EN_PASSANT;
} }
// returns true if a move is generated from the capture stage // Returns true if a move is generated from the capture stage, having also
// having also queen promotions covered, i.e. consistency with the capture stage move generation // queen promotions covered, i.e. consistency with the capture stage move
// is needed to avoid the generation of duplicate moves. // generation is needed to avoid the generation of duplicate moves.
inline bool Position::capture_stage(Move m) const { inline bool Position::capture_stage(Move m) const {
assert(is_ok(m)); assert(m.is_ok());
return capture(m) || promotion_type(m) == QUEEN; return capture(m) || m.promotion_type() == QUEEN;
} }
inline Piece Position::captured_piece() const { inline Piece Position::captured_piece() const { return st->capturedPiece; }
return st->capturedPiece;
}
inline Thread* Position::this_thread() const {
return thisThread;
}
inline void Position::put_piece(Piece pc, Square s) { inline void Position::put_piece(Piece pc, Square s) {
board[s] = pc; board[s] = pc;
byTypeBB[ALL_PIECES] |= byTypeBB[type_of(pc)] |= s; byTypeBB[ALL_PIECES] |= byTypeBB[type_of(pc)] |= s;
byColorBB[color_of(pc)] |= s; byColorBB[color_of(pc)] |= s;
pieceCount[pc]++; pieceCount[pc]++;
pieceCount[make_piece(color_of(pc), ALL_PIECES)]++; pieceCount[make_piece(color_of(pc), ALL_PIECES)]++;
psq += PSQT::psq[pc][s];
} }
inline void Position::remove_piece(Square s) { inline void Position::remove_piece(Square s) {
Piece pc = board[s]; Piece pc = board[s];
byTypeBB[ALL_PIECES] ^= s; byTypeBB[ALL_PIECES] ^= s;
byTypeBB[type_of(pc)] ^= s; byTypeBB[type_of(pc)] ^= s;
byColorBB[color_of(pc)] ^= s; byColorBB[color_of(pc)] ^= s;
board[s] = NO_PIECE; board[s] = NO_PIECE;
pieceCount[pc]--; pieceCount[pc]--;
pieceCount[make_piece(color_of(pc), ALL_PIECES)]--; pieceCount[make_piece(color_of(pc), ALL_PIECES)]--;
psq -= PSQT::psq[pc][s];
} }
inline void Position::move_piece(Square from, Square to) { inline void Position::move_piece(Square from, Square to) {
Piece pc = board[from]; Piece pc = board[from];
Bitboard fromTo = from | to; Bitboard fromTo = from | to;
byTypeBB[ALL_PIECES] ^= fromTo; byTypeBB[ALL_PIECES] ^= fromTo;
byTypeBB[type_of(pc)] ^= fromTo; byTypeBB[type_of(pc)] ^= fromTo;
byColorBB[color_of(pc)] ^= fromTo; byColorBB[color_of(pc)] ^= fromTo;
board[from] = NO_PIECE; board[from] = NO_PIECE;
board[to] = pc; board[to] = pc;
psq += PSQT::psq[pc][to] - PSQT::psq[pc][from];
} }
inline void Position::do_move(Move m, StateInfo& newSt) { inline void Position::do_move(Move m, StateInfo& newSt, const TranspositionTable* tt = nullptr) {
do_move(m, newSt, gives_check(m)); do_move(m, newSt, gives_check(m), tt);
} }
inline StateInfo* Position::state() const { inline StateInfo* Position::state() const { return st; }
return st; } // namespace Stockfish
}
} // namespace Stockfish #endif // #ifndef POSITION_H_INCLUDED
#endif // #ifndef POSITION_H_INCLUDED
-131
View File
@@ -1,131 +0,0 @@
/*
Stockfish, a UCI chess playing engine derived from Glaurung 2.1
Copyright (C) 2004-2023 The Stockfish developers (see AUTHORS file)
Stockfish is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
Stockfish is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "psqt.h"
#include <algorithm>
#include "bitboard.h"
#include "types.h"
namespace Stockfish {
namespace
{
auto constexpr S = make_score;
// 'Bonus' contains Piece-Square parameters.
// Scores are explicit for files A to D, implicitly mirrored for E to H.
constexpr Score Bonus[][RANK_NB][int(FILE_NB) / 2] = {
{ },
{ },
{ // Knight
{ S(-175, -96), S(-92,-65), S(-74,-49), S(-73,-21) },
{ S( -77, -67), S(-41,-54), S(-27,-18), S(-15, 8) },
{ S( -61, -40), S(-17,-27), S( 6, -8), S( 12, 29) },
{ S( -35, -35), S( 8, -2), S( 40, 13), S( 49, 28) },
{ S( -34, -45), S( 13,-16), S( 44, 9), S( 51, 39) },
{ S( -9, -51), S( 22,-44), S( 58,-16), S( 53, 17) },
{ S( -67, -69), S(-27,-50), S( 4,-51), S( 37, 12) },
{ S(-201,-100), S(-83,-88), S(-56,-56), S(-26,-17) }
},
{ // Bishop
{ S(-37,-40), S(-4 ,-21), S( -6,-26), S(-16, -8) },
{ S(-11,-26), S( 6, -9), S( 13,-12), S( 3, 1) },
{ S(-5 ,-11), S( 15, -1), S( -4, -1), S( 12, 7) },
{ S(-4 ,-14), S( 8, -4), S( 18, 0), S( 27, 12) },
{ S(-8 ,-12), S( 20, -1), S( 15,-10), S( 22, 11) },
{ S(-11,-21), S( 4, 4), S( 1, 3), S( 8, 4) },
{ S(-12,-22), S(-10,-14), S( 4, -1), S( 0, 1) },
{ S(-34,-32), S( 1,-29), S(-10,-26), S(-16,-17) }
},
{ // Rook
{ S(-31, -9), S(-20,-13), S(-14,-10), S(-5, -9) },
{ S(-21,-12), S(-13, -9), S( -8, -1), S( 6, -2) },
{ S(-25, 6), S(-11, -8), S( -1, -2), S( 3, -6) },
{ S(-13, -6), S( -5, 1), S( -4, -9), S(-6, 7) },
{ S(-27, -5), S(-15, 8), S( -4, 7), S( 3, -6) },
{ S(-22, 6), S( -2, 1), S( 6, -7), S(12, 10) },
{ S( -2, 4), S( 12, 5), S( 16, 20), S(18, -5) },
{ S(-17, 18), S(-19, 0), S( -1, 19), S( 9, 13) }
},
{ // Queen
{ S( 3,-69), S(-5,-57), S(-5,-47), S( 4,-26) },
{ S(-3,-54), S( 5,-31), S( 8,-22), S(12, -4) },
{ S(-3,-39), S( 6,-18), S(13, -9), S( 7, 3) },
{ S( 4,-23), S( 5, -3), S( 9, 13), S( 8, 24) },
{ S( 0,-29), S(14, -6), S(12, 9), S( 5, 21) },
{ S(-4,-38), S(10,-18), S( 6,-11), S( 8, 1) },
{ S(-5,-50), S( 6,-27), S(10,-24), S( 8, -8) },
{ S(-2,-74), S(-2,-52), S( 1,-43), S(-2,-34) }
},
{ // King
{ S(271, 1), S(327, 45), S(271, 85), S(198, 76) },
{ S(278, 53), S(303,100), S(234,133), S(179,135) },
{ S(195, 88), S(258,130), S(169,169), S(120,175) },
{ S(164,103), S(190,156), S(138,172), S( 98,172) },
{ S(154, 96), S(179,166), S(105,199), S( 70,199) },
{ S(123, 92), S(145,172), S( 81,184), S( 31,191) },
{ S( 88, 47), S(120,121), S( 65,116), S( 33,131) },
{ S( 59, 11), S( 89, 59), S( 45, 73), S( -1, 78) }
}
};
constexpr Score PBonus[RANK_NB][FILE_NB] =
{ // Pawn (asymmetric distribution)
{ },
{ S( 2, -8), S( 4, -6), S( 11, 9), S( 18, 5), S( 16, 16), S( 21, 6), S( 9, -6), S( -3,-18) },
{ S( -9, -9), S(-15, -7), S( 11,-10), S( 15, 5), S( 31, 2), S( 23, 3), S( 6, -8), S(-20, -5) },
{ S( -3, 7), S(-20, 1), S( 8, -8), S( 19, -2), S( 39,-14), S( 17,-13), S( 2,-11), S( -5, -6) },
{ S( 11, 12), S( -4, 6), S(-11, 2), S( 2, -6), S( 11, -5), S( 0, -4), S(-12, 14), S( 5, 9) },
{ S( 3, 27), S(-11, 18), S( -6, 19), S( 22, 29), S( -8, 30), S( -5, 9), S(-14, 8), S(-11, 14) },
{ S( -7, -1), S( 6,-14), S( -2, 13), S(-11, 22), S( 4, 24), S(-14, 17), S( 10, 7), S( -9, 7) }
};
} // namespace
namespace PSQT
{
Score psq[PIECE_NB][SQUARE_NB];
// PSQT::init() initializes piece-square tables: the white halves of the tables are
// copied from Bonus[] and PBonus[], adding the piece value, then the black halves of
// the tables are initialized by flipping and changing the sign of the white scores.
void init() {
for (Piece pc : {W_PAWN, W_KNIGHT, W_BISHOP, W_ROOK, W_QUEEN, W_KING})
{
Score score = make_score(PieceValue[MG][pc], PieceValue[EG][pc]);
for (Square s = SQ_A1; s <= SQ_H8; ++s)
{
File f = File(edge_distance(file_of(s)));
psq[ pc][s] = score + (type_of(pc) == PAWN ? PBonus[rank_of(s)][file_of(s)]
: Bonus[pc][rank_of(s)][f]);
psq[~pc][flip_rank(s)] = -psq[pc][s];
}
}
}
} // namespace PSQT
} // namespace Stockfish
+25 -15
View File
@@ -1,6 +1,6 @@
/* /*
Stockfish, a UCI chess playing engine derived from Glaurung 2.1 Stockfish, a UCI chess playing engine derived from Glaurung 2.1
Copyright (C) 2004-2023 The Stockfish developers (see AUTHORS file) Copyright (C) 2004-2025 The Stockfish developers (see AUTHORS file)
Stockfish is free software: you can redistribute it and/or modify Stockfish is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by it under the terms of the GNU General Public License as published by
@@ -16,23 +16,33 @@
along with this program. If not, see <http://www.gnu.org/licenses/>. along with this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
#include "score.h"
#ifndef PSQT_H_INCLUDED #include <cassert>
#define PSQT_H_INCLUDED #include <cmath>
#include <cstdlib>
#include "uci.h"
#include "types.h" namespace Stockfish {
Score::Score(Value v, const Position& pos) {
assert(-VALUE_INFINITE < v && v < VALUE_INFINITE);
namespace Stockfish::PSQT if (!is_decisive(v))
{ {
score = InternalUnits{UCIEngine::to_cp(v, pos)};
}
else if (std::abs(v) <= VALUE_TB)
{
auto distance = VALUE_TB - std::abs(v);
score = (v > 0) ? Tablebase{distance, true} : Tablebase{-distance, false};
}
else
{
auto distance = VALUE_MATE - std::abs(v);
score = (v > 0) ? Mate{distance} : Mate{-distance};
}
}
extern Score psq[PIECE_NB][SQUARE_NB]; }
// Fill psqt array from a set of internally linked parameters
void init();
} // namespace Stockfish::PSQT
#endif // PSQT_H_INCLUDED
+70
View File
@@ -0,0 +1,70 @@
/*
Stockfish, a UCI chess playing engine derived from Glaurung 2.1
Copyright (C) 2004-2025 The Stockfish developers (see AUTHORS file)
Stockfish is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
Stockfish is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef SCORE_H_INCLUDED
#define SCORE_H_INCLUDED
#include <variant>
#include <utility>
#include "types.h"
namespace Stockfish {
class Position;
class Score {
public:
struct Mate {
int plies;
};
struct Tablebase {
int plies;
bool win;
};
struct InternalUnits {
int value;
};
Score() = default;
Score(Value v, const Position& pos);
template<typename T>
bool is() const {
return std::holds_alternative<T>(score);
}
template<typename T>
T get() const {
return std::get<T>(score);
}
template<typename F>
decltype(auto) visit(F&& f) const {
return std::visit(std::forward<F>(f), score);
}
private:
std::variant<Mate, Tablebase, InternalUnits> score;
};
}
#endif // #ifndef SCORE_H_INCLUDED
+1646 -1456
View File
File diff suppressed because it is too large Load Diff
+314 -64
View File
@@ -1,6 +1,6 @@
/* /*
Stockfish, a UCI chess playing engine derived from Glaurung 2.1 Stockfish, a UCI chess playing engine derived from Glaurung 2.1
Copyright (C) 2004-2023 The Stockfish developers (see AUTHORS file) Copyright (C) 2004-2025 The Stockfish developers (see AUTHORS file)
Stockfish is free software: you can redistribute it and/or modify Stockfish is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by it under the terms of the GNU General Public License as published by
@@ -19,98 +19,348 @@
#ifndef SEARCH_H_INCLUDED #ifndef SEARCH_H_INCLUDED
#define SEARCH_H_INCLUDED #define SEARCH_H_INCLUDED
#include <algorithm>
#include <array>
#include <atomic>
#include <cassert>
#include <cstddef>
#include <cstdint>
#include <functional>
#include <memory>
#include <string>
#include <string_view>
#include <vector> #include <vector>
#include "history.h"
#include "misc.h" #include "misc.h"
#include "movepick.h" #include "nnue/network.h"
#include "nnue/nnue_accumulator.h"
#include "numa.h"
#include "position.h"
#include "score.h"
#include "syzygy/tbprobe.h"
#include "timeman.h"
#include "types.h" #include "types.h"
namespace Stockfish { namespace Stockfish {
class Position; // Different node types, used as a template parameter
enum NodeType {
NonPV,
PV,
Root
};
class TranspositionTable;
class ThreadPool;
class OptionsMap;
namespace Search { namespace Search {
// 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 // its own array of Stack objects, indexed by the current ply.
/// its own array of Stack objects, indexed by the current ply.
struct Stack { struct Stack {
Move* pv; Move* pv;
PieceToHistory* continuationHistory; PieceToHistory* continuationHistory;
int ply; CorrectionHistory<PieceTo>* continuationCorrectionHistory;
Move currentMove; int ply;
Move excludedMove; Move currentMove;
Move killers[2]; Move excludedMove;
Value staticEval; Value staticEval;
int statScore; int statScore;
int moveCount; int moveCount;
bool inCheck; bool inCheck;
bool ttPv; bool ttPv;
bool ttHit; bool ttHit;
int doubleExtensions; int cutoffCnt;
int cutoffCnt; int reduction;
bool isTTMove;
}; };
/// RootMove struct is used for moves at the root of the tree. For each root move // RootMove struct is used for moves at the root of the tree. For each root move
/// we store a score and a PV (really a refutation in the case of moves which // we store a score and a PV (really a refutation in the case of moves which
/// fail low). Score is normally set at -VALUE_INFINITE for all non-pv moves. // fail low). Score is normally set at -VALUE_INFINITE for all non-pv moves.
struct RootMove { struct RootMove {
explicit RootMove(Move m) : pv(1, m) {} explicit RootMove(Move m) :
bool extract_ponder_from_tt(Position& pos); pv(1, m) {}
bool operator==(const Move& m) const { return pv[0] == m; } bool extract_ponder_from_tt(const TranspositionTable& tt, Position& pos);
bool operator<(const RootMove& m) const { // Sort in descending order bool operator==(const Move& m) const { return pv[0] == m; }
return m.score != score ? m.score < score // Sort in descending order
: m.previousScore < previousScore; bool operator<(const RootMove& m) const {
} return m.score != score ? m.score < score : m.previousScore < previousScore;
}
Value score = -VALUE_INFINITE; uint64_t effort = 0;
Value previousScore = -VALUE_INFINITE; Value score = -VALUE_INFINITE;
Value averageScore = -VALUE_INFINITE; Value previousScore = -VALUE_INFINITE;
Value uciScore = -VALUE_INFINITE; Value averageScore = -VALUE_INFINITE;
bool scoreLowerbound = false; Value meanSquaredScore = -VALUE_INFINITE * VALUE_INFINITE;
bool scoreUpperbound = false; Value uciScore = -VALUE_INFINITE;
int selDepth = 0; bool scoreLowerbound = false;
int tbRank = 0; bool scoreUpperbound = false;
Value tbScore; int selDepth = 0;
std::vector<Move> pv; int tbRank = 0;
Value tbScore;
std::vector<Move> pv;
}; };
using RootMoves = std::vector<RootMove>; using RootMoves = std::vector<RootMove>;
/// LimitsType struct stores information sent by GUI about available time to // LimitsType struct stores information sent by the caller about the analysis required.
/// search the current move, maximum depth/time, or if we are in analysis mode.
struct LimitsType { struct LimitsType {
LimitsType() { // Init explicitly due to broken value-initialization of non POD in MSVC // Init explicitly due to broken value-initialization of non POD in MSVC
time[WHITE] = time[BLACK] = inc[WHITE] = inc[BLACK] = npmsec = movetime = TimePoint(0); LimitsType() {
movestogo = depth = mate = perft = infinite = 0; time[WHITE] = time[BLACK] = inc[WHITE] = inc[BLACK] = npmsec = movetime = TimePoint(0);
nodes = 0; movestogo = depth = mate = perft = infinite = 0;
} nodes = 0;
ponderMode = false;
}
bool use_time_management() const { bool use_time_management() const { return time[WHITE] || time[BLACK]; }
return time[WHITE] || time[BLACK];
}
std::vector<Move> searchmoves; std::vector<std::string> searchmoves;
TimePoint time[COLOR_NB], inc[COLOR_NB], npmsec, movetime, startTime; TimePoint time[COLOR_NB], inc[COLOR_NB], npmsec, movetime, startTime;
int movestogo, depth, mate, perft, infinite; int movestogo, depth, mate, perft, infinite;
int64_t nodes; uint64_t nodes;
bool ponderMode;
}; };
extern LimitsType Limits;
void init(); // The UCI stores the uci options, thread pool, and transposition table.
void clear(); // This struct is used to easily forward data to the Search::Worker class.
struct SharedState {
SharedState(const OptionsMap& optionsMap,
ThreadPool& threadPool,
TranspositionTable& transpositionTable,
const LazyNumaReplicated<Eval::NNUE::Networks>& nets) :
options(optionsMap),
threads(threadPool),
tt(transpositionTable),
networks(nets) {}
} // namespace Search const OptionsMap& options;
ThreadPool& threads;
TranspositionTable& tt;
const LazyNumaReplicated<Eval::NNUE::Networks>& networks;
};
} // namespace Stockfish class Worker;
#endif // #ifndef SEARCH_H_INCLUDED // Null Object Pattern, implement a common interface for the SearchManagers.
// A Null Object will be given to non-mainthread workers.
class ISearchManager {
public:
virtual ~ISearchManager() {}
virtual void check_time(Search::Worker&) = 0;
};
struct InfoShort {
int depth;
Score score;
};
struct InfoFull: InfoShort {
int selDepth;
size_t multiPV;
std::string_view wdl;
std::string_view bound;
size_t timeMs;
size_t nodes;
size_t nps;
size_t tbHits;
std::string_view pv;
int hashfull;
};
struct InfoIteration {
int depth;
std::string_view currmove;
size_t currmovenumber;
};
// Skill structure is used to implement strength limit. If we have a UCI_Elo,
// we convert it to an appropriate skill level, anchored to the Stash engine.
// This method is based on a fit of the Elo results for games played between
// Stockfish at various skill levels and various versions of the Stash engine.
// Skill 0 .. 19 now covers CCRL Blitz Elo from 1320 to 3190, approximately
// Reference: https://github.com/vondele/Stockfish/commit/a08b8d4e9711c2
struct Skill {
// Lowest and highest Elo ratings used in the skill level calculation
constexpr static int LowestElo = 1320;
constexpr static int HighestElo = 3190;
Skill(int skill_level, int uci_elo) {
if (uci_elo)
{
double e = double(uci_elo - LowestElo) / (HighestElo - LowestElo);
level = std::clamp((((37.2473 * e - 40.8525) * e + 22.2943) * e - 0.311438), 0.0, 19.0);
}
else
level = double(skill_level);
}
bool enabled() const { return level < 20.0; }
bool time_to_pick(Depth depth) const { return depth == 1 + int(level); }
Move pick_best(const RootMoves&, size_t multiPV);
double level;
Move best = Move::none();
};
// SearchManager manages the search from the main thread. It is responsible for
// keeping track of the time, and storing data strictly related to the main thread.
class SearchManager: public ISearchManager {
public:
using UpdateShort = std::function<void(const InfoShort&)>;
using UpdateFull = std::function<void(const InfoFull&)>;
using UpdateIter = std::function<void(const InfoIteration&)>;
using UpdateBestmove = std::function<void(std::string_view, std::string_view)>;
struct UpdateContext {
UpdateShort onUpdateNoMoves;
UpdateFull onUpdateFull;
UpdateIter onIter;
UpdateBestmove onBestmove;
};
SearchManager(const UpdateContext& updateContext) :
updates(updateContext) {}
void check_time(Search::Worker& worker) override;
void pv(Search::Worker& worker,
const ThreadPool& threads,
const TranspositionTable& tt,
Depth depth);
Stockfish::TimeManagement tm;
double originalTimeAdjust;
int callsCnt;
std::atomic_bool ponder;
std::array<Value, 4> iterValue;
double previousTimeReduction;
Value bestPreviousScore;
Value bestPreviousAverageScore;
bool stopOnPonderhit;
size_t id;
const UpdateContext& updates;
};
class NullSearchManager: public ISearchManager {
public:
void check_time(Search::Worker&) override {}
};
// Search::Worker is the class that does the actual search.
// It is instantiated once per thread, and it is responsible for keeping track
// of the search history, and storing data required for the search.
class Worker {
public:
Worker(SharedState&, std::unique_ptr<ISearchManager>, size_t, NumaReplicatedAccessToken);
// Called at instantiation to initialize reductions tables.
// Reset histories, usually before a new game.
void clear();
// Called when the program receives the UCI 'go' command.
// It searches from the root position and outputs the "bestmove".
void start_searching();
bool is_mainthread() const { return threadIdx == 0; }
void ensure_network_replicated();
// Public because they need to be updatable by the stats
ButterflyHistory mainHistory;
LowPlyHistory lowPlyHistory;
CapturePieceToHistory captureHistory;
ContinuationHistory continuationHistory[2][2];
PawnHistory pawnHistory;
CorrectionHistory<Pawn> pawnCorrectionHistory;
CorrectionHistory<Minor> minorPieceCorrectionHistory;
CorrectionHistory<NonPawn> nonPawnCorrectionHistory[COLOR_NB];
CorrectionHistory<Continuation> continuationCorrectionHistory;
private:
void iterative_deepening();
// This is the main search function, for both PV and non-PV nodes
template<NodeType nodeType>
Value search(Position& pos, Stack* ss, Value alpha, Value beta, Depth depth, bool cutNode);
// Quiescence search function, which is called by the main search
template<NodeType nodeType>
Value qsearch(Position& pos, Stack* ss, Value alpha, Value beta);
Depth reduction(bool i, Depth d, int mn, int delta) const;
// Pointer to the search manager, only allowed to be called by the main thread
SearchManager* main_manager() const {
assert(threadIdx == 0);
return static_cast<SearchManager*>(manager.get());
}
TimePoint elapsed() const;
TimePoint elapsed_time() const;
Value evaluate(const Position&);
LimitsType limits;
size_t pvIdx, pvLast;
std::atomic<uint64_t> nodes, tbHits, bestMoveChanges;
int selDepth, nmpMinPly;
Value optimism[COLOR_NB];
Position rootPos;
StateInfo rootState;
RootMoves rootMoves;
Depth rootDepth, completedDepth;
Value rootDelta;
size_t threadIdx;
NumaReplicatedAccessToken numaAccessToken;
// Reductions lookup table initialized at startup
std::array<int, MAX_MOVES> reductions; // [depth or moveNumber]
// The main thread has a SearchManager, the others have a NullSearchManager
std::unique_ptr<ISearchManager> manager;
Tablebases::Config tbConfig;
const OptionsMap& options;
ThreadPool& threads;
TranspositionTable& tt;
const LazyNumaReplicated<Eval::NNUE::Networks>& networks;
// Used by NNUE
Eval::NNUE::AccumulatorCaches refreshTable;
friend class Stockfish::ThreadPool;
friend class SearchManager;
};
struct ConthistBonus {
int index;
int weight;
};
} // namespace Search
} // namespace Stockfish
#endif // #ifndef SEARCH_H_INCLUDED
+501 -362
View File
File diff suppressed because it is too large Load Diff
+41 -39
View File
@@ -1,6 +1,6 @@
/* /*
Stockfish, a UCI chess playing engine derived from Glaurung 2.1 Stockfish, a UCI chess playing engine derived from Glaurung 2.1
Copyright (C) 2004-2023 The Stockfish developers (see AUTHORS file) Copyright (C) 2004-2025 The Stockfish developers (see AUTHORS file)
Stockfish is free software: you can redistribute it and/or modify Stockfish is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by it under the terms of the GNU General Public License as published by
@@ -19,58 +19,60 @@
#ifndef TBPROBE_H #ifndef TBPROBE_H
#define TBPROBE_H #define TBPROBE_H
#include <ostream> #include <string>
#include <vector>
#include "../search.h"
namespace Stockfish {
class Position;
class OptionsMap;
using Depth = int;
namespace Search {
struct RootMove;
using RootMoves = std::vector<RootMove>;
}
}
namespace Stockfish::Tablebases { namespace Stockfish::Tablebases {
struct Config {
int cardinality = 0;
bool rootInTB = false;
bool useRule50 = false;
Depth probeDepth = 0;
};
enum WDLScore { enum WDLScore {
WDLLoss = -2, // Loss WDLLoss = -2, // Loss
WDLBlessedLoss = -1, // Loss, but draw under 50-move rule WDLBlessedLoss = -1, // Loss, but draw under 50-move rule
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
}; };
// Possible states after a probing operation // Possible states after a probing operation
enum ProbeState { enum ProbeState {
FAIL = 0, // Probe failed (missing file table) FAIL = 0, // Probe failed (missing file table)
OK = 1, // Probe successful OK = 1, // Probe successful
CHANGE_STM = -1, // DTZ should check the other side CHANGE_STM = -1, // DTZ should check the other side
ZEROING_BEST_MOVE = 2 // Best move zeroes DTZ (capture or pawn move) ZEROING_BEST_MOVE = 2 // Best move zeroes DTZ (capture or pawn move)
}; };
extern int MaxCardinality; extern int MaxCardinality;
void init(const std::string& paths);
void init(const std::string& paths);
WDLScore probe_wdl(Position& pos, ProbeState* result); WDLScore probe_wdl(Position& pos, ProbeState* result);
int probe_dtz(Position& pos, ProbeState* result); int probe_dtz(Position& pos, ProbeState* result);
bool root_probe(Position& pos, Search::RootMoves& rootMoves); bool root_probe(Position& pos, Search::RootMoves& rootMoves, bool rule50, bool rankDTZ);
bool root_probe_wdl(Position& pos, Search::RootMoves& rootMoves); bool root_probe_wdl(Position& pos, Search::RootMoves& rootMoves, bool rule50);
void rank_root_moves(Position& pos, Search::RootMoves& rootMoves); Config rank_root_moves(const OptionsMap& options,
Position& pos,
Search::RootMoves& rootMoves,
bool rankDTZ = false);
inline std::ostream& operator<<(std::ostream& os, const WDLScore v) { } // namespace Stockfish::Tablebases
os << (v == WDLLoss ? "Loss" :
v == WDLBlessedLoss ? "Blessed loss" :
v == WDLDraw ? "Draw" :
v == WDLCursedWin ? "Cursed win" :
v == WDLWin ? "Win" : "None");
return os;
}
inline std::ostream& operator<<(std::ostream& os, const ProbeState v) {
os << (v == FAIL ? "Failed" :
v == OK ? "Success" :
v == CHANGE_STM ? "Probed opponent side" :
v == ZEROING_BEST_MOVE ? "Best move zeroes DTZ" : "None");
return os;
}
} // namespace Stockfish::Tablebases
#endif #endif
+304 -162
View File
@@ -1,6 +1,6 @@
/* /*
Stockfish, a UCI chess playing engine derived from Glaurung 2.1 Stockfish, a UCI chess playing engine derived from Glaurung 2.1
Copyright (C) 2004-2023 The Stockfish developers (see AUTHORS file) Copyright (C) 2004-2025 The Stockfish developers (see AUTHORS file)
Stockfish is free software: you can redistribute it and/or modify Stockfish is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by it under the terms of the GNU General Public License as published by
@@ -16,253 +16,395 @@
along with this program. If not, see <http://www.gnu.org/licenses/>. along with this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
#include <cassert> #include "thread.h"
#include <algorithm>
#include <cassert>
#include <deque>
#include <memory>
#include <string>
#include <unordered_map>
#include <utility>
#include <algorithm> // For std::count
#include "movegen.h" #include "movegen.h"
#include "search.h" #include "search.h"
#include "thread.h"
#include "uci.h"
#include "syzygy/tbprobe.h" #include "syzygy/tbprobe.h"
#include "tt.h" #include "timeman.h"
#include "types.h"
#include "uci.h"
#include "ucioption.h"
namespace Stockfish { namespace Stockfish {
ThreadPool Threads; // Global object // Constructor launches the thread and waits until it goes to sleep
// in idle_loop(). Note that 'searching' and 'exit' should be already set.
Thread::Thread(Search::SharedState& sharedState,
std::unique_ptr<Search::ISearchManager> sm,
size_t n,
OptionalThreadToNumaNodeBinder binder) :
idx(n),
nthreads(sharedState.options["Threads"]),
stdThread(&Thread::idle_loop, this) {
wait_for_search_finished();
/// Thread constructor launches the thread and waits until it goes to sleep run_custom_job([this, &binder, &sharedState, &sm, n]() {
/// in idle_loop(). Note that 'searching' and 'exit' should be already set. // Use the binder to [maybe] bind the threads to a NUMA node before doing
// the Worker allocation. Ideally we would also allocate the SearchManager
// here, but that's minor.
this->numaAccessToken = binder();
this->worker =
std::make_unique<Search::Worker>(sharedState, std::move(sm), n, this->numaAccessToken);
});
Thread::Thread(size_t n) : idx(n), stdThread(&Thread::idle_loop, this) { wait_for_search_finished();
wait_for_search_finished();
} }
/// Thread destructor wakes up the thread in idle_loop() and waits // Destructor wakes up the thread in idle_loop() and waits
/// for its termination. Thread should be already waiting. // for its termination. Thread should be already waiting.
Thread::~Thread() { Thread::~Thread() {
assert(!searching); assert(!searching);
exit = true; exit = true;
start_searching(); start_searching();
stdThread.join(); stdThread.join();
} }
// Wakes up the thread that will start the search
/// Thread::clear() reset histories, usually before a new game
void Thread::clear() {
counterMoves.fill(MOVE_NONE);
mainHistory.fill(0);
captureHistory.fill(0);
for (bool inCheck : { false, true })
for (StatsType c : { NoCaptures, Captures })
for (auto& to : continuationHistory[inCheck][c])
for (auto& h : to)
h->fill(-71);
}
/// Thread::start_searching() wakes up the thread that will start the search
void Thread::start_searching() { void Thread::start_searching() {
mutex.lock(); assert(worker != nullptr);
searching = true; run_custom_job([this]() { worker->start_searching(); });
mutex.unlock(); // Unlock before notifying saves a few CPU-cycles
cv.notify_one(); // Wake up the thread in idle_loop()
} }
// Clears the histories for the thread worker (usually before a new game)
void Thread::clear_worker() {
assert(worker != nullptr);
run_custom_job([this]() { worker->clear(); });
}
/// Thread::wait_for_search_finished() blocks on the condition variable // Blocks on the condition variable until the thread has finished searching
/// until the thread has finished searching.
void Thread::wait_for_search_finished() { void Thread::wait_for_search_finished() {
std::unique_lock<std::mutex> lk(mutex); std::unique_lock<std::mutex> lk(mutex);
cv.wait(lk, [&]{ return !searching; }); cv.wait(lk, [&] { return !searching; });
} }
// Launching a function in the thread
void Thread::run_custom_job(std::function<void()> f) {
{
std::unique_lock<std::mutex> lk(mutex);
cv.wait(lk, [&] { return !searching; });
jobFunc = std::move(f);
searching = true;
}
cv.notify_one();
}
/// Thread::idle_loop() is where the thread is parked, blocked on the void Thread::ensure_network_replicated() { worker->ensure_network_replicated(); }
/// condition variable, when it has no work to do.
// Thread gets parked here, blocked on the condition variable
// when the thread has no work to do.
void Thread::idle_loop() { void Thread::idle_loop() {
while (true)
{
std::unique_lock<std::mutex> lk(mutex);
searching = false;
cv.notify_one(); // Wake up anyone waiting for search finished
cv.wait(lk, [&] { return searching; });
// If OS already scheduled us on a different group than 0 then don't overwrite if (exit)
// the choice, eventually we are one of many one-threaded processes running on return;
// some Windows NUMA hardware, for instance in fishtest. To make it simple,
// just check if running threads are below a threshold, in this case all this
// NUMA machinery is not needed.
if (Options["Threads"] > 8)
WinProcGroup::bindThisThread(idx);
while (true) std::function<void()> job = std::move(jobFunc);
{ jobFunc = nullptr;
std::unique_lock<std::mutex> lk(mutex);
searching = false;
cv.notify_one(); // Wake up anyone waiting for search finished
cv.wait(lk, [&]{ return searching; });
if (exit) lk.unlock();
return;
lk.unlock(); if (job)
job();
search(); }
}
} }
/// ThreadPool::set() creates/destroys threads to match the requested number. Search::SearchManager* ThreadPool::main_manager() { return main_thread()->worker->main_manager(); }
/// Created and launched threads will immediately go to sleep in idle_loop.
/// Upon resizing, threads are recreated to allow for binding if necessary.
void ThreadPool::set(size_t requested) { uint64_t ThreadPool::nodes_searched() const { return accumulate(&Search::Worker::nodes); }
uint64_t ThreadPool::tb_hits() const { return accumulate(&Search::Worker::tbHits); }
if (threads.size() > 0) // destroy any existing thread(s) // Creates/destroys threads to match the requested number.
{ // Created and launched threads will immediately go to sleep in idle_loop.
main()->wait_for_search_finished(); // Upon resizing, threads are recreated to allow for binding if necessary.
void ThreadPool::set(const NumaConfig& numaConfig,
Search::SharedState sharedState,
const Search::SearchManager::UpdateContext& updateContext) {
while (threads.size() > 0) if (threads.size() > 0) // destroy any existing thread(s)
delete threads.back(), threads.pop_back(); {
} main_thread()->wait_for_search_finished();
if (requested > 0) // create new thread(s) threads.clear();
{
threads.push_back(new MainThread(0));
while (threads.size() < requested) boundThreadToNumaNode.clear();
threads.push_back(new Thread(threads.size())); }
clear();
// Reallocate the hash with the new threadpool size const size_t requested = sharedState.options["Threads"];
TT.resize(size_t(Options["Hash"]));
// Init thread number dependent search params. if (requested > 0) // create new thread(s)
Search::init(); {
} // Binding threads may be problematic when there's multiple NUMA nodes and
// multiple Stockfish instances running. In particular, if each instance
// runs a single thread then they would all be mapped to the first NUMA node.
// This is undesirable, and so the default behaviour (i.e. when the user does not
// change the NumaConfig UCI setting) is to not bind the threads to processors
// unless we know for sure that we span NUMA nodes and replication is required.
const std::string numaPolicy(sharedState.options["NumaPolicy"]);
const bool doBindThreads = [&]() {
if (numaPolicy == "none")
return false;
if (numaPolicy == "auto")
return numaConfig.suggests_binding_threads(requested);
// numaPolicy == "system", or explicitly set by the user
return true;
}();
boundThreadToNumaNode = doBindThreads
? numaConfig.distribute_threads_among_numa_nodes(requested)
: std::vector<NumaIndex>{};
while (threads.size() < requested)
{
const size_t threadId = threads.size();
const NumaIndex numaId = doBindThreads ? boundThreadToNumaNode[threadId] : 0;
auto manager = threadId == 0 ? std::unique_ptr<Search::ISearchManager>(
std::make_unique<Search::SearchManager>(updateContext))
: std::make_unique<Search::NullSearchManager>();
// When not binding threads we want to force all access to happen
// from the same NUMA node, because in case of NUMA replicated memory
// accesses we don't want to trash cache in case the threads get scheduled
// on the same NUMA node.
auto binder = doBindThreads ? OptionalThreadToNumaNodeBinder(numaConfig, numaId)
: OptionalThreadToNumaNodeBinder(numaId);
threads.emplace_back(
std::make_unique<Thread>(sharedState, std::move(manager), threadId, binder));
}
clear();
main_thread()->wait_for_search_finished();
}
} }
/// ThreadPool::clear() sets threadPool data to initial values // Sets threadPool data to initial values
void ThreadPool::clear() { void ThreadPool::clear() {
if (threads.size() == 0)
return;
for (Thread* th : threads) for (auto&& th : threads)
th->clear(); th->clear_worker();
main()->callsCnt = 0; for (auto&& th : threads)
main()->bestPreviousScore = VALUE_INFINITE; th->wait_for_search_finished();
main()->bestPreviousAverageScore = VALUE_INFINITE;
main()->previousTimeReduction = 1.0; // These two affect the time taken on the first move of a game:
main_manager()->bestPreviousAverageScore = VALUE_INFINITE;
main_manager()->previousTimeReduction = 0.85;
main_manager()->callsCnt = 0;
main_manager()->bestPreviousScore = VALUE_INFINITE;
main_manager()->originalTimeAdjust = -1;
main_manager()->tm.clear();
} }
void ThreadPool::run_on_thread(size_t threadId, std::function<void()> f) {
assert(threads.size() > threadId);
threads[threadId]->run_custom_job(std::move(f));
}
/// ThreadPool::start_thinking() wakes up main thread waiting in idle_loop() and void ThreadPool::wait_on_thread(size_t threadId) {
/// returns immediately. Main thread will wake up other threads and start the search. assert(threads.size() > threadId);
threads[threadId]->wait_for_search_finished();
}
void ThreadPool::start_thinking(Position& pos, StateListPtr& states, size_t ThreadPool::num_threads() const { return threads.size(); }
const Search::LimitsType& limits, bool ponderMode) {
main()->wait_for_search_finished();
main()->stopOnPonderhit = stop = false; // Wakes up main thread waiting in idle_loop() and returns immediately.
increaseDepth = true; // Main thread will wake up other threads and start the search.
main()->ponder = ponderMode; void ThreadPool::start_thinking(const OptionsMap& options,
Search::Limits = limits; Position& pos,
Search::RootMoves rootMoves; StateListPtr& states,
Search::LimitsType limits) {
for (const auto& m : MoveList<LEGAL>(pos)) main_thread()->wait_for_search_finished();
if ( limits.searchmoves.empty()
|| std::count(limits.searchmoves.begin(), limits.searchmoves.end(), m))
rootMoves.emplace_back(m);
if (!rootMoves.empty()) main_manager()->stopOnPonderhit = stop = abortedSearch = false;
Tablebases::rank_root_moves(pos, rootMoves); main_manager()->ponder = limits.ponderMode;
// After ownership transfer 'states' becomes empty, so if we stop the search increaseDepth = true;
// and call 'go' again without setting a new position states.get() == nullptr.
assert(states.get() || setupStates.get());
if (states.get()) Search::RootMoves rootMoves;
setupStates = std::move(states); // Ownership transfer, states is now empty const auto legalmoves = MoveList<LEGAL>(pos);
// We use Position::set() to set root position across threads. But there are for (const auto& uciMove : limits.searchmoves)
// some StateInfo fields (previous, pliesFromNull, capturedPiece) that cannot {
// be deduced from a fen string, so set() clears them and they are set from auto move = UCIEngine::to_move(pos, uciMove);
// setupStates->back() later. The rootState is per thread, earlier states are shared
// since they are read-only.
for (Thread* th : threads)
{
th->nodes = th->tbHits = th->nmpMinPly = th->bestMoveChanges = 0;
th->rootDepth = th->completedDepth = 0;
th->rootMoves = rootMoves;
th->rootPos.set(pos.fen(), pos.is_chess960(), &th->rootState, th);
th->rootState = setupStates->back();
}
main()->start_searching(); if (std::find(legalmoves.begin(), legalmoves.end(), move) != legalmoves.end())
rootMoves.emplace_back(move);
}
if (rootMoves.empty())
for (const auto& m : legalmoves)
rootMoves.emplace_back(m);
Tablebases::Config tbConfig = Tablebases::rank_root_moves(options, pos, rootMoves);
// After ownership transfer 'states' becomes empty, so if we stop the search
// and call 'go' again without setting a new position states.get() == nullptr.
assert(states.get() || setupStates.get());
if (states.get())
setupStates = std::move(states); // Ownership transfer, states is now empty
// We use Position::set() to set root position across threads. But there are
// some StateInfo fields (previous, pliesFromNull, capturedPiece) that cannot
// be deduced from a fen string, so set() clears them and they are set from
// setupStates->back() later. The rootState is per thread, earlier states are
// shared since they are read-only.
for (auto&& th : threads)
{
th->run_custom_job([&]() {
th->worker->limits = limits;
th->worker->nodes = th->worker->tbHits = th->worker->nmpMinPly =
th->worker->bestMoveChanges = 0;
th->worker->rootDepth = th->worker->completedDepth = 0;
th->worker->rootMoves = rootMoves;
th->worker->rootPos.set(pos.fen(), pos.is_chess960(), &th->worker->rootState);
th->worker->rootState = setupStates->back();
th->worker->tbConfig = tbConfig;
});
}
for (auto&& th : threads)
th->wait_for_search_finished();
main_thread()->start_searching();
} }
Thread* ThreadPool::get_best_thread() const { Thread* ThreadPool::get_best_thread() const {
Thread* bestThread = threads.front(); Thread* bestThread = threads.front().get();
std::map<Move, int64_t> votes; Value minScore = VALUE_NONE;
Value minScore = VALUE_NONE;
// Find minimum score of all threads std::unordered_map<Move, int64_t, Move::MoveHash> votes(
for (Thread* th: threads) 2 * std::min(size(), bestThread->worker->rootMoves.size()));
minScore = std::min(minScore, th->rootMoves[0].score);
// Find the minimum score of all threads
for (auto&& th : threads)
minScore = std::min(minScore, th->worker->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
auto thread_value = [minScore](Thread* th) { auto thread_voting_value = [minScore](Thread* th) {
return (th->rootMoves[0].score - minScore + 14) * int(th->completedDepth); return (th->worker->rootMoves[0].score - minScore + 14) * int(th->worker->completedDepth);
}; };
for (Thread* th : threads) for (auto&& th : threads)
votes[th->rootMoves[0].pv[0]] += thread_value(th); votes[th->worker->rootMoves[0].pv[0]] += thread_voting_value(th.get());
for (Thread* th : threads) for (auto&& th : threads)
if (abs(bestThread->rootMoves[0].score) >= VALUE_TB_WIN_IN_MAX_PLY) {
const auto bestThreadScore = bestThread->worker->rootMoves[0].score;
const auto newThreadScore = th->worker->rootMoves[0].score;
const auto& bestThreadPV = bestThread->worker->rootMoves[0].pv;
const auto& newThreadPV = th->worker->rootMoves[0].pv;
const auto bestThreadMoveVote = votes[bestThreadPV[0]];
const auto newThreadMoveVote = votes[newThreadPV[0]];
const bool bestThreadInProvenWin = is_win(bestThreadScore);
const bool newThreadInProvenWin = is_win(newThreadScore);
const bool bestThreadInProvenLoss =
bestThreadScore != -VALUE_INFINITE && is_loss(bestThreadScore);
const bool newThreadInProvenLoss =
newThreadScore != -VALUE_INFINITE && is_loss(newThreadScore);
// We make sure not to pick a thread with truncated principal variation
const bool betterVotingValue =
thread_voting_value(th.get()) * int(newThreadPV.size() > 2)
> thread_voting_value(bestThread) * int(bestThreadPV.size() > 2);
if (bestThreadInProvenWin)
{ {
// Make sure we pick the shortest mate / TB conversion or stave off mate the longest // Make sure we pick the shortest mate / TB conversion
if (th->rootMoves[0].score > bestThread->rootMoves[0].score) if (newThreadScore > bestThreadScore)
bestThread = th; bestThread = th.get();
} }
else if ( th->rootMoves[0].score >= VALUE_TB_WIN_IN_MAX_PLY else if (bestThreadInProvenLoss)
|| ( th->rootMoves[0].score > VALUE_TB_LOSS_IN_MAX_PLY {
&& ( votes[th->rootMoves[0].pv[0]] > votes[bestThread->rootMoves[0].pv[0]] // Make sure we pick the shortest mated / TB conversion
|| ( votes[th->rootMoves[0].pv[0]] == votes[bestThread->rootMoves[0].pv[0]] if (newThreadInProvenLoss && newThreadScore < bestThreadScore)
&& thread_value(th) * int(th->rootMoves[0].pv.size() > 2) bestThread = th.get();
> thread_value(bestThread) * int(bestThread->rootMoves[0].pv.size() > 2))))) }
bestThread = th; else if (newThreadInProvenWin || newThreadInProvenLoss
|| (!is_loss(newThreadScore)
&& (newThreadMoveVote > bestThreadMoveVote
|| (newThreadMoveVote == bestThreadMoveVote && betterVotingValue))))
bestThread = th.get();
}
return bestThread; return bestThread;
} }
/// Start non-main threads // Start non-main threads.
// Will be invoked by main thread after it has started searching.
void ThreadPool::start_searching() { void ThreadPool::start_searching() {
for (Thread* th : threads) for (auto&& th : threads)
if (th != threads.front()) if (th != threads.front())
th->start_searching(); th->start_searching();
} }
/// Wait for non-main threads // Wait for non-main threads
void ThreadPool::wait_for_search_finished() const { void ThreadPool::wait_for_search_finished() const {
for (Thread* th : threads) for (auto&& th : threads)
if (th != threads.front()) if (th != threads.front())
th->wait_for_search_finished(); th->wait_for_search_finished();
} }
} // namespace Stockfish std::vector<size_t> ThreadPool::get_bound_thread_count_by_numa_node() const {
std::vector<size_t> counts;
if (!boundThreadToNumaNode.empty())
{
NumaIndex highestNumaNode = 0;
for (NumaIndex n : boundThreadToNumaNode)
if (n > highestNumaNode)
highestNumaNode = n;
counts.resize(highestNumaNode + 1, 0);
for (NumaIndex n : boundThreadToNumaNode)
counts[n] += 1;
}
return counts;
}
void ThreadPool::ensure_network_replicated() {
for (auto&& th : threads)
th->ensure_network_replicated();
}
} // namespace Stockfish
+131 -94
View File
@@ -1,6 +1,6 @@
/* /*
Stockfish, a UCI chess playing engine derived from Glaurung 2.1 Stockfish, a UCI chess playing engine derived from Glaurung 2.1
Copyright (C) 2004-2023 The Stockfish developers (see AUTHORS file) Copyright (C) 2004-2025 The Stockfish developers (see AUTHORS file)
Stockfish is free software: you can redistribute it and/or modify Stockfish is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by it under the terms of the GNU General Public License as published by
@@ -21,121 +21,158 @@
#include <atomic> #include <atomic>
#include <condition_variable> #include <condition_variable>
#include <cstddef>
#include <cstdint>
#include <functional>
#include <memory>
#include <mutex> #include <mutex>
#include <thread>
#include <vector> #include <vector>
#include "material.h" #include "numa.h"
#include "movepick.h"
#include "pawns.h"
#include "position.h" #include "position.h"
#include "search.h" #include "search.h"
#include "thread_win32_osx.h" #include "thread_win32_osx.h"
namespace Stockfish { namespace Stockfish {
/// Thread class keeps together all the thread-related stuff. We use
/// per-thread pawn and material hash tables so that once we get a
/// pointer to an entry its life time is unlimited and we don't have
/// to care about someone changing the entry under our feet.
class OptionsMap;
using Value = int;
// Sometimes we don't want to actually bind the threads, but the recipient still
// needs to think it runs on *some* NUMA node, such that it can access structures
// that rely on NUMA node knowledge. This class encapsulates this optional process
// such that the recipient does not need to know whether the binding happened or not.
class OptionalThreadToNumaNodeBinder {
public:
OptionalThreadToNumaNodeBinder(NumaIndex n) :
numaConfig(nullptr),
numaId(n) {}
OptionalThreadToNumaNodeBinder(const NumaConfig& cfg, NumaIndex n) :
numaConfig(&cfg),
numaId(n) {}
NumaReplicatedAccessToken operator()() const {
if (numaConfig != nullptr)
return numaConfig->bind_current_thread_to_numa_node(numaId);
else
return NumaReplicatedAccessToken(numaId);
}
private:
const NumaConfig* numaConfig;
NumaIndex numaId;
};
// Abstraction of a thread. It contains a pointer to the worker and a native thread.
// After construction, the native thread is started with idle_loop()
// waiting for a signal to start searching.
// When the signal is received, the thread starts searching and when
// the search is finished, it goes back to idle_loop() waiting for a new signal.
class Thread { class Thread {
public:
Thread(Search::SharedState&,
std::unique_ptr<Search::ISearchManager>,
size_t,
OptionalThreadToNumaNodeBinder);
virtual ~Thread();
std::mutex mutex; void idle_loop();
std::condition_variable cv; void start_searching();
size_t idx; void clear_worker();
bool exit = false, searching = true; // Set before starting std::thread void run_custom_job(std::function<void()> f);
NativeThread stdThread;
public: void ensure_network_replicated();
explicit Thread(size_t);
virtual ~Thread();
virtual void search();
void clear();
void idle_loop();
void start_searching();
void wait_for_search_finished();
size_t id() const { return idx; }
Pawns::Table pawnsTable; // Thread has been slightly altered to allow running custom jobs, so
Material::Table materialTable; // this name is no longer correct. However, this class (and ThreadPool)
size_t pvIdx, pvLast; // require further work to make them properly generic while maintaining
std::atomic<uint64_t> nodes, tbHits, bestMoveChanges; // appropriate specificity regarding search, from the point of view of an
int selDepth, nmpMinPly; // outside user, so renaming of this function is left for whenever that happens.
Value bestValue, optimism[COLOR_NB]; void wait_for_search_finished();
size_t id() const { return idx; }
Position rootPos; std::unique_ptr<Search::Worker> worker;
StateInfo rootState; std::function<void()> jobFunc;
Search::RootMoves rootMoves;
Depth rootDepth, completedDepth; private:
Value rootDelta; std::mutex mutex;
CounterMoveHistory counterMoves; std::condition_variable cv;
ButterflyHistory mainHistory; size_t idx, nthreads;
CapturePieceToHistory captureHistory; bool exit = false, searching = true; // Set before starting std::thread
ContinuationHistory continuationHistory[2][2]; NativeThread stdThread;
NumaReplicatedAccessToken numaAccessToken;
}; };
/// MainThread is a derived class specific for main thread // ThreadPool struct handles all the threads-related stuff like init, starting,
// parking and, most importantly, launching a thread. All the access to threads
// is done through this class.
class ThreadPool {
public:
ThreadPool() {}
struct MainThread : public Thread { ~ThreadPool() {
// destroy any existing thread(s)
if (threads.size() > 0)
{
main_thread()->wait_for_search_finished();
using Thread::Thread; threads.clear();
}
}
void search() override; ThreadPool(const ThreadPool&) = delete;
void check_time(); ThreadPool(ThreadPool&&) = delete;
double previousTimeReduction; ThreadPool& operator=(const ThreadPool&) = delete;
Value bestPreviousScore; ThreadPool& operator=(ThreadPool&&) = delete;
Value bestPreviousAverageScore;
Value iterValue[4]; void start_thinking(const OptionsMap&, Position&, StateListPtr&, Search::LimitsType);
int callsCnt; void run_on_thread(size_t threadId, std::function<void()> f);
bool stopOnPonderhit; void wait_on_thread(size_t threadId);
std::atomic_bool ponder; size_t num_threads() const;
void clear();
void set(const NumaConfig& numaConfig,
Search::SharedState,
const Search::SearchManager::UpdateContext&);
Search::SearchManager* main_manager();
Thread* main_thread() const { return threads.front().get(); }
uint64_t nodes_searched() const;
uint64_t tb_hits() const;
Thread* get_best_thread() const;
void start_searching();
void wait_for_search_finished() const;
std::vector<size_t> get_bound_thread_count_by_numa_node() const;
void ensure_network_replicated();
std::atomic_bool stop, abortedSearch, increaseDepth;
auto cbegin() const noexcept { return threads.cbegin(); }
auto begin() noexcept { return threads.begin(); }
auto end() noexcept { return threads.end(); }
auto cend() const noexcept { return threads.cend(); }
auto size() const noexcept { return threads.size(); }
auto empty() const noexcept { return threads.empty(); }
private:
StateListPtr setupStates;
std::vector<std::unique_ptr<Thread>> threads;
std::vector<NumaIndex> boundThreadToNumaNode;
uint64_t accumulate(std::atomic<uint64_t> Search::Worker::*member) const {
uint64_t sum = 0;
for (auto&& th : threads)
sum += (th->worker.get()->*member).load(std::memory_order_relaxed);
return sum;
}
}; };
} // namespace Stockfish
/// ThreadPool struct handles all the threads-related stuff like init, starting, #endif // #ifndef THREAD_H_INCLUDED
/// parking and, most importantly, launching a thread. All the access to threads
/// is done through this class.
struct ThreadPool {
void start_thinking(Position&, StateListPtr&, const Search::LimitsType&, bool = false);
void clear();
void set(size_t);
MainThread* main() const { return static_cast<MainThread*>(threads.front()); }
uint64_t nodes_searched() const { return accumulate(&Thread::nodes); }
uint64_t tb_hits() const { return accumulate(&Thread::tbHits); }
Thread* get_best_thread() const;
void start_searching();
void wait_for_search_finished() const;
std::atomic_bool stop, increaseDepth;
auto cbegin() const noexcept { return threads.cbegin(); }
auto begin() noexcept { return threads.begin(); }
auto end() noexcept { return threads.end(); }
auto cend() const noexcept { return threads.cend(); }
auto size() const noexcept { return threads.size(); }
auto empty() const noexcept { return threads.empty(); }
private:
StateListPtr setupStates;
std::vector<Thread*> threads;
uint64_t accumulate(std::atomic<uint64_t> Thread::* member) const {
uint64_t sum = 0;
for (Thread* th : threads)
sum += (th->*member).load(std::memory_order_relaxed);
return sum;
}
};
extern ThreadPool Threads;
} // namespace Stockfish
#endif // #ifndef THREAD_H_INCLUDED
+36 -32
View File
@@ -1,6 +1,6 @@
/* /*
Stockfish, a UCI chess playing engine derived from Glaurung 2.1 Stockfish, a UCI chess playing engine derived from Glaurung 2.1
Copyright (C) 2004-2023 The Stockfish developers (see AUTHORS file) Copyright (C) 2004-2025 The Stockfish developers (see AUTHORS file)
Stockfish is free software: you can redistribute it and/or modify Stockfish is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by it under the terms of the GNU General Public License as published by
@@ -21,54 +21,58 @@
#include <thread> #include <thread>
/// On OSX threads other than the main thread are created with a reduced stack // On OSX threads other than the main thread are created with a reduced stack
/// size of 512KB by default, this is too low for deep searches, which require // size of 512KB by default, this is too low for deep searches, which require
/// somewhat more than 1MB stack, so adjust it to TH_STACK_SIZE. // somewhat more than 1MB stack, so adjust it to TH_STACK_SIZE.
/// The implementation calls pthread_create() with the stack size parameter // The implementation calls pthread_create() with the stack size parameter
/// equal to the linux 8MB default, on platforms that support it. // equal to the Linux 8MB default, on platforms that support it.
#if defined(__APPLE__) || defined(__MINGW32__) || defined(__MINGW64__) || defined(USE_PTHREADS) #if defined(__APPLE__) || defined(__MINGW32__) || defined(__MINGW64__) || defined(USE_PTHREADS)
#include <pthread.h> #include <pthread.h>
#include <functional>
namespace Stockfish { namespace Stockfish {
static const size_t TH_STACK_SIZE = 8 * 1024 * 1024;
template <class T, class P = std::pair<T*, void(T::*)()>>
void* start_routine(void* ptr)
{
P* p = reinterpret_cast<P*>(ptr);
(p->first->*(p->second))(); // Call member function pointer
delete p;
return nullptr;
}
class NativeThread { class NativeThread {
pthread_t thread;
pthread_t thread; static constexpr size_t TH_STACK_SIZE = 8 * 1024 * 1024;
public: public:
template<class T, class P = std::pair<T*, void(T::*)()>> template<class Function, class... Args>
explicit NativeThread(void(T::*fun)(), T* obj) { explicit NativeThread(Function&& fun, Args&&... args) {
pthread_attr_t attr_storage, *attr = &attr_storage; auto func = new std::function<void()>(
pthread_attr_init(attr); std::bind(std::forward<Function>(fun), std::forward<Args>(args)...));
pthread_attr_setstacksize(attr, TH_STACK_SIZE);
pthread_create(&thread, attr, start_routine<T>, new P(obj, fun)); pthread_attr_t attr_storage, *attr = &attr_storage;
} pthread_attr_init(attr);
void join() { pthread_join(thread, nullptr); } pthread_attr_setstacksize(attr, TH_STACK_SIZE);
auto start_routine = [](void* ptr) -> void* {
auto f = reinterpret_cast<std::function<void()>*>(ptr);
// Call the function
(*f)();
delete f;
return nullptr;
};
pthread_create(&thread, attr, start_routine, func);
}
void join() { pthread_join(thread, nullptr); }
}; };
} // namespace Stockfish } // namespace Stockfish
#else // Default case: use STL classes #else // Default case: use STL classes
namespace Stockfish { namespace Stockfish {
using NativeThread = std::thread; using NativeThread = std::thread;
} // namespace Stockfish } // namespace Stockfish
#endif #endif
#endif // #ifndef THREAD_WIN32_OSX_H_INCLUDED #endif // #ifndef THREAD_WIN32_OSX_H_INCLUDED
+116 -82
View File
@@ -1,6 +1,6 @@
/* /*
Stockfish, a UCI chess playing engine derived from Glaurung 2.1 Stockfish, a UCI chess playing engine derived from Glaurung 2.1
Copyright (C) 2004-2023 The Stockfish developers (see AUTHORS file) Copyright (C) 2004-2025 The Stockfish developers (see AUTHORS file)
Stockfish is free software: you can redistribute it and/or modify Stockfish is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by it under the terms of the GNU General Public License as published by
@@ -16,94 +16,128 @@
along with this program. If not, see <http://www.gnu.org/licenses/>. along with this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
#include "timeman.h"
#include <algorithm> #include <algorithm>
#include <cfloat> #include <cassert>
#include <cmath> #include <cmath>
#include <cstdint>
#include "search.h" #include "search.h"
#include "timeman.h" #include "ucioption.h"
#include "uci.h"
namespace Stockfish { namespace Stockfish {
TimeManagement Time; // Our global time management object TimePoint TimeManagement::optimum() const { return optimumTime; }
TimePoint TimeManagement::maximum() const { return maximumTime; }
void TimeManagement::clear() {
/// TimeManagement::init() is called at the beginning of the search and calculates availableNodes = -1; // When in 'nodes as time' mode
/// the bounds of time allowed for the current game ply. We currently support:
// 1) x basetime (+ z increment)
// 2) x moves in y seconds (+ z increment)
void TimeManagement::init(Search::LimitsType& limits, Color us, int ply) {
// if we have no time, no need to initialize TM, except for the start time,
// which is used by movetime.
startTime = limits.startTime;
if (limits.time[us] == 0)
return;
TimePoint moveOverhead = TimePoint(Options["Move Overhead"]);
TimePoint slowMover = TimePoint(Options["Slow Mover"]);
TimePoint npmsec = TimePoint(Options["nodestime"]);
// optScale is a percentage of available time to use for the current move.
// maxScale is a multiplier applied to optimumTime.
double optScale, maxScale;
// If we have to play in 'nodes as time' mode, then convert from time
// to nodes, and use resulting values in time management formulas.
// WARNING: to avoid time losses, the given npmsec (nodes per millisecond)
// must be much lower than the real engine speed.
if (npmsec)
{
if (!availableNodes) // Only once at game start
availableNodes = npmsec * limits.time[us]; // Time is in msec
// Convert from milliseconds to nodes
limits.time[us] = TimePoint(availableNodes);
limits.inc[us] *= npmsec;
limits.npmsec = npmsec;
}
// Maximum move horizon of 50 moves
int mtg = limits.movestogo ? std::min(limits.movestogo, 50) : 50;
// Make sure timeLeft is > 0 since we may use it as a divisor
TimePoint timeLeft = std::max(TimePoint(1),
limits.time[us] + limits.inc[us] * (mtg - 1) - moveOverhead * (2 + mtg));
// Use extra time with larger increments
double optExtra = std::clamp(1.0 + 12.0 * limits.inc[us] / limits.time[us], 1.0, 1.12);
// A user may scale time usage by setting UCI option "Slow Mover"
// Default is 100 and changing this value will probably lose elo.
timeLeft = slowMover * timeLeft / 100;
// x basetime (+ z increment)
// If there is a healthy increment, timeLeft can exceed actual available
// game time for the current move, so also cap to 20% of available game time.
if (limits.movestogo == 0)
{
optScale = std::min(0.0120 + std::pow(ply + 3.0, 0.45) * 0.0039,
0.2 * limits.time[us] / double(timeLeft))
* optExtra;
maxScale = std::min(7.0, 4.0 + ply / 12.0);
}
// x moves in y seconds (+ z increment)
else
{
optScale = std::min((0.88 + ply / 116.4) / mtg,
0.88 * limits.time[us] / double(timeLeft));
maxScale = std::min(6.3, 1.5 + 0.11 * mtg);
}
// Never use more than 80% of the available time for this move
optimumTime = TimePoint(optScale * timeLeft);
maximumTime = TimePoint(std::min(0.8 * limits.time[us] - moveOverhead, maxScale * optimumTime));
if (Options["Ponder"])
optimumTime += optimumTime / 4;
} }
} // namespace Stockfish void TimeManagement::advance_nodes_time(std::int64_t nodes) {
assert(useNodesTime);
availableNodes = std::max(int64_t(0), availableNodes - nodes);
}
// Called at the beginning of the search and calculates
// the bounds of time allowed for the current game ply. We currently support:
// 1) x basetime (+ z increment)
// 2) x moves in y seconds (+ z increment)
void TimeManagement::init(Search::LimitsType& limits,
Color us,
int ply,
const OptionsMap& options,
double& originalTimeAdjust) {
TimePoint npmsec = TimePoint(options["nodestime"]);
// If we have no time, we don't need to fully initialize TM.
// startTime is used by movetime and useNodesTime is used in elapsed calls.
startTime = limits.startTime;
useNodesTime = npmsec != 0;
if (limits.time[us] == 0)
return;
TimePoint moveOverhead = TimePoint(options["Move Overhead"]);
// optScale is a percentage of available time to use for the current move.
// maxScale is a multiplier applied to optimumTime.
double optScale, maxScale;
// If we have to play in 'nodes as time' mode, then convert from time
// to nodes, and use resulting values in time management formulas.
// WARNING: to avoid time losses, the given npmsec (nodes per millisecond)
// must be much lower than the real engine speed.
if (useNodesTime)
{
if (availableNodes == -1) // Only once at game start
availableNodes = npmsec * limits.time[us]; // Time is in msec
// Convert from milliseconds to nodes
limits.time[us] = TimePoint(availableNodes);
limits.inc[us] *= npmsec;
limits.npmsec = npmsec;
moveOverhead *= npmsec;
}
// These numbers are used where multiplications, divisions or comparisons
// with constants are involved.
const int64_t scaleFactor = useNodesTime ? npmsec : 1;
const TimePoint scaledTime = limits.time[us] / scaleFactor;
const TimePoint scaledInc = limits.inc[us] / scaleFactor;
// Maximum move horizon
int centiMTG = limits.movestogo ? std::min(limits.movestogo * 100, 5000) : 5051;
// If less than one second, gradually reduce mtg
if (scaledTime < 1000 && double(centiMTG) / scaledInc > 5.051)
{
centiMTG = scaledTime * 5.051;
}
// Make sure timeLeft is > 0 since we may use it as a divisor
TimePoint timeLeft =
std::max(TimePoint(1),
limits.time[us]
+ (limits.inc[us] * (centiMTG - 100) - moveOverhead * (200 + centiMTG)) / 100);
// x basetime (+ z increment)
// If there is a healthy increment, timeLeft can exceed the actual available
// game time for the current move, so also cap to a percentage of available game time.
if (limits.movestogo == 0)
{
// Extra time according to timeLeft
if (originalTimeAdjust < 0)
originalTimeAdjust = 0.3128 * std::log10(timeLeft) - 0.4354;
// Calculate time constants based on current time left.
double logTimeInSec = std::log10(scaledTime / 1000.0);
double optConstant = std::min(0.0032116 + 0.000321123 * logTimeInSec, 0.00508017);
double maxConstant = std::max(3.3977 + 3.03950 * logTimeInSec, 2.94761);
optScale = std::min(0.0121431 + std::pow(ply + 2.94693, 0.461073) * optConstant,
0.213035 * limits.time[us] / timeLeft)
* originalTimeAdjust;
maxScale = std::min(6.67704, maxConstant + ply / 11.9847);
}
// x moves in y seconds (+ z increment)
else
{
optScale =
std::min((0.88 + ply / 116.4) / (centiMTG / 100.0), 0.88 * limits.time[us] / timeLeft);
maxScale = 1.3 + 0.11 * (centiMTG / 100.0);
}
// Limit the maximum possible time for this move
optimumTime = TimePoint(optScale * timeLeft);
maximumTime =
TimePoint(std::min(0.825179 * limits.time[us] - moveOverhead, maxScale * optimumTime)) - 10;
if (options["Ponder"])
optimumTime += optimumTime / 4;
}
} // namespace Stockfish
+36 -20
View File
@@ -1,6 +1,6 @@
/* /*
Stockfish, a UCI chess playing engine derived from Glaurung 2.1 Stockfish, a UCI chess playing engine derived from Glaurung 2.1
Copyright (C) 2004-2023 The Stockfish developers (see AUTHORS file) Copyright (C) 2004-2025 The Stockfish developers (see AUTHORS file)
Stockfish is free software: you can redistribute it and/or modify Stockfish is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by it under the terms of the GNU General Public License as published by
@@ -19,33 +19,49 @@
#ifndef TIMEMAN_H_INCLUDED #ifndef TIMEMAN_H_INCLUDED
#define TIMEMAN_H_INCLUDED #define TIMEMAN_H_INCLUDED
#include <cstdint>
#include "misc.h" #include "misc.h"
#include "search.h" #include "types.h"
#include "thread.h"
namespace Stockfish { namespace Stockfish {
/// The TimeManagement class computes the optimal time to think depending on class OptionsMap;
/// the maximum available time, the game move number and other parameters.
namespace Search {
struct LimitsType;
}
// The TimeManagement class computes the optimal time to think depending on
// the maximum available time, the game move number, and other parameters.
class TimeManagement { class TimeManagement {
public: public:
void init(Search::LimitsType& limits, Color us, int ply); void init(Search::LimitsType& limits,
TimePoint optimum() const { return optimumTime; } Color us,
TimePoint maximum() const { return maximumTime; } int ply,
TimePoint elapsed() const { return Search::Limits.npmsec ? const OptionsMap& options,
TimePoint(Threads.nodes_searched()) : now() - startTime; } double& originalTimeAdjust);
int64_t availableNodes; // When in 'nodes as time' mode TimePoint optimum() const;
TimePoint maximum() const;
template<typename FUNC>
TimePoint elapsed(FUNC nodes) const {
return useNodesTime ? TimePoint(nodes()) : elapsed_time();
}
TimePoint elapsed_time() const { return now() - startTime; };
private: void clear();
TimePoint startTime; void advance_nodes_time(std::int64_t nodes);
TimePoint optimumTime;
TimePoint maximumTime; private:
TimePoint startTime;
TimePoint optimumTime;
TimePoint maximumTime;
std::int64_t availableNodes = -1; // When in 'nodes as time' mode
bool useNodesTime = false; // True if we are in 'nodes as time' mode
}; };
extern TimeManagement Time; } // namespace Stockfish
} // namespace Stockfish #endif // #ifndef TIMEMAN_H_INCLUDED
#endif // #ifndef TIMEMAN_H_INCLUDED
+201 -112
View File
@@ -1,6 +1,6 @@
/* /*
Stockfish, a UCI chess playing engine derived from Glaurung 2.1 Stockfish, a UCI chess playing engine derived from Glaurung 2.1
Copyright (C) 2004-2023 The Stockfish developers (see AUTHORS file) Copyright (C) 2004-2025 The Stockfish developers (see AUTHORS file)
Stockfish is free software: you can redistribute it and/or modify Stockfish is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by it under the terms of the GNU General Public License as published by
@@ -16,147 +16,236 @@
along with this program. If not, see <http://www.gnu.org/licenses/>. along with this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
#include <cstring> // For std::memset
#include <iostream>
#include <thread>
#include "bitboard.h"
#include "misc.h"
#include "thread.h"
#include "tt.h" #include "tt.h"
#include "uci.h"
#include <cassert>
#include <cstdint>
#include <cstdlib>
#include <cstring>
#include <iostream>
#include "memory.h"
#include "misc.h"
#include "syzygy/tbprobe.h"
#include "thread.h"
namespace Stockfish { namespace Stockfish {
TranspositionTable TT; // Our global transposition table
/// TTEntry::save() populates the TTEntry with a new node's data, possibly // TTEntry struct is the 10 bytes transposition table entry, defined as below:
/// overwriting an old position. Update is not atomic and can be racy. //
// key 16 bit
// depth 8 bit
// generation 5 bit
// pv node 1 bit
// bound type 2 bit
// move 16 bit
// value 16 bit
// evaluation 16 bit
//
// These fields are in the same order as accessed by TT::probe(), since memory is fastest sequentially.
// Equally, the store order in save() matches this order.
void TTEntry::save(Key k, Value v, bool pv, Bound b, Depth d, Move m, Value ev) { struct TTEntry {
// Preserve any existing move for the same position // Convert internal bitfields to external types
if (m || (uint16_t)k != key16) TTData read() const {
move16 = (uint16_t)m; return TTData{Move(move16), Value(value16),
Value(eval16), Depth(depth8 + DEPTH_ENTRY_OFFSET),
Bound(genBound8 & 0x3), bool(genBound8 & 0x4)};
}
// Overwrite less valuable entries (cheapest checks first) bool is_occupied() const;
if ( b == BOUND_EXACT void save(Key k, Value v, bool pv, Bound b, Depth d, Move m, Value ev, uint8_t generation8);
|| (uint16_t)k != key16 // The returned age is a multiple of TranspositionTable::GENERATION_DELTA
|| d - DEPTH_OFFSET + 2 * pv > depth8 - 4) uint8_t relative_age(const uint8_t generation8) const;
{
assert(d > DEPTH_OFFSET);
assert(d < 256 + DEPTH_OFFSET);
key16 = (uint16_t)k; private:
depth8 = (uint8_t)(d - DEPTH_OFFSET); friend class TranspositionTable;
genBound8 = (uint8_t)(TT.generation8 | uint8_t(pv) << 2 | b);
value16 = (int16_t)v; uint16_t key16;
eval16 = (int16_t)ev; uint8_t depth8;
} uint8_t genBound8;
Move move16;
int16_t value16;
int16_t eval16;
};
// `genBound8` is where most of the details are. We use the following constants to manipulate 5 leading generation bits
// and 3 trailing miscellaneous bits.
// These bits are reserved for other things.
static constexpr unsigned GENERATION_BITS = 3;
// increment for generation field
static constexpr int GENERATION_DELTA = (1 << GENERATION_BITS);
// cycle length
static constexpr int GENERATION_CYCLE = 255 + GENERATION_DELTA;
// mask to pull out generation number
static constexpr int GENERATION_MASK = (0xFF << GENERATION_BITS) & 0xFF;
// DEPTH_ENTRY_OFFSET exists because 1) we use `bool(depth8)` as the occupancy check, but
// 2) we need to store negative depths for QS. (`depth8` is the only field with "spare bits":
// we sacrifice the ability to store depths greater than 1<<8 less the offset, as asserted in `save`.)
bool TTEntry::is_occupied() const { return bool(depth8); }
// Populates the TTEntry with a new node's data, possibly
// overwriting an old position. The update is not atomic and can be racy.
void TTEntry::save(
Key k, Value v, bool pv, Bound b, Depth d, Move m, Value ev, uint8_t generation8) {
// Preserve the old ttmove if we don't have a new one
if (m || uint16_t(k) != key16)
move16 = m;
// Overwrite less valuable entries (cheapest checks first)
if (b == BOUND_EXACT || uint16_t(k) != key16 || d - DEPTH_ENTRY_OFFSET + 2 * pv > depth8 - 4
|| relative_age(generation8))
{
assert(d > DEPTH_ENTRY_OFFSET);
assert(d < 256 + DEPTH_ENTRY_OFFSET);
key16 = uint16_t(k);
depth8 = uint8_t(d - DEPTH_ENTRY_OFFSET);
genBound8 = uint8_t(generation8 | uint8_t(pv) << 2 | b);
value16 = int16_t(v);
eval16 = int16_t(ev);
}
} }
/// TranspositionTable::resize() sets the size of the transposition table, uint8_t TTEntry::relative_age(const uint8_t generation8) const {
/// measured in megabytes. Transposition table consists of a power of 2 number // Due to our packed storage format for generation and its cyclic
/// of clusters and each cluster consists of ClusterSize number of TTEntry. // nature we add GENERATION_CYCLE (256 is the modulus, plus what
// is needed to keep the unrelated lowest n bits from affecting
void TranspositionTable::resize(size_t mbSize) { // the result) to calculate the entry age correctly even after
// generation8 overflows into the next cycle.
Threads.main()->wait_for_search_finished(); return (GENERATION_CYCLE + generation8 - genBound8) & GENERATION_MASK;
aligned_large_pages_free(table);
clusterCount = mbSize * 1024 * 1024 / sizeof(Cluster);
table = static_cast<Cluster*>(aligned_large_pages_alloc(clusterCount * sizeof(Cluster)));
if (!table)
{
std::cerr << "Failed to allocate " << mbSize
<< "MB for transposition table." << std::endl;
exit(EXIT_FAILURE);
}
clear();
} }
/// TranspositionTable::clear() initializes the entire transposition table to zero, // TTWriter is but a very thin wrapper around the pointer
// in a multi-threaded way. TTWriter::TTWriter(TTEntry* tte) :
entry(tte) {}
void TranspositionTable::clear() { void TTWriter::write(
Key k, Value v, bool pv, Bound b, Depth d, Move m, Value ev, uint8_t generation8) {
std::vector<std::thread> threads; entry->save(k, v, pv, b, d, m, ev, generation8);
for (size_t idx = 0; idx < size_t(Options["Threads"]); ++idx)
{
threads.emplace_back([this, idx]() {
// Thread binding gives faster search on systems with a first-touch policy
if (Options["Threads"] > 8)
WinProcGroup::bindThisThread(idx);
// Each thread will zero its part of the hash table
const size_t stride = size_t(clusterCount / Options["Threads"]),
start = size_t(stride * idx),
len = idx != size_t(Options["Threads"]) - 1 ?
stride : clusterCount - start;
std::memset(&table[start], 0, len * sizeof(Cluster));
});
}
for (std::thread& th : threads)
th.join();
} }
/// TranspositionTable::probe() looks up the current position in the transposition // A TranspositionTable is an array of Cluster, of size clusterCount. Each cluster consists of ClusterSize number
/// table. It returns true and a pointer to the TTEntry if the position is found. // of TTEntry. Each non-empty TTEntry contains information on exactly one position. The size of a Cluster should
/// Otherwise, it returns false and a pointer to an empty or least valuable TTEntry // divide the size of a cache line for best performance, as the cacheline is prefetched when possible.
/// to be replaced later. The replace value of an entry is calculated as its depth
/// minus 8 times its relative age. TTEntry t1 is considered more valuable than
/// TTEntry t2 if its replace value is greater than that of t2.
TTEntry* TranspositionTable::probe(const Key key, bool& found) const { static constexpr int ClusterSize = 3;
TTEntry* const tte = first_entry(key); struct Cluster {
const uint16_t key16 = (uint16_t)key; // Use the low 16 bits as key inside the cluster TTEntry entry[ClusterSize];
char padding[2]; // Pad to 32 bytes
};
for (int i = 0; i < ClusterSize; ++i) static_assert(sizeof(Cluster) == 32, "Suboptimal Cluster size");
if (tte[i].key16 == key16 || !tte[i].depth8)
{
tte[i].genBound8 = uint8_t(generation8 | (tte[i].genBound8 & (GENERATION_DELTA - 1))); // Refresh
return found = (bool)tte[i].depth8, &tte[i];
}
// Find an entry to be replaced according to the replacement strategy // Sets the size of the transposition table,
TTEntry* replace = tte; // measured in megabytes. Transposition table consists
for (int i = 1; i < ClusterSize; ++i) // of clusters and each cluster consists of ClusterSize number of TTEntry.
// Due to our packed storage format for generation and its cyclic void TranspositionTable::resize(size_t mbSize, ThreadPool& threads) {
// nature we add GENERATION_CYCLE (256 is the modulus, plus what aligned_large_pages_free(table);
// is needed to keep the unrelated lowest n bits from affecting
// the result) to calculate the entry age correctly even after
// generation8 overflows into the next cycle.
if ( replace->depth8 - ((GENERATION_CYCLE + generation8 - replace->genBound8) & GENERATION_MASK)
> tte[i].depth8 - ((GENERATION_CYCLE + generation8 - tte[i].genBound8) & GENERATION_MASK))
replace = &tte[i];
return found = false, replace; clusterCount = mbSize * 1024 * 1024 / sizeof(Cluster);
table = static_cast<Cluster*>(aligned_large_pages_alloc(clusterCount * sizeof(Cluster)));
if (!table)
{
std::cerr << "Failed to allocate " << mbSize << "MB for transposition table." << std::endl;
exit(EXIT_FAILURE);
}
clear(threads);
} }
/// TranspositionTable::hashfull() returns an approximation of the hashtable // Initializes the entire transposition table to zero,
/// occupation during a search. The hash is x permill full, as per UCI protocol. // in a multi-threaded way.
void TranspositionTable::clear(ThreadPool& threads) {
generation8 = 0;
const size_t threadCount = threads.num_threads();
int TranspositionTable::hashfull() const { for (size_t i = 0; i < threadCount; ++i)
{
threads.run_on_thread(i, [this, i, threadCount]() {
// Each thread will zero its part of the hash table
const size_t stride = clusterCount / threadCount;
const size_t start = stride * i;
const size_t len = i + 1 != threadCount ? stride : clusterCount - start;
int cnt = 0; std::memset(&table[start], 0, len * sizeof(Cluster));
for (int i = 0; i < 1000; ++i) });
for (int j = 0; j < ClusterSize; ++j) }
cnt += table[i].entry[j].depth8 && (table[i].entry[j].genBound8 & GENERATION_MASK) == generation8;
return cnt / ClusterSize; for (size_t i = 0; i < threadCount; ++i)
threads.wait_on_thread(i);
} }
} // namespace Stockfish
// Returns an approximation of the hashtable
// occupation during a search. The hash is x permill full, as per UCI protocol.
// Only counts entries which match the current generation.
int TranspositionTable::hashfull(int maxAge) const {
int maxAgeInternal = maxAge << GENERATION_BITS;
int cnt = 0;
for (int i = 0; i < 1000; ++i)
for (int j = 0; j < ClusterSize; ++j)
cnt += table[i].entry[j].is_occupied()
&& table[i].entry[j].relative_age(generation8) <= maxAgeInternal;
return cnt / ClusterSize;
}
void TranspositionTable::new_search() {
// increment by delta to keep lower bits as is
generation8 += GENERATION_DELTA;
}
uint8_t TranspositionTable::generation() const { return generation8; }
// Looks up the current position in the transposition
// table. It returns true if the position is found.
// Otherwise, it returns false and a pointer to an empty or least valuable TTEntry
// to be replaced later. The replace value of an entry is calculated as its depth
// minus 8 times its relative age. TTEntry t1 is considered more valuable than
// TTEntry t2 if its replace value is greater than that of t2.
std::tuple<bool, TTData, TTWriter> TranspositionTable::probe(const Key key) const {
TTEntry* const tte = first_entry(key);
const uint16_t key16 = uint16_t(key); // Use the low 16 bits as key inside the cluster
for (int i = 0; i < ClusterSize; ++i)
if (tte[i].key16 == key16)
// This gap is the main place for read races.
// After `read()` completes that copy is final, but may be self-inconsistent.
return {tte[i].is_occupied(), tte[i].read(), TTWriter(&tte[i])};
// Find an entry to be replaced according to the replacement strategy
TTEntry* replace = tte;
for (int i = 1; i < ClusterSize; ++i)
if (replace->depth8 - replace->relative_age(generation8) * 2
> tte[i].depth8 - tte[i].relative_age(generation8) * 2)
replace = &tte[i];
return {false,
TTData{Move::none(), VALUE_NONE, VALUE_NONE, DEPTH_ENTRY_OFFSET, BOUND_NONE, false},
TTWriter(replace)};
}
TTEntry* TranspositionTable::first_entry(const Key key) const {
return &table[mul_hi64(key, clusterCount)].entry[0];
}
} // namespace Stockfish
+68 -65
View File
@@ -1,6 +1,6 @@
/* /*
Stockfish, a UCI chess playing engine derived from Glaurung 2.1 Stockfish, a UCI chess playing engine derived from Glaurung 2.1
Copyright (C) 2004-2023 The Stockfish developers (see AUTHORS file) Copyright (C) 2004-2025 The Stockfish developers (see AUTHORS file)
Stockfish is free software: you can redistribute it and/or modify Stockfish is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by it under the terms of the GNU General Public License as published by
@@ -19,89 +19,92 @@
#ifndef TT_H_INCLUDED #ifndef TT_H_INCLUDED
#define TT_H_INCLUDED #define TT_H_INCLUDED
#include "misc.h" #include <cstddef>
#include <cstdint>
#include <tuple>
#include "memory.h"
#include "types.h" #include "types.h"
namespace Stockfish { namespace Stockfish {
/// TTEntry struct is the 10 bytes transposition table entry, defined as below: class ThreadPool;
/// struct TTEntry;
/// key 16 bit struct Cluster;
/// depth 8 bit
/// generation 5 bit
/// pv node 1 bit
/// bound type 2 bit
/// move 16 bit
/// value 16 bit
/// eval value 16 bit
struct TTEntry { // There is only one global hash table for the engine and all its threads. For chess in particular, we even allow racy
// updates between threads to and from the TT, as taking the time to synchronize access would cost thinking time and
// thus elo. As a hash table, collisions are possible and may cause chess playing issues (bizarre blunders, faulty mate
// reports, etc). Fixing these also loses elo; however such risk decreases quickly with larger TT size.
//
// `probe` is the primary method: given a board position, we lookup its entry in the table, and return a tuple of:
// 1) whether the entry already has this position
// 2) a copy of the prior data (if any) (may be inconsistent due to read races)
// 3) a writer object to this entry
// The copied data and the writer are separated to maintain clear boundaries between local vs global objects.
Move move() const { return (Move )move16; }
Value value() const { return (Value)value16; }
Value eval() const { return (Value)eval16; }
Depth depth() const { return (Depth)depth8 + DEPTH_OFFSET; }
bool is_pv() const { return (bool)(genBound8 & 0x4); }
Bound bound() const { return (Bound)(genBound8 & 0x3); }
void save(Key k, Value v, bool pv, Bound b, Depth d, Move m, Value ev);
private: // A copy of the data already in the entry (possibly collided). `probe` may be racy, resulting in inconsistent data.
friend class TranspositionTable; struct TTData {
Move move;
Value value, eval;
Depth depth;
Bound bound;
bool is_pv;
uint16_t key16; TTData() = delete;
uint8_t depth8;
uint8_t genBound8; // clang-format off
uint16_t move16; TTData(Move m, Value v, Value ev, Depth d, Bound b, bool pv) :
int16_t value16; move(m),
int16_t eval16; value(v),
eval(ev),
depth(d),
bound(b),
is_pv(pv) {};
// clang-format on
}; };
/// A TranspositionTable is an array of Cluster, of size clusterCount. Each // This is used to make racy writes to the global TT.
/// cluster consists of ClusterSize number of TTEntry. Each non-empty TTEntry struct TTWriter {
/// contains information on exactly one position. The size of a Cluster should public:
/// divide the size of a cache line for best performance, as the cacheline is void write(Key k, Value v, bool pv, Bound b, Depth d, Move m, Value ev, uint8_t generation8);
/// prefetched when possible.
private:
friend class TranspositionTable;
TTEntry* entry;
TTWriter(TTEntry* tte);
};
class TranspositionTable { class TranspositionTable {
static constexpr int ClusterSize = 3; public:
~TranspositionTable() { aligned_large_pages_free(table); }
struct Cluster { void resize(size_t mbSize, ThreadPool& threads); // Set TT size
TTEntry entry[ClusterSize]; void clear(ThreadPool& threads); // Re-initialize memory, multithreaded
char padding[2]; // Pad to 32 bytes int hashfull(int maxAge = 0)
}; const; // Approximate what fraction of entries (permille) have been written to during this root search
static_assert(sizeof(Cluster) == 32, "Unexpected Cluster size"); void
new_search(); // This must be called at the beginning of each root search to track entry aging
uint8_t generation() const; // The current age, used when writing new data to the TT
std::tuple<bool, TTData, TTWriter>
probe(const Key key) const; // The main method, whose retvals separate local vs global objects
TTEntry* first_entry(const Key key)
const; // This is the hash function; its only external use is memory prefetching.
// Constants used to refresh the hash table periodically private:
static constexpr unsigned GENERATION_BITS = 3; // nb of bits reserved for other things friend struct TTEntry;
static constexpr int GENERATION_DELTA = (1 << GENERATION_BITS); // increment for generation field
static constexpr int GENERATION_CYCLE = 255 + (1 << GENERATION_BITS); // cycle length
static constexpr int GENERATION_MASK = (0xFF << GENERATION_BITS) & 0xFF; // mask to pull out generation number
public: size_t clusterCount;
~TranspositionTable() { aligned_large_pages_free(table); } Cluster* table = nullptr;
void new_search() { generation8 += GENERATION_DELTA; } // Lower bits are used for other things
TTEntry* probe(const Key key, bool& found) const;
int hashfull() const;
void resize(size_t mbSize);
void clear();
TTEntry* first_entry(const Key key) const { uint8_t generation8 = 0; // Size must be not bigger than TTEntry::genBound8
return &table[mul_hi64(key, clusterCount)].entry[0];
}
private:
friend struct TTEntry;
size_t clusterCount;
Cluster* table;
uint8_t generation8; // Size must be not bigger than TTEntry::genBound8
}; };
extern TranspositionTable TT; } // namespace Stockfish
} // namespace Stockfish #endif // #ifndef TT_H_INCLUDED
#endif // #ifndef TT_H_INCLUDED
+68 -75
View File
@@ -1,6 +1,6 @@
/* /*
Stockfish, a UCI chess playing engine derived from Glaurung 2.1 Stockfish, a UCI chess playing engine derived from Glaurung 2.1
Copyright (C) 2004-2023 The Stockfish developers (see AUTHORS file) Copyright (C) 2004-2025 The Stockfish developers (see AUTHORS file)
Stockfish is free software: you can redistribute it and/or modify Stockfish is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by it under the terms of the GNU General Public License as published by
@@ -16,100 +16,97 @@
along with this program. If not, see <http://www.gnu.org/licenses/>. along with this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
#include "tune.h"
#include <algorithm> #include <algorithm>
#include <iostream> #include <iostream>
#include <map>
#include <optional>
#include <sstream> #include <sstream>
#include <string>
#include "types.h" #include "ucioption.h"
#include "misc.h"
#include "uci.h"
using std::string; using std::string;
namespace Stockfish { namespace Stockfish {
bool Tune::update_on_last; bool Tune::update_on_last;
const UCI::Option* LastOption = nullptr; const Option* LastOption = nullptr;
static std::map<std::string, int> TuneResults; OptionsMap* Tune::options;
namespace {
std::map<std::string, int> TuneResults;
std::optional<std::string> on_tune(const Option& o) {
if (!Tune::update_on_last || LastOption == &o)
Tune::read_options();
return std::nullopt;
}
}
void Tune::make_option(OptionsMap* opts, const string& n, int v, const SetRange& r) {
// Do not generate option when there is nothing to tune (ie. min = max)
if (r(v).first == r(v).second)
return;
if (TuneResults.count(n))
v = TuneResults[n];
opts->add(n, Option(v, r(v).first, r(v).second, on_tune));
LastOption = &((*opts)[n]);
// Print formatted parameters, ready to be copy-pasted in Fishtest
std::cout << n << "," //
<< v << "," //
<< r(v).first << "," //
<< r(v).second << "," //
<< (r(v).second - r(v).first) / 20.0 << "," //
<< "0.0020" << std::endl;
}
string Tune::next(string& names, bool pop) { string Tune::next(string& names, bool pop) {
string name; string name;
do { do
string token = names.substr(0, names.find(',')); {
string token = names.substr(0, names.find(','));
if (pop) if (pop)
names.erase(0, token.size() + 1); names.erase(0, token.size() + 1);
std::stringstream ws(token); std::stringstream ws(token);
name += (ws >> token, token); // Remove trailing whitespace name += (ws >> token, token); // Remove trailing whitespace
} while ( std::count(name.begin(), name.end(), '(') } while (std::count(name.begin(), name.end(), '(') - std::count(name.begin(), name.end(), ')'));
- std::count(name.begin(), name.end(), ')'));
return name; return name;
} }
static void on_tune(const UCI::Option& o) {
if (!Tune::update_on_last || LastOption == &o) template<>
Tune::read_options(); void Tune::Entry<int>::init_option() {
make_option(options, name, value, range);
} }
static void make_option(const string& n, int v, const SetRange& r) { template<>
void Tune::Entry<int>::read_option() {
// Do not generate option when there is nothing to tune (ie. min = max) if (options->count(name))
if (r(v).first == r(v).second) value = int((*options)[name]);
return;
if (TuneResults.count(n))
v = TuneResults[n];
Options[n] << UCI::Option(v, r(v).first, r(v).second, on_tune);
LastOption = &Options[n];
// Print formatted parameters, ready to be copy-pasted in Fishtest
std::cout << n << ","
<< v << ","
<< r(v).first << "," << r(v).second << ","
<< (r(v).second - r(v).first) / 20.0 << ","
<< "0.0020"
<< std::endl;
}
template<> void Tune::Entry<int>::init_option() { make_option(name, value, range); }
template<> void Tune::Entry<int>::read_option() {
if (Options.count(name))
value = int(Options[name]);
}
template<> void Tune::Entry<Value>::init_option() { make_option(name, value, range); }
template<> void Tune::Entry<Value>::read_option() {
if (Options.count(name))
value = Value(int(Options[name]));
}
template<> void Tune::Entry<Score>::init_option() {
make_option("m" + name, mg_value(value), range);
make_option("e" + name, eg_value(value), range);
}
template<> void Tune::Entry<Score>::read_option() {
if (Options.count("m" + name))
value = make_score(int(Options["m" + name]), eg_value(value));
if (Options.count("e" + name))
value = make_score(mg_value(value), int(Options["e" + name]));
} }
// Instead of a variable here we have a PostUpdate function: just call it // Instead of a variable here we have a PostUpdate function: just call it
template<> void Tune::Entry<Tune::PostUpdate>::init_option() {} template<>
template<> void Tune::Entry<Tune::PostUpdate>::read_option() { value(); } void Tune::Entry<Tune::PostUpdate>::init_option() {}
template<>
void Tune::Entry<Tune::PostUpdate>::read_option() {
value();
}
} // namespace Stockfish } // namespace Stockfish
// Init options with tuning session results instead of default values. Useful to // Init options with tuning session results instead of default values. Useful to
@@ -121,13 +118,9 @@ template<> void Tune::Entry<Tune::PostUpdate>::read_option() { value(); }
// //
// Then paste the output below, as the function body // Then paste the output below, as the function body
#include <cmath>
namespace Stockfish { namespace Stockfish {
void Tune::read_results() { void Tune::read_results() { /* ...insert your values here... */ }
/* ...insert your values here... */ } // namespace Stockfish
}
} // namespace Stockfish
+121 -101
View File
@@ -1,6 +1,6 @@
/* /*
Stockfish, a UCI chess playing engine derived from Glaurung 2.1 Stockfish, a UCI chess playing engine derived from Glaurung 2.1
Copyright (C) 2004-2023 The Stockfish developers (see AUTHORS file) Copyright (C) 2004-2025 The Stockfish developers (see AUTHORS file)
Stockfish is free software: you can redistribute it and/or modify Stockfish is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by it under the terms of the GNU General Public License as published by
@@ -19,145 +19,165 @@
#ifndef TUNE_H_INCLUDED #ifndef TUNE_H_INCLUDED
#define TUNE_H_INCLUDED #define TUNE_H_INCLUDED
#include <cstddef>
#include <memory> #include <memory>
#include <string> #include <string>
#include <type_traits> #include <type_traits> // IWYU pragma: keep
#include <utility>
#include <vector> #include <vector>
namespace Stockfish { namespace Stockfish {
using Range = std::pair<int, int>; // Option's min-max values class OptionsMap;
using RangeFun = Range (int);
using Range = std::pair<int, int>; // Option's min-max values
using RangeFun = Range(int);
// Default Range function, to calculate Option's min-max values // Default Range function, to calculate Option's min-max values
inline Range default_range(int v) { inline Range default_range(int v) { return v > 0 ? Range(0, 2 * v) : Range(2 * v, 0); }
return v > 0 ? Range(0, 2 * v) : Range(2 * v, 0);
}
struct SetRange { struct SetRange {
explicit SetRange(RangeFun f) : fun(f) {} explicit SetRange(RangeFun f) :
SetRange(int min, int max) : fun(nullptr), range(min, max) {} fun(f) {}
Range operator()(int v) const { return fun ? fun(v) : range; } SetRange(int min, int max) :
fun(nullptr),
range(min, max) {}
Range operator()(int v) const { return fun ? fun(v) : range; }
RangeFun* fun; RangeFun* fun;
Range range; Range range;
}; };
#define SetDefaultRange SetRange(default_range) #define SetDefaultRange SetRange(default_range)
/// Tune class implements the 'magic' code that makes the setup of a fishtest // Tune class implements the 'magic' code that makes the setup of a fishtest tuning
/// tuning session as easy as it can be. Mainly you have just to remove const // session as easy as it can be. Mainly you have just to remove const qualifiers
/// qualifiers from the variables you want to tune and flag them for tuning, so // from the variables you want to tune and flag them for tuning, so if you have:
/// if you have: //
/// // const Value myValue[][2] = { { V(100), V(20) }, { V(7), V(78) } };
/// const Score myScore = S(10, 15); //
/// const Value myValue[][2] = { { V(100), V(20) }, { V(7), V(78) } }; // If you have a my_post_update() function to run after values have been updated,
/// // and a my_range() function to set custom Option's min-max values, then you just
/// If you have a my_post_update() function to run after values have been updated, // remove the 'const' qualifiers and write somewhere below in the file:
/// and a my_range() function to set custom Option's min-max values, then you just //
/// remove the 'const' qualifiers and write somewhere below in the file: // TUNE(SetRange(my_range), myValue, my_post_update);
/// //
/// TUNE(SetRange(my_range), myScore, myValue, my_post_update); // You can also set the range directly, and restore the default at the end
/// //
/// You can also set the range directly, and restore the default at the end // TUNE(SetRange(-100, 100), myValue, SetDefaultRange);
/// //
/// TUNE(SetRange(-100, 100), myScore, SetDefaultRange); // In case update function is slow and you have many parameters, you can add:
/// //
/// In case update function is slow and you have many parameters, you can add: // UPDATE_ON_LAST();
/// //
/// UPDATE_ON_LAST(); // And the values update, including post update function call, will be done only
/// // once, after the engine receives the last UCI option, that is the one defined
/// And the values update, including post update function call, will be done only // and created as the last one, so the GUI should send the options in the same
/// once, after the engine receives the last UCI option, that is the one defined // order in which have been defined.
/// and created as the last one, so the GUI should send the options in the same
/// order in which have been defined.
class Tune { class Tune {
using PostUpdate = void (); // Post-update function using PostUpdate = void(); // Post-update function
Tune() { read_results(); } Tune() { read_results(); }
Tune(const Tune&) = delete; Tune(const Tune&) = delete;
void operator=(const Tune&) = delete; void operator=(const Tune&) = delete;
void read_results(); void read_results();
static Tune& instance() { static Tune t; return t; } // Singleton static Tune& instance() {
static Tune t;
return t;
} // Singleton
// Use polymorphism to accommodate Entry of different types in the same vector // Use polymorphism to accommodate Entry of different types in the same vector
struct EntryBase { struct EntryBase {
virtual ~EntryBase() = default; virtual ~EntryBase() = default;
virtual void init_option() = 0; virtual void init_option() = 0;
virtual void read_option() = 0; virtual void read_option() = 0;
}; };
template<typename T> template<typename T>
struct Entry : public EntryBase { struct Entry: public EntryBase {
static_assert(!std::is_const<T>::value, "Parameter cannot be const!"); static_assert(!std::is_const_v<T>, "Parameter cannot be const!");
static_assert( std::is_same<T, int>::value static_assert(std::is_same_v<T, int> || std::is_same_v<T, PostUpdate>,
|| std::is_same<T, Value>::value "Parameter type not supported!");
|| std::is_same<T, Score>::value
|| std::is_same<T, PostUpdate>::value, "Parameter type not supported!");
Entry(const std::string& n, T& v, const SetRange& r) : name(n), value(v), range(r) {} Entry(const std::string& n, T& v, const SetRange& r) :
void operator=(const Entry&) = delete; // Because 'value' is a reference name(n),
void init_option() override; value(v),
void read_option() override; range(r) {}
void operator=(const Entry&) = delete; // Because 'value' is a reference
void init_option() override;
void read_option() override;
std::string name; std::string name;
T& value; T& value;
SetRange range; SetRange range;
}; };
// Our facility to fill the container, each Entry corresponds to a parameter // Our facility to fill the container, each Entry corresponds to a parameter
// to tune. We use variadic templates to deal with an unspecified number of // to tune. We use variadic templates to deal with an unspecified number of
// entries, each one of a possible different type. // entries, each one of a possible different type.
static std::string next(std::string& names, bool pop = true); static std::string next(std::string& names, bool pop = true);
int add(const SetRange&, std::string&&) { return 0; } int add(const SetRange&, std::string&&) { return 0; }
template<typename T, typename... Args> template<typename T, typename... Args>
int add(const SetRange& range, std::string&& names, T& value, Args&&... args) { int add(const SetRange& range, std::string&& names, T& value, Args&&... args) {
list.push_back(std::unique_ptr<EntryBase>(new Entry<T>(next(names), value, range))); list.push_back(std::unique_ptr<EntryBase>(new Entry<T>(next(names), value, range)));
return add(range, std::move(names), args...); return add(range, std::move(names), args...);
} }
// Template specialization for arrays: recursively handle multi-dimensional arrays // Template specialization for arrays: recursively handle multi-dimensional arrays
template<typename T, size_t N, typename... Args> template<typename T, size_t N, typename... Args>
int add(const SetRange& range, std::string&& names, T (&value)[N], Args&&... args) { int add(const SetRange& range, std::string&& names, T (&value)[N], Args&&... args) {
for (size_t i = 0; i < N; i++) for (size_t i = 0; i < N; i++)
add(range, next(names, i == N - 1) + "[" + std::to_string(i) + "]", value[i]); add(range, next(names, i == N - 1) + "[" + std::to_string(i) + "]", value[i]);
return add(range, std::move(names), args...); return add(range, std::move(names), args...);
} }
// Template specialization for SetRange // Template specialization for SetRange
template<typename... Args> template<typename... Args>
int add(const SetRange&, std::string&& names, SetRange& value, Args&&... args) { int add(const SetRange&, std::string&& names, SetRange& value, Args&&... args) {
return add(value, (next(names), std::move(names)), args...); return add(value, (next(names), std::move(names)), args...);
} }
std::vector<std::unique_ptr<EntryBase>> list; static void make_option(OptionsMap* options, const std::string& n, int v, const SetRange& r);
public: std::vector<std::unique_ptr<EntryBase>> list;
template<typename... Args>
static int add(const std::string& names, Args&&... args) { public:
return instance().add(SetDefaultRange, names.substr(1, names.size() - 2), args...); // Remove trailing parenthesis template<typename... Args>
} static int add(const std::string& names, Args&&... args) {
static void init() { for (auto& e : instance().list) e->init_option(); read_options(); } // Deferred, due to UCI::Options access return instance().add(SetDefaultRange, names.substr(1, names.size() - 2),
static void read_options() { for (auto& e : instance().list) e->read_option(); } args...); // Remove trailing parenthesis
static bool update_on_last; }
static void init(OptionsMap& o) {
options = &o;
for (auto& e : instance().list)
e->init_option();
read_options();
} // Deferred, due to UCIEngine::Options access
static void read_options() {
for (auto& e : instance().list)
e->read_option();
}
static bool update_on_last;
static OptionsMap* options;
}; };
// Some macro magic :-) we define a dummy int variable that compiler initializes calling Tune::add() // Some macro magic :-) we define a dummy int variable that the compiler initializes calling Tune::add()
#define STRINGIFY(x) #x #define STRINGIFY(x) #x
#define UNIQUE2(x, y) x ## y #define UNIQUE2(x, y) x##y
#define UNIQUE(x, y) UNIQUE2(x, y) // Two indirection levels to expand __LINE__ #define UNIQUE(x, y) UNIQUE2(x, y) // Two indirection levels to expand __LINE__
#define TUNE(...) int UNIQUE(p, __LINE__) = Tune::add(STRINGIFY((__VA_ARGS__)), __VA_ARGS__) #define TUNE(...) int UNIQUE(p, __LINE__) = Tune::add(STRINGIFY((__VA_ARGS__)), __VA_ARGS__)
#define UPDATE_ON_LAST() bool UNIQUE(p, __LINE__) = Tune::update_on_last = true #define UPDATE_ON_LAST() bool UNIQUE(p, __LINE__) = Tune::update_on_last = true
} // namespace Stockfish } // namespace Stockfish
#endif // #ifndef TUNE_H_INCLUDED #endif // #ifndef TUNE_H_INCLUDED
+304 -359
View File
@@ -1,6 +1,6 @@
/* /*
Stockfish, a UCI chess playing engine derived from Glaurung 2.1 Stockfish, a UCI chess playing engine derived from Glaurung 2.1
Copyright (C) 2004-2023 The Stockfish developers (see AUTHORS file) Copyright (C) 2004-2025 The Stockfish developers (see AUTHORS file)
Stockfish is free software: you can redistribute it and/or modify Stockfish is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by it under the terms of the GNU General Public License as published by
@@ -17,475 +17,420 @@
*/ */
#ifndef TYPES_H_INCLUDED #ifndef TYPES_H_INCLUDED
#define TYPES_H_INCLUDED #define TYPES_H_INCLUDED
/// When compiling with provided Makefile (e.g. for Linux and OSX), configuration // When compiling with provided Makefile (e.g. for Linux and OSX), configuration
/// is done automatically. To get started type 'make help'. // is done automatically. To get started type 'make help'.
/// //
/// When Makefile is not used (e.g. with Microsoft Visual Studio) some switches // When Makefile is not used (e.g. with Microsoft Visual Studio) some switches
/// need to be set manually: // need to be set manually:
/// //
/// -DNDEBUG | Disable debugging mode. Always use this for release. // -DNDEBUG | Disable debugging mode. Always use this for release.
/// //
/// -DNO_PREFETCH | Disable use of prefetch asm-instruction. You may need this to // -DNO_PREFETCH | Disable use of prefetch asm-instruction. You may need this to
/// | run on some very old machines. // | run on some very old machines.
/// //
/// -DUSE_POPCNT | Add runtime support for use of popcnt asm-instruction. Works // -DUSE_POPCNT | Add runtime support for use of popcnt asm-instruction. Works
/// | only in 64-bit mode and requires hardware with popcnt support. // | only in 64-bit mode and requires hardware with popcnt support.
/// //
/// -DUSE_PEXT | Add runtime support for use of pext asm-instruction. Works // -DUSE_PEXT | Add runtime support for use of pext asm-instruction. Works
/// | only in 64-bit mode and requires hardware with pext support. // | only in 64-bit mode and requires hardware with pext support.
#include <cassert> #include <cassert>
#include <cctype> #include <cstdint>
#include <cstdint>
#include <cstdlib>
#include <algorithm>
#if defined(_MSC_VER) #if defined(_MSC_VER)
// Disable some silly and noisy warning from MSVC compiler // Disable some silly and noisy warnings from MSVC compiler
#pragma warning(disable: 4127) // Conditional expression is constant #pragma warning(disable: 4127) // Conditional expression is constant
#pragma warning(disable: 4146) // Unary minus operator applied to unsigned type #pragma warning(disable: 4146) // Unary minus operator applied to unsigned type
#pragma warning(disable: 4800) // Forcing value to bool 'true' or 'false' #pragma warning(disable: 4800) // Forcing value to bool 'true' or 'false'
#endif #endif
/// Predefined macros hell: // Predefined macros hell:
/// //
/// __GNUC__ Compiler is gcc, Clang or Intel on Linux // __GNUC__ Compiler is GCC, Clang or ICX
/// __INTEL_COMPILER Compiler is Intel // __clang__ Compiler is Clang or ICX
/// _MSC_VER Compiler is MSVC or Intel on Windows // __INTEL_LLVM_COMPILER Compiler is ICX
/// _WIN32 Building on Windows (any) // _MSC_VER Compiler is MSVC
/// _WIN64 Building on Windows 64 bit // _WIN32 Building on Windows (any)
// _WIN64 Building on Windows 64 bit
#if defined(__GNUC__ ) && (__GNUC__ < 9 || (__GNUC__ == 9 && __GNUC_MINOR__ <= 2)) && defined(_WIN32) && !defined(__clang__) #if defined(__GNUC__) && (__GNUC__ < 9 || (__GNUC__ == 9 && __GNUC_MINOR__ <= 2)) \
#define ALIGNAS_ON_STACK_VARIABLES_BROKEN && defined(_WIN32) && !defined(__clang__)
#endif #define ALIGNAS_ON_STACK_VARIABLES_BROKEN
#endif
#define ASSERT_ALIGNED(ptr, alignment) assert(reinterpret_cast<uintptr_t>(ptr) % alignment == 0) #define ASSERT_ALIGNED(ptr, alignment) assert(reinterpret_cast<uintptr_t>(ptr) % alignment == 0)
#if defined(_WIN64) && defined(_MSC_VER) // No Makefile used #if defined(_WIN64) && defined(_MSC_VER) // No Makefile used
# include <intrin.h> // Microsoft header for _BitScanForward64() #include <intrin.h> // Microsoft header for _BitScanForward64()
# define IS_64BIT #define IS_64BIT
#endif #endif
#if defined(USE_POPCNT) && (defined(__INTEL_COMPILER) || defined(_MSC_VER)) #if defined(USE_POPCNT) && defined(_MSC_VER)
# include <nmmintrin.h> // Intel and Microsoft header for _mm_popcnt_u64() #include <nmmintrin.h> // Microsoft header for _mm_popcnt_u64()
#endif #endif
#if !defined(NO_PREFETCH) && (defined(__INTEL_COMPILER) || defined(_MSC_VER)) #if !defined(NO_PREFETCH) && defined(_MSC_VER)
# include <xmmintrin.h> // Intel and Microsoft header for _mm_prefetch() #include <xmmintrin.h> // Microsoft header for _mm_prefetch()
#endif #endif
#if defined(USE_PEXT) #if defined(USE_PEXT)
# include <immintrin.h> // Header for _pext_u64() intrinsic #include <immintrin.h> // Header for _pext_u64() intrinsic
# define pext(b, m) _pext_u64(b, m) #define pext(b, m) _pext_u64(b, m)
#else #else
# define pext(b, m) 0 #define pext(b, m) 0
#endif #endif
namespace Stockfish { namespace Stockfish {
#ifdef USE_POPCNT #ifdef USE_POPCNT
constexpr bool HasPopCnt = true; constexpr bool HasPopCnt = true;
#else #else
constexpr bool HasPopCnt = false; constexpr bool HasPopCnt = false;
#endif #endif
#ifdef USE_PEXT #ifdef USE_PEXT
constexpr bool HasPext = true; constexpr bool HasPext = true;
#else #else
constexpr bool HasPext = false; constexpr bool HasPext = false;
#endif #endif
#ifdef IS_64BIT #ifdef IS_64BIT
constexpr bool Is64Bit = true; constexpr bool Is64Bit = true;
#else #else
constexpr bool Is64Bit = false; constexpr bool Is64Bit = false;
#endif #endif
using Key = uint64_t; using Key = uint64_t;
using Bitboard = uint64_t; using Bitboard = uint64_t;
constexpr int MAX_MOVES = 256; constexpr int MAX_MOVES = 256;
constexpr int MAX_PLY = 246; constexpr int MAX_PLY = 246;
/// A move needs 16 bits to be stored
///
/// bit 0- 5: destination square (from 0 to 63)
/// bit 6-11: origin square (from 0 to 63)
/// bit 12-13: promotion piece type - 2 (from KNIGHT-2 to QUEEN-2)
/// bit 14-15: special move flag: promotion (1), en passant (2), castling (3)
/// NOTE: en passant bit is set only when a pawn can be captured
///
/// Special cases are MOVE_NONE and MOVE_NULL. We can sneak these in because in
/// any normal move destination square is always different from origin square
/// while MOVE_NONE and MOVE_NULL have the same origin and destination square.
enum Move : int {
MOVE_NONE,
MOVE_NULL = 65
};
enum MoveType {
NORMAL,
PROMOTION = 1 << 14,
EN_PASSANT = 2 << 14,
CASTLING = 3 << 14
};
enum Color { enum Color {
WHITE, BLACK, COLOR_NB = 2 WHITE,
BLACK,
COLOR_NB = 2
}; };
enum CastlingRights { enum CastlingRights {
NO_CASTLING, NO_CASTLING,
WHITE_OO, WHITE_OO,
WHITE_OOO = WHITE_OO << 1, WHITE_OOO = WHITE_OO << 1,
BLACK_OO = WHITE_OO << 2, BLACK_OO = WHITE_OO << 2,
BLACK_OOO = WHITE_OO << 3, BLACK_OOO = WHITE_OO << 3,
KING_SIDE = WHITE_OO | BLACK_OO, KING_SIDE = WHITE_OO | BLACK_OO,
QUEEN_SIDE = WHITE_OOO | BLACK_OOO, QUEEN_SIDE = WHITE_OOO | BLACK_OOO,
WHITE_CASTLING = WHITE_OO | WHITE_OOO, WHITE_CASTLING = WHITE_OO | WHITE_OOO,
BLACK_CASTLING = BLACK_OO | BLACK_OOO, BLACK_CASTLING = BLACK_OO | BLACK_OOO,
ANY_CASTLING = WHITE_CASTLING | BLACK_CASTLING, ANY_CASTLING = WHITE_CASTLING | BLACK_CASTLING,
CASTLING_RIGHT_NB = 16 CASTLING_RIGHT_NB = 16
};
enum Phase {
PHASE_ENDGAME,
PHASE_MIDGAME = 128,
MG = 0, EG = 1, PHASE_NB = 2
};
enum ScaleFactor {
SCALE_FACTOR_DRAW = 0,
SCALE_FACTOR_NORMAL = 64,
SCALE_FACTOR_MAX = 128,
SCALE_FACTOR_NONE = 255
}; };
enum Bound { enum Bound {
BOUND_NONE, BOUND_NONE,
BOUND_UPPER, BOUND_UPPER,
BOUND_LOWER, BOUND_LOWER,
BOUND_EXACT = BOUND_UPPER | BOUND_LOWER BOUND_EXACT = BOUND_UPPER | BOUND_LOWER
}; };
enum Value : int { // Value is used as an alias for int, this is done to differentiate between a search
VALUE_ZERO = 0, // value and any other integer value. The values used in search are always supposed
VALUE_DRAW = 0, // to be in the range (-VALUE_NONE, VALUE_NONE] and should not exceed this range.
VALUE_KNOWN_WIN = 10000, using Value = int;
VALUE_MATE = 32000,
VALUE_INFINITE = 32001,
VALUE_NONE = 32002,
VALUE_TB_WIN_IN_MAX_PLY = VALUE_MATE - 2 * MAX_PLY, constexpr Value VALUE_ZERO = 0;
VALUE_TB_LOSS_IN_MAX_PLY = -VALUE_TB_WIN_IN_MAX_PLY, constexpr Value VALUE_DRAW = 0;
VALUE_MATE_IN_MAX_PLY = VALUE_MATE - MAX_PLY, constexpr Value VALUE_NONE = 32002;
VALUE_MATED_IN_MAX_PLY = -VALUE_MATE_IN_MAX_PLY, constexpr Value VALUE_INFINITE = 32001;
// In the code, we make the assumption that these values constexpr Value VALUE_MATE = 32000;
// are such that non_pawn_material() can be used to uniquely constexpr Value VALUE_MATE_IN_MAX_PLY = VALUE_MATE - MAX_PLY;
// identify the material on the board. constexpr Value VALUE_MATED_IN_MAX_PLY = -VALUE_MATE_IN_MAX_PLY;
PawnValueMg = 126, PawnValueEg = 208,
KnightValueMg = 781, KnightValueEg = 854,
BishopValueMg = 825, BishopValueEg = 915,
RookValueMg = 1276, RookValueEg = 1380,
QueenValueMg = 2538, QueenValueEg = 2682,
MidgameLimit = 15258, EndgameLimit = 3915 constexpr Value VALUE_TB = VALUE_MATE_IN_MAX_PLY - 1;
}; constexpr Value VALUE_TB_WIN_IN_MAX_PLY = VALUE_TB - MAX_PLY;
constexpr Value VALUE_TB_LOSS_IN_MAX_PLY = -VALUE_TB_WIN_IN_MAX_PLY;
constexpr bool is_valid(Value value) { return value != VALUE_NONE; }
constexpr bool is_win(Value value) {
assert(is_valid(value));
return value >= VALUE_TB_WIN_IN_MAX_PLY;
}
constexpr bool is_loss(Value value) {
assert(is_valid(value));
return value <= VALUE_TB_LOSS_IN_MAX_PLY;
}
constexpr bool is_decisive(Value value) { return is_win(value) || is_loss(value); }
// In the code, we make the assumption that these values
// are such that non_pawn_material() can be used to uniquely
// identify the material on the board.
constexpr Value PawnValue = 208;
constexpr Value KnightValue = 781;
constexpr Value BishopValue = 825;
constexpr Value RookValue = 1276;
constexpr Value QueenValue = 2538;
// clang-format off
enum PieceType { enum PieceType {
NO_PIECE_TYPE, PAWN, KNIGHT, BISHOP, ROOK, QUEEN, KING, NO_PIECE_TYPE, PAWN, KNIGHT, BISHOP, ROOK, QUEEN, KING,
ALL_PIECES = 0, ALL_PIECES = 0,
PIECE_TYPE_NB = 8 PIECE_TYPE_NB = 8
}; };
enum Piece { enum Piece {
NO_PIECE, NO_PIECE,
W_PAWN = PAWN, W_KNIGHT, W_BISHOP, W_ROOK, W_QUEEN, W_KING, W_PAWN = PAWN, W_KNIGHT, W_BISHOP, W_ROOK, W_QUEEN, W_KING,
B_PAWN = PAWN + 8, B_KNIGHT, B_BISHOP, B_ROOK, B_QUEEN, B_KING, B_PAWN = PAWN + 8, B_KNIGHT, B_BISHOP, B_ROOK, B_QUEEN, B_KING,
PIECE_NB = 16 PIECE_NB = 16
}; };
// clang-format on
constexpr Value PieceValue[PHASE_NB][PIECE_NB] = { constexpr Value PieceValue[PIECE_NB] = {
{ VALUE_ZERO, PawnValueMg, KnightValueMg, BishopValueMg, RookValueMg, QueenValueMg, VALUE_ZERO, VALUE_ZERO, VALUE_ZERO, PawnValue, KnightValue, BishopValue, RookValue, QueenValue, VALUE_ZERO, VALUE_ZERO,
VALUE_ZERO, PawnValueMg, KnightValueMg, BishopValueMg, RookValueMg, QueenValueMg, VALUE_ZERO, VALUE_ZERO }, VALUE_ZERO, PawnValue, KnightValue, BishopValue, RookValue, QueenValue, VALUE_ZERO, VALUE_ZERO};
{ VALUE_ZERO, PawnValueEg, KnightValueEg, BishopValueEg, RookValueEg, QueenValueEg, VALUE_ZERO, VALUE_ZERO,
VALUE_ZERO, PawnValueEg, KnightValueEg, BishopValueEg, RookValueEg, QueenValueEg, VALUE_ZERO, VALUE_ZERO }
};
using Depth = int; using Depth = int;
enum : int { enum : int {
DEPTH_QS_CHECKS = 0, // The following DEPTH_ constants are used for transposition table entries
DEPTH_QS_NO_CHECKS = -1, // and quiescence search move generation stages. In regular search, the
DEPTH_QS_RECAPTURES = -5, // depth stored in the transposition table is literal: the search depth
// (effort) used to make the corresponding transposition table value. In
DEPTH_NONE = -6, // quiescence search, however, the transposition table entries only store
// the current quiescence move generation stage (which should thus compare
DEPTH_OFFSET = -7 // value used only for TT entry occupancy check // lower than any regular search depth).
DEPTH_QS = 0,
// For transposition table entries where no searching at all was done
// (whether regular or qsearch) we use DEPTH_UNSEARCHED, which should thus
// compare lower than any quiescence or regular depth. DEPTH_ENTRY_OFFSET
// is used only for the transposition table entry occupancy check (see tt.cpp),
// and should thus be lower than DEPTH_UNSEARCHED.
DEPTH_UNSEARCHED = -2,
DEPTH_ENTRY_OFFSET = -3
}; };
// clang-format off
enum Square : int { enum Square : int {
SQ_A1, SQ_B1, SQ_C1, SQ_D1, SQ_E1, SQ_F1, SQ_G1, SQ_H1, SQ_A1, SQ_B1, SQ_C1, SQ_D1, SQ_E1, SQ_F1, SQ_G1, SQ_H1,
SQ_A2, SQ_B2, SQ_C2, SQ_D2, SQ_E2, SQ_F2, SQ_G2, SQ_H2, SQ_A2, SQ_B2, SQ_C2, SQ_D2, SQ_E2, SQ_F2, SQ_G2, SQ_H2,
SQ_A3, SQ_B3, SQ_C3, SQ_D3, SQ_E3, SQ_F3, SQ_G3, SQ_H3, SQ_A3, SQ_B3, SQ_C3, SQ_D3, SQ_E3, SQ_F3, SQ_G3, SQ_H3,
SQ_A4, SQ_B4, SQ_C4, SQ_D4, SQ_E4, SQ_F4, SQ_G4, SQ_H4, SQ_A4, SQ_B4, SQ_C4, SQ_D4, SQ_E4, SQ_F4, SQ_G4, SQ_H4,
SQ_A5, SQ_B5, SQ_C5, SQ_D5, SQ_E5, SQ_F5, SQ_G5, SQ_H5, SQ_A5, SQ_B5, SQ_C5, SQ_D5, SQ_E5, SQ_F5, SQ_G5, SQ_H5,
SQ_A6, SQ_B6, SQ_C6, SQ_D6, SQ_E6, SQ_F6, SQ_G6, SQ_H6, SQ_A6, SQ_B6, SQ_C6, SQ_D6, SQ_E6, SQ_F6, SQ_G6, SQ_H6,
SQ_A7, SQ_B7, SQ_C7, SQ_D7, SQ_E7, SQ_F7, SQ_G7, SQ_H7, SQ_A7, SQ_B7, SQ_C7, SQ_D7, SQ_E7, SQ_F7, SQ_G7, SQ_H7,
SQ_A8, SQ_B8, SQ_C8, SQ_D8, SQ_E8, SQ_F8, SQ_G8, SQ_H8, SQ_A8, SQ_B8, SQ_C8, SQ_D8, SQ_E8, SQ_F8, SQ_G8, SQ_H8,
SQ_NONE, SQ_NONE,
SQUARE_ZERO = 0, SQUARE_ZERO = 0,
SQUARE_NB = 64 SQUARE_NB = 64
}; };
// clang-format on
enum Direction : int { enum Direction : int {
NORTH = 8, NORTH = 8,
EAST = 1, EAST = 1,
SOUTH = -NORTH, SOUTH = -NORTH,
WEST = -EAST, WEST = -EAST,
NORTH_EAST = NORTH + EAST, NORTH_EAST = NORTH + EAST,
SOUTH_EAST = SOUTH + EAST, SOUTH_EAST = SOUTH + EAST,
SOUTH_WEST = SOUTH + WEST, SOUTH_WEST = SOUTH + WEST,
NORTH_WEST = NORTH + WEST NORTH_WEST = NORTH + WEST
}; };
enum File : int { enum File : int {
FILE_A, FILE_B, FILE_C, FILE_D, FILE_E, FILE_F, FILE_G, FILE_H, FILE_NB FILE_A,
FILE_B,
FILE_C,
FILE_D,
FILE_E,
FILE_F,
FILE_G,
FILE_H,
FILE_NB
}; };
enum Rank : int { enum Rank : int {
RANK_1, RANK_2, RANK_3, RANK_4, RANK_5, RANK_6, RANK_7, RANK_8, RANK_NB RANK_1,
RANK_2,
RANK_3,
RANK_4,
RANK_5,
RANK_6,
RANK_7,
RANK_8,
RANK_NB
}; };
// Keep track of what a move changes on the board (used by NNUE) // Keep track of what a move changes on the board (used by NNUE)
struct DirtyPiece { struct DirtyPiece {
// Number of changed pieces // Number of changed pieces
int dirty_num; int dirty_num;
// Max 3 pieces can change in one move. A promotion with capture moves // Max 3 pieces can change in one move. A promotion with capture moves
// both the pawn and the captured piece to SQ_NONE and the piece promoted // both the pawn and the captured piece to SQ_NONE and the piece promoted
// to from SQ_NONE to the capture square. // to from SQ_NONE to the capture square.
Piece piece[3]; Piece piece[3];
// From and to squares, which may be SQ_NONE // From and to squares, which may be SQ_NONE
Square from[3]; Square from[3];
Square to[3]; Square to[3];
}; };
/// Score enum stores a middlegame and an endgame value in a single integer (enum). #define ENABLE_INCR_OPERATORS_ON(T) \
/// The least significant 16 bits are used to store the middlegame value and the inline T& operator++(T& d) { return d = T(int(d) + 1); } \
/// upper 16 bits are used to store the endgame value. We have to take care to inline T& operator--(T& d) { return d = T(int(d) - 1); }
/// avoid left-shifting a signed int to avoid undefined behavior.
enum Score : int { SCORE_ZERO };
constexpr Score make_score(int mg, int eg) {
return Score((int)((unsigned int)eg << 16) + mg);
}
/// Extracting the signed lower and upper 16 bits is not so trivial because
/// according to the standard a simple cast to short is implementation defined
/// and so is a right shift of a signed integer.
inline Value eg_value(Score s) {
union { uint16_t u; int16_t s; } eg = { uint16_t(unsigned(s + 0x8000) >> 16) };
return Value(eg.s);
}
inline Value mg_value(Score s) {
union { uint16_t u; int16_t s; } mg = { uint16_t(unsigned(s)) };
return Value(mg.s);
}
#define ENABLE_BASE_OPERATORS_ON(T) \
constexpr T operator+(T d1, int d2) { return T(int(d1) + d2); } \
constexpr T operator-(T d1, int d2) { return T(int(d1) - d2); } \
constexpr T operator-(T d) { return T(-int(d)); } \
inline T& operator+=(T& d1, int d2) { return d1 = d1 + d2; } \
inline T& operator-=(T& d1, int d2) { return d1 = d1 - d2; }
#define ENABLE_INCR_OPERATORS_ON(T) \
inline T& operator++(T& d) { return d = T(int(d) + 1); } \
inline T& operator--(T& d) { return d = T(int(d) - 1); }
#define ENABLE_FULL_OPERATORS_ON(T) \
ENABLE_BASE_OPERATORS_ON(T) \
constexpr T operator*(int i, T d) { return T(i * int(d)); } \
constexpr T operator*(T d, int i) { return T(int(d) * i); } \
constexpr T operator/(T d, int i) { return T(int(d) / i); } \
constexpr int operator/(T d1, T d2) { return int(d1) / int(d2); } \
inline T& operator*=(T& d, int i) { return d = T(int(d) * i); } \
inline T& operator/=(T& d, int i) { return d = T(int(d) / i); }
ENABLE_FULL_OPERATORS_ON(Value)
ENABLE_FULL_OPERATORS_ON(Direction)
ENABLE_INCR_OPERATORS_ON(Piece)
ENABLE_INCR_OPERATORS_ON(PieceType) ENABLE_INCR_OPERATORS_ON(PieceType)
ENABLE_INCR_OPERATORS_ON(Square) ENABLE_INCR_OPERATORS_ON(Square)
ENABLE_INCR_OPERATORS_ON(File) ENABLE_INCR_OPERATORS_ON(File)
ENABLE_INCR_OPERATORS_ON(Rank) ENABLE_INCR_OPERATORS_ON(Rank)
ENABLE_BASE_OPERATORS_ON(Score) #undef ENABLE_INCR_OPERATORS_ON
#undef ENABLE_FULL_OPERATORS_ON constexpr Direction operator+(Direction d1, Direction d2) { return Direction(int(d1) + int(d2)); }
#undef ENABLE_INCR_OPERATORS_ON constexpr Direction operator*(int i, Direction d) { return Direction(i * int(d)); }
#undef ENABLE_BASE_OPERATORS_ON
/// Additional operators to add a Direction to a Square // Additional operators to add a Direction to a Square
constexpr Square operator+(Square s, Direction d) { return Square(int(s) + int(d)); } constexpr Square operator+(Square s, Direction d) { return Square(int(s) + int(d)); }
constexpr Square operator-(Square s, Direction d) { return Square(int(s) - int(d)); } constexpr Square operator-(Square s, Direction d) { return Square(int(s) - int(d)); }
inline Square& operator+=(Square& s, Direction d) { return s = s + d; } inline Square& operator+=(Square& s, Direction d) { return s = s + d; }
inline Square& operator-=(Square& s, Direction d) { return s = s - d; } inline Square& operator-=(Square& s, Direction d) { return s = s - d; }
/// Only declared but not defined. We don't want to multiply two scores due to // Toggle color
/// a very high risk of overflow. So user should explicitly convert to integer. constexpr Color operator~(Color c) { return Color(c ^ BLACK); }
Score operator*(Score, Score) = delete;
/// Division of a Score must be handled separately for each term // Swap A1 <-> A8
inline Score operator/(Score s, int i) { constexpr Square flip_rank(Square s) { return Square(s ^ SQ_A8); }
return make_score(mg_value(s) / i, eg_value(s) / i);
}
/// Multiplication of a Score by an integer. We check for overflow in debug mode. // Swap A1 <-> H1
inline Score operator*(Score s, int i) { constexpr Square flip_file(Square s) { return Square(s ^ SQ_H1); }
Score result = Score(int(s) * i); // Swap color of piece B_KNIGHT <-> W_KNIGHT
constexpr Piece operator~(Piece pc) { return Piece(pc ^ 8); }
assert(eg_value(result) == (i * eg_value(s)));
assert(mg_value(result) == (i * mg_value(s)));
assert((i == 0) || (result / i) == s);
return result;
}
/// Multiplication of a Score by a boolean
inline Score operator*(Score s, bool b) {
return b ? s : SCORE_ZERO;
}
constexpr Color operator~(Color c) {
return Color(c ^ BLACK); // Toggle color
}
constexpr Square flip_rank(Square s) { // Swap A1 <-> A8
return Square(s ^ SQ_A8);
}
constexpr Square flip_file(Square s) { // Swap A1 <-> H1
return Square(s ^ SQ_H1);
}
constexpr Piece operator~(Piece pc) {
return Piece(pc ^ 8); // Swap color of piece B_KNIGHT <-> W_KNIGHT
}
constexpr CastlingRights operator&(Color c, CastlingRights cr) { constexpr CastlingRights operator&(Color c, CastlingRights cr) {
return CastlingRights((c == WHITE ? WHITE_CASTLING : BLACK_CASTLING) & cr); return CastlingRights((c == WHITE ? WHITE_CASTLING : BLACK_CASTLING) & cr);
} }
constexpr Value mate_in(int ply) { constexpr Value mate_in(int ply) { return VALUE_MATE - ply; }
return VALUE_MATE - ply;
}
constexpr Value mated_in(int ply) { constexpr Value mated_in(int ply) { return -VALUE_MATE + ply; }
return -VALUE_MATE + ply;
}
constexpr Square make_square(File f, Rank r) { constexpr Square make_square(File f, Rank r) { return Square((r << 3) + f); }
return Square((r << 3) + f);
}
constexpr Piece make_piece(Color c, PieceType pt) { constexpr Piece make_piece(Color c, PieceType pt) { return Piece((c << 3) + pt); }
return Piece((c << 3) + pt);
}
constexpr PieceType type_of(Piece pc) { constexpr PieceType type_of(Piece pc) { return PieceType(pc & 7); }
return PieceType(pc & 7);
}
inline Color color_of(Piece pc) { inline Color color_of(Piece pc) {
assert(pc != NO_PIECE); assert(pc != NO_PIECE);
return Color(pc >> 3); return Color(pc >> 3);
} }
constexpr bool is_ok(Move m) { constexpr bool is_ok(Square s) { return s >= SQ_A1 && s <= SQ_H8; }
return m != MOVE_NONE && m != MOVE_NULL;
}
constexpr bool is_ok(Square s) { constexpr File file_of(Square s) { return File(s & 7); }
return s >= SQ_A1 && s <= SQ_H8;
}
constexpr File file_of(Square s) { constexpr Rank rank_of(Square s) { return Rank(s >> 3); }
return File(s & 7);
}
constexpr Rank rank_of(Square s) { constexpr Square relative_square(Color c, Square s) { return Square(s ^ (c * 56)); }
return Rank(s >> 3);
}
constexpr Square relative_square(Color c, Square s) { constexpr Rank relative_rank(Color c, Rank r) { return Rank(r ^ (c * 7)); }
return Square(s ^ (c * 56));
}
constexpr Rank relative_rank(Color c, Rank r) { constexpr Rank relative_rank(Color c, Square s) { return relative_rank(c, rank_of(s)); }
return Rank(r ^ (c * 7));
}
constexpr Rank relative_rank(Color c, Square s) { constexpr Direction pawn_push(Color c) { return c == WHITE ? NORTH : SOUTH; }
return relative_rank(c, rank_of(s));
}
constexpr Direction pawn_push(Color c) {
return c == WHITE ? NORTH : SOUTH;
}
constexpr Square from_sq(Move m) { // Based on a congruential pseudo-random number generator
assert(is_ok(m));
return Square((m >> 6) & 0x3F);
}
constexpr Square to_sq(Move m) {
assert(is_ok(m));
return Square(m & 0x3F);
}
constexpr int from_to(Move m) {
return m & 0xFFF;
}
constexpr MoveType type_of(Move m) {
return MoveType(m & (3 << 14));
}
constexpr PieceType promotion_type(Move m) {
return PieceType(((m >> 12) & 3) + KNIGHT);
}
constexpr Move make_move(Square from, Square to) {
return Move((from << 6) + to);
}
template<MoveType T>
constexpr Move make(Square from, Square to, PieceType pt = KNIGHT) {
return Move(T + ((pt - KNIGHT) << 12) + (from << 6) + to);
}
/// Based on a congruential pseudo random number generator
constexpr Key make_key(uint64_t seed) { constexpr Key make_key(uint64_t seed) {
return seed * 6364136223846793005ULL + 1442695040888963407ULL; return seed * 6364136223846793005ULL + 1442695040888963407ULL;
} }
} // namespace Stockfish
#endif // #ifndef TYPES_H_INCLUDED enum MoveType {
NORMAL,
PROMOTION = 1 << 14,
EN_PASSANT = 2 << 14,
CASTLING = 3 << 14
};
#include "tune.h" // Global visibility to tuning setup // A move needs 16 bits to be stored
//
// bit 0- 5: destination square (from 0 to 63)
// bit 6-11: origin square (from 0 to 63)
// bit 12-13: promotion piece type - 2 (from KNIGHT-2 to QUEEN-2)
// bit 14-15: special move flag: promotion (1), en passant (2), castling (3)
// NOTE: en passant bit is set only when a pawn can be captured
//
// Special cases are Move::none() and Move::null(). We can sneak these in because
// in any normal move the destination square and origin square are always different,
// but Move::none() and Move::null() have the same origin and destination square.
class Move {
public:
Move() = default;
constexpr explicit Move(std::uint16_t d) :
data(d) {}
constexpr Move(Square from, Square to) :
data((from << 6) + to) {}
template<MoveType T>
static constexpr Move make(Square from, Square to, PieceType pt = KNIGHT) {
return Move(T + ((pt - KNIGHT) << 12) + (from << 6) + to);
}
constexpr Square from_sq() const {
assert(is_ok());
return Square((data >> 6) & 0x3F);
}
constexpr Square to_sq() const {
assert(is_ok());
return Square(data & 0x3F);
}
constexpr int from_to() const { return data & 0xFFF; }
constexpr MoveType type_of() const { return MoveType(data & (3 << 14)); }
constexpr PieceType promotion_type() const { return PieceType(((data >> 12) & 3) + KNIGHT); }
constexpr bool is_ok() const { return none().data != data && null().data != data; }
static constexpr Move null() { return Move(65); }
static constexpr Move none() { return Move(0); }
constexpr bool operator==(const Move& m) const { return data == m.data; }
constexpr bool operator!=(const Move& m) const { return data != m.data; }
constexpr explicit operator bool() const { return data != 0; }
constexpr std::uint16_t raw() const { return data; }
struct MoveHash {
std::size_t operator()(const Move& m) const { return make_key(m.data); }
};
protected:
std::uint16_t data;
};
} // namespace Stockfish
#endif // #ifndef TYPES_H_INCLUDED
#include "tune.h" // Global visibility to tuning setup
+569 -300
View File
@@ -1,6 +1,6 @@
/* /*
Stockfish, a UCI chess playing engine derived from Glaurung 2.1 Stockfish, a UCI chess playing engine derived from Glaurung 2.1
Copyright (C) 2004-2023 The Stockfish developers (see AUTHORS file) Copyright (C) 2004-2025 The Stockfish developers (see AUTHORS file)
Stockfish is free software: you can redistribute it and/or modify Stockfish is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by it under the terms of the GNU General Public License as published by
@@ -16,50 +16,470 @@
along with this program. If not, see <http://www.gnu.org/licenses/>. along with this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
#include <cassert> #include "uci.h"
#include <algorithm>
#include <cctype>
#include <cmath> #include <cmath>
#include <iostream> #include <cstdint>
#include <iterator>
#include <optional>
#include <sstream> #include <sstream>
#include <string> #include <string_view>
#include <utility>
#include <vector>
#include "benchmark.h" #include "benchmark.h"
#include "evaluate.h" #include "engine.h"
#include "memory.h"
#include "movegen.h" #include "movegen.h"
#include "position.h" #include "position.h"
#include "score.h"
#include "search.h" #include "search.h"
#include "thread.h" #include "types.h"
#include "timeman.h" #include "ucioption.h"
#include "tt.h"
#include "uci.h"
#include "syzygy/tbprobe.h"
#include "nnue/evaluate_nnue.h"
using namespace std;
namespace Stockfish { namespace Stockfish {
namespace { constexpr auto BenchmarkCommand = "speedtest";
// FEN string for the initial position in standard chess constexpr auto 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"; template<typename... Ts>
struct overload: Ts... {
using Ts::operator()...;
};
template<typename... Ts>
overload(Ts...) -> overload<Ts...>;
// position() is called when the engine receives the "position" UCI command. void UCIEngine::print_info_string(std::string_view str) {
// It sets up the position that is described in the given FEN string ("fen") or sync_cout_start();
// the initial position ("startpos") and then makes the moves given in the following for (auto& line : split(str, "\n"))
// move list ("moves"). {
if (!is_whitespace(line))
{
std::cout << "info string " << line << '\n';
}
}
sync_cout_end();
}
void position(Position& pos, istringstream& is, StateListPtr& states) { UCIEngine::UCIEngine(int argc, char** argv) :
engine(argv[0]),
cli(argc, argv) {
Move m; engine.get_options().add_info_listener([](const std::optional<std::string>& str) {
string token, fen; if (str.has_value())
print_info_string(*str);
});
init_search_update_listeners();
}
void UCIEngine::init_search_update_listeners() {
engine.set_on_iter([](const auto& i) { on_iter(i); });
engine.set_on_update_no_moves([](const auto& i) { on_update_no_moves(i); });
engine.set_on_update_full(
[this](const auto& i) { on_update_full(i, engine.get_options()["UCI_ShowWDL"]); });
engine.set_on_bestmove([](const auto& bm, const auto& p) { on_bestmove(bm, p); });
engine.set_on_verify_networks([](const auto& s) { print_info_string(s); });
}
void UCIEngine::loop() {
std::string token, cmd;
for (int i = 1; i < cli.argc; ++i)
cmd += std::string(cli.argv[i]) + " ";
do
{
if (cli.argc == 1
&& !getline(std::cin, cmd)) // Wait for an input or an end-of-file (EOF) indication
cmd = "quit";
std::istringstream is(cmd);
token.clear(); // Avoid a stale if getline() returns nothing or a blank line
is >> std::skipws >> token;
if (token == "quit" || token == "stop")
engine.stop();
// The GUI sends 'ponderhit' to tell that the user has played the expected move.
// So, 'ponderhit' is sent if pondering was done on the same move that the user
// has played. The search should continue, but should also switch from pondering
// to the normal search.
else if (token == "ponderhit")
engine.set_ponderhit(false);
else if (token == "uci")
{
sync_cout << "id name " << engine_info(true) << "\n"
<< engine.get_options() << sync_endl;
sync_cout << "uciok" << sync_endl;
}
else if (token == "setoption")
setoption(is);
else if (token == "go")
{
// send info strings after the go command is sent for old GUIs and python-chess
print_info_string(engine.numa_config_information_as_string());
print_info_string(engine.thread_allocation_information_as_string());
go(is);
}
else if (token == "position")
position(is);
else if (token == "ucinewgame")
engine.search_clear();
else if (token == "isready")
sync_cout << "readyok" << sync_endl;
// Add custom non-UCI commands, mainly for debugging purposes.
// These commands must not be used during a search!
else if (token == "flip")
engine.flip();
else if (token == "bench")
bench(is);
else if (token == BenchmarkCommand)
benchmark(is);
else if (token == "d")
sync_cout << engine.visualize() << sync_endl;
else if (token == "eval")
engine.trace_eval();
else if (token == "compiler")
sync_cout << compiler_info() << sync_endl;
else if (token == "export_net")
{
std::pair<std::optional<std::string>, std::string> files[2];
if (is >> std::skipws >> files[0].second)
files[0].first = files[0].second;
if (is >> std::skipws >> files[1].second)
files[1].first = files[1].second;
engine.save_network(files);
}
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] != '#')
sync_cout << "Unknown command: '" << cmd << "'. Type help for more information."
<< sync_endl;
} while (token != "quit" && cli.argc == 1); // The command-line arguments are one-shot
}
Search::LimitsType UCIEngine::parse_limits(std::istream& is) {
Search::LimitsType limits;
std::string token;
limits.startTime = now(); // The search starts as early as possible
while (is >> token)
if (token == "searchmoves") // Needs to be the last command on the line
while (is >> token)
limits.searchmoves.push_back(to_lower(token));
else if (token == "wtime")
is >> limits.time[WHITE];
else if (token == "btime")
is >> limits.time[BLACK];
else if (token == "winc")
is >> limits.inc[WHITE];
else if (token == "binc")
is >> limits.inc[BLACK];
else if (token == "movestogo")
is >> limits.movestogo;
else if (token == "depth")
is >> limits.depth;
else if (token == "nodes")
is >> limits.nodes;
else if (token == "movetime")
is >> limits.movetime;
else if (token == "mate")
is >> limits.mate;
else if (token == "perft")
is >> limits.perft;
else if (token == "infinite")
limits.infinite = 1;
else if (token == "ponder")
limits.ponderMode = true;
return limits;
}
void UCIEngine::go(std::istringstream& is) {
Search::LimitsType limits = parse_limits(is);
if (limits.perft)
perft(limits);
else
engine.go(limits);
}
void UCIEngine::bench(std::istream& args) {
std::string token;
uint64_t num, nodes = 0, cnt = 1;
uint64_t nodesSearched = 0;
const auto& options = engine.get_options();
engine.set_on_update_full([&](const auto& i) {
nodesSearched = i.nodes;
on_update_full(i, options["UCI_ShowWDL"]);
});
std::vector<std::string> list = Benchmark::setup_bench(engine.fen(), args);
num = count_if(list.begin(), list.end(),
[](const std::string& s) { return s.find("go ") == 0 || s.find("eval") == 0; });
TimePoint elapsed = now();
for (const auto& cmd : list)
{
std::istringstream is(cmd);
is >> std::skipws >> token;
if (token == "go" || token == "eval")
{
std::cerr << "\nPosition: " << cnt++ << '/' << num << " (" << engine.fen() << ")"
<< std::endl;
if (token == "go")
{
Search::LimitsType limits = parse_limits(is);
if (limits.perft)
nodesSearched = perft(limits);
else
{
engine.go(limits);
engine.wait_for_search_finished();
}
nodes += nodesSearched;
nodesSearched = 0;
}
else
engine.trace_eval();
}
else if (token == "setoption")
setoption(is);
else if (token == "position")
position(is);
else if (token == "ucinewgame")
{
engine.search_clear(); // search_clear may take a while
elapsed = now();
}
}
elapsed = now() - elapsed + 1; // Ensure positivity to avoid a 'divide by zero'
dbg_print();
std::cerr << "\n===========================" //
<< "\nTotal time (ms) : " << elapsed //
<< "\nNodes searched : " << nodes //
<< "\nNodes/second : " << 1000 * nodes / elapsed << std::endl;
// reset callback, to not capture a dangling reference to nodesSearched
engine.set_on_update_full([&](const auto& i) { on_update_full(i, options["UCI_ShowWDL"]); });
}
void UCIEngine::benchmark(std::istream& args) {
// Probably not very important for a test this long, but include for completeness and sanity.
static constexpr int NUM_WARMUP_POSITIONS = 3;
std::string token;
uint64_t nodes = 0, cnt = 1;
uint64_t nodesSearched = 0;
engine.set_on_update_full([&](const Engine::InfoFull& i) { nodesSearched = i.nodes; });
engine.set_on_iter([](const auto&) {});
engine.set_on_update_no_moves([](const auto&) {});
engine.set_on_bestmove([](const auto&, const auto&) {});
engine.set_on_verify_networks([](const auto&) {});
Benchmark::BenchmarkSetup setup = Benchmark::setup_benchmark(args);
const int numGoCommands = count_if(setup.commands.begin(), setup.commands.end(),
[](const std::string& s) { return s.find("go ") == 0; });
TimePoint totalTime = 0;
// Set options once at the start.
auto ss = std::istringstream("name Threads value " + std::to_string(setup.threads));
setoption(ss);
ss = std::istringstream("name Hash value " + std::to_string(setup.ttSize));
setoption(ss);
ss = std::istringstream("name UCI_Chess960 value false");
setoption(ss);
// Warmup
for (const auto& cmd : setup.commands)
{
std::istringstream is(cmd);
is >> std::skipws >> token;
if (token == "go")
{
// One new line is produced by the search, so omit it here
std::cerr << "\rWarmup position " << cnt++ << '/' << NUM_WARMUP_POSITIONS;
Search::LimitsType limits = parse_limits(is);
TimePoint elapsed = now();
// Run with silenced network verification
engine.go(limits);
engine.wait_for_search_finished();
totalTime += now() - elapsed;
nodes += nodesSearched;
nodesSearched = 0;
}
else if (token == "position")
position(is);
else if (token == "ucinewgame")
{
engine.search_clear(); // search_clear may take a while
}
if (cnt > NUM_WARMUP_POSITIONS)
break;
}
std::cerr << "\n";
cnt = 1;
nodes = 0;
int numHashfullReadings = 0;
constexpr int hashfullAges[] = {0, 999}; // Only normal hashfull and touched hash.
int totalHashfull[std::size(hashfullAges)] = {0};
int maxHashfull[std::size(hashfullAges)] = {0};
auto updateHashfullReadings = [&]() {
numHashfullReadings += 1;
for (int i = 0; i < static_cast<int>(std::size(hashfullAges)); ++i)
{
const int hashfull = engine.get_hashfull(hashfullAges[i]);
maxHashfull[i] = std::max(maxHashfull[i], hashfull);
totalHashfull[i] += hashfull;
}
};
engine.search_clear(); // search_clear may take a while
for (const auto& cmd : setup.commands)
{
std::istringstream is(cmd);
is >> std::skipws >> token;
if (token == "go")
{
// One new line is produced by the search, so omit it here
std::cerr << "\rPosition " << cnt++ << '/' << numGoCommands;
Search::LimitsType limits = parse_limits(is);
TimePoint elapsed = now();
// Run with silenced network verification
engine.go(limits);
engine.wait_for_search_finished();
totalTime += now() - elapsed;
updateHashfullReadings();
nodes += nodesSearched;
nodesSearched = 0;
}
else if (token == "position")
position(is);
else if (token == "ucinewgame")
{
engine.search_clear(); // search_clear may take a while
}
}
totalTime = std::max<TimePoint>(totalTime, 1); // Ensure positivity to avoid a 'divide by zero'
dbg_print();
std::cerr << "\n";
static_assert(
std::size(hashfullAges) == 2 && hashfullAges[0] == 0 && hashfullAges[1] == 999,
"Hardcoded for display. Would complicate the code needlessly in the current state.");
std::string threadBinding = engine.thread_binding_information_as_string();
if (threadBinding.empty())
threadBinding = "none";
// clang-format off
std::cerr << "==========================="
<< "\nVersion : "
<< engine_version_info()
// "\nCompiled by : "
<< compiler_info()
<< "Large pages : " << (has_large_pages() ? "yes" : "no")
<< "\nUser invocation : " << BenchmarkCommand << " "
<< setup.originalInvocation << "\nFilled invocation : " << BenchmarkCommand
<< " " << setup.filledInvocation
<< "\nAvailable processors : " << engine.get_numa_config_as_string()
<< "\nThread count : " << setup.threads
<< "\nThread binding : " << threadBinding
<< "\nTT size [MiB] : " << setup.ttSize
<< "\nHash max, avg [per mille] : "
<< "\n single search : " << maxHashfull[0] << ", "
<< totalHashfull[0] / numHashfullReadings
<< "\n single game : " << maxHashfull[1] << ", "
<< totalHashfull[1] / numHashfullReadings
<< "\nTotal nodes searched : " << nodes
<< "\nTotal search time [s] : " << totalTime / 1000.0
<< "\nNodes/second : " << 1000 * nodes / totalTime << std::endl;
// clang-format on
init_search_update_listeners();
}
void UCIEngine::setoption(std::istringstream& is) {
engine.wait_for_search_finished();
engine.get_options().setoption(is);
}
std::uint64_t UCIEngine::perft(const Search::LimitsType& limits) {
auto nodes = engine.perft(engine.fen(), limits.perft, engine.get_options()["UCI_Chess960"]);
sync_cout << "\nNodes searched: " << nodes << "\n" << sync_endl;
return nodes;
}
void UCIEngine::position(std::istringstream& is) {
std::string token, fen;
is >> token; is >> token;
if (token == "startpos") if (token == "startpos")
{ {
fen = StartFEN; fen = StartFEN;
is >> token; // Consume the "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,332 +487,181 @@ namespace {
else else
return; return;
states = StateListPtr(new std::deque<StateInfo>(1)); // Drop the old state and create a new one std::vector<std::string> moves;
pos.set(fen, Options["UCI_Chess960"], &states->back(), Threads.main());
// Parse the move list, if any
while (is >> token && (m = UCI::to_move(pos, token)) != MOVE_NONE)
{
states->emplace_back();
pos.do_move(m, states->back());
}
}
// trace_eval() prints the evaluation of the current position, consistent with
// the UCI options set so far.
void trace_eval(Position& pos) {
StateListPtr states(new std::deque<StateInfo>(1));
Position p;
p.set(pos.fen(), Options["UCI_Chess960"], &states->back(), Threads.main());
Eval::NNUE::verify();
sync_cout << "\n" << Eval::trace(p) << sync_endl;
}
// setoption() is called when the engine receives the "setoption" UCI command.
// The function updates the UCI option ("name") to the given value ("value").
void setoption(istringstream& is) {
string token, name, value;
is >> token; // Consume the "name" token
// Read the option name (can contain spaces)
while (is >> token && token != "value")
name += (name.empty() ? "" : " ") + token;
// Read the option value (can contain spaces)
while (is >> token)
value += (value.empty() ? "" : " ") + token;
if (Options.count(name))
Options[name] = value;
else
sync_cout << "No such option: " << name << sync_endl;
}
// go() is called when the engine receives the "go" UCI command. The function
// sets the thinking time and other parameters from the input string, then starts
// with a search.
void go(Position& pos, istringstream& is, StateListPtr& states) {
Search::LimitsType limits;
string token;
bool ponderMode = false;
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
while (is >> token)
limits.searchmoves.push_back(UCI::to_move(pos, token));
else if (token == "wtime") is >> limits.time[WHITE];
else if (token == "btime") is >> limits.time[BLACK];
else if (token == "winc") is >> limits.inc[WHITE];
else if (token == "binc") is >> limits.inc[BLACK];
else if (token == "movestogo") is >> limits.movestogo;
else if (token == "depth") is >> limits.depth;
else if (token == "nodes") is >> limits.nodes;
else if (token == "movetime") is >> limits.movetime;
else if (token == "mate") is >> limits.mate;
else if (token == "perft") is >> limits.perft;
else if (token == "infinite") limits.infinite = 1;
else if (token == "ponder") ponderMode = true;
Threads.start_thinking(pos, states, limits, ponderMode);
}
// bench() is called when the engine receives the "bench" command.
// Firstly, a list of UCI commands is set up according to the bench
// parameters, then it is run one by one, printing a summary at the end.
void bench(Position& pos, istream& args, StateListPtr& states) {
string token;
uint64_t num, nodes = 0, cnt = 1;
vector<string> list = setup_bench(pos, args);
num = count_if(list.begin(), list.end(), [](const string& s) { return s.find("go ") == 0 || s.find("eval") == 0; });
TimePoint elapsed = now();
for (const auto& cmd : list)
{ {
istringstream is(cmd); moves.push_back(token);
is >> skipws >> token;
if (token == "go" || token == "eval")
{
cerr << "\nPosition: " << cnt++ << '/' << num << " (" << pos.fen() << ")" << endl;
if (token == "go")
{
go(pos, is, states);
Threads.main()->wait_for_search_finished();
nodes += Threads.nodes_searched();
}
else
trace_eval(pos);
}
else if (token == "setoption") setoption(is);
else if (token == "position") position(pos, is, states);
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' engine.set_position(fen, moves);
}
dbg_print(); namespace {
cerr << "\n===========================" struct WinRateParams {
<< "\nTotal time (ms) : " << elapsed double a;
<< "\nNodes searched : " << nodes double b;
<< "\nNodes/second : " << 1000 * nodes / elapsed << endl; };
}
// The win rate model returns the probability of winning (in per mille units) given an WinRateParams win_rate_params(const Position& pos) {
// eval and a game ply. It fits the LTC fishtest statistics rather accurately.
int win_rate_model(Value v, int ply) {
// The model only captures up to 240 plies, so limit the input and then rescale int material = pos.count<PAWN>() + 3 * pos.count<KNIGHT>() + 3 * pos.count<BISHOP>()
double m = std::min(240, ply) / 64.0; + 5 * pos.count<ROOK>() + 9 * pos.count<QUEEN>();
// The coefficients of a third-order polynomial fit is based on the fishtest data // The fitted model only uses data for material counts in [17, 78], and is anchored at count 58.
// for two parameters that need to transform eval to the argument of a logistic double m = std::clamp(material, 17, 78) / 58.0;
// function.
constexpr double as[] = { 0.38036525, -2.82015070, 23.17882135, 307.36768407};
constexpr double bs[] = { -2.29434733, 13.27689788, -14.26828904, 63.45318330 };
// Enforce that NormalizeToPawnValue corresponds to a 50% win rate at ply 64 // Return a = p_a(material) and b = p_b(material), see github.com/official-stockfish/WDL_model
static_assert(UCI::NormalizeToPawnValue == int(as[0] + as[1] + as[2] + as[3])); constexpr double as[] = {-37.45051876, 121.19101539, -132.78783573, 420.70576692};
constexpr double bs[] = {90.26261072, -137.26549898, 71.10130540, 51.35259597};
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 the eval to centipawns with limited range return {a, b};
double x = std::clamp(double(v), -4000.0, 4000.0); }
// Return the win rate in per mille units rounded to the nearest value // The win rate model is 1 / (1 + exp((a - eval) / b)), where a = p_a(material) and b = p_b(material).
return int(0.5 + 1000 / (1 + std::exp((a - x) / b))); // It fits the LTC fishtest statistics rather accurately.
} int win_rate_model(Value v, const Position& pos) {
} // namespace auto [a, b] = win_rate_params(pos);
// Return the win rate in per mille units, rounded to the nearest integer.
return int(0.5 + 1000 / (1 + std::exp((a - double(v)) / b)));
}
}
/// UCI::loop() waits for a command from the stdin, parses it and then calls the appropriate std::string UCIEngine::format_score(const Score& s) {
/// function. It also intercepts an end-of-file (EOF) indication from the stdin to ensure a constexpr int TB_CP = 20000;
/// graceful exit if the GUI dies unexpectedly. When called with some command-line arguments, const auto format =
/// like running 'bench', the function returns immediately after the command is executed. overload{[](Score::Mate mate) -> std::string {
/// In addition to the UCI ones, some additional debug commands are also supported. auto m = (mate.plies > 0 ? (mate.plies + 1) : mate.plies) / 2;
return std::string("mate ") + std::to_string(m);
},
[](Score::Tablebase tb) -> std::string {
return std::string("cp ")
+ std::to_string((tb.win ? TB_CP - tb.plies : -TB_CP - tb.plies));
},
[](Score::InternalUnits units) -> std::string {
return std::string("cp ") + std::to_string(units.value);
}};
void UCI::loop(int argc, char* argv[]) { return s.visit(format);
}
Position pos; // Turns a Value to an integer centipawn number,
string token, cmd; // without treatment of mate and similar special scores.
StateListPtr states(new std::deque<StateInfo>(1)); int UCIEngine::to_cp(Value v, const Position& pos) {
pos.set(StartFEN, false, &states->back(), Threads.main()); // In general, the score can be defined via the WDL as
// (log(1/L - 1) - log(1/W - 1)) / (log(1/L - 1) + log(1/W - 1)).
// Based on our win_rate_model, this simply yields v / a.
for (int i = 1; i < argc; ++i) auto [a, b] = win_rate_params(pos);
cmd += std::string(argv[i]) + " ";
do { return std::round(100 * int(v) / a);
if (argc == 1 && !getline(cin, cmd)) // Wait for an input or an end-of-file (EOF) indication }
cmd = "quit";
istringstream is(cmd); std::string UCIEngine::wdl(Value v, const Position& pos) {
std::stringstream ss;
token.clear(); // Avoid a stale if getline() returns nothing or a blank line int wdl_w = win_rate_model(v, pos);
is >> skipws >> token; int wdl_l = win_rate_model(-v, pos);
int wdl_d = 1000 - wdl_w - wdl_l;
ss << wdl_w << " " << wdl_d << " " << wdl_l;
if ( token == "quit" return ss.str();
|| token == "stop") }
Threads.stop = true;
// The GUI sends 'ponderhit' to tell that the user has played the expected move. std::string UCIEngine::square(Square s) {
// So, 'ponderhit' is sent if pondering was done on the same move that the user return std::string{char('a' + file_of(s)), char('1' + rank_of(s))};
// has played. The search should continue, but should also switch from pondering }
// to the normal search.
else if (token == "ponderhit")
Threads.main()->ponder = false; // Switch to the normal search
else if (token == "uci") std::string UCIEngine::move(Move m, bool chess960) {
sync_cout << "id name " << engine_info(true) if (m == Move::none())
<< "\n" << Options return "(none)";
<< "\nuciok" << sync_endl;
else if (token == "setoption") setoption(is); if (m == Move::null())
else if (token == "go") go(pos, is, states); return "0000";
else if (token == "position") position(pos, is, states);
else if (token == "ucinewgame") Search::clear();
else if (token == "isready") sync_cout << "readyok" << sync_endl;
// Add custom non-UCI commands, mainly for debugging purposes. Square from = m.from_sq();
// These commands must not be used during a search! Square to = m.to_sq();
else if (token == "flip") pos.flip();
else if (token == "bench") bench(pos, is, states);
else if (token == "d") sync_cout << pos << sync_endl;
else if (token == "eval") trace_eval(pos);
else if (token == "compiler") sync_cout << compiler_info() << sync_endl;
else if (token == "export_net")
{
std::optional<std::string> filename;
std::string f;
if (is >> skipws >> f)
filename = f;
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] != '#')
sync_cout << "Unknown command: '" << cmd << "'. Type help for more information." << sync_endl;
} while (token != "quit" && argc == 1); // The command-line arguments are one-shot if (m.type_of() == CASTLING && !chess960)
to = make_square(to > from ? FILE_G : FILE_C, rank_of(from));
std::string move = square(from) + square(to);
if (m.type_of() == PROMOTION)
move += " pnbrqk"[m.promotion_type()];
return move;
} }
/// UCI::value() converts a Value to a string by adhering to the UCI protocol specification: std::string UCIEngine::to_lower(std::string str) {
/// std::transform(str.begin(), str.end(), str.begin(), [](auto c) { return std::tolower(c); });
/// 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,
/// uses negative values for 'y'.
string UCI::value(Value v) { return str;
assert(-VALUE_INFINITE < v && v < VALUE_INFINITE);
stringstream ss;
if (abs(v) < VALUE_TB_WIN_IN_MAX_PLY)
ss << "cp " << v * 100 / NormalizeToPawnValue;
else if (abs(v) < VALUE_MATE_IN_MAX_PLY)
{
const int ply = VALUE_MATE_IN_MAX_PLY - 1 - std::abs(v); // recompute ss->ply
ss << "cp " << (v > 0 ? 20000 - ply : -20000 + ply);
}
else
ss << "mate " << (v > 0 ? VALUE_MATE - v + 1 : -VALUE_MATE - v) / 2;
return ss.str();
} }
Move UCIEngine::to_move(const Position& pos, std::string str) {
str = to_lower(str);
/// UCI::wdl() reports the win-draw-loss (WDL) statistics given an evaluation for (const auto& m : MoveList<LEGAL>(pos))
/// and a game ply based on the data gathered for fishtest LTC games. if (str == move(m, pos.is_chess960()))
return m;
string UCI::wdl(Value v, int ply) { return Move::none();
stringstream ss;
int wdl_w = win_rate_model( v, ply);
int wdl_l = win_rate_model(-v, ply);
int wdl_d = 1000 - wdl_w - wdl_l;
ss << " wdl " << wdl_w << " " << wdl_d << " " << wdl_l;
return ss.str();
} }
void UCIEngine::on_update_no_moves(const Engine::InfoShort& info) {
/// UCI::square() converts a Square to a string in algebraic notation (g1, a7, etc.) sync_cout << "info depth " << info.depth << " score " << format_score(info.score) << sync_endl;
std::string UCI::square(Square s) {
return std::string{ char('a' + file_of(s)), char('1' + rank_of(s)) };
} }
void UCIEngine::on_update_full(const Engine::InfoFull& info, bool showWDL) {
std::stringstream ss;
/// UCI::move() converts a Move to a string in coordinate notation (g1f3, a7a8q). ss << "info";
/// The only special case is castling where the e1g1 notation is printed in ss << " depth " << info.depth //
/// standard chess mode and in e1h1 notation it is printed in Chess960 mode. << " seldepth " << info.selDepth //
/// Internally, all castling moves are always encoded as 'king captures rook'. << " multipv " << info.multiPV //
<< " score " << format_score(info.score); //
string UCI::move(Move m, bool chess960) { if (showWDL)
ss << " wdl " << info.wdl;
if (m == MOVE_NONE) if (!info.bound.empty())
return "(none)"; ss << " " << info.bound;
if (m == MOVE_NULL) ss << " nodes " << info.nodes //
return "0000"; << " nps " << info.nps //
<< " hashfull " << info.hashfull //
<< " tbhits " << info.tbHits //
<< " time " << info.timeMs //
<< " pv " << info.pv; //
Square from = from_sq(m); sync_cout << ss.str() << sync_endl;
Square to = to_sq(m);
if (type_of(m) == CASTLING && !chess960)
to = make_square(to > from ? FILE_G : FILE_C, rank_of(from));
string move = UCI::square(from) + UCI::square(to);
if (type_of(m) == PROMOTION)
move += " pnbrqk"[promotion_type(m)];
return move;
} }
void UCIEngine::on_iter(const Engine::InfoIter& info) {
std::stringstream ss;
/// UCI::to_move() converts a string representing a move in coordinate notation ss << "info";
/// (g1f3, a7a8q) to the corresponding legal Move, if any. ss << " depth " << info.depth //
<< " currmove " << info.currmove //
<< " currmovenumber " << info.currmovenumber; //
Move UCI::to_move(const Position& pos, string& str) { sync_cout << ss.str() << sync_endl;
if (str.length() == 5)
str[4] = char(tolower(str[4])); // The promotion piece character must be lowercased
for (const auto& m : MoveList<LEGAL>(pos))
if (str == UCI::move(m, pos.is_chess960()))
return m;
return MOVE_NONE;
} }
} // namespace Stockfish void UCIEngine::on_bestmove(std::string_view bestmove, std::string_view ponder) {
sync_cout << "bestmove " << bestmove;
if (!ponder.empty())
std::cout << " ponder " << ponder;
std::cout << sync_endl;
}
} // namespace Stockfish
+47 -59
View File
@@ -1,6 +1,6 @@
/* /*
Stockfish, a UCI chess playing engine derived from Glaurung 2.1 Stockfish, a UCI chess playing engine derived from Glaurung 2.1
Copyright (C) 2004-2023 The Stockfish developers (see AUTHORS file) Copyright (C) 2004-2025 The Stockfish developers (see AUTHORS file)
Stockfish is free software: you can redistribute it and/or modify Stockfish is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by it under the terms of the GNU General Public License as published by
@@ -19,74 +19,62 @@
#ifndef UCI_H_INCLUDED #ifndef UCI_H_INCLUDED
#define UCI_H_INCLUDED #define UCI_H_INCLUDED
#include <map> #include <cstdint>
#include <iostream>
#include <string> #include <string>
#include <string_view>
#include "types.h" #include "engine.h"
#include "misc.h"
#include "search.h"
namespace Stockfish { namespace Stockfish {
class Position; class Position;
class Move;
class Score;
enum Square : int;
using Value = int;
namespace UCI { class UCIEngine {
public:
UCIEngine(int argc, char** argv);
// Normalizes the internal value as reported by evaluate or search void loop();
// 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 = 328;
class Option; static int to_cp(Value v, const Position& pos);
static std::string format_score(const Score& s);
static std::string square(Square s);
static std::string move(Move m, bool chess960);
static std::string wdl(Value v, const Position& pos);
static std::string to_lower(std::string str);
static Move to_move(const Position& pos, std::string str);
/// Define a custom comparator, because the UCI options should be case-insensitive static Search::LimitsType parse_limits(std::istream& is);
struct CaseInsensitiveLess {
bool operator() (const std::string&, const std::string&) const; auto& engine_options() { return engine.get_options(); }
private:
Engine engine;
CommandLine cli;
static void print_info_string(std::string_view str);
void go(std::istringstream& is);
void bench(std::istream& args);
void benchmark(std::istream& args);
void position(std::istringstream& is);
void setoption(std::istringstream& is);
std::uint64_t perft(const Search::LimitsType&);
static void on_update_no_moves(const Engine::InfoShort& info);
static void on_update_full(const Engine::InfoFull& info, bool showWDL);
static void on_iter(const Engine::InfoIter& info);
static void on_bestmove(std::string_view bestmove, std::string_view ponder);
void init_search_update_listeners();
}; };
/// The options container is defined as a std::map } // namespace Stockfish
using OptionsMap = std::map<std::string, Option, CaseInsensitiveLess>;
/// The Option class implements each option as specified by the UCI protocol #endif // #ifndef UCI_H_INCLUDED
class Option {
using OnChange = void (*)(const Option&);
public:
Option(OnChange = nullptr);
Option(bool v, OnChange = nullptr);
Option(const char* v, OnChange = nullptr);
Option(double v, int minv, int maxv, OnChange = nullptr);
Option(const char* v, const char* cur, OnChange = nullptr);
Option& operator=(const std::string&);
void operator<<(const Option&);
operator int() const;
operator std::string() const;
bool operator==(const char*) const;
private:
friend std::ostream& operator<<(std::ostream&, const OptionsMap&);
std::string defaultValue, currentValue, type;
int min, max;
size_t idx;
OnChange on_change;
};
void init(OptionsMap&);
void loop(int argc, char* argv[]);
std::string value(Value v);
std::string square(Square s);
std::string move(Move m, bool chess960);
std::string pv(const Position& pos, Depth depth);
std::string wdl(Value v, int ply);
Move to_move(const Position& pos, std::string& str);
} // namespace UCI
extern UCI::OptionsMap Options;
} // namespace Stockfish
#endif // #ifndef UCI_H_INCLUDED
+151 -132
View File
@@ -1,6 +1,6 @@
/* /*
Stockfish, a UCI chess playing engine derived from Glaurung 2.1 Stockfish, a UCI chess playing engine derived from Glaurung 2.1
Copyright (C) 2004-2023 The Stockfish developers (see AUTHORS file) Copyright (C) 2004-2025 The Stockfish developers (see AUTHORS file)
Stockfish is free software: you can redistribute it and/or modify Stockfish is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by it under the terms of the GNU General Public License as published by
@@ -16,179 +16,198 @@
along with this program. If not, see <http://www.gnu.org/licenses/>. along with this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
#include "ucioption.h"
#include <algorithm> #include <algorithm>
#include <cassert> #include <cassert>
#include <ostream> #include <cctype>
#include <cstdlib>
#include <iostream>
#include <sstream> #include <sstream>
#include <utility>
#include "evaluate.h"
#include "misc.h" #include "misc.h"
#include "search.h"
#include "thread.h"
#include "tt.h"
#include "uci.h"
#include "syzygy/tbprobe.h"
using std::string;
namespace Stockfish { namespace Stockfish {
UCI::OptionsMap Options; // Global object bool CaseInsensitiveLess::operator()(const std::string& s1, const std::string& s2) const {
namespace UCI { return std::lexicographical_compare(
s1.begin(), s1.end(), s2.begin(), s2.end(),
[](char c1, char c2) { return std::tolower(c1) < std::tolower(c2); });
}
/// 'On change' actions, triggered by an option's value change void OptionsMap::add_info_listener(InfoListener&& message_func) { info = std::move(message_func); }
static void on_clear_hash(const Option&) { Search::clear(); }
static void on_hash_size(const Option& o) { TT.resize(size_t(o)); }
static void on_logger(const Option& o) { start_logger(o); }
static void on_threads(const Option& o) { Threads.set(size_t(o)); }
static void on_tb_path(const Option& o) { Tablebases::init(o); }
static void on_use_NNUE(const Option&) { Eval::NNUE::init(); }
static void on_eval_file(const Option&) { Eval::NNUE::init(); }
/// Our case insensitive less() function as required by UCI protocol void OptionsMap::setoption(std::istringstream& is) {
bool CaseInsensitiveLess::operator() (const string& s1, const string& s2) const { std::string token, name, value;
return std::lexicographical_compare(s1.begin(), s1.end(), s2.begin(), s2.end(), is >> token; // Consume the "name" token
[](char c1, char c2) { return tolower(c1) < tolower(c2); });
// Read the option name (can contain spaces)
while (is >> token && token != "value")
name += (name.empty() ? "" : " ") + token;
// Read the option value (can contain spaces)
while (is >> token)
value += (value.empty() ? "" : " ") + token;
if (options_map.count(name))
options_map[name] = value;
else
sync_cout << "No such option: " << name << sync_endl;
}
const Option& OptionsMap::operator[](const std::string& name) const {
auto it = options_map.find(name);
assert(it != options_map.end());
return it->second;
}
// Inits options and assigns idx in the correct printing order
void OptionsMap::add(const std::string& name, const Option& option) {
if (!options_map.count(name))
{
static size_t insert_order = 0;
options_map[name] = option;
options_map[name].parent = this;
options_map[name].idx = insert_order++;
}
else
{
std::cerr << "Option \"" << name << "\" was already added!" << std::endl;
std::exit(EXIT_FAILURE);
}
} }
/// UCI::init() initializes the UCI options to their hard-coded default values std::size_t OptionsMap::count(const std::string& name) const { return options_map.count(name); }
void init(OptionsMap& o) { Option::Option(const OptionsMap* map) :
parent(map) {}
constexpr int MaxHashMB = Is64Bit ? 33554432 : 2048; Option::Option(const char* v, OnChange f) :
type("string"),
o["Debug Log File"] << Option("", on_logger); min(0),
o["Threads"] << Option(1, 1, 1024, on_threads); max(0),
o["Hash"] << Option(16, 1, MaxHashMB, on_hash_size); on_change(std::move(f)) {
o["Clear Hash"] << Option(on_clear_hash); defaultValue = currentValue = v;
o["Ponder"] << Option(false);
o["MultiPV"] << Option(1, 1, 500);
o["Skill Level"] << Option(20, 0, 20);
o["Move Overhead"] << Option(10, 0, 5000);
o["Slow Mover"] << Option(100, 10, 1000);
o["nodestime"] << Option(0, 0, 10000);
o["UCI_Chess960"] << Option(false);
o["UCI_AnalyseMode"] << Option(false);
o["UCI_LimitStrength"] << Option(false);
o["UCI_Elo"] << Option(1320, 1320, 3190);
o["UCI_ShowWDL"] << Option(false);
o["SyzygyPath"] << Option("<empty>", on_tb_path);
o["SyzygyProbeDepth"] << Option(1, 1, 100);
o["Syzygy50MoveRule"] << Option(true);
o["SyzygyProbeLimit"] << Option(7, 0, 7);
o["Use NNUE"] << Option(true, on_use_NNUE);
o["EvalFile"] << Option(EvalFileDefaultName, on_eval_file);
} }
Option::Option(bool v, OnChange f) :
/// operator<<() is used to print all the options default values in chronological type("check"),
/// insertion order (the idx field) and in the format defined by the UCI protocol. min(0),
max(0),
std::ostream& operator<<(std::ostream& os, const OptionsMap& om) { on_change(std::move(f)) {
defaultValue = currentValue = (v ? "true" : "false");
for (size_t idx = 0; idx < om.size(); ++idx)
for (const auto& it : om)
if (it.second.idx == idx)
{
const Option& o = it.second;
os << "\noption name " << it.first << " type " << o.type;
if (o.type == "string" || o.type == "check" || o.type == "combo")
os << " default " << o.defaultValue;
if (o.type == "spin")
os << " default " << int(stof(o.defaultValue))
<< " min " << o.min
<< " max " << o.max;
break;
}
return os;
} }
Option::Option(OnChange f) :
type("button"),
min(0),
max(0),
on_change(std::move(f)) {}
/// Option class constructors and conversion operators Option::Option(double v, int minv, int maxv, OnChange f) :
type("spin"),
min(minv),
max(maxv),
on_change(std::move(f)) {
defaultValue = currentValue = std::to_string(v);
}
Option::Option(const char* v, OnChange f) : type("string"), min(0), max(0), on_change(f) Option::Option(const char* v, const char* cur, OnChange f) :
{ defaultValue = currentValue = v; } type("combo"),
min(0),
Option::Option(bool v, OnChange f) : type("check"), min(0), max(0), on_change(f) max(0),
{ defaultValue = currentValue = (v ? "true" : "false"); } on_change(std::move(f)) {
defaultValue = v;
Option::Option(OnChange f) : type("button"), min(0), max(0), on_change(f) currentValue = cur;
{} }
Option::Option(double v, int minv, int maxv, OnChange f) : type("spin"), min(minv), max(maxv), on_change(f)
{ defaultValue = currentValue = std::to_string(v); }
Option::Option(const char* v, const char* cur, OnChange f) : type("combo"), min(0), max(0), on_change(f)
{ defaultValue = v; currentValue = cur; }
Option::operator int() const { Option::operator int() const {
assert(type == "check" || type == "spin"); assert(type == "check" || type == "spin");
return (type == "spin" ? std::stoi(currentValue) : currentValue == "true"); return (type == "spin" ? std::stoi(currentValue) : currentValue == "true");
} }
Option::operator std::string() const { Option::operator std::string() const {
assert(type == "string"); assert(type == "string");
return currentValue; return currentValue;
} }
bool Option::operator==(const char* s) const { bool Option::operator==(const char* s) const {
assert(type == "combo"); assert(type == "combo");
return !CaseInsensitiveLess()(currentValue, s) return !CaseInsensitiveLess()(currentValue, s) && !CaseInsensitiveLess()(s, currentValue);
&& !CaseInsensitiveLess()(s, currentValue);
} }
bool Option::operator!=(const char* s) const { return !(*this == s); }
/// operator<<() inits options and assigns idx in the correct printing order
void Option::operator<<(const Option& o) { // Updates currentValue and triggers on_change() action. It's up to
// the GUI to check for option's limits, but we could receive the new value
// from the user by console window, so let's check the bounds anyway.
Option& Option::operator=(const std::string& v) {
static size_t insert_order = 0; assert(!type.empty());
*this = o; if ((type != "button" && type != "string" && v.empty())
idx = insert_order++; || (type == "check" && v != "true" && v != "false")
|| (type == "spin" && (std::stof(v) < min || std::stof(v) > max)))
return *this;
if (type == "combo")
{
OptionsMap comboMap; // To have case insensitive compare
std::string token;
std::istringstream ss(defaultValue);
while (ss >> token)
comboMap.add(token, Option());
if (!comboMap.count(v) || v == "var")
return *this;
}
if (type == "string")
currentValue = v == "<empty>" ? "" : v;
else if (type != "button")
currentValue = v;
if (on_change)
{
const auto ret = on_change(*this);
if (ret && parent != nullptr && parent->info != nullptr)
parent->info(ret);
}
return *this;
} }
std::ostream& operator<<(std::ostream& os, const OptionsMap& om) {
for (size_t idx = 0; idx < om.options_map.size(); ++idx)
for (const auto& it : om.options_map)
if (it.second.idx == idx)
{
const Option& o = it.second;
os << "\noption name " << it.first << " type " << o.type;
/// operator=() updates currentValue and triggers on_change() action. It's up to if (o.type == "check" || o.type == "combo")
/// the GUI to check for option's limits, but we could receive the new value os << " default " << o.defaultValue;
/// from the user by console window, so let's check the bounds anyway.
Option& Option::operator=(const string& v) { else if (o.type == "string")
{
std::string defaultValue = o.defaultValue.empty() ? "<empty>" : o.defaultValue;
os << " default " << defaultValue;
}
assert(!type.empty()); else if (o.type == "spin")
os << " default " << int(stof(o.defaultValue)) << " min " << o.min << " max "
<< o.max;
if ( (type != "button" && type != "string" && v.empty()) break;
|| (type == "check" && v != "true" && v != "false") }
|| (type == "spin" && (stof(v) < min || stof(v) > max)))
return *this;
if (type == "combo") return os;
{ }
OptionsMap comboMap; // To have case insensitive compare
string token;
std::istringstream ss(defaultValue);
while (ss >> token)
comboMap[token] << Option();
if (!comboMap.count(v) || v == "var")
return *this;
}
if (type != "button")
currentValue = v;
if (on_change)
on_change(*this);
return *this;
} }
} // namespace UCI
} // namespace Stockfish
+106
View File
@@ -0,0 +1,106 @@
/*
Stockfish, a UCI chess playing engine derived from Glaurung 2.1
Copyright (C) 2004-2025 The Stockfish developers (see AUTHORS file)
Stockfish is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
Stockfish is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef UCIOPTION_H_INCLUDED
#define UCIOPTION_H_INCLUDED
#include <cstddef>
#include <functional>
#include <iosfwd>
#include <map>
#include <optional>
#include <string>
namespace Stockfish {
// Define a custom comparator, because the UCI options should be case-insensitive
struct CaseInsensitiveLess {
bool operator()(const std::string&, const std::string&) const;
};
class OptionsMap;
// The Option class implements each option as specified by the UCI protocol
class Option {
public:
using OnChange = std::function<std::optional<std::string>(const Option&)>;
Option(const OptionsMap*);
Option(OnChange = nullptr);
Option(bool v, OnChange = nullptr);
Option(const char* v, OnChange = nullptr);
Option(double v, int minv, int maxv, OnChange = nullptr);
Option(const char* v, const char* cur, OnChange = nullptr);
Option& operator=(const std::string&);
operator int() const;
operator std::string() const;
bool operator==(const char*) const;
bool operator!=(const char*) const;
friend std::ostream& operator<<(std::ostream&, const OptionsMap&);
int operator<<(const Option&) = delete;
private:
friend class OptionsMap;
friend class Engine;
friend class Tune;
std::string defaultValue, currentValue, type;
int min, max;
size_t idx;
OnChange on_change;
const OptionsMap* parent = nullptr;
};
class OptionsMap {
public:
using InfoListener = std::function<void(std::optional<std::string>)>;
OptionsMap() = default;
OptionsMap(const OptionsMap&) = delete;
OptionsMap(OptionsMap&&) = delete;
OptionsMap& operator=(const OptionsMap&) = delete;
OptionsMap& operator=(OptionsMap&&) = delete;
void add_info_listener(InfoListener&&);
void setoption(std::istringstream&);
const Option& operator[](const std::string&) const;
void add(const std::string&, const Option& option);
std::size_t count(const std::string&) const;
private:
friend class Engine;
friend class Option;
friend std::ostream& operator<<(std::ostream&, const OptionsMap&);
// The options container is defined as a std::map
using OptionsStore = std::map<std::string, Option, CaseInsensitiveLess>;
OptionsStore options_map;
InfoListener info;
};
}
#endif // #ifndef UCIOPTION_H_INCLUDED

Some files were not shown because too many files have changed in this diff Show More