Compare commits

..

188 Commits

Author SHA1 Message Date
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
78 changed files with 3610 additions and 1840 deletions
+4 -4
View File
@@ -1,8 +1,8 @@
{ {
"config": [ "config": [
{ {
"name": "Ubuntu 20.04 GCC", "name": "Ubuntu 22.04 GCC",
"os": "ubuntu-20.04", "os": "ubuntu-22.04",
"simple_name": "ubuntu", "simple_name": "ubuntu",
"compiler": "g++", "compiler": "g++",
"comp": "gcc", "comp": "gcc",
@@ -111,7 +111,7 @@
{ {
"binaries": "x86-64-avxvnni", "binaries": "x86-64-avxvnni",
"config": { "config": {
"ubuntu-20.04": null "ubuntu-22.04": null
} }
}, },
{ {
@@ -153,7 +153,7 @@
{ {
"binaries": "apple-silicon", "binaries": "apple-silicon",
"config": { "config": {
"os": "ubuntu-20.04" "os": "ubuntu-22.04"
} }
} }
] ]
+1 -1
View File
@@ -18,7 +18,7 @@ permissions:
jobs: jobs:
Clang-Format: Clang-Format:
name: Clang-Format name: Clang-Format
runs-on: ubuntu-20.04 runs-on: ubuntu-22.04
steps: steps:
- uses: actions/checkout@v4 - uses: actions/checkout@v4
with: with:
+8 -8
View File
@@ -19,22 +19,22 @@ jobs:
working-directory: Stockfish/src working-directory: Stockfish/src
run: make -j build debug=yes run: make -j build debug=yes
- name: Checkout fast-chess repo - name: Checkout fastchess repo
uses: actions/checkout@v4 uses: actions/checkout@v4
with: with:
repository: Disservin/fast-chess repository: Disservin/fastchess
path: fast-chess path: fastchess
ref: d54af1910d5479c669dc731f1f54f9108a251951 ref: 894616028492ae6114835195f14a899f6fa237d3
persist-credentials: false persist-credentials: false
- name: fast-chess build - name: fastchess build
working-directory: fast-chess working-directory: fastchess
run: make -j run: make -j
- name: Run games - name: Run games
working-directory: fast-chess working-directory: fastchess
run: | run: |
./fast-chess -rounds 4 -games 2 -repeat -concurrency 4 -openings file=app/tests/data/openings.epd format=epd order=random -srand $RANDOM\ ./fastchess -rounds 4 -games 2 -repeat -concurrency 4 -openings file=app/tests/data/openings.epd format=epd order=random -srand $RANDOM\
-engine name=sf1 cmd=/home/runner/work/Stockfish/Stockfish/Stockfish/src/stockfish\ -engine name=sf1 cmd=/home/runner/work/Stockfish/Stockfish/Stockfish/src/stockfish\
-engine name=sf2 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 -ratinginterval 1 -report penta=true -each proto=uci tc=4+0.04 -log file=fast.log | tee fast.out
+19 -2
View File
@@ -24,7 +24,7 @@ jobs:
with: with:
repository: vondele/matetrack repository: vondele/matetrack
path: matetrack path: matetrack
ref: 814160f82e6428ed2f6522dc06c2a6fa539cd413 ref: 4f8a80860ed8f3607f05a9195df8b40203bdc360
persist-credentials: false persist-credentials: false
- name: matetrack install deps - name: matetrack install deps
@@ -50,5 +50,22 @@ jobs:
- name: Run matetrack - name: Run matetrack
working-directory: matetrack working-directory: matetrack
run: | run: |
python matecheck.py --syzygyPath 3-4-5-wdl/:3-4-5-dtz/ --engine /home/runner/work/Stockfish/Stockfish/Stockfish/src/stockfish --epdFile mates2000.epd --nodes 100000 | tee matecheckout.out python matecheck.py --syzygyPath 3-4-5-wdl/:3-4-5-dtz/ --engine /home/runner/work/Stockfish/Stockfish/Stockfish/src/stockfish --epdFile mates2000.epd --nodes 100000 | tee matecheckout.out
! grep "issues were detected" matecheckout.out > /dev/null ! grep "issues were detected" matecheckout.out > /dev/null
- name: Run matetrack with --syzygy50MoveRule false
working-directory: matetrack
run: |
grep 5men cursed.epd > cursed5.epd
python matecheck.py --syzygyPath 3-4-5-wdl/:3-4-5-dtz/ --engine /home/runner/work/Stockfish/Stockfish/Stockfish/src/stockfish --epdFile cursed5.epd --nodes 100000 --syzygy50MoveRule false | tee matecheckcursed.out
! grep "issues were detected" matecheckcursed.out > /dev/null
- name: Verify mate and TB win count for matecheckcursed.out
working-directory: matetrack
run: |
mates=$(grep "Found mates:" matecheckcursed.out | awk '{print $3}')
tbwins=$(grep "Found TB wins:" matecheckcursed.out | awk '{print $4}')
if [ $(($mates + $tbwins)) -ne 32 ]; then
echo "Sum of mates and TB wins is not 32 in matecheckcursed.out" >&2
exit 1
fi
+11 -2
View File
@@ -21,19 +21,28 @@ jobs:
sanitizers: sanitizers:
- name: Run with thread sanitizer - name: Run with thread sanitizer
make_option: sanitize=thread make_option: sanitize=thread
cxx_extra_flags: ""
instrumented_option: sanitizer-thread instrumented_option: sanitizer-thread
- name: Run with UB sanitizer - name: Run with UB sanitizer
make_option: sanitize=undefined make_option: sanitize=undefined
cxx_extra_flags: ""
instrumented_option: sanitizer-undefined instrumented_option: sanitizer-undefined
- name: Run under valgrind - name: Run under valgrind
make_option: "" make_option: ""
cxx_extra_flags: ""
instrumented_option: valgrind instrumented_option: valgrind
- name: Run under valgrind-thread - name: Run under valgrind-thread
make_option: "" make_option: ""
cxx_extra_flags: ""
instrumented_option: valgrind-thread instrumented_option: valgrind-thread
- name: Run non-instrumented - name: Run non-instrumented
make_option: "" make_option: ""
cxx_extra_flags: ""
instrumented_option: none instrumented_option: none
- name: Run with glibcxx assertions
make_option: ""
cxx_extra_flags: -D_GLIBCXX_ASSERTIONS
instrumented_option: non
defaults: defaults:
run: run:
working-directory: src working-directory: src
@@ -72,7 +81,7 @@ jobs:
- name: ${{ matrix.sanitizers.name }} - name: ${{ matrix.sanitizers.name }}
run: | run: |
export CXXFLAGS="-O1 -fno-inline" export CXXFLAGS="-O1 -fno-inline ${{ matrix.sanitizers.cxx_extra_flags }}"
make clean make clean
make -j4 ARCH=x86-64-sse41-popcnt ${{ matrix.sanitizers.make_option }} debug=yes optimize=no build > /dev/null make -j4 ARCH=x86-64-sse41-popcnt ${{ matrix.sanitizers.make_option }} debug=yes optimize=no build > /dev/null
../tests/instrumented.sh --${{ matrix.sanitizers.instrumented_option }} python3 ../tests/instrumented.py --${{ matrix.sanitizers.instrumented_option }} ./stockfish
+11 -11
View File
@@ -13,15 +13,15 @@ jobs:
fail-fast: false fail-fast: false
matrix: matrix:
config: config:
- name: Ubuntu 20.04 GCC - name: Ubuntu 22.04 GCC
os: ubuntu-20.04 os: ubuntu-22.04
compiler: g++ compiler: g++
comp: gcc comp: gcc
run_32bit_tests: true run_32bit_tests: true
run_64bit_tests: true run_64bit_tests: true
shell: bash shell: bash
- name: Ubuntu 20.04 Clang - name: Ubuntu 22.04 Clang
os: ubuntu-20.04 os: ubuntu-22.04
compiler: clang++ compiler: clang++
comp: clang comp: clang
run_32bit_tests: true run_32bit_tests: true
@@ -139,11 +139,11 @@ jobs:
- name: Build Docker container - name: Build Docker container
if: matrix.config.base_image if: matrix.config.base_image
run: | run: |
docker buildx build --load -t sf_builder - << EOF docker buildx build --platform ${{ matrix.config.platform }} --load -t sf_builder - << EOF
FROM ${{ matrix.config.base_image }} FROM ${{ matrix.config.base_image }}
WORKDIR /app WORKDIR /app
RUN apk update && apk add make g++ RUN apk update && apk add make g++
CMD ["sh", "script.sh"] CMD ["sh", "src/script.sh"]
EOF EOF
- name: Download required macOS packages - name: Download required macOS packages
@@ -176,7 +176,7 @@ jobs:
$COMPCXX -v $COMPCXX -v
else else
echo "$COMPCXX -v" > script.sh echo "$COMPCXX -v" > script.sh
docker run --rm --platform ${{ matrix.config.platform }} -v ${{ github.workspace }}/src:/app sf_builder docker run --rm --platform ${{ matrix.config.platform }} -v ${{ github.workspace }}:/app sf_builder
fi fi
- name: Test help target - name: Test help target
@@ -342,8 +342,8 @@ jobs:
- name: Test riscv64 build - name: Test riscv64 build
if: matrix.config.run_riscv64_tests if: matrix.config.run_riscv64_tests
run: | run: |
echo "export LDFLAGS='-static' && make clean && make -j4 ARCH=riscv64 build" > script.sh 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 }}/src:/app sf_builder docker run --rm --platform ${{ matrix.config.platform }} -v ${{ github.workspace }}:/app sf_builder
../tests/signature.sh $benchref ../tests/signature.sh $benchref
# ppc64 tests # ppc64 tests
@@ -351,8 +351,8 @@ jobs:
- name: Test ppc64 build - name: Test ppc64 build
if: matrix.config.run_ppc64_tests if: matrix.config.run_ppc64_tests
run: | run: |
echo "export LDFLAGS='-static' && make clean && make -j4 ARCH=ppc-64 build" > script.sh 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 }}/src:/app sf_builder docker run --rm --platform ${{ matrix.config.platform }} -v ${{ github.workspace }}:/app sf_builder
../tests/signature.sh $benchref ../tests/signature.sh $benchref
# Other tests # Other tests
+1
View File
@@ -59,6 +59,7 @@ jobs:
mv "${{ matrix.config.simple_name }} ${{ matrix.binaries }}" stockfish-workflow mv "${{ matrix.config.simple_name }} ${{ matrix.binaries }}" stockfish-workflow
cd stockfish-workflow cd stockfish-workflow
cp -r src ../stockfish/ cp -r src ../stockfish/
cp -r scripts ../stockfish/
cp stockfish-$NAME-$BINARY$EXT ../stockfish/ cp stockfish-$NAME-$BINARY$EXT ../stockfish/
cp "Top CPU Contributors.txt" ../stockfish/ cp "Top CPU Contributors.txt" ../stockfish/
cp Copying.txt ../stockfish/ cp Copying.txt ../stockfish/
+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
+7
View File
@@ -45,7 +45,9 @@ 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 Ciekce
clefrks clefrks
@@ -123,10 +125,12 @@ 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--)
@@ -143,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)
@@ -176,6 +181,7 @@ 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
@@ -237,6 +243,7 @@ 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) Xiang Wang (KatyushaScarlet)
+1 -2
View File
@@ -49,7 +49,7 @@ further discussion._
- Provide a clear and concise description of the changes in the pull request - Provide a clear and concise description of the changes in the pull request
description. description.
_First time contributors should add their name to [AUTHORS](../AUTHORS)._ _First time contributors should add their name to [AUTHORS](./AUTHORS)._
_Stockfish's development is not focused on adding new features. Thus any pull _Stockfish's development is not focused on adding new features. Thus any pull
request introducing new features will potentially be closed without further request introducing new features will potentially be closed without further
@@ -86,7 +86,6 @@ more details.
Thank you for contributing to Stockfish and helping us make it even better! 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 [copying-link]: https://github.com/official-stockfish/Stockfish/blob/master/Copying.txt
[discord-link]: https://discord.gg/GWDRS3kU6R [discord-link]: https://discord.gg/GWDRS3kU6R
[discussions-link]: https://github.com/official-stockfish/Stockfish/discussions/new [discussions-link]: https://github.com/official-stockfish/Stockfish/discussions/new
+8 -1
View File
@@ -97,7 +97,7 @@ descriptions. An example suitable for most Intel and AMD chips:
``` ```
cd src cd src
make -j profile-build ARCH=x86-64-avx2 make -j profile-build
``` ```
Detailed compilation instructions for all platforms can be found in our Detailed compilation instructions for all platforms can be found in our
@@ -120,6 +120,11 @@ where the source code can be found) to generate the exact binary you are
distributing. If you make any changes to the source code, these changes must 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
@@ -144,6 +149,8 @@ also be made available under GPL v3.
[wiki-uci-link]: https://github.com/official-stockfish/Stockfish/wiki/UCI-&-Commands [wiki-uci-link]: https://github.com/official-stockfish/Stockfish/wiki/UCI-&-Commands
[wiki-usage-link]: https://github.com/official-stockfish/Stockfish/wiki/Download-and-usage [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 [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
+1
View File
@@ -0,0 +1 @@
*.sh text eol=lf
+34 -1
View File
@@ -26,6 +26,17 @@ check_znver_1_2() {
[ "$vendor_id" = "AuthenticAMD" ] && [ "$cpu_family" = "23" ] && znver_1_2=true [ "$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 the file CPU x86_64 architecture
set_arch_x86_64() { set_arch_x86_64() {
if check_flags 'avx512vnni' 'avx512dq' 'avx512f' 'avx512bw' 'avx512vl'; then if check_flags 'avx512vnni' 'avx512dq' 'avx512f' 'avx512bw' 'avx512vl'; then
@@ -43,6 +54,20 @@ set_arch_x86_64() {
fi 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 # Check the system type
uname_s=$(uname -s) uname_s=$(uname -s)
uname_m=$(uname -m) uname_m=$(uname -m)
@@ -51,7 +76,7 @@ case $uname_s in
case $uname_m in case $uname_m in
'arm64') 'arm64')
true_arch='apple-silicon' true_arch='apple-silicon'
file_arch='x86-64-sse41-popcnt' # Supported by Rosetta 2 file_arch='m1-apple-silicon'
;; ;;
'x86_64') 'x86_64')
flags=$(sysctl -n machdep.cpu.features machdep.cpu.leaf7_features | tr '\n' ' ' | tr '[:upper:]' '[:lower:]' | tr -d '_.') flags=$(sysctl -n machdep.cpu.features machdep.cpu.leaf7_features | tr '\n' ' ' | tr '[:upper:]' '[:lower:]' | tr -d '_.')
@@ -76,6 +101,10 @@ case $uname_s in
file_os='ubuntu' file_os='ubuntu'
true_arch='x86-32' true_arch='x86-32'
;; ;;
'ppc64'*)
file_os='ubuntu'
set_arch_ppc_64
;;
'aarch64') 'aarch64')
file_os='android' file_os='android'
true_arch='armv8' true_arch='armv8'
@@ -90,6 +119,10 @@ case $uname_s in
true_arch="$true_arch-neon" true_arch="$true_arch-neon"
fi fi
;; ;;
'loongarch64'*)
file_os='linux'
set_arch_loongarch64
;;
*) # Unsupported machine type, exit with error *) # Unsupported machine type, exit with error
printf 'Unsupported machine type: %s\n' "$uname_m" printf 'Unsupported machine type: %s\n' "$uname_m"
exit 1 exit 1
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
+202 -178
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-2024 The Stockfish developers (see AUTHORS file) # Copyright (C) 2004-2025 The Stockfish developers (see AUTHORS file)
# #
# Stockfish is free software: you can redistribute it and/or modify # 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
@@ -57,7 +57,7 @@ SRCS = benchmark.cpp bitboard.cpp evaluate.cpp main.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/nnue_misc.cpp nnue/features/half_ka_v2_hm.cpp nnue/network.cpp engine.cpp score.cpp memory.cpp nnue/nnue_misc.cpp nnue/features/half_ka_v2_hm.cpp nnue/network.cpp engine.cpp score.cpp memory.cpp
HEADERS = benchmark.h bitboard.h evaluate.h misc.h movegen.h movepick.h \ HEADERS = benchmark.h bitboard.h evaluate.h misc.h movegen.h movepick.h history.h \
nnue/nnue_misc.h nnue/features/half_ka_v2_hm.h nnue/layers/affine_transform.h \ nnue/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/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/layers/sqr_clipped_relu.h nnue/nnue_accumulator.h nnue/nnue_architecture.h \
@@ -98,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
@@ -124,8 +128,9 @@ endif
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 loongarch64)) 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
@@ -148,9 +153,13 @@ 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),) ifneq ($(shell which clang-format-18 2> /dev/null),)
@@ -355,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
@@ -370,8 +393,19 @@ ifeq ($(ARCH),riscv64)
arch = riscv64 arch = riscv64
endif endif
ifeq ($(ARCH),loongarch64) ifeq ($(findstring loongarch64,$(ARCH)),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 endif
@@ -408,7 +442,7 @@ ifeq ($(COMP),gcc)
ifeq ($(ARCH),riscv64) ifeq ($(ARCH),riscv64)
CXXFLAGS += -latomic CXXFLAGS += -latomic
endif endif
else ifeq ($(ARCH),loongarch64) else ifeq ($(arch),loongarch64)
CXXFLAGS += -latomic CXXFLAGS += -latomic
else else
CXXFLAGS += -m$(bits) CXXFLAGS += -m$(bits)
@@ -480,7 +514,7 @@ ifeq ($(COMP),clang)
ifeq ($(ARCH),riscv64) ifeq ($(ARCH),riscv64)
CXXFLAGS += -latomic CXXFLAGS += -latomic
endif endif
else ifeq ($(ARCH),loongarch64) else ifeq ($(arch),loongarch64)
CXXFLAGS += -latomic CXXFLAGS += -latomic
else else
CXXFLAGS += -m$(bits) CXXFLAGS += -m$(bits)
@@ -634,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
@@ -704,6 +738,20 @@ ifeq ($(mmx),yes)
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)
@@ -719,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
@@ -791,71 +851,75 @@ endif
### ========================================================================== ### ==========================================================================
help: help:
@echo "" @echo "" && \
@echo "To compile stockfish, type: " echo "To compile stockfish, type: " && \
@echo "" echo "" && \
@echo "make -j 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 nets" 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 "native > select the best architecture for the host processor (default)" echo "native > select the best architecture for the host processor (default)" && \
@echo "x86-64-vnni512 > x86 64-bit with vnni 512bit support" echo "x86-64-vnni512 > x86 64-bit with vnni 512bit support" && \
@echo "x86-64-vnni256 > x86 64-bit with vnni 512bit support, limit operands to 256bit wide" echo "x86-64-vnni256 > x86 64-bit with vnni 512bit support, limit operands to 256bit wide" && \
@echo "x86-64-avx512 > x86 64-bit with avx512 support" echo "x86-64-avx512 > x86 64-bit with avx512 support" && \
@echo "x86-64-avxvnni > x86 64-bit with vnni 256bit support" echo "x86-64-avxvnni > x86 64-bit with vnni 256bit support" && \
@echo "x86-64-bmi2 > x86 64-bit with bmi2 support" echo "x86-64-bmi2 > x86 64-bit with bmi2 support" && \
@echo "x86-64-avx2 > x86 64-bit with avx2 support" echo "x86-64-avx2 > x86 64-bit with avx2 support" && \
@echo "x86-64-sse41-popcnt > x86 64-bit with sse41 and popcnt support" echo "x86-64-sse41-popcnt > x86 64-bit with sse41 and popcnt support" && \
@echo "x86-64-modern > deprecated, currently x86-64-sse41-popcnt" echo "x86-64-modern > deprecated, currently x86-64-sse41-popcnt" && \
@echo "x86-64-ssse3 > x86 64-bit with ssse3 support" echo "x86-64-ssse3 > x86 64-bit with ssse3 support" && \
@echo "x86-64-sse3-popcnt > x86 64-bit with sse3 compile and popcnt support" echo "x86-64-sse3-popcnt > x86 64-bit with sse3 compile and popcnt support" && \
@echo "x86-64 > x86 64-bit generic (with sse2 support)" echo "x86-64 > x86 64-bit generic (with sse2 support)" && \
@echo "x86-32-sse41-popcnt > x86 32-bit with sse41 and popcnt support" echo "x86-32-sse41-popcnt > x86 32-bit with sse41 and popcnt support" && \
@echo "x86-32-sse2 > x86 32-bit with sse2 support" echo "x86-32-sse2 > x86 32-bit with sse2 support" && \
@echo "x86-32 > x86 32-bit generic (with mmx compile support)" echo "x86-32 > x86 32-bit generic (with mmx compile support)" && \
@echo "ppc-64 > PPC 64-bit" echo "ppc-64 > PPC 64-bit" && \
@echo "ppc-32 > PPC 32-bit" echo "ppc-64-altivec > PPC 64-bit with altivec support" && \
@echo "armv7 > ARMv7 32-bit" echo "ppc-64-vsx > PPC 64-bit with vsx support" && \
@echo "armv7-neon > ARMv7 32-bit with popcnt and neon" echo "ppc-32 > PPC 32-bit" && \
@echo "armv8 > ARMv8 64-bit with popcnt and neon" echo "armv7 > ARMv7 32-bit" && \
@echo "armv8-dotprod > ARMv8 64-bit with popcnt, neon and dot product support" echo "armv7-neon > ARMv7 32-bit with popcnt and neon" && \
@echo "e2k > Elbrus 2000" echo "armv8 > ARMv8 64-bit with popcnt and neon" && \
@echo "apple-silicon > Apple silicon ARM64" echo "armv8-dotprod > ARMv8 64-bit with popcnt, neon and dot product support" && \
@echo "general-64 > unspecified 64-bit" echo "e2k > Elbrus 2000" && \
@echo "general-32 > unspecified 32-bit" echo "apple-silicon > Apple silicon ARM64" && \
@echo "riscv64 > RISC-V 64-bit" echo "general-64 > unspecified 64-bit" && \
@echo "loongarch64 > LoongArch 64-bit" echo "general-32 > unspecified 32-bit" && \
@echo "" echo "riscv64 > RISC-V 64-bit" && \
@echo "Supported compilers:" echo "loongarch64 > LoongArch 64-bit" && \
@echo "" echo "loongarch64-lsx > LoongArch 64-bit with SIMD eXtension" && \
@echo "gcc > GNU compiler (default)" echo "loongarch64-lasx > LoongArch 64-bit with Advanced SIMD eXtension" && \
@echo "mingw > GNU compiler with MinGW under Windows" echo "" && \
@echo "clang > LLVM Clang compiler" echo "Supported compilers:" && \
@echo "icx > Intel oneAPI DPC++/C++ Compiler" echo "" && \
@echo "ndk > Google NDK to cross-compile for Android" echo "gcc > GNU compiler (default)" && \
@echo "" echo "mingw > GNU compiler with MinGW under Windows" && \
@echo "Simple examples. If you don't know what to do, you likely want to run one of: " echo "clang > LLVM Clang compiler" && \
@echo "" echo "icx > Intel oneAPI DPC++/C++ Compiler" && \
@echo "make -j profile-build ARCH=x86-64-avx2 # typically a fast compile for common systems " echo "ndk > Google NDK to cross-compile for Android" && \
@echo "make -j profile-build ARCH=x86-64-sse41-popcnt # A more portable compile for 64-bit systems " echo "" && \
@echo "make -j profile-build ARCH=x86-64 # A portable compile for 64-bit systems " echo "Simple examples. If you don't know what to do, you likely want to run one of: " && \
@echo "" echo "" && \
@echo "Advanced examples, for experienced users: " echo "make -j profile-build ARCH=x86-64-avx2 # typically a fast compile for common systems " && \
@echo "" echo "make -j profile-build ARCH=x86-64-sse41-popcnt # A more portable compile for 64-bit systems " && \
@echo "make -j profile-build ARCH=x86-64-avxvnni" echo "make -j profile-build ARCH=x86-64 # A portable compile for 64-bit systems " && \
@echo "make -j profile-build ARCH=x86-64-avxvnni COMP=gcc COMPCXX=g++-12.0" echo "" && \
@echo "make -j build ARCH=x86-64-ssse3 COMP=clang" echo "Advanced examples, for experienced users: " && \
@echo "" echo "" && \
echo "make -j profile-build ARCH=x86-64-avxvnni" && \
echo "make -j profile-build ARCH=x86-64-avxvnni COMP=gcc COMPCXX=g++-12.0" && \
echo "make -j build ARCH=x86-64-ssse3 COMP=clang" && \
echo ""
ifneq ($(SUPPORTED_ARCH), true) 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 ""
@@ -917,59 +981,9 @@ profileclean:
@rm -f stockfish.res @rm -f stockfish.res
@rm -f ./-lstdc++.res @rm -f ./-lstdc++.res
define fetch_network
@echo "Default net: $(nnuenet)"
@if [ "x$(curl_or_wget)" = "x" ]; then \
echo "Neither curl nor wget is installed. Install one of these tools unless the net has been downloaded manually"; \
fi
@if [ "x$(shasum_command)" = "x" ]; then \
echo "shasum / sha256sum not found, skipping net validation"; \
elif test -f "$(nnuenet)"; then \
if [ "$(nnuenet)" != "nn-"`$(shasum_command) $(nnuenet) | cut -c1-12`".nnue" ]; then \
echo "Removing invalid network"; rm -f $(nnuenet); \
fi; \
fi;
@for nnuedownloadurl in "$(nnuedownloadurl1)" "$(nnuedownloadurl2)"; do \
if test -f "$(nnuenet)"; then \
echo "$(nnuenet) available : OK"; break; \
else \
if [ "x$(curl_or_wget)" != "x" ]; then \
echo "Downloading $${nnuedownloadurl}"; $(curl_or_wget) $${nnuedownloadurl} > $(nnuenet);\
else \
echo "No net found and download not possible"; exit 1;\
fi; \
fi; \
if [ "x$(shasum_command)" != "x" ]; then \
if [ "$(nnuenet)" != "nn-"`$(shasum_command) $(nnuenet) | cut -c1-12`".nnue" ]; then \
echo "Removing failed download"; rm -f $(nnuenet); \
fi; \
fi; \
done
@if ! test -f "$(nnuenet)"; then \
echo "Failed to download $(nnuenet)."; \
fi;
@if [ "x$(shasum_command)" != "x" ]; then \
if [ "$(nnuenet)" = "nn-"`$(shasum_command) $(nnuenet) | cut -c1-12`".nnue" ]; then \
echo "Network validated"; break; \
fi; \
fi;
endef
# set up shell variables for the net stuff
define netvariables
$(eval nnuenet := $(shell grep $(1) evaluate.h | grep define | sed 's/.*\(nn-[a-z0-9]\{12\}.nnue\).*/\1/'))
$(eval nnuedownloadurl1 := https://tests.stockfishchess.org/api/nn/$(nnuenet))
$(eval nnuedownloadurl2 := https://github.com/official-stockfish/networks/raw/master/$(nnuenet))
$(eval curl_or_wget := $(shell if hash curl 2>/dev/null; then echo "curl -skL"; elif hash wget 2>/dev/null; then echo "wget -qO-"; fi))
$(eval shasum_command := $(shell if hash shasum 2>/dev/null; then echo "shasum -a 256 "; elif hash sha256sum 2>/dev/null; then echo "sha256sum "; fi))
endef
# evaluation network (nnue) # evaluation network (nnue)
net: net:
$(call netvariables, EvalFileDefaultNameBig) @$(SHELL) ../scripts/net.sh
$(call fetch_network)
$(call netvariables, EvalFileDefaultNameSmall)
$(call fetch_network)
format: format:
$(CLANG-FORMAT) -i $(SRCS) $(HEADERS) -style=file $(CLANG-FORMAT) -i $(SRCS) $(HEADERS) -style=file
@@ -986,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)" = "loongarch64" 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)
+350 -1
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-2024 The Stockfish developers (see AUTHORS file) Copyright (C) 2004-2025 The Stockfish developers (see AUTHORS file)
Stockfish is free software: you can redistribute it and/or modify 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,6 +17,7 @@
*/ */
#include "benchmark.h" #include "benchmark.h"
#include "numa.h"
#include <cstdlib> #include <cstdlib>
#include <fstream> #include <fstream>
@@ -91,6 +92,282 @@ const std::vector<std::string> Defaults = {
}; };
// clang-format on // clang-format on
// clang-format off
// human-randomly picked 5 games with <60 moves from
// https://tests.stockfishchess.org/tests/view/665c71f9fd45fb0f907c21e0
// only moves for one side
const std::vector<std::vector<std::string>> BenchmarkPositions = {
{
"rnbq1k1r/ppp1bppp/4pn2/8/2B5/2NP1N2/PPP2PPP/R1BQR1K1 b - - 2 8",
"rnbq1k1r/pp2bppp/4pn2/2p5/2B2B2/2NP1N2/PPP2PPP/R2QR1K1 b - - 1 9",
"r1bq1k1r/pp2bppp/2n1pn2/2p5/2B1NB2/3P1N2/PPP2PPP/R2QR1K1 b - - 3 10",
"r1bq1k1r/pp2bppp/2n1p3/2p5/2B1PB2/5N2/PPP2PPP/R2QR1K1 b - - 0 11",
"r1b2k1r/pp2bppp/2n1p3/2p5/2B1PB2/5N2/PPP2PPP/3RR1K1 b - - 0 12",
"r1b1k2r/pp2bppp/2n1p3/2p5/2B1PB2/2P2N2/PP3PPP/3RR1K1 b - - 0 13",
"r1b1k2r/1p2bppp/p1n1p3/2p5/4PB2/2P2N2/PP2BPPP/3RR1K1 b - - 1 14",
"r1b1k2r/4bppp/p1n1p3/1pp5/P3PB2/2P2N2/1P2BPPP/3RR1K1 b - - 0 15",
"r1b1k2r/4bppp/p1n1p3/1P6/2p1PB2/2P2N2/1P2BPPP/3RR1K1 b - - 0 16",
"r1b1k2r/4bppp/2n1p3/1p6/2p1PB2/1PP2N2/4BPPP/3RR1K1 b - - 0 17",
"r3k2r/3bbppp/2n1p3/1p6/2P1PB2/2P2N2/4BPPP/3RR1K1 b - - 0 18",
"r3k2r/3bbppp/2n1p3/8/1pP1P3/2P2N2/3BBPPP/3RR1K1 b - - 1 19",
"1r2k2r/3bbppp/2n1p3/8/1pPNP3/2P5/3BBPPP/3RR1K1 b - - 3 20",
"1r2k2r/3bbppp/2n1p3/8/2PNP3/2B5/4BPPP/3RR1K1 b - - 0 21",
"1r2k2r/3bb1pp/2n1pp2/1N6/2P1P3/2B5/4BPPP/3RR1K1 b - - 1 22",
"1r2k2r/3b2pp/2n1pp2/1N6/1BP1P3/8/4BPPP/3RR1K1 b - - 0 23",
"1r2k2r/3b2pp/4pp2/1N6/1nP1P3/8/3RBPPP/4R1K1 b - - 1 24",
"1r5r/3bk1pp/4pp2/1N6/1nP1PP2/8/3RB1PP/4R1K1 b - - 0 25",
"1r5r/3bk1pp/2n1pp2/1N6/2P1PP2/8/3RBKPP/4R3 b - - 2 26",
"1r5r/3bk1pp/2n2p2/1N2p3/2P1PP2/6P1/3RBK1P/4R3 b - - 0 27",
"1r1r4/3bk1pp/2n2p2/1N2p3/2P1PP2/6P1/3RBK1P/R7 b - - 2 28",
"1r1r4/N3k1pp/2n1bp2/4p3/2P1PP2/6P1/3RBK1P/R7 b - - 4 29",
"1r1r4/3bk1pp/2N2p2/4p3/2P1PP2/6P1/3RBK1P/R7 b - - 0 30",
"1r1R4/4k1pp/2b2p2/4p3/2P1PP2/6P1/4BK1P/R7 b - - 0 31",
"3r4/4k1pp/2b2p2/4P3/2P1P3/6P1/4BK1P/R7 b - - 0 32",
"3r4/R3k1pp/2b5/4p3/2P1P3/6P1/4BK1P/8 b - - 1 33",
"8/3rk1pp/2b5/R3p3/2P1P3/6P1/4BK1P/8 b - - 3 34",
"8/3r2pp/2bk4/R1P1p3/4P3/6P1/4BK1P/8 b - - 0 35",
"8/2kr2pp/2b5/R1P1p3/4P3/4K1P1/4B2P/8 b - - 2 36",
"1k6/3r2pp/2b5/RBP1p3/4P3/4K1P1/7P/8 b - - 4 37",
"8/1k1r2pp/2b5/R1P1p3/4P3/3BK1P1/7P/8 b - - 6 38",
"1k6/3r2pp/2b5/2P1p3/4P3/3BK1P1/7P/R7 b - - 8 39",
"1k6/r5pp/2b5/2P1p3/4P3/3BK1P1/7P/5R2 b - - 10 40",
"1k3R2/6pp/2b5/2P1p3/4P3/r2BK1P1/7P/8 b - - 12 41",
"5R2/2k3pp/2b5/2P1p3/4P3/r2B2P1/3K3P/8 b - - 14 42",
"5R2/2k3pp/2b5/2P1p3/4P3/3BK1P1/r6P/8 b - - 16 43",
"5R2/2k3pp/2b5/2P1p3/4P3/r2B2P1/4K2P/8 b - - 18 44",
"5R2/2k3pp/2b5/2P1p3/4P3/3B1KP1/r6P/8 b - - 20 45",
"8/2k2Rpp/2b5/2P1p3/4P3/r2B1KP1/7P/8 b - - 22 46",
"3k4/5Rpp/2b5/2P1p3/4P3/r2B2P1/4K2P/8 b - - 24 47",
"3k4/5Rpp/2b5/2P1p3/4P3/3B1KP1/r6P/8 b - - 26 48",
"3k4/5Rpp/2b5/2P1p3/4P3/r2B2P1/4K2P/8 b - - 28 49",
"3k4/5Rpp/2b5/2P1p3/4P3/3BK1P1/r6P/8 b - - 30 50",
"3k4/5Rpp/2b5/2P1p3/4P3/r2B2P1/3K3P/8 b - - 32 51",
"3k4/5Rpp/2b5/2P1p3/4P3/2KB2P1/r6P/8 b - - 34 52",
"3k4/5Rpp/2b5/2P1p3/4P3/r2B2P1/2K4P/8 b - - 36 53",
"3k4/5Rpp/2b5/2P1p3/4P3/1K1B2P1/r6P/8 b - - 38 54",
"3k4/6Rp/2b5/2P1p3/4P3/1K1B2P1/7r/8 b - - 0 55",
"3k4/8/2b3Rp/2P1p3/4P3/1K1B2P1/7r/8 b - - 1 56",
"8/2k3R1/2b4p/2P1p3/4P3/1K1B2P1/7r/8 b - - 3 57",
"3k4/8/2b3Rp/2P1p3/4P3/1K1B2P1/7r/8 b - - 5 58",
"8/2k5/2b3Rp/2P1p3/1K2P3/3B2P1/7r/8 b - - 7 59",
"8/2k5/2b3Rp/2P1p3/4P3/2KB2P1/3r4/8 b - - 9 60",
"8/2k5/2b3Rp/2P1p3/1K2P3/3B2P1/6r1/8 b - - 11 61",
"8/2k5/2b3Rp/2P1p3/4P3/2KB2P1/3r4/8 b - - 13 62",
"8/2k5/2b3Rp/2P1p3/2K1P3/3B2P1/6r1/8 b - - 15 63",
"4b3/2k3R1/7p/2P1p3/2K1P3/3B2P1/6r1/8 b - - 17 64",
},
{
"r1bqkbnr/npp1pppp/p7/3P4/4pB2/2N5/PPP2PPP/R2QKBNR w KQkq - 1 6",
"r1bqkb1r/npp1pppp/p4n2/3P4/4pB2/2N5/PPP1QPPP/R3KBNR w KQkq - 3 7",
"r2qkb1r/npp1pppp/p4n2/3P1b2/4pB2/2N5/PPP1QPPP/2KR1BNR w kq - 5 8",
"r2qkb1r/1pp1pppp/p4n2/1n1P1b2/4pB2/2N4P/PPP1QPP1/2KR1BNR w kq - 1 9",
"r2qkb1r/1pp1pppp/5n2/1p1P1b2/4pB2/7P/PPP1QPP1/2KR1BNR w kq - 0 10",
"r2qkb1r/1ppbpppp/5n2/1Q1P4/4pB2/7P/PPP2PP1/2KR1BNR w kq - 1 11",
"3qkb1r/1Qpbpppp/5n2/3P4/4pB2/7P/rPP2PP1/2KR1BNR w k - 0 12",
"q3kb1r/1Qpbpppp/5n2/3P4/4pB2/7P/rPP2PP1/1K1R1BNR w k - 2 13",
"r3kb1r/2pbpppp/5n2/3P4/4pB2/7P/1PP2PP1/1K1R1BNR w k - 0 14",
"r3kb1r/2Bb1ppp/4pn2/3P4/4p3/7P/1PP2PP1/1K1R1BNR w k - 0 15",
"r3kb1r/2Bb2pp/4pn2/8/4p3/7P/1PP2PP1/1K1R1BNR w k - 0 16",
"r3k2r/2Bb2pp/4pn2/2b5/4p3/7P/1PP1NPP1/1K1R1B1R w k - 2 17",
"r6r/2Bbk1pp/4pn2/2b5/3Np3/7P/1PP2PP1/1K1R1B1R w - - 4 18",
"r6r/b2bk1pp/4pn2/4B3/3Np3/7P/1PP2PP1/1K1R1B1R w - - 6 19",
"r1r5/b2bk1pp/4pn2/4B3/2BNp3/7P/1PP2PP1/1K1R3R w - - 8 20",
"r7/b2bk1pp/4pn2/2r1B3/2BNp3/1P5P/2P2PP1/1K1R3R w - - 1 21",
"rb6/3bk1pp/4pn2/2r1B3/2BNpP2/1P5P/2P3P1/1K1R3R w - - 1 22",
"1r6/3bk1pp/4pn2/2r5/2BNpP2/1P5P/2P3P1/1K1R3R w - - 0 23",
"1r6/3bk1p1/4pn1p/2r5/2BNpP2/1P5P/2P3P1/2KR3R w - - 0 24",
"8/3bk1p1/1r2pn1p/2r5/2BNpP1P/1P6/2P3P1/2KR3R w - - 1 25",
"8/3bk3/1r2pnpp/2r5/2BNpP1P/1P6/2P3P1/2K1R2R w - - 0 26",
"2b5/4k3/1r2pnpp/2r5/2BNpP1P/1P4P1/2P5/2K1R2R w - - 1 27",
"8/1b2k3/1r2pnpp/2r5/2BNpP1P/1P4P1/2P5/2K1R1R1 w - - 3 28",
"8/1b1nk3/1r2p1pp/2r5/2BNpPPP/1P6/2P5/2K1R1R1 w - - 1 29",
"8/1b2k3/1r2p1pp/2r1nP2/2BNp1PP/1P6/2P5/2K1R1R1 w - - 1 30",
"8/1b2k3/1r2p1p1/2r1nPp1/2BNp2P/1P6/2P5/2K1R1R1 w - - 0 31",
"8/1b2k3/1r2p1n1/2r3p1/2BNp2P/1P6/2P5/2K1R1R1 w - - 0 32",
"8/1b2k3/1r2p1n1/6r1/2BNp2P/1P6/2P5/2K1R3 w - - 0 33",
"8/1b2k3/1r2p3/4n1P1/2BNp3/1P6/2P5/2K1R3 w - - 1 34",
"8/1b2k3/1r2p3/4n1P1/2BN4/1P2p3/2P5/2K4R w - - 0 35",
"8/1b2k3/1r2p2R/6P1/2nN4/1P2p3/2P5/2K5 w - - 0 36",
"8/1b2k3/3rp2R/6P1/2PN4/4p3/2P5/2K5 w - - 1 37",
"8/4k3/3rp2R/6P1/2PN4/2P1p3/6b1/2K5 w - - 1 38",
"8/4k3/r3p2R/2P3P1/3N4/2P1p3/6b1/2K5 w - - 1 39",
"8/3k4/r3p2R/2P2NP1/8/2P1p3/6b1/2K5 w - - 3 40",
"8/3k4/4p2R/2P3P1/8/2P1N3/6b1/r1K5 w - - 1 41",
"8/3k4/4p2R/2P3P1/8/2P1N3/3K2b1/6r1 w - - 3 42",
"8/3k4/4p2R/2P3P1/8/2PKNb2/8/6r1 w - - 5 43",
"8/4k3/4p1R1/2P3P1/8/2PKNb2/8/6r1 w - - 7 44",
"8/4k3/4p1R1/2P3P1/3K4/2P1N3/8/6rb w - - 9 45",
"8/3k4/4p1R1/2P1K1P1/8/2P1N3/8/6rb w - - 11 46",
"8/3k4/4p1R1/2P3P1/5K2/2P1N3/8/4r2b w - - 13 47",
"8/3k4/2b1p2R/2P3P1/5K2/2P1N3/8/4r3 w - - 15 48",
"8/3k4/2b1p3/2P3P1/5K2/2P1N2R/8/6r1 w - - 17 49",
"2k5/7R/2b1p3/2P3P1/5K2/2P1N3/8/6r1 w - - 19 50",
"2k5/7R/4p3/2P3P1/b1P2K2/4N3/8/6r1 w - - 1 51",
"2k5/3bR3/4p3/2P3P1/2P2K2/4N3/8/6r1 w - - 3 52",
"3k4/3b2R1/4p3/2P3P1/2P2K2/4N3/8/6r1 w - - 5 53",
"3kb3/6R1/4p1P1/2P5/2P2K2/4N3/8/6r1 w - - 1 54",
"3kb3/6R1/4p1P1/2P5/2P2KN1/8/8/2r5 w - - 3 55",
"3kb3/6R1/4p1P1/2P1N3/2P2K2/8/8/5r2 w - - 5 56",
"3kb3/6R1/4p1P1/2P1N3/2P5/4K3/8/4r3 w - - 7 57",
},
{
"rnbq1rk1/ppp1npb1/4p1p1/3P3p/3PP3/2N2N2/PP2BPPP/R1BQ1RK1 b - - 0 8",
"rnbq1rk1/ppp1npb1/6p1/3pP2p/3P4/2N2N2/PP2BPPP/R1BQ1RK1 b - - 0 9",
"rn1q1rk1/ppp1npb1/6p1/3pP2p/3P2b1/2N2N2/PP2BPPP/R1BQR1K1 b - - 2 10",
"r2q1rk1/ppp1npb1/2n3p1/3pP2p/3P2bN/2N5/PP2BPPP/R1BQR1K1 b - - 4 11",
"r4rk1/pppqnpb1/2n3p1/3pP2p/3P2bN/2N4P/PP2BPP1/R1BQR1K1 b - - 0 12",
"r4rk1/pppqnpb1/2n3p1/3pP2p/3P3N/7P/PP2NPP1/R1BQR1K1 b - - 0 13",
"r4rk1/pppq1pb1/2n3p1/3pPN1p/3P4/7P/PP2NPP1/R1BQR1K1 b - - 0 14",
"r4rk1/ppp2pb1/2n3p1/3pPq1p/3P1N2/7P/PP3PP1/R1BQR1K1 b - - 1 15",
"r4rk1/pppq1pb1/2n3p1/3pP2p/P2P1N2/7P/1P3PP1/R1BQR1K1 b - - 0 16",
"r2n1rk1/pppq1pb1/6p1/3pP2p/P2P1N2/R6P/1P3PP1/2BQR1K1 b - - 2 17",
"r4rk1/pppq1pb1/4N1p1/3pP2p/P2P4/R6P/1P3PP1/2BQR1K1 b - - 0 18",
"r4rk1/ppp2pb1/4q1p1/3pP1Bp/P2P4/R6P/1P3PP1/3QR1K1 b - - 1 19",
"r3r1k1/ppp2pb1/4q1p1/3pP1Bp/P2P1P2/R6P/1P4P1/3QR1K1 b - - 0 20",
"r3r1k1/ppp3b1/4qpp1/3pP2p/P2P1P1B/R6P/1P4P1/3QR1K1 b - - 1 21",
"r3r1k1/ppp3b1/4q1p1/3pP2p/P4P1B/R6P/1P4P1/3QR1K1 b - - 0 22",
"r4rk1/ppp3b1/4q1p1/3pP1Bp/P4P2/R6P/1P4P1/3QR1K1 b - - 2 23",
"r4rk1/pp4b1/4q1p1/2ppP1Bp/P4P2/3R3P/1P4P1/3QR1K1 b - - 1 24",
"r4rk1/pp4b1/4q1p1/2p1P1Bp/P2p1PP1/3R3P/1P6/3QR1K1 b - - 0 25",
"r4rk1/pp4b1/4q1p1/2p1P1B1/P2p1PP1/3R4/1P6/3QR1K1 b - - 0 26",
"r5k1/pp3rb1/4q1p1/2p1P1B1/P2p1PP1/6R1/1P6/3QR1K1 b - - 2 27",
"5rk1/pp3rb1/4q1p1/2p1P1B1/P2pRPP1/6R1/1P6/3Q2K1 b - - 4 28",
"5rk1/1p3rb1/p3q1p1/P1p1P1B1/3pRPP1/6R1/1P6/3Q2K1 b - - 0 29",
"4r1k1/1p3rb1/p3q1p1/P1p1P1B1/3pRPP1/1P4R1/8/3Q2K1 b - - 0 30",
"4r1k1/5rb1/pP2q1p1/2p1P1B1/3pRPP1/1P4R1/8/3Q2K1 b - - 0 31",
"4r1k1/5rb1/pq4p1/2p1P1B1/3pRPP1/1P4R1/4Q3/6K1 b - - 1 32",
"4r1k1/1r4b1/pq4p1/2p1P1B1/3pRPP1/1P4R1/2Q5/6K1 b - - 3 33",
"4r1k1/1r4b1/1q4p1/p1p1P1B1/3p1PP1/1P4R1/2Q5/4R1K1 b - - 1 34",
"4r1k1/3r2b1/1q4p1/p1p1P1B1/2Qp1PP1/1P4R1/8/4R1K1 b - - 3 35",
"4r1k1/3r2b1/4q1p1/p1p1P1B1/2Qp1PP1/1P4R1/5K2/4R3 b - - 5 36",
"4r1k1/3r2b1/6p1/p1p1P1B1/2Pp1PP1/6R1/5K2/4R3 b - - 0 37",
"4r1k1/3r2b1/6p1/p1p1P1B1/2P2PP1/3p2R1/5K2/3R4 b - - 1 38",
"5rk1/3r2b1/6p1/p1p1P1B1/2P2PP1/3p2R1/8/3RK3 b - - 3 39",
"5rk1/6b1/6p1/p1p1P1B1/2Pr1PP1/3R4/8/3RK3 b - - 0 40",
"5rk1/3R2b1/6p1/p1p1P1B1/2r2PP1/8/8/3RK3 b - - 1 41",
"5rk1/3R2b1/6p1/p1p1P1B1/4rPP1/8/3K4/3R4 b - - 3 42",
"1r4k1/3R2b1/6p1/p1p1P1B1/4rPP1/2K5/8/3R4 b - - 5 43",
"1r4k1/3R2b1/6p1/p1p1P1B1/2K2PP1/4r3/8/3R4 b - - 7 44",
"1r3bk1/8/3R2p1/p1p1P1B1/2K2PP1/4r3/8/3R4 b - - 9 45",
"1r3bk1/8/6R1/2p1P1B1/p1K2PP1/4r3/8/3R4 b - - 0 46",
"1r3b2/5k2/R7/2p1P1B1/p1K2PP1/4r3/8/3R4 b - - 2 47",
"5b2/1r3k2/R7/2p1P1B1/p1K2PP1/4r3/8/7R b - - 4 48",
"5b2/5k2/R7/2pKP1B1/pr3PP1/4r3/8/7R b - - 6 49",
"5b2/5k2/R1K5/2p1P1B1/p2r1PP1/4r3/8/7R b - - 8 50",
"8/R4kb1/2K5/2p1P1B1/p2r1PP1/4r3/8/7R b - - 10 51",
"8/R5b1/2K3k1/2p1PPB1/p2r2P1/4r3/8/7R b - - 0 52",
"8/6R1/2K5/2p1PPk1/p2r2P1/4r3/8/7R b - - 0 53",
"8/6R1/2K5/2p1PP2/p2r1kP1/4r3/8/5R2 b - - 2 54",
"8/6R1/2K2P2/2p1P3/p2r2P1/4r1k1/8/5R2 b - - 0 55",
"8/5PR1/2K5/2p1P3/p2r2P1/4r3/6k1/5R2 b - - 0 56",
},
{
"rn1qkb1r/p1pbpppp/5n2/8/2pP4/2N5/1PQ1PPPP/R1B1KBNR w KQkq - 0 7",
"r2qkb1r/p1pbpppp/2n2n2/8/2pP4/2N2N2/1PQ1PPPP/R1B1KB1R w KQkq - 2 8",
"r2qkb1r/p1pbpppp/5n2/8/1npPP3/2N2N2/1PQ2PPP/R1B1KB1R w KQkq - 1 9",
"r2qkb1r/p1pb1ppp/4pn2/8/1npPP3/2N2N2/1P3PPP/R1BQKB1R w KQkq - 0 10",
"r2qk2r/p1pbbppp/4pn2/8/1nBPP3/2N2N2/1P3PPP/R1BQK2R w KQkq - 1 11",
"r2q1rk1/p1pbbppp/4pn2/8/1nBPP3/2N2N2/1P3PPP/R1BQ1RK1 w - - 3 12",
"r2q1rk1/2pbbppp/p3pn2/8/1nBPPB2/2N2N2/1P3PPP/R2Q1RK1 w - - 0 13",
"r2q1rk1/2p1bppp/p3pn2/1b6/1nBPPB2/2N2N2/1P3PPP/R2QR1K1 w - - 2 14",
"r2q1rk1/4bppp/p1p1pn2/1b6/1nBPPB2/1PN2N2/5PPP/R2QR1K1 w - - 0 15",
"r4rk1/3qbppp/p1p1pn2/1b6/1nBPPB2/1PN2N2/3Q1PPP/R3R1K1 w - - 2 16",
"r4rk1/1q2bppp/p1p1pn2/1b6/1nBPPB2/1PN2N1P/3Q1PP1/R3R1K1 w - - 1 17",
"r3r1k1/1q2bppp/p1p1pn2/1b6/1nBPPB2/1PN2N1P/4QPP1/R3R1K1 w - - 3 18",
"r3r1k1/1q1nbppp/p1p1p3/1b6/1nBPPB2/1PN2N1P/4QPP1/3RR1K1 w - - 5 19",
"r3rbk1/1q1n1ppp/p1p1p3/1b6/1nBPPB2/1PN2N1P/3RQPP1/4R1K1 w - - 7 20",
"r3rbk1/1q3ppp/pnp1p3/1b6/1nBPPB2/1PN2N1P/3RQPP1/4R2K w - - 9 21",
"2r1rbk1/1q3ppp/pnp1p3/1b6/1nBPPB2/1PN2N1P/3RQPP1/1R5K w - - 11 22",
"2r1rbk1/1q4pp/pnp1pp2/1b6/1nBPPB2/1PN2N1P/4QPP1/1R1R3K w - - 0 23",
"2r1rbk1/5qpp/pnp1pp2/1b6/1nBPP3/1PN1BN1P/4QPP1/1R1R3K w - - 2 24",
"2r1rbk1/5qp1/pnp1pp1p/1b6/1nBPP3/1PN1BN1P/4QPP1/1R1R2K1 w - - 0 25",
"2r1rbk1/5qp1/pnp1pp1p/1b6/2BPP3/1P2BN1P/n3QPP1/1R1R2K1 w - - 0 26",
"r3rbk1/5qp1/pnp1pp1p/1b6/2BPP3/1P2BN1P/Q4PP1/1R1R2K1 w - - 1 27",
"rr3bk1/5qp1/pnp1pp1p/1b6/2BPP3/1P2BN1P/Q4PP1/R2R2K1 w - - 3 28",
"rr2qbk1/6p1/pnp1pp1p/1b6/2BPP3/1P2BN1P/4QPP1/R2R2K1 w - - 5 29",
"rr2qbk1/6p1/1np1pp1p/pb6/2BPP3/1P1QBN1P/5PP1/R2R2K1 w - - 0 30",
"rr2qbk1/6p1/1n2pp1p/pp6/3PP3/1P1QBN1P/5PP1/R2R2K1 w - - 0 31",
"rr2qbk1/6p1/1n2pp1p/1p1P4/p3P3/1P1QBN1P/5PP1/R2R2K1 w - - 0 32",
"rr2qbk1/3n2p1/3Ppp1p/1p6/p3P3/1P1QBN1P/5PP1/R2R2K1 w - - 1 33",
"rr3bk1/3n2p1/3Ppp1p/1p5q/pP2P3/3QBN1P/5PP1/R2R2K1 w - - 1 34",
"rr3bk1/3n2p1/3Ppp1p/1p5q/1P2P3/p2QBN1P/5PP1/2RR2K1 w - - 0 35",
"1r3bk1/3n2p1/r2Ppp1p/1p5q/1P2P3/pQ2BN1P/5PP1/2RR2K1 w - - 2 36",
"1r2qbk1/2Rn2p1/r2Ppp1p/1p6/1P2P3/pQ2BN1P/5PP1/3R2K1 w - - 4 37",
"1r2qbk1/2Rn2p1/r2Ppp1p/1pB5/1P2P3/1Q3N1P/p4PP1/3R2K1 w - - 0 38",
"1r2q1k1/2Rn2p1/r2bpp1p/1pB5/1P2P3/1Q3N1P/p4PP1/R5K1 w - - 0 39",
"1r2q1k1/2Rn2p1/3rpp1p/1p6/1P2P3/1Q3N1P/p4PP1/R5K1 w - - 0 40",
"2r1q1k1/2Rn2p1/3rpp1p/1p6/1P2P3/5N1P/Q4PP1/R5K1 w - - 1 41",
"1r2q1k1/1R1n2p1/3rpp1p/1p6/1P2P3/5N1P/Q4PP1/R5K1 w - - 3 42",
"2r1q1k1/2Rn2p1/3rpp1p/1p6/1P2P3/5N1P/Q4PP1/R5K1 w - - 5 43",
"1r2q1k1/1R1n2p1/3rpp1p/1p6/1P2P3/5N1P/Q4PP1/R5K1 w - - 7 44",
"1rq3k1/R2n2p1/3rpp1p/1p6/1P2P3/5N1P/Q4PP1/R5K1 w - - 9 45",
"2q3k1/Rr1n2p1/3rpp1p/1p6/1P2P3/5N1P/4QPP1/R5K1 w - - 11 46",
"Rrq3k1/3n2p1/3rpp1p/1p6/1P2P3/5N1P/4QPP1/R5K1 w - - 13 47",
},
{
"rn1qkb1r/1pp2ppp/p4p2/3p1b2/5P2/1P2PN2/P1PP2PP/RN1QKB1R b KQkq - 1 6",
"r2qkb1r/1pp2ppp/p1n2p2/3p1b2/3P1P2/1P2PN2/P1P3PP/RN1QKB1R b KQkq - 0 7",
"r2qkb1r/1pp2ppp/p4p2/3p1b2/1n1P1P2/1P1BPN2/P1P3PP/RN1QK2R b KQkq - 2 8",
"r2qkb1r/1pp2ppp/p4p2/3p1b2/3P1P2/1P1PPN2/P5PP/RN1QK2R b KQkq - 0 9",
"r2qk2r/1pp2ppp/p2b1p2/3p1b2/3P1P2/1PNPPN2/P5PP/R2QK2R b KQkq - 2 10",
"r2qk2r/1p3ppp/p1pb1p2/3p1b2/3P1P2/1PNPPN2/P5PP/R2Q1RK1 b kq - 1 11",
"r2q1rk1/1p3ppp/p1pb1p2/3p1b2/3P1P2/1PNPPN2/P2Q2PP/R4RK1 b - - 3 12",
"r2qr1k1/1p3ppp/p1pb1p2/3p1b2/3P1P2/1P1PPN2/P2QN1PP/R4RK1 b - - 5 13",
"r3r1k1/1p3ppp/pqpb1p2/3p1b2/3P1P2/1P1PPNN1/P2Q2PP/R4RK1 b - - 7 14",
"r3r1k1/1p3ppp/pqp2p2/3p1b2/1b1P1P2/1P1PPNN1/P1Q3PP/R4RK1 b - - 9 15",
"r3r1k1/1p1b1ppp/pqp2p2/3p4/1b1P1P2/1P1PPNN1/P4QPP/R4RK1 b - - 11 16",
"2r1r1k1/1p1b1ppp/pqp2p2/3p4/1b1PPP2/1P1P1NN1/P4QPP/R4RK1 b - - 0 17",
"2r1r1k1/1p1b1ppp/pq3p2/2pp4/1b1PPP2/PP1P1NN1/5QPP/R4RK1 b - - 0 18",
"2r1r1k1/1p1b1ppp/pq3p2/2Pp4/4PP2/PPbP1NN1/5QPP/R4RK1 b - - 0 19",
"2r1r1k1/1p1b1ppp/p4p2/2Pp4/4PP2/PqbP1NN1/5QPP/RR4K1 b - - 1 20",
"2r1r1k1/1p1b1ppp/p4p2/2Pp4/q3PP2/P1bP1NN1/R4QPP/1R4K1 b - - 3 21",
"2r1r1k1/1p3ppp/p4p2/1bPP4/q4P2/P1bP1NN1/R4QPP/1R4K1 b - - 0 22",
"2r1r1k1/1p3ppp/p4p2/2PP4/q4P2/P1bb1NN1/R4QPP/2R3K1 b - - 1 23",
"2r1r1k1/1p3ppp/p2P1p2/2P5/2q2P2/P1bb1NN1/R4QPP/2R3K1 b - - 0 24",
"2rr2k1/1p3ppp/p2P1p2/2P5/2q2P2/P1bb1NN1/R4QPP/2R4K b - - 2 25",
"2rr2k1/1p3ppp/p2P1p2/2Q5/5P2/P1bb1NN1/R5PP/2R4K b - - 0 26",
"3r2k1/1p3ppp/p2P1p2/2r5/5P2/P1bb1N2/R3N1PP/2R4K b - - 1 27",
"3r2k1/1p3ppp/p2P1p2/2r5/5P2/P1b2N2/4R1PP/2R4K b - - 0 28",
"3r2k1/1p3ppp/p2P1p2/2r5/1b3P2/P4N2/4R1PP/3R3K b - - 2 29",
"3r2k1/1p2Rppp/p2P1p2/b1r5/5P2/P4N2/6PP/3R3K b - - 4 30",
"3r2k1/1R3ppp/p1rP1p2/b7/5P2/P4N2/6PP/3R3K b - - 0 31",
"3r2k1/1R3ppp/p2R1p2/b7/5P2/P4N2/6PP/7K b - - 0 32",
"6k1/1R3ppp/p2r1p2/b7/5P2/P4NP1/7P/7K b - - 0 33",
"6k1/1R3p1p/p2r1pp1/b7/5P1P/P4NP1/8/7K b - - 0 34",
"6k1/3R1p1p/pr3pp1/b7/5P1P/P4NP1/8/7K b - - 2 35",
"6k1/5p2/pr3pp1/b2R3p/5P1P/P4NP1/8/7K b - - 1 36",
"6k1/5p2/pr3pp1/7p/5P1P/P1bR1NP1/8/7K b - - 3 37",
"6k1/5p2/p1r2pp1/7p/5P1P/P1bR1NP1/6K1/8 b - - 5 38",
"6k1/5p2/p1r2pp1/b2R3p/5P1P/P4NP1/6K1/8 b - - 7 39",
"6k1/5p2/p4pp1/b2R3p/5P1P/P4NPK/2r5/8 b - - 9 40",
"6k1/2b2p2/p4pp1/7p/5P1P/P2R1NPK/2r5/8 b - - 11 41",
"6k1/2b2p2/5pp1/p6p/3N1P1P/P2R2PK/2r5/8 b - - 1 42",
"6k1/2b2p2/5pp1/p6p/3N1P1P/P1R3PK/r7/8 b - - 3 43",
"6k1/5p2/1b3pp1/p6p/5P1P/P1R3PK/r1N5/8 b - - 5 44",
"8/5pk1/1bR2pp1/p6p/5P1P/P5PK/r1N5/8 b - - 7 45",
"3b4/5pk1/2R2pp1/p4P1p/7P/P5PK/r1N5/8 b - - 0 46",
"8/4bpk1/2R2pp1/p4P1p/6PP/P6K/r1N5/8 b - - 0 47",
"8/5pk1/2R2pP1/p6p/6PP/b6K/r1N5/8 b - - 0 48",
"8/6k1/2R2pp1/p6P/7P/b6K/r1N5/8 b - - 0 49",
"8/6k1/2R2p2/p6p/7P/b5K1/r1N5/8 b - - 1 50",
"8/8/2R2pk1/p6p/7P/b4K2/r1N5/8 b - - 3 51",
"8/8/2R2pk1/p6p/7P/4NK2/rb6/8 b - - 5 52",
"2R5/8/5pk1/7p/p6P/4NK2/rb6/8 b - - 1 53",
"6R1/8/5pk1/7p/p6P/4NK2/1b6/r7 b - - 3 54",
"R7/5k2/5p2/7p/p6P/4NK2/1b6/r7 b - - 5 55",
"R7/5k2/5p2/7p/7P/p3N3/1b2K3/r7 b - - 1 56",
"8/R4k2/5p2/7p/7P/p3N3/1b2K3/7r b - - 3 57",
"8/8/5pk1/7p/R6P/p3N3/1b2K3/7r b - - 5 58",
"8/8/5pk1/7p/R6P/p7/4K3/2bN3r b - - 7 59",
"8/8/5pk1/7p/R6P/p7/4KN1r/2b5 b - - 9 60",
"8/8/5pk1/7p/R6P/p3K3/1b3N1r/8 b - - 11 61",
"8/8/R4pk1/7p/7P/p1b1K3/5N1r/8 b - - 13 62",
"8/8/5pk1/7p/7P/2b1K3/R4N1r/8 b - - 0 63",
"8/8/5pk1/7p/3K3P/8/R4N1r/4b3 b - - 2 64",
}
};
// clang-format on
} // namespace } // namespace
namespace Stockfish::Benchmark { namespace Stockfish::Benchmark {
@@ -160,4 +437,76 @@ std::vector<std::string> setup_bench(const std::string& currentFen, std::istream
return list; return list;
} }
BenchmarkSetup setup_benchmark(std::istream& is) {
// TT_SIZE_PER_THREAD is chosen such that roughly half of the hash is used all positions
// for the current sequence have been searched.
static constexpr int TT_SIZE_PER_THREAD = 128;
static constexpr int DEFAULT_DURATION_S = 150;
BenchmarkSetup setup{};
// Assign default values to missing arguments
int desiredTimeS;
if (!(is >> setup.threads))
setup.threads = get_hardware_concurrency();
else
setup.originalInvocation += std::to_string(setup.threads);
if (!(is >> setup.ttSize))
setup.ttSize = TT_SIZE_PER_THREAD * setup.threads;
else
setup.originalInvocation += " " + std::to_string(setup.ttSize);
if (!(is >> desiredTimeS))
desiredTimeS = DEFAULT_DURATION_S;
else
setup.originalInvocation += " " + std::to_string(desiredTimeS);
setup.filledInvocation += std::to_string(setup.threads) + " " + std::to_string(setup.ttSize)
+ " " + std::to_string(desiredTimeS);
auto getCorrectedTime = [&](int ply) {
// time per move is fit roughly based on LTC games
// seconds = 50/{ply+15}
// ms = 50000/{ply+15}
// with this fit 10th move gets 2000ms
// adjust for desired 10th move time
return 50000.0 / (static_cast<double>(ply) + 15.0);
};
float totalTime = 0;
for (const auto& game : BenchmarkPositions)
{
setup.commands.emplace_back("ucinewgame");
int ply = 1;
for (int i = 0; i < static_cast<int>(game.size()); ++i)
{
const float correctedTime = getCorrectedTime(ply);
totalTime += correctedTime;
ply += 1;
}
}
float timeScaleFactor = static_cast<float>(desiredTimeS * 1000) / totalTime;
for (const auto& game : BenchmarkPositions)
{
setup.commands.emplace_back("ucinewgame");
int ply = 1;
for (const std::string& fen : game)
{
setup.commands.emplace_back("position fen " + fen);
const int correctedTime = static_cast<int>(getCorrectedTime(ply) * timeScaleFactor);
setup.commands.emplace_back("go movetime " + std::to_string(correctedTime));
ply += 1;
}
}
return setup;
}
} // namespace Stockfish } // namespace Stockfish
+11 -1
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-2024 The Stockfish developers (see AUTHORS file) Copyright (C) 2004-2025 The Stockfish developers (see AUTHORS file)
Stockfish is free software: you can redistribute it and/or modify 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
@@ -27,6 +27,16 @@ namespace Stockfish::Benchmark {
std::vector<std::string> setup_bench(const std::string&, std::istream&); std::vector<std::string> setup_bench(const std::string&, std::istream&);
struct BenchmarkSetup {
int ttSize;
int threads;
std::vector<std::string> commands;
std::string originalInvocation;
std::string filledInvocation;
};
BenchmarkSetup setup_benchmark(std::istream&);
} // namespace Stockfish } // namespace Stockfish
#endif // #ifndef BENCHMARK_H_INCLUDED #endif // #ifndef BENCHMARK_H_INCLUDED
+26 -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-2024 The Stockfish developers (see AUTHORS file) Copyright (C) 2004-2025 The Stockfish developers (see AUTHORS file)
Stockfish is free software: you can redistribute it and/or modify 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
@@ -34,15 +34,14 @@ 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 // Returns the bitboard of target square for the given step
// from the given square. If the step is off the board, returns empty bitboard. // from the given square. If the step is off the board, returns empty bitboard.
@@ -82,8 +81,8 @@ void Bitboards::init() {
for (Square s2 = SQ_A1; s2 <= SQ_H8; ++s2) 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)
{ {
@@ -140,41 +139,49 @@ Bitboard sliding_attack(PieceType pt, Square sq, Bitboard occupied) {
// 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[]) { void init_magics(PieceType pt, Bitboard table[], Magic magics[][2]) {
#ifndef USE_PEXT
// Optimal PRNG seeds to pick the correct magics in the shortest time // 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;
m.shift = (Is64Bit ? 64 : 32) - popcount(m.mask); #ifndef USE_PEXT
m.shift = (Is64Bit ? 64 : 32) - popcount(m.mask);
#endif
// Set the offset for the attacks table of the square. We have individual // 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)
@@ -184,9 +191,7 @@ void init_magics(PieceType pt, Bitboard table[], Magic magics[]) {
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
@@ -215,6 +220,7 @@ void init_magics(PieceType pt, Bitboard table[], Magic magics[]) {
break; break;
} }
} }
#endif
} }
} }
} }
+18 -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-2024 The Stockfish developers (see AUTHORS file) Copyright (C) 2004-2025 The Stockfish developers (see AUTHORS file)
Stockfish is free software: you can redistribute it and/or modify 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
@@ -22,6 +22,7 @@
#include <algorithm> #include <algorithm>
#include <cassert> #include <cassert>
#include <cmath> #include <cmath>
#include <cstring>
#include <cstdint> #include <cstdint>
#include <cstdlib> #include <cstdlib>
#include <string> #include <string>
@@ -67,27 +68,31 @@ 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;
unsigned shift; #ifndef USE_PEXT
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) if (Is64Bit)
return unsigned(((occupied & mask) * magic) >> shift); return unsigned(((occupied & mask) * magic) >> shift);
unsigned lo = unsigned(occupied) & unsigned(mask); unsigned lo = unsigned(occupied) & unsigned(mask);
unsigned hi = unsigned(occupied >> 32) & unsigned(mask >> 32); unsigned hi = unsigned(occupied >> 32) & unsigned(mask >> 32);
return (lo * unsigned(magic) ^ hi * unsigned(magic >> 32)) >> shift; return (lo * unsigned(magic) ^ hi * unsigned(magic >> 32)) >> shift;
#endif
} }
Bitboard attacks_bb(Bitboard occupied) const { return attacks[index(occupied)]; }
}; };
extern Magic RookMagics[SQUARE_NB]; extern Magic Magics[SQUARE_NB][2];
extern Magic BishopMagics[SQUARE_NB];
constexpr Bitboard square_bb(Square s) { constexpr Bitboard square_bb(Square s) {
assert(is_ok(s)); assert(is_ok(s));
@@ -229,9 +234,8 @@ inline Bitboard attacks_bb(Square s, Bitboard occupied) {
switch (Pt) switch (Pt)
{ {
case BISHOP : case BISHOP :
return BishopMagics[s].attacks[BishopMagics[s].index(occupied)];
case ROOK : case ROOK :
return RookMagics[s].attacks[RookMagics[s].index(occupied)]; return Magics[s][Pt - BISHOP].attacks_bb(occupied);
case QUEEN : case QUEEN :
return attacks_bb<BISHOP>(s, occupied) | attacks_bb<ROOK>(s, occupied); return attacks_bb<BISHOP>(s, occupied) | attacks_bb<ROOK>(s, occupied);
default : default :
@@ -265,11 +269,10 @@ inline int popcount(Bitboard b) {
#ifndef USE_POPCNT #ifndef USE_POPCNT
union { std::uint16_t indices[4];
Bitboard bb; std::memcpy(indices, &b, sizeof(b));
uint16_t u[4]; return PopCnt16[indices[0]] + PopCnt16[indices[1]] + PopCnt16[indices[2]]
} v = {b}; + PopCnt16[indices[3]];
return PopCnt16[v.u[0]] + PopCnt16[v.u[1]] + PopCnt16[v.u[2]] + PopCnt16[v.u[3]];
#elif defined(_MSC_VER) #elif defined(_MSC_VER)
+99 -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-2024 The Stockfish developers (see AUTHORS file) Copyright (C) 2004-2025 The Stockfish developers (see AUTHORS file)
Stockfish is free software: you can redistribute it and/or modify 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
@@ -47,8 +47,8 @@ namespace NN = Eval::NNUE;
constexpr auto StartFEN = "rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq - 0 1"; constexpr auto StartFEN = "rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq - 0 1";
constexpr int MaxHashMB = Is64Bit ? 33554432 : 2048; constexpr int MaxHashMB = Is64Bit ? 33554432 : 2048;
Engine::Engine(std::string path) : Engine::Engine(std::optional<std::string> path) :
binaryDirectory(CommandLine::get_binary_directory(path)), binaryDirectory(path ? CommandLine::get_binary_directory(*path) : ""),
numaContext(NumaConfig::from_system()), numaContext(NumaConfig::from_system()),
states(new std::deque<StateInfo>(1)), states(new std::deque<StateInfo>(1)),
threads(), threads(),
@@ -58,58 +58,84 @@ Engine::Engine(std::string path) :
NN::NetworkBig({EvalFileDefaultNameBig, "None", ""}, NN::EmbeddedNNUEType::BIG), NN::NetworkBig({EvalFileDefaultNameBig, "None", ""}, NN::EmbeddedNNUEType::BIG),
NN::NetworkSmall({EvalFileDefaultNameSmall, "None", ""}, NN::EmbeddedNNUEType::SMALL))) { NN::NetworkSmall({EvalFileDefaultNameSmall, "None", ""}, NN::EmbeddedNNUEType::SMALL))) {
pos.set(StartFEN, false, &states->back()); pos.set(StartFEN, false, &states->back());
capSq = SQ_NONE;
options["Debug Log File"] << Option("", [](const Option& o) {
start_logger(o);
return std::nullopt;
});
options["NumaPolicy"] << Option("auto", [this](const Option& o) { options.add( //
set_numa_config_from_option(o); "Debug Log File", Option("", [](const Option& o) {
return numa_config_information_as_string() + "\n" + thread_binding_information_as_string(); start_logger(o);
}); return std::nullopt;
}));
options["Threads"] << Option(1, 1, 1024, [this](const Option&) { options.add( //
resize_threads(); "NumaPolicy", Option("auto", [this](const Option& o) {
return thread_binding_information_as_string(); set_numa_config_from_option(o);
}); return numa_config_information_as_string() + "\n"
+ thread_allocation_information_as_string();
}));
options["Hash"] << Option(16, 1, MaxHashMB, [this](const Option& o) { options.add( //
set_tt_size(o); "Threads", Option(1, 1, 1024, [this](const Option&) {
return std::nullopt; resize_threads();
}); return thread_allocation_information_as_string();
}));
options["Clear Hash"] << Option([this](const Option&) { options.add( //
search_clear(); "Hash", Option(16, 1, MaxHashMB, [this](const Option& o) {
return std::nullopt; set_tt_size(o);
}); return std::nullopt;
options["Ponder"] << Option(false); }));
options["MultiPV"] << Option(1, 1, MAX_MOVES);
options["Skill Level"] << Option(20, 0, 20); options.add( //
options["Move Overhead"] << Option(10, 0, 5000); "Clear Hash", Option([this](const Option&) {
options["nodestime"] << Option(0, 0, 10000); search_clear();
options["UCI_Chess960"] << Option(false); return std::nullopt;
options["UCI_LimitStrength"] << Option(false); }));
options["UCI_Elo"] << Option(Stockfish::Search::Skill::LowestElo,
Stockfish::Search::Skill::LowestElo, options.add( //
Stockfish::Search::Skill::HighestElo); "Ponder", Option(false));
options["UCI_ShowWDL"] << Option(false);
options["SyzygyPath"] << Option("", [](const Option& o) { options.add( //
Tablebases::init(o); "MultiPV", Option(1, 1, MAX_MOVES));
return std::nullopt;
}); options.add("Skill Level", Option(20, 0, 20));
options["SyzygyProbeDepth"] << Option(1, 1, 100);
options["Syzygy50MoveRule"] << Option(true); options.add("Move Overhead", Option(10, 0, 5000));
options["SyzygyProbeLimit"] << Option(7, 0, 7);
options["EvalFile"] << Option(EvalFileDefaultNameBig, [this](const Option& o) { options.add("nodestime", Option(0, 0, 10000));
load_big_network(o);
return std::nullopt; options.add("UCI_Chess960", Option(false));
});
options["EvalFileSmall"] << Option(EvalFileDefaultNameSmall, [this](const Option& o) { options.add("UCI_LimitStrength", Option(false));
load_small_network(o);
return std::nullopt; 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(); load_networks();
resize_threads(); resize_threads();
@@ -124,7 +150,6 @@ std::uint64_t Engine::perft(const std::string& fen, Depth depth, bool isChess960
void Engine::go(Search::LimitsType& limits) { void Engine::go(Search::LimitsType& limits) {
assert(limits.perft == 0); assert(limits.perft == 0);
verify_networks(); verify_networks();
limits.capSq = capSq;
threads.start_thinking(options, pos, states, limits); threads.start_thinking(options, pos, states, limits);
} }
@@ -156,6 +181,10 @@ void Engine::set_on_bestmove(std::function<void(std::string_view, std::string_vi
updateContext.onBestmove = std::move(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::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) { void Engine::set_position(const std::string& fen, const std::vector<std::string>& moves) {
@@ -163,7 +192,6 @@ void Engine::set_position(const std::string& fen, const std::vector<std::string>
states = StateListPtr(new std::deque<StateInfo>(1)); states = StateListPtr(new std::deque<StateInfo>(1));
pos.set(fen, options["UCI_Chess960"], &states->back()); pos.set(fen, options["UCI_Chess960"], &states->back());
capSq = SQ_NONE;
for (const auto& move : moves) for (const auto& move : moves)
{ {
auto m = UCIEngine::to_move(pos, move); auto m = UCIEngine::to_move(pos, move);
@@ -173,11 +201,6 @@ void Engine::set_position(const std::string& fen, const std::vector<std::string>
states->emplace_back(); states->emplace_back();
pos.do_move(m, states->back()); pos.do_move(m, states->back());
capSq = SQ_NONE;
DirtyPiece& dp = states->back().dirtyPiece;
if (dp.dirty_num > 1 && dp.to[1] == SQ_NONE)
capSq = m.to_sq();
} }
} }
@@ -226,8 +249,8 @@ void Engine::set_ponderhit(bool b) { threads.main_manager()->ponder = b; }
// network related // network related
void Engine::verify_networks() const { void Engine::verify_networks() const {
networks->big.verify(options["EvalFile"]); networks->big.verify(options["EvalFile"], onVerifyNetworks);
networks->small.verify(options["EvalFileSmall"]); networks->small.verify(options["EvalFileSmall"], onVerifyNetworks);
} }
void Engine::load_networks() { void Engine::load_networks() {
@@ -285,6 +308,8 @@ std::string Engine::visualize() const {
return ss.str(); 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 { 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(); auto counts = threads.get_bound_thread_count_by_numa_node();
const NumaConfig& cfg = numaContext.get_numa_config(); const NumaConfig& cfg = numaContext.get_numa_config();
@@ -310,15 +335,9 @@ std::string Engine::numa_config_information_as_string() const {
std::string Engine::thread_binding_information_as_string() const { std::string Engine::thread_binding_information_as_string() const {
auto boundThreadsByNode = get_bound_thread_count_by_numa_node(); auto boundThreadsByNode = get_bound_thread_count_by_numa_node();
std::stringstream ss; std::stringstream ss;
size_t threadsSize = threads.size();
ss << "Using " << threadsSize << (threadsSize > 1 ? " threads" : " thread");
if (boundThreadsByNode.empty()) if (boundThreadsByNode.empty())
return ss.str(); return ss.str();
ss << " with NUMA node thread binding: ";
bool isFirst = true; bool isFirst = true;
for (auto&& [current, total] : boundThreadsByNode) for (auto&& [current, total] : boundThreadsByNode)
@@ -332,4 +351,19 @@ std::string Engine::thread_binding_information_as_string() const {
return ss.str(); return ss.str();
} }
std::string Engine::thread_allocation_information_as_string() const {
std::stringstream ss;
size_t threadsSize = threads.size();
ss << "Using " << threadsSize << (threadsSize > 1 ? " threads" : " thread");
auto boundThreadsByNodeStr = thread_binding_information_as_string();
if (boundThreadsByNodeStr.empty())
return ss.str();
ss << " with NUMA node thread binding: ";
ss << boundThreadsByNodeStr;
return ss.str();
}
} }
+8 -6
View File
@@ -1,6 +1,6 @@
/* /*
Stockfish, a UCI chess playing engine derived from Glaurung 2.1 Stockfish, a UCI chess playing engine derived from Glaurung 2.1
Copyright (C) 2004-2024 The Stockfish developers (see AUTHORS file) Copyright (C) 2004-2025 The Stockfish developers (see AUTHORS file)
Stockfish is free software: you can redistribute it and/or modify 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
@@ -39,15 +39,13 @@
namespace Stockfish { namespace Stockfish {
enum Square : int;
class Engine { class Engine {
public: public:
using InfoShort = Search::InfoShort; using InfoShort = Search::InfoShort;
using InfoFull = Search::InfoFull; using InfoFull = Search::InfoFull;
using InfoIter = Search::InfoIteration; using InfoIter = Search::InfoIteration;
Engine(std::string path = ""); Engine(std::optional<std::string> path = std::nullopt);
// Cannot be movable due to components holding backreferences to fields // Cannot be movable due to components holding backreferences to fields
Engine(const Engine&) = delete; Engine(const Engine&) = delete;
@@ -81,6 +79,7 @@ class Engine {
void set_on_update_full(std::function<void(const InfoFull&)>&&); void set_on_update_full(std::function<void(const InfoFull&)>&&);
void set_on_iter(std::function<void(const InfoIter&)>&&); 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_bestmove(std::function<void(std::string_view, std::string_view)>&&);
void set_on_verify_networks(std::function<void(std::string_view)>&&);
// network related // network related
@@ -97,12 +96,15 @@ class Engine {
const OptionsMap& get_options() const; const OptionsMap& get_options() const;
OptionsMap& get_options(); OptionsMap& get_options();
int get_hashfull(int maxAge = 0) const;
std::string fen() const; std::string fen() const;
void flip(); void flip();
std::string visualize() const; std::string visualize() const;
std::vector<std::pair<size_t, size_t>> get_bound_thread_count_by_numa_node() 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 get_numa_config_as_string() const;
std::string numa_config_information_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; std::string thread_binding_information_as_string() const;
private: private:
@@ -112,14 +114,14 @@ class Engine {
Position pos; Position pos;
StateListPtr states; StateListPtr states;
Square capSq;
OptionsMap options; OptionsMap options;
ThreadPool threads; ThreadPool threads;
TranspositionTable tt; TranspositionTable tt;
LazyNumaReplicated<Eval::NNUE::Networks> networks; LazyNumaReplicated<Eval::NNUE::Networks> networks;
Search::SearchManager::UpdateContext updateContext; Search::SearchManager::UpdateContext updateContext;
std::function<void(std::string_view)> onVerifyNetworks;
}; };
} // namespace Stockfish } // namespace Stockfish
+7 -12
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-2024 The Stockfish developers (see AUTHORS file) Copyright (C) 2004-2025 The Stockfish developers (see AUTHORS file)
Stockfish is free software: you can redistribute it and/or modify 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
@@ -59,16 +59,14 @@ Value Eval::evaluate(const Eval::NNUE::Networks& networks,
assert(!pos.checkers()); assert(!pos.checkers());
bool smallNet = use_smallnet(pos); bool smallNet = use_smallnet(pos);
int v;
auto [psqt, positional] = smallNet ? networks.small.evaluate(pos, &caches.small) auto [psqt, positional] = smallNet ? networks.small.evaluate(pos, &caches.small)
: networks.big.evaluate(pos, &caches.big); : networks.big.evaluate(pos, &caches.big);
Value nnue = (125 * psqt + 131 * positional) / 128; Value nnue = (125 * psqt + 131 * positional) / 128;
// Re-evaluate the position when higher eval accuracy is worth the time spent // Re-evaluate the position when higher eval accuracy is worth the time spent
if (smallNet && (nnue * psqt < 0 || std::abs(nnue) < 227)) if (smallNet && (std::abs(nnue) < 236))
{ {
std::tie(psqt, positional) = networks.big.evaluate(pos, &caches.big); std::tie(psqt, positional) = networks.big.evaluate(pos, &caches.big);
nnue = (125 * psqt + 131 * positional) / 128; nnue = (125 * psqt + 131 * positional) / 128;
@@ -77,14 +75,11 @@ Value Eval::evaluate(const Eval::NNUE::Networks& networks,
// Blend optimism and eval with nnue complexity // Blend optimism and eval with nnue complexity
int nnueComplexity = std::abs(psqt - positional); int nnueComplexity = std::abs(psqt - positional);
optimism += optimism * nnueComplexity / (smallNet ? 433 : 453); optimism += optimism * nnueComplexity / 468;
nnue -= nnue * nnueComplexity / (smallNet ? 18815 : 17864); nnue -= nnue * nnueComplexity / (smallNet ? 20233 : 17879);
int material = (smallNet ? 553 : 532) * pos.count<PAWN>() + pos.non_pawn_material(); int material = 535 * pos.count<PAWN>() + pos.non_pawn_material();
v = (nnue * (73921 + material) + optimism * (8112 + material)) / (smallNet ? 68104 : 74715); int v = (nnue * (77777 + material) + optimism * (7777 + material)) / 77777;
// Evaluation grain (to get more alpha-beta cuts) with randomization (for robustness)
v = (v / 16) * 16 - 1 + (pos.key() & 0x2);
// Damp down the evaluation linearly when shuffling // Damp down the evaluation linearly when shuffling
v -= v * pos.rule50_count() / 212; v -= v * pos.rule50_count() / 212;
+2 -2
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-2024 The Stockfish developers (see AUTHORS file) Copyright (C) 2004-2025 The Stockfish developers (see AUTHORS file)
Stockfish is free software: you can redistribute it and/or modify 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
@@ -33,7 +33,7 @@ namespace Eval {
// for the build process (profile-build and fishtest) to work. Do not change the // for the build process (profile-build and fishtest) to work. Do not change the
// name of the macro or the location where this macro is defined, as it is used // name of the macro or the location where this macro is defined, as it is used
// in the Makefile/Fishtest. // in the Makefile/Fishtest.
#define EvalFileDefaultNameBig "nn-1111cefa1111.nnue" #define EvalFileDefaultNameBig "nn-1c0000000000.nnue"
#define EvalFileDefaultNameSmall "nn-37f18f62d772.nnue" #define EvalFileDefaultNameSmall "nn-37f18f62d772.nnue"
namespace NNUE { namespace NNUE {
+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
+166 -58
View File
@@ -3,8 +3,8 @@
* @author Dale Weiler * @author Dale Weiler
* @brief Utility for including binary files * @brief Utility for including binary files
* *
* Facilities for including binary files into the current translation unit * Facilities for including binary files into the current translation unit and
* and making use of them externally in other translation units. * making use from them externally in other translation units.
*/ */
#ifndef INCBIN_HDR #ifndef INCBIN_HDR
#define INCBIN_HDR #define INCBIN_HDR
@@ -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,29 +122,50 @@
#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 * @warning If you use this facility, you might have to deal with
* section naming on your own * 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__)
/* The directives are different for Apple-branded compilers */ # include "TargetConditionals.h"
# if defined(TARGET_OS_IPHONE) && !defined(INCBIN_SILENCE_BITCODE_WARNING)
# warning "incbin is incompatible with bitcode. Using the library will break upload to App Store if you have bitcode enabled. Add `#define INCBIN_SILENCE_BITCODE_WARNING` before including this header to silence this warning."
# endif
/* The directives are different for Apple branded compilers */
# define INCBIN_SECTION INCBIN_OUTPUT_SECTION "\n" # define INCBIN_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"
# define INCBIN_INT ".long " # define INCBIN_INT ".long "
@@ -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"
@@ -261,8 +267,8 @@
INCBIN_STRINGIZE( \ INCBIN_STRINGIZE( \
INCBIN_STYLE_IDENT(TYPE)) \ INCBIN_STYLE_IDENT(TYPE)) \
/* Generate the global labels by indirectly invoking the macro /* Generate the global labels by indirectly invoking the macro with our style
* with our style type and concatenate the name against them. */ * type and concatenating the name against them. */
#define INCBIN_GLOBAL_LABELS(NAME, TYPE) \ #define INCBIN_GLOBAL_LABELS(NAME, TYPE) \
INCBIN_INVOKE( \ INCBIN_INVOKE( \
INCBIN_GLOBAL, \ INCBIN_GLOBAL, \
@@ -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
+1 -1
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-2024 The Stockfish developers (see AUTHORS file) Copyright (C) 2004-2025 The Stockfish developers (see AUTHORS file)
Stockfish is free software: you can redistribute it and/or modify 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
+32 -1
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-2024 The Stockfish developers (see AUTHORS file) Copyright (C) 2004-2025 The Stockfish developers (see AUTHORS file)
Stockfish is free software: you can redistribute it and/or modify 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
@@ -212,6 +212,37 @@ void* aligned_large_pages_alloc(size_t allocSize) {
#endif #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 // aligned_large_pages_free() will free the previously memory allocated
// by aligned_large_pages_alloc(). The effect is a nop if mem == nullptr. // by aligned_large_pages_alloc(). The effect is a nop if mem == nullptr.
+3 -1
View File
@@ -1,6 +1,6 @@
/* /*
Stockfish, a UCI chess playing engine derived from Glaurung 2.1 Stockfish, a UCI chess playing engine derived from Glaurung 2.1
Copyright (C) 2004-2024 The Stockfish developers (see AUTHORS file) Copyright (C) 2004-2025 The Stockfish developers (see AUTHORS file)
Stockfish is free software: you can redistribute it and/or modify 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
@@ -38,6 +38,8 @@ void std_aligned_free(void* ptr);
void* aligned_large_pages_alloc(size_t size); void* aligned_large_pages_alloc(size_t size);
void aligned_large_pages_free(void* mem); void aligned_large_pages_free(void* mem);
bool has_large_pages();
// Frees memory which was placed there with placement new. // Frees memory which was placed there with placement new.
// Works for both single objects and arrays of unknown bound. // Works for both single objects and arrays of unknown bound.
template<typename T, typename FREE_FUNC> template<typename T, typename FREE_FUNC>
+38 -30
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-2024 The Stockfish developers (see AUTHORS file) Copyright (C) 2004-2025 The Stockfish developers (see AUTHORS file)
Stockfish is free software: you can redistribute it and/or modify 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
@@ -18,7 +18,9 @@
#include "misc.h" #include "misc.h"
#include <array>
#include <atomic> #include <atomic>
#include <cassert>
#include <cctype> #include <cctype>
#include <cmath> #include <cmath>
#include <cstdlib> #include <cstdlib>
@@ -38,7 +40,7 @@ namespace Stockfish {
namespace { namespace {
// Version number or dev. // Version number or dev.
constexpr std::string_view version = "17"; constexpr std::string_view version = "dev";
// Our fancy logging facility. The trick here is to replace cin.rdbuf() and // Our fancy logging facility. The trick here is to replace cin.rdbuf() and
// cout.rdbuf() with two Tie objects that tie cin and cout to a file stream. We // cout.rdbuf() with two Tie objects that tie cin and cout to a file stream. We
@@ -122,7 +124,7 @@ class Logger {
// //
// For releases (non-dev builds) we only include the version number: // For releases (non-dev builds) we only include the version number:
// Stockfish version // Stockfish version
std::string engine_info(bool to_uci) { std::string engine_version_info() {
std::stringstream ss; std::stringstream ss;
ss << "Stockfish " << version << std::setfill('0'); ss << "Stockfish " << version << std::setfill('0');
@@ -151,11 +153,14 @@ std::string engine_info(bool to_uci) {
#endif #endif
} }
ss << (to_uci ? "\nid author " : " by ") << "the Stockfish developers (see AUTHORS file)";
return ss.str(); return ss.str();
} }
std::string engine_info(bool to_uci) {
return engine_version_info() + (to_uci ? "\nid author " : " by ")
+ "the Stockfish developers (see AUTHORS file)";
}
// Returns a string trying to describe the compiler we use // Returns a string trying to describe the compiler we use
std::string compiler_info() { std::string compiler_info() {
@@ -284,7 +289,10 @@ template<size_t N>
struct DebugInfo { struct DebugInfo {
std::atomic<int64_t> data[N] = {0}; std::atomic<int64_t> data[N] = {0};
constexpr std::atomic<int64_t>& operator[](int index) { return data[index]; } [[nodiscard]] constexpr std::atomic<int64_t>& operator[](size_t index) {
assert(index < N);
return data[index];
}
}; };
struct DebugExtremes: public DebugInfo<3> { struct DebugExtremes: public DebugInfo<3> {
@@ -294,54 +302,54 @@ struct DebugExtremes: public DebugInfo<3> {
} }
}; };
DebugInfo<2> hit[MaxDebugSlots]; std::array<DebugInfo<2>, MaxDebugSlots> hit;
DebugInfo<2> mean[MaxDebugSlots]; std::array<DebugInfo<2>, MaxDebugSlots> mean;
DebugInfo<3> stdev[MaxDebugSlots]; std::array<DebugInfo<3>, MaxDebugSlots> stdev;
DebugInfo<6> correl[MaxDebugSlots]; std::array<DebugInfo<6>, MaxDebugSlots> correl;
DebugExtremes extremes[MaxDebugSlots]; std::array<DebugExtremes, MaxDebugSlots> extremes;
} // namespace } // namespace
void dbg_hit_on(bool cond, int slot) { void dbg_hit_on(bool cond, int slot) {
++hit[slot][0]; ++hit.at(slot)[0];
if (cond) if (cond)
++hit[slot][1]; ++hit.at(slot)[1];
} }
void dbg_mean_of(int64_t value, int slot) { void dbg_mean_of(int64_t value, int slot) {
++mean[slot][0]; ++mean.at(slot)[0];
mean[slot][1] += value; mean.at(slot)[1] += value;
} }
void dbg_stdev_of(int64_t value, int slot) { void dbg_stdev_of(int64_t value, int slot) {
++stdev[slot][0]; ++stdev.at(slot)[0];
stdev[slot][1] += value; stdev.at(slot)[1] += value;
stdev[slot][2] += value * value; stdev.at(slot)[2] += value * value;
} }
void dbg_extremes_of(int64_t value, int slot) { void dbg_extremes_of(int64_t value, int slot) {
++extremes[slot][0]; ++extremes.at(slot)[0];
int64_t current_max = extremes[slot][1].load(); int64_t current_max = extremes.at(slot)[1].load();
while (current_max < value && !extremes[slot][1].compare_exchange_weak(current_max, value)) while (current_max < value && !extremes.at(slot)[1].compare_exchange_weak(current_max, value))
{} {}
int64_t current_min = extremes[slot][2].load(); int64_t current_min = extremes.at(slot)[2].load();
while (current_min > value && !extremes[slot][2].compare_exchange_weak(current_min, value)) while (current_min > value && !extremes.at(slot)[2].compare_exchange_weak(current_min, value))
{} {}
} }
void dbg_correl_of(int64_t value1, int64_t value2, int slot) { void dbg_correl_of(int64_t value1, int64_t value2, int slot) {
++correl[slot][0]; ++correl.at(slot)[0];
correl[slot][1] += value1; correl.at(slot)[1] += value1;
correl[slot][2] += value1 * value1; correl.at(slot)[2] += value1 * value1;
correl[slot][3] += value2; correl.at(slot)[3] += value2;
correl[slot][4] += value2 * value2; correl.at(slot)[4] += value2 * value2;
correl[slot][5] += value1 * value2; correl.at(slot)[5] += value1 * value2;
} }
void dbg_print() { void dbg_print() {
@@ -451,7 +459,7 @@ void remove_whitespace(std::string& s) {
s.erase(std::remove_if(s.begin(), s.end(), [](char c) { return std::isspace(c); }), s.end()); s.erase(std::remove_if(s.begin(), s.end(), [](char c) { return std::isspace(c); }), s.end());
} }
bool is_whitespace(const std::string& s) { bool is_whitespace(std::string_view s) {
return std::all_of(s.begin(), s.end(), [](char c) { return std::isspace(c); }); return std::all_of(s.begin(), s.end(), [](char c) { return std::isspace(c); });
} }
+95 -9
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-2024 The Stockfish developers (see AUTHORS file) Copyright (C) 2004-2025 The Stockfish developers (see AUTHORS file)
Stockfish is free software: you can redistribute it and/or modify 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,6 +20,7 @@
#define MISC_H_INCLUDED #define MISC_H_INCLUDED
#include <algorithm> #include <algorithm>
#include <array>
#include <cassert> #include <cassert>
#include <chrono> #include <chrono>
#include <cstddef> #include <cstddef>
@@ -28,6 +29,7 @@
#include <iosfwd> #include <iosfwd>
#include <optional> #include <optional>
#include <string> #include <string>
#include <string_view>
#include <vector> #include <vector>
#define stringify2(x) #x #define stringify2(x) #x
@@ -35,6 +37,7 @@
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();
@@ -79,8 +82,8 @@ inline TimePoint now() {
.count(); .count();
} }
inline std::vector<std::string> split(const std::string& s, const std::string& delimiter) { inline std::vector<std::string_view> split(std::string_view s, std::string_view delimiter) {
std::vector<std::string> res; std::vector<std::string_view> res;
if (s.empty()) if (s.empty())
return res; return res;
@@ -102,7 +105,7 @@ inline std::vector<std::string> split(const std::string& s, const std::string& d
} }
void remove_whitespace(std::string& s); void remove_whitespace(std::string& s);
bool is_whitespace(const std::string& s); bool is_whitespace(std::string_view s);
enum SyncCout { enum SyncCout {
IO_LOCK, IO_LOCK,
@@ -117,11 +120,8 @@ void sync_cout_start();
void sync_cout_end(); void sync_cout_end();
// True if and only if the binary is compiled on a little-endian machine // True if and only if the binary is compiled on a little-endian machine
static inline const union { static inline const std::uint16_t Le = 1;
uint32_t i; static inline const bool IsLittleEndian = *reinterpret_cast<const char*>(&Le) == 1;
char c[4];
} Le = {0x01020304};
static inline const bool IsLittleEndian = (Le.c[0] == 4);
template<typename T, std::size_t MaxSize> template<typename T, std::size_t MaxSize>
@@ -140,6 +140,92 @@ class ValueList {
}; };
template<typename T, std::size_t Size, std::size_t... Sizes>
class MultiArray;
namespace Detail {
template<typename T, std::size_t Size, std::size_t... Sizes>
struct MultiArrayHelper {
using ChildType = MultiArray<T, Sizes...>;
};
template<typename T, std::size_t Size>
struct MultiArrayHelper<T, Size> {
using ChildType = T;
};
}
// 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 // xorshift64star Pseudo-Random Number Generator
// This class is based on original code written and dedicated // This class is based on original code written and dedicated
// to the public domain by Sebastiano Vigna (2014). // to the public domain by Sebastiano Vigna (2014).
+1 -1
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-2024 The Stockfish developers (see AUTHORS file) Copyright (C) 2004-2025 The Stockfish developers (see AUTHORS file)
Stockfish is free software: you can redistribute it and/or modify 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
+1 -1
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-2024 The Stockfish developers (see AUTHORS file) Copyright (C) 2004-2025 The Stockfish developers (see AUTHORS file)
Stockfish is free software: you can redistribute it and/or modify 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
+33 -31
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-2024 The Stockfish developers (see AUTHORS file) Copyright (C) 2004-2025 The Stockfish developers (see AUTHORS file)
Stockfish is free software: you can redistribute it and/or modify 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
@@ -18,11 +18,11 @@
#include "movepick.h" #include "movepick.h"
#include <algorithm>
#include <cassert> #include <cassert>
#include <utility> #include <limits>
#include "bitboard.h" #include "bitboard.h"
#include "misc.h"
#include "position.h" #include "position.h"
namespace Stockfish { namespace Stockfish {
@@ -82,16 +82,20 @@ MovePicker::MovePicker(const Position& p,
Move ttm, Move ttm,
Depth d, Depth d,
const ButterflyHistory* mh, const ButterflyHistory* mh,
const LowPlyHistory* lph,
const CapturePieceToHistory* cph, const CapturePieceToHistory* cph,
const PieceToHistory** ch, const PieceToHistory** ch,
const PawnHistory* ph) : const PawnHistory* ph,
int pl) :
pos(p), pos(p),
mainHistory(mh), mainHistory(mh),
lowPlyHistory(lph),
captureHistory(cph), captureHistory(cph),
continuationHistory(ch), continuationHistory(ch),
pawnHistory(ph), pawnHistory(ph),
ttMove(ttm), ttMove(ttm),
depth(d) { depth(d),
ply(pl) {
if (pos.checkers()) if (pos.checkers())
stage = EVASION_TT + !(ttm && pos.pseudo_legal(ttm)); stage = EVASION_TT + !(ttm && pos.pseudo_legal(ttm));
@@ -152,12 +156,13 @@ void MovePicker::score() {
Square to = m.to_sq(); Square to = m.to_sq();
// histories // histories
m.value = (*mainHistory)[pos.side_to_move()][m.from_to()]; m.value = 2 * (*mainHistory)[pos.side_to_move()][m.from_to()];
m.value += 2 * (*pawnHistory)[pawn_structure_index(pos)][pc][to]; m.value += 2 * (*pawnHistory)[pawn_structure_index(pos)][pc][to];
m.value += 2 * (*continuationHistory[0])[pc][to]; m.value += (*continuationHistory[0])[pc][to];
m.value += (*continuationHistory[1])[pc][to]; m.value += (*continuationHistory[1])[pc][to];
m.value += (*continuationHistory[2])[pc][to] / 3; m.value += (*continuationHistory[2])[pc][to];
m.value += (*continuationHistory[3])[pc][to]; m.value += (*continuationHistory[3])[pc][to];
m.value += (*continuationHistory[4])[pc][to] / 3;
m.value += (*continuationHistory[5])[pc][to]; m.value += (*continuationHistory[5])[pc][to];
// bonus for checks // bonus for checks
@@ -171,16 +176,18 @@ void MovePicker::score() {
: 0; : 0;
// malus for putting piece en prise // malus for putting piece en prise
m.value -= (pt == QUEEN ? bool(to & threatenedByRook) * 49000 m.value -= (pt == QUEEN ? bool(to & threatenedByRook) * 49000
: pt == ROOK ? bool(to & threatenedByMinor) * 24335 : pt == ROOK && bool(to & threatenedByMinor) ? 24335
: bool(to & threatenedByPawn) * 14900); : 0);
if (ply < LOW_PLY_HISTORY_SIZE)
m.value += 8 * (*lowPlyHistory)[ply][m.from_to()] / (1 + 2 * ply);
} }
else // Type == EVASIONS else // Type == EVASIONS
{ {
if (pos.capture_stage(m)) if (pos.capture_stage(m))
m.value = m.value = PieceValue[pos.piece_on(m.to_sq())] + (1 << 28);
PieceValue[pos.piece_on(m.to_sq())] - type_of(pos.moved_piece(m)) + (1 << 28);
else else
m.value = (*mainHistory)[pos.side_to_move()][m.from_to()] m.value = (*mainHistory)[pos.side_to_move()][m.from_to()]
+ (*continuationHistory[0])[pos.moved_piece(m)][m.to_sq()] + (*continuationHistory[0])[pos.moved_piece(m)][m.to_sq()]
@@ -190,26 +197,20 @@ void MovePicker::score() {
// Returns the next move satisfying a predicate function. // Returns the next move satisfying a predicate function.
// This never returns the TT move, as it was emitted before. // 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 constexpr (T == Best)
std::swap(*cur, *std::max_element(cur, endMoves));
if (*cur != ttMove && filter()) if (*cur != ttMove && filter())
return *cur++; return *cur++;
cur++;
}
return Move::none(); return Move::none();
} }
// This is the most important method of the MovePicker class. We emit one // This is the most important method of the MovePicker class. We emit one
// new pseudo-legal move on every call until there are no more moves left, // new pseudo-legal move on every call until there are no more moves left,
// picking the move with the highest score from a list of generated moves. // 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; }; auto quiet_threshold = [](Depth d) { return -3560 * d; };
@@ -236,7 +237,7 @@ top:
goto top; goto top;
case GOOD_CAPTURE : case GOOD_CAPTURE :
if (select<Next>([&]() { if (select([&]() {
// 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 return pos.see_ge(*cur, -cur->value / 18) ? true
: (*endBadCaptures++ = *cur, false); : (*endBadCaptures++ = *cur, false);
@@ -260,7 +261,7 @@ top:
[[fallthrough]]; [[fallthrough]];
case GOOD_QUIET : case GOOD_QUIET :
if (!skipQuiets && select<Next>([]() { return true; })) if (!skipQuiets && select([]() { return true; }))
{ {
if ((cur - 1)->value > -7998 || (cur - 1)->value <= quiet_threshold(depth)) if ((cur - 1)->value > -7998 || (cur - 1)->value <= quiet_threshold(depth))
return *(cur - 1); return *(cur - 1);
@@ -277,7 +278,7 @@ top:
[[fallthrough]]; [[fallthrough]];
case BAD_CAPTURE : case BAD_CAPTURE :
if (select<Next>([]() { return true; })) if (select([]() { return true; }))
return *(cur - 1); return *(cur - 1);
// Prepare the pointers to loop over the bad quiets // Prepare the pointers to loop over the bad quiets
@@ -289,7 +290,7 @@ top:
case BAD_QUIET : case BAD_QUIET :
if (!skipQuiets) if (!skipQuiets)
return select<Next>([]() { return true; }); return select([]() { return true; });
return Move::none(); return Move::none();
@@ -298,21 +299,22 @@ top:
endMoves = generate<EVASIONS>(pos, cur); endMoves = generate<EVASIONS>(pos, cur);
score<EVASIONS>(); score<EVASIONS>();
partial_insertion_sort(cur, endMoves, std::numeric_limits<int>::min());
++stage; ++stage;
[[fallthrough]]; [[fallthrough]];
case EVASION : case EVASION :
return select<Best>([]() { return true; }); case QCAPTURE :
return select([]() { return true; });
case PROBCUT : case PROBCUT :
return select<Next>([&]() { return pos.see_ge(*cur, threshold); }); return select([&]() { return pos.see_ge(*cur, threshold); });
case QCAPTURE :
return select<Next>([]() { return true; });
} }
assert(false); assert(false);
return Move::none(); // Silence warning return Move::none(); // Silence warning
} }
void MovePicker::skip_quiet_moves() { skipQuiets = true; }
} // namespace Stockfish } // namespace Stockfish
+12 -121
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-2024 The Stockfish developers (see AUTHORS file) Copyright (C) 2004-2025 The Stockfish developers (see AUTHORS file)
Stockfish is free software: you can redistribute it and/or modify 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,123 +19,13 @@
#ifndef MOVEPICK_H_INCLUDED #ifndef MOVEPICK_H_INCLUDED
#define MOVEPICK_H_INCLUDED #define MOVEPICK_H_INCLUDED
#include <algorithm> #include "history.h"
#include <array>
#include <cassert>
#include <cmath>
#include <cstdint>
#include <cstdlib>
#include <limits>
#include <type_traits> // IWYU pragma: keep
#include "movegen.h" #include "movegen.h"
#include "position.h"
#include "types.h" #include "types.h"
namespace Stockfish { namespace Stockfish {
constexpr int PAWN_HISTORY_SIZE = 512; // has to be a power of 2 class Position;
constexpr int CORRECTION_HISTORY_SIZE = 16384; // has to be a power of 2
constexpr int CORRECTION_HISTORY_LIMIT = 1024;
static_assert((PAWN_HISTORY_SIZE & (PAWN_HISTORY_SIZE - 1)) == 0,
"PAWN_HISTORY_SIZE has to be a power of 2");
static_assert((CORRECTION_HISTORY_SIZE & (CORRECTION_HISTORY_SIZE - 1)) == 0,
"CORRECTION_HISTORY_SIZE has to be a power of 2");
enum PawnHistoryType {
Normal,
Correction
};
template<PawnHistoryType T = Normal>
inline int pawn_structure_index(const Position& pos) {
return pos.pawn_key() & ((T == Normal ? PAWN_HISTORY_SIZE : CORRECTION_HISTORY_SIZE) - 1);
}
// StatsEntry stores the stat table value. It is usually a number but could
// be a move or even a nested history. We use a class instead of a naked value
// to directly call history update operator<<() on the entry so to use stats
// tables at caller sites as simple multi-dim arrays.
template<typename T, int D>
class StatsEntry {
T entry;
public:
void operator=(const T& v) { entry = v; }
T* operator&() { return &entry; }
T* operator->() { return &entry; }
operator const T&() const { return entry; }
void operator<<(int bonus) {
static_assert(D <= std::numeric_limits<T>::max(), "D overflows T");
// Make sure that bonus is in range [-D, D]
int clampedBonus = std::clamp(bonus, -D, D);
entry += clampedBonus - entry * std::abs(clampedBonus) / D;
assert(std::abs(entry) <= D);
}
};
// Stats is a generic N-dimensional array used to store various statistics.
// The first template parameter T is the base type of the array, and the second
// template parameter D limits the range of updates in [-D, D] when we update
// values with the << operator, while the last parameters (Size and Sizes)
// encode the dimensions of the array.
template<typename T, int D, int Size, int... Sizes>
struct Stats: public std::array<Stats<T, D, Sizes...>, Size> {
using stats = Stats<T, D, Size, Sizes...>;
void fill(const T& v) {
// For standard-layout 'this' points to the first struct member
assert(std::is_standard_layout_v<stats>);
using entry = StatsEntry<T, D>;
entry* p = reinterpret_cast<entry*>(this);
std::fill(p, p + sizeof(*this) / sizeof(entry), v);
}
};
template<typename T, int D, int Size>
struct Stats<T, D, Size>: public std::array<StatsEntry<T, D>, Size> {};
// In stats table, D=0 means that the template parameter is not used
enum StatsParams {
NOT_USED = 0
};
enum StatsType {
NoCaptures,
Captures
};
// ButterflyHistory records how often quiet moves have been successful or unsuccessful
// during the current search, and is used for reduction and move ordering decisions.
// It uses 2 tables (one for each color) indexed by the move's from and to squares,
// see www.chessprogramming.org/Butterfly_Boards (~11 elo)
using ButterflyHistory = Stats<int16_t, 7183, COLOR_NB, int(SQUARE_NB) * int(SQUARE_NB)>;
// CapturePieceToHistory is addressed by a move's [piece][to][captured piece type]
using CapturePieceToHistory = Stats<int16_t, 10692, PIECE_NB, SQUARE_NB, PIECE_TYPE_NB>;
// PieceToHistory is like ButterflyHistory but is addressed by a move's [piece][to]
using PieceToHistory = Stats<int16_t, 29952, PIECE_NB, SQUARE_NB>;
// ContinuationHistory is the combined history of a given pair of moves, usually
// the current one given a previous one. The nested history table is based on
// PieceToHistory instead of ButterflyBoards.
// (~63 elo)
using ContinuationHistory = Stats<PieceToHistory, NOT_USED, PIECE_NB, SQUARE_NB>;
// PawnHistory is addressed by the pawn structure and a move's [piece][to]
using PawnHistory = Stats<int16_t, 8192, PAWN_HISTORY_SIZE, PIECE_NB, SQUARE_NB>;
// CorrectionHistory is addressed by color and pawn structure
using CorrectionHistory =
Stats<int16_t, CORRECTION_HISTORY_LIMIT, COLOR_NB, CORRECTION_HISTORY_SIZE>;
// The MovePicker class is used to pick one pseudo-legal move at a time from the // 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 // current position. The most important method is next_move(), which emits one
@@ -145,11 +35,6 @@ using CorrectionHistory =
// a cut-off first. // a cut-off first.
class MovePicker { class MovePicker {
enum PickType {
Next,
Best
};
public: public:
MovePicker(const MovePicker&) = delete; MovePicker(const MovePicker&) = delete;
MovePicker& operator=(const MovePicker&) = delete; MovePicker& operator=(const MovePicker&) = delete;
@@ -157,14 +42,17 @@ class MovePicker {
Move, Move,
Depth, Depth,
const ButterflyHistory*, const ButterflyHistory*,
const LowPlyHistory*,
const CapturePieceToHistory*, const CapturePieceToHistory*,
const PieceToHistory**, const PieceToHistory**,
const PawnHistory*); const PawnHistory*,
int);
MovePicker(const Position&, Move, int, const CapturePieceToHistory*); MovePicker(const Position&, Move, int, const CapturePieceToHistory*);
Move next_move(bool skipQuiets = false); Move next_move();
void skip_quiet_moves();
private: private:
template<PickType T, typename Pred> template<typename Pred>
Move select(Pred); Move select(Pred);
template<GenType> template<GenType>
void score(); void score();
@@ -173,6 +61,7 @@ class MovePicker {
const Position& pos; const Position& pos;
const ButterflyHistory* mainHistory; const ButterflyHistory* mainHistory;
const LowPlyHistory* lowPlyHistory;
const CapturePieceToHistory* captureHistory; const CapturePieceToHistory* captureHistory;
const PieceToHistory** continuationHistory; const PieceToHistory** continuationHistory;
const PawnHistory* pawnHistory; const PawnHistory* pawnHistory;
@@ -181,6 +70,8 @@ class MovePicker {
int stage; int stage;
int threshold; int threshold;
Depth depth; Depth depth;
int ply;
bool skipQuiets = false;
ExtMove moves[MAX_MOVES]; ExtMove moves[MAX_MOVES];
}; };
+1 -1
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-2024 The Stockfish developers (see AUTHORS file) Copyright (C) 2004-2025 The Stockfish developers (see AUTHORS file)
Stockfish is free software: you can redistribute it and/or modify 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
+1 -1
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-2024 The Stockfish developers (see AUTHORS file) Copyright (C) 2004-2025 The Stockfish developers (see AUTHORS file)
Stockfish is free software: you can redistribute it and/or modify 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
+1 -1
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-2024 The Stockfish developers (see AUTHORS file) Copyright (C) 2004-2025 The Stockfish developers (see AUTHORS file)
Stockfish is free software: you can redistribute it and/or modify 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
+44 -16
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-2024 The Stockfish developers (see AUTHORS file) Copyright (C) 2004-2025 The Stockfish developers (see AUTHORS file)
Stockfish is free software: you can redistribute it and/or modify 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
@@ -38,17 +38,41 @@
namespace Stockfish::Eval::NNUE::Layers { namespace Stockfish::Eval::NNUE::Layers {
#if (USE_SSSE3 | (USE_NEON >= 8)) #if (USE_SSSE3 | (USE_NEON >= 8))
alignas(CacheLineSize) static inline const static constexpr int lsb_index64[64] = {
std::array<std::array<std::uint16_t, 8>, 256> lookup_indices = []() { 0, 47, 1, 56, 48, 27, 2, 60, 57, 49, 41, 37, 28, 16, 3, 61, 54, 58, 35, 52, 50, 42,
std::array<std::array<std::uint16_t, 8>, 256> v{}; 21, 44, 38, 32, 29, 23, 17, 11, 4, 62, 46, 55, 26, 59, 40, 36, 15, 53, 34, 51, 20, 43,
for (unsigned i = 0; i < 256; ++i) 31, 22, 10, 45, 25, 39, 14, 33, 19, 30, 9, 24, 13, 18, 8, 12, 7, 6, 5, 63};
{
std::uint64_t j = i, k = 0; constexpr int constexpr_lsb(uint64_t bb) {
while (j) assert(bb != 0);
v[i][k++] = pop_lsb(j); constexpr uint64_t debruijn64 = 0x03F79D71B4CB0A89ULL;
} return lsb_index64[((bb ^ (bb - 1)) * debruijn64) >> 58];
return v; }
}();
alignas(CacheLineSize) static constexpr struct OffsetIndices {
#if (USE_SSE41)
std::uint8_t offset_indices[256][8];
#else
std::uint16_t offset_indices[256][8];
#endif
constexpr OffsetIndices() :
offset_indices() {
for (int i = 0; i < 256; ++i)
{
std::uint64_t j = i, k = 0;
while (j)
{
offset_indices[i][k++] = constexpr_lsb(j);
j &= j - 1;
}
while (k < 8)
offset_indices[i][k++] = 0;
}
}
} Lookup;
// Find indices of nonzero numbers in an int32_t array // Find indices of nonzero numbers in an int32_t array
template<const IndexType InputDimensions> template<const IndexType InputDimensions>
@@ -74,7 +98,11 @@ void find_nnz(const std::int32_t* input, std::uint16_t* out, IndexType& count_ou
using vec128_t = __m128i; using vec128_t = __m128i;
#define vec128_zero _mm_setzero_si128() #define vec128_zero _mm_setzero_si128()
#define vec128_set_16(a) _mm_set1_epi16(a) #define vec128_set_16(a) _mm_set1_epi16(a)
#define vec128_load(a) _mm_load_si128(a) #if (USE_SSE41)
#define vec128_load(a) _mm_cvtepu8_epi16(_mm_loadl_epi64(a))
#else
#define vec128_load(a) _mm_load_si128(a)
#endif
#define vec128_storeu(a, b) _mm_storeu_si128(a, b) #define vec128_storeu(a, b) _mm_storeu_si128(a, b)
#define vec128_add(a, b) _mm_add_epi16(a, b) #define vec128_add(a, b) _mm_add_epi16(a, b)
#elif defined(USE_NEON) #elif defined(USE_NEON)
@@ -110,9 +138,9 @@ void find_nnz(const std::int32_t* input, std::uint16_t* out, IndexType& count_ou
} }
for (IndexType j = 0; j < OutputsPerChunk; ++j) for (IndexType j = 0; j < OutputsPerChunk; ++j)
{ {
const auto lookup = (nnz >> (j * 8)) & 0xFF; const unsigned lookup = (nnz >> (j * 8)) & 0xFF;
const auto offsets = const vec128_t offsets =
vec128_load(reinterpret_cast<const vec128_t*>(&lookup_indices[lookup])); vec128_load(reinterpret_cast<const vec128_t*>(&Lookup.offset_indices[lookup]));
vec128_storeu(reinterpret_cast<vec128_t*>(out + count), vec128_add(base, offsets)); vec128_storeu(reinterpret_cast<vec128_t*>(out + count), vec128_add(base, offsets));
count += popcount(lookup); count += popcount(lookup);
base = vec128_add(base, increment); base = vec128_add(base, increment);
+1 -1
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-2024 The Stockfish developers (see AUTHORS file) Copyright (C) 2004-2025 The Stockfish developers (see AUTHORS file)
Stockfish is free software: you can redistribute it and/or modify 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
+1 -1
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-2024 The Stockfish developers (see AUTHORS file) Copyright (C) 2004-2025 The Stockfish developers (see AUTHORS file)
Stockfish is free software: you can redistribute it and/or modify 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
+1 -1
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-2024 The Stockfish developers (see AUTHORS file) Copyright (C) 2004-2025 The Stockfish developers (see AUTHORS file)
Stockfish is free software: you can redistribute it and/or modify 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
+36 -24
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-2024 The Stockfish developers (see AUTHORS file) Copyright (C) 2004-2025 The Stockfish developers (see AUTHORS file)
Stockfish is free software: you can redistribute it and/or modify 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
@@ -26,8 +26,10 @@
#include <type_traits> #include <type_traits>
#include <vector> #include <vector>
#include "../evaluate.h" #define INCBIN_SILENCE_BITCODE_WARNING
#include "../incbin/incbin.h" #include "../incbin/incbin.h"
#include "../evaluate.h"
#include "../memory.h" #include "../memory.h"
#include "../misc.h" #include "../misc.h"
#include "../position.h" #include "../position.h"
@@ -36,7 +38,6 @@
#include "nnue_common.h" #include "nnue_common.h"
#include "nnue_misc.h" #include "nnue_misc.h"
namespace {
// Macro to embed the default efficiently updatable neural network (NNUE) file // Macro to embed the default efficiently updatable neural network (NNUE) file
// data in the engine binary (using incbin.h, by Dale Weiler). // data in the engine binary (using incbin.h, by Dale Weiler).
// This macro invocation will declare the following three variables // This macro invocation will declare the following three variables
@@ -56,6 +57,8 @@ const unsigned char* const gEmbeddedNNUESmallEnd = &gEmbeddedNNUESmallData[1
const unsigned int gEmbeddedNNUESmallSize = 1; const unsigned int gEmbeddedNNUESmallSize = 1;
#endif #endif
namespace {
struct EmbeddedNNUE { struct EmbeddedNNUE {
EmbeddedNNUE(const unsigned char* embeddedData, EmbeddedNNUE(const unsigned char* embeddedData,
const unsigned char* embeddedEnd, const unsigned char* embeddedEnd,
@@ -98,7 +101,7 @@ bool read_parameters(std::istream& stream, T& reference) {
// Write evaluation function parameters // Write evaluation function parameters
template<typename T> template<typename T>
bool write_parameters(std::ostream& stream, const T& reference) { bool write_parameters(std::ostream& stream, T& reference) {
write_little_endian<std::uint32_t>(stream, T::get_hash_value()); write_little_endian<std::uint32_t>(stream, T::get_hash_value());
return reference.write_parameters(stream); return reference.write_parameters(stream);
@@ -234,35 +237,44 @@ Network<Arch, Transformer>::evaluate(const Position& pos
template<typename Arch, typename Transformer> template<typename Arch, typename Transformer>
void Network<Arch, Transformer>::verify(std::string evalfilePath) const { void Network<Arch, Transformer>::verify(std::string evalfilePath,
const std::function<void(std::string_view)>& f) const {
if (evalfilePath.empty()) if (evalfilePath.empty())
evalfilePath = evalFile.defaultName; evalfilePath = evalFile.defaultName;
if (evalFile.current != evalfilePath) if (evalFile.current != evalfilePath)
{ {
std::string msg1 = if (f)
"Network evaluation parameters compatible with the engine must be available."; {
std::string msg2 = "The network file " + evalfilePath + " was not loaded successfully."; std::string msg1 =
std::string msg3 = "The UCI option EvalFile might need to specify the full path, " "Network evaluation parameters compatible with the engine must be available.";
"including the directory name, to the network file."; std::string msg2 = "The network file " + evalfilePath + " was not loaded successfully.";
std::string msg4 = "The default net can be downloaded from: " std::string msg3 = "The UCI option EvalFile might need to specify the full path, "
"https://tests.stockfishchess.org/api/nn/" "including the directory name, to the network file.";
+ evalFile.defaultName; std::string msg4 = "The default net can be downloaded from: "
std::string msg5 = "The engine will be terminated now."; "https://tests.stockfishchess.org/api/nn/"
+ evalFile.defaultName;
std::string msg5 = "The engine will be terminated now.";
std::string msg = "ERROR: " + msg1 + '\n' + "ERROR: " + msg2 + '\n' + "ERROR: " + msg3
+ '\n' + "ERROR: " + msg4 + '\n' + "ERROR: " + msg5 + '\n';
f(msg);
}
sync_cout << "info string ERROR: " << msg1 << sync_endl;
sync_cout << "info string ERROR: " << msg2 << sync_endl;
sync_cout << "info string ERROR: " << msg3 << sync_endl;
sync_cout << "info string ERROR: " << msg4 << sync_endl;
sync_cout << "info string ERROR: " << msg5 << sync_endl;
exit(EXIT_FAILURE); exit(EXIT_FAILURE);
} }
size_t size = sizeof(*featureTransformer) + sizeof(Arch) * LayerStacks; if (f)
sync_cout << "info string NNUE evaluation using " << evalfilePath << " (" {
<< size / (1024 * 1024) << "MiB, (" << featureTransformer->InputDimensions << ", " size_t size = sizeof(*featureTransformer) + sizeof(Arch) * LayerStacks;
<< network[0].TransformedFeatureDimensions << ", " << network[0].FC_0_OUTPUTS << ", " f("info string NNUE evaluation using " + evalfilePath + " ("
<< network[0].FC_1_OUTPUTS << ", 1))" << sync_endl; + 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))");
}
} }
+4 -2
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-2024 The Stockfish developers (see AUTHORS file) Copyright (C) 2004-2025 The Stockfish developers (see AUTHORS file)
Stockfish is free software: you can redistribute it and/or modify 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,11 @@
#define NETWORK_H_INCLUDED #define NETWORK_H_INCLUDED
#include <cstdint> #include <cstdint>
#include <functional>
#include <iostream> #include <iostream>
#include <optional> #include <optional>
#include <string> #include <string>
#include <string_view>
#include <tuple> #include <tuple>
#include <utility> #include <utility>
@@ -68,7 +70,7 @@ class Network {
void hint_common_access(const Position& pos, void hint_common_access(const Position& pos,
AccumulatorCaches::Cache<FTDimensions>* cache) const; AccumulatorCaches::Cache<FTDimensions>* cache) const;
void verify(std::string evalfilePath) const; void verify(std::string evalfilePath, const std::function<void(std::string_view)>&) const;
NnueEvalTrace trace_evaluate(const Position& pos, NnueEvalTrace trace_evaluate(const Position& pos,
AccumulatorCaches::Cache<FTDimensions>* cache) const; AccumulatorCaches::Cache<FTDimensions>* cache) const;
+1 -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-2024 The Stockfish developers (see AUTHORS file) Copyright (C) 2004-2025 The Stockfish developers (see AUTHORS file)
Stockfish is free software: you can redistribute it and/or modify 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
@@ -80,11 +80,6 @@ struct AccumulatorCaches {
entry.clear(network.featureTransformer->biases); entry.clear(network.featureTransformer->biases);
} }
void clear(const BiasType* biases) {
for (auto& entry : entries)
entry.clear(biases);
}
std::array<Entry, COLOR_NB>& operator[](Square sq) { return entries[sq]; } std::array<Entry, COLOR_NB>& operator[](Square sq) { return entries[sq]; }
std::array<std::array<Entry, COLOR_NB>, SQUARE_NB> entries; std::array<std::array<Entry, COLOR_NB>, SQUARE_NB> entries;
+1 -1
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-2024 The Stockfish developers (see AUTHORS file) Copyright (C) 2004-2025 The Stockfish developers (see AUTHORS file)
Stockfish is free software: you can redistribute it and/or modify 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
+1 -1
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-2024 The Stockfish developers (see AUTHORS file) Copyright (C) 2004-2025 The Stockfish developers (see AUTHORS file)
Stockfish is free software: you can redistribute it and/or modify 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
+292 -381
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-2024 The Stockfish developers (see AUTHORS file) Copyright (C) 2004-2025 The Stockfish developers (see AUTHORS file)
Stockfish is free software: you can redistribute it and/or modify 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
@@ -26,6 +26,7 @@
#include <cstdint> #include <cstdint>
#include <cstring> #include <cstring>
#include <iosfwd> #include <iosfwd>
#include <type_traits>
#include <utility> #include <utility>
#include "../position.h" #include "../position.h"
@@ -145,11 +146,51 @@ using psqt_vec_t = int32x4_t;
#endif #endif
// Returns the inverse of a permutation
template<std::size_t Len>
constexpr std::array<std::size_t, Len>
invert_permutation(const std::array<std::size_t, Len>& order) {
std::array<std::size_t, Len> inverse{};
for (std::size_t i = 0; i < order.size(); i++)
inverse[order[i]] = i;
return inverse;
}
// Divide a byte region of size TotalSize to chunks of size
// BlockSize, and permute the blocks by a given order
template<std::size_t BlockSize, typename T, std::size_t N, std::size_t OrderSize>
void permute(T (&data)[N], const std::array<std::size_t, OrderSize>& order) {
constexpr std::size_t TotalSize = N * sizeof(T);
static_assert(TotalSize % (BlockSize * OrderSize) == 0,
"ChunkSize * OrderSize must perfectly divide TotalSize");
constexpr std::size_t ProcessChunkSize = BlockSize * OrderSize;
std::array<std::byte, ProcessChunkSize> buffer{};
std::byte* const bytes = reinterpret_cast<std::byte*>(data);
for (std::size_t i = 0; i < TotalSize; i += ProcessChunkSize)
{
std::byte* const values = &bytes[i];
for (std::size_t j = 0; j < OrderSize; j++)
{
auto* const buffer_chunk = &buffer[j * BlockSize];
auto* const value_chunk = &values[order[j] * BlockSize];
std::copy(value_chunk, value_chunk + BlockSize, buffer_chunk);
}
std::copy(std::begin(buffer), std::end(buffer), values);
}
}
// Compute optimal SIMD register count for feature transformer accumulation.
template<IndexType TransformedFeatureWidth, IndexType HalfDimensions>
class SIMDTiling {
#ifdef VECTOR #ifdef VECTOR
// Compute optimal SIMD register count for feature transformer accumulation.
// We use __m* types as template arguments, which causes GCC to emit warnings // We use __m* types as template arguments, which causes GCC to emit warnings
// about losing some attribute information. This is irrelevant to us as we // about losing some attribute information. This is irrelevant to us as we
// only take their size, so the following pragma are harmless. // only take their size, so the following pragma are harmless.
@@ -158,33 +199,47 @@ using psqt_vec_t = int32x4_t;
#pragma GCC diagnostic ignored "-Wignored-attributes" #pragma GCC diagnostic ignored "-Wignored-attributes"
#endif #endif
template<typename SIMDRegisterType, typename LaneType, int NumLanes, int MaxRegisters> template<typename SIMDRegisterType, typename LaneType, int NumLanes, int MaxRegisters>
static constexpr int BestRegisterCount() { static constexpr int BestRegisterCount() {
#define RegisterSize sizeof(SIMDRegisterType) constexpr std::size_t RegisterSize = sizeof(SIMDRegisterType);
#define LaneSize sizeof(LaneType) constexpr std::size_t LaneSize = sizeof(LaneType);
static_assert(RegisterSize >= LaneSize); static_assert(RegisterSize >= LaneSize);
static_assert(MaxRegisters <= NumRegistersSIMD); static_assert(MaxRegisters <= NumRegistersSIMD);
static_assert(MaxRegisters > 0); static_assert(MaxRegisters > 0);
static_assert(NumRegistersSIMD > 0); static_assert(NumRegistersSIMD > 0);
static_assert(RegisterSize % LaneSize == 0); static_assert(RegisterSize % LaneSize == 0);
static_assert((NumLanes * LaneSize) % RegisterSize == 0); static_assert((NumLanes * LaneSize) % RegisterSize == 0);
const int ideal = (NumLanes * LaneSize) / RegisterSize; const int ideal = (NumLanes * LaneSize) / RegisterSize;
if (ideal <= MaxRegisters) if (ideal <= MaxRegisters)
return ideal; return ideal;
// Look for the largest divisor of the ideal register count that is smaller than MaxRegisters // Look for the largest divisor of the ideal register count that is smaller than MaxRegisters
for (int divisor = MaxRegisters; divisor > 1; --divisor) for (int divisor = MaxRegisters; divisor > 1; --divisor)
if (ideal % divisor == 0) if (ideal % divisor == 0)
return divisor; return divisor;
return 1;
}
return 1;
}
#if defined(__GNUC__) #if defined(__GNUC__)
#pragma GCC diagnostic pop #pragma GCC diagnostic pop
#endif #endif
public:
static constexpr int NumRegs =
BestRegisterCount<vec_t, WeightType, TransformedFeatureWidth, NumRegistersSIMD>();
static constexpr int NumPsqtRegs =
BestRegisterCount<psqt_vec_t, PSQTWeightType, PSQTBuckets, NumRegistersSIMD>();
static constexpr IndexType TileHeight = NumRegs * sizeof(vec_t) / 2;
static constexpr IndexType PsqtTileHeight = NumPsqtRegs * sizeof(psqt_vec_t) / 4;
static_assert(HalfDimensions % TileHeight == 0, "TileHeight must divide HalfDimensions");
static_assert(PSQTBuckets % PsqtTileHeight == 0, "PsqtTileHeight must divide PSQTBuckets");
#endif #endif
};
// Input feature converter // Input feature converter
@@ -196,17 +251,7 @@ class FeatureTransformer {
static constexpr IndexType HalfDimensions = TransformedFeatureDimensions; static constexpr IndexType HalfDimensions = TransformedFeatureDimensions;
private: private:
#ifdef VECTOR using Tiling = SIMDTiling<TransformedFeatureDimensions, HalfDimensions>;
static constexpr int NumRegs =
BestRegisterCount<vec_t, WeightType, TransformedFeatureDimensions, NumRegistersSIMD>();
static constexpr int NumPsqtRegs =
BestRegisterCount<psqt_vec_t, PSQTWeightType, PSQTBuckets, NumRegistersSIMD>();
static constexpr IndexType TileHeight = NumRegs * sizeof(vec_t) / 2;
static constexpr IndexType PsqtTileHeight = NumPsqtRegs * sizeof(psqt_vec_t) / 4;
static_assert(HalfDimensions % TileHeight == 0, "TileHeight must divide HalfDimensions");
static_assert(PSQTBuckets % PsqtTileHeight == 0, "PsqtTileHeight must divide PSQTBuckets");
#endif
public: public:
// Output type // Output type
@@ -219,76 +264,54 @@ class FeatureTransformer {
// Size of forward propagation buffer // Size of forward propagation buffer
static constexpr std::size_t BufferSize = OutputDimensions * sizeof(OutputType); static constexpr std::size_t BufferSize = OutputDimensions * sizeof(OutputType);
// Store the order by which 128-bit blocks of a 1024-bit data must
// be permuted so that calling packus on adjacent vectors of 16-bit
// integers loaded from the data results in the pre-permutation order
static constexpr auto PackusEpi16Order = []() -> std::array<std::size_t, 8> {
#if defined(USE_AVX512)
// _mm512_packus_epi16 after permutation:
// | 0 | 2 | 4 | 6 | // Vector 0
// | 1 | 3 | 5 | 7 | // Vector 1
// | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | // Packed Result
return {0, 2, 4, 6, 1, 3, 5, 7};
#elif defined(USE_AVX2)
// _mm256_packus_epi16 after permutation:
// | 0 | 2 | | 4 | 6 | // Vector 0, 2
// | 1 | 3 | | 5 | 7 | // Vector 1, 3
// | 0 | 1 | 2 | 3 | | 4 | 5 | 6 | 7 | // Packed Result
return {0, 2, 1, 3, 4, 6, 5, 7};
#else
return {0, 1, 2, 3, 4, 5, 6, 7};
#endif
}();
static constexpr auto InversePackusEpi16Order = invert_permutation(PackusEpi16Order);
// Hash value embedded in the evaluation file // Hash value embedded in the evaluation file
static constexpr std::uint32_t get_hash_value() { static constexpr std::uint32_t get_hash_value() {
return FeatureSet::HashValue ^ (OutputDimensions * 2); return FeatureSet::HashValue ^ (OutputDimensions * 2);
} }
static constexpr void order_packs([[maybe_unused]] uint64_t* v) { void permute_weights() {
#if defined(USE_AVX512) // _mm512_packs_epi16 ordering permute<16>(biases, PackusEpi16Order);
uint64_t tmp0 = v[2], tmp1 = v[3]; permute<16>(weights, PackusEpi16Order);
v[2] = v[8], v[3] = v[9];
v[8] = v[4], v[9] = v[5];
v[4] = tmp0, v[5] = tmp1;
tmp0 = v[6], tmp1 = v[7];
v[6] = v[10], v[7] = v[11];
v[10] = v[12], v[11] = v[13];
v[12] = tmp0, v[13] = tmp1;
#elif defined(USE_AVX2) // _mm256_packs_epi16 ordering
std::swap(v[2], v[4]);
std::swap(v[3], v[5]);
#endif
} }
static constexpr void inverse_order_packs([[maybe_unused]] uint64_t* v) { void unpermute_weights() {
#if defined(USE_AVX512) // Inverse _mm512_packs_epi16 ordering permute<16>(biases, InversePackusEpi16Order);
uint64_t tmp0 = v[2], tmp1 = v[3]; permute<16>(weights, InversePackusEpi16Order);
v[2] = v[4], v[3] = v[5];
v[4] = v[8], v[5] = v[9];
v[8] = tmp0, v[9] = tmp1;
tmp0 = v[6], tmp1 = v[7];
v[6] = v[12], v[7] = v[13];
v[12] = v[10], v[13] = v[11];
v[10] = tmp0, v[11] = tmp1;
#elif defined(USE_AVX2) // Inverse _mm256_packs_epi16 ordering
std::swap(v[2], v[4]);
std::swap(v[3], v[5]);
#endif
} }
void permute_weights([[maybe_unused]] void (*order_fn)(uint64_t*)) const { inline void scale_weights(bool read) {
#if defined(USE_AVX2)
#if defined(USE_AVX512)
constexpr IndexType di = 16;
#else
constexpr IndexType di = 8;
#endif
uint64_t* b = reinterpret_cast<uint64_t*>(const_cast<BiasType*>(&biases[0]));
for (IndexType i = 0; i < HalfDimensions * sizeof(BiasType) / sizeof(uint64_t); i += di)
order_fn(&b[i]);
for (IndexType j = 0; j < InputDimensions; ++j) for (IndexType j = 0; j < InputDimensions; ++j)
{ {
uint64_t* w = WeightType* w = &weights[j * HalfDimensions];
reinterpret_cast<uint64_t*>(const_cast<WeightType*>(&weights[j * HalfDimensions]));
for (IndexType i = 0; i < HalfDimensions * sizeof(WeightType) / sizeof(uint64_t);
i += di)
order_fn(&w[i]);
}
#endif
}
inline void scale_weights(bool read) const {
for (IndexType j = 0; j < InputDimensions; ++j)
{
WeightType* w = const_cast<WeightType*>(&weights[j * HalfDimensions]);
for (IndexType i = 0; i < HalfDimensions; ++i) for (IndexType i = 0; i < HalfDimensions; ++i)
w[i] = read ? w[i] * 2 : w[i] / 2; w[i] = read ? w[i] * 2 : w[i] / 2;
} }
BiasType* b = const_cast<BiasType*>(biases);
for (IndexType i = 0; i < HalfDimensions; ++i) for (IndexType i = 0; i < HalfDimensions; ++i)
b[i] = read ? b[i] * 2 : b[i] / 2; biases[i] = read ? biases[i] * 2 : biases[i] / 2;
} }
// Read network parameters // Read network parameters
@@ -298,22 +321,22 @@ class FeatureTransformer {
read_leb_128<WeightType>(stream, weights, HalfDimensions * InputDimensions); read_leb_128<WeightType>(stream, weights, HalfDimensions * InputDimensions);
read_leb_128<PSQTWeightType>(stream, psqtWeights, PSQTBuckets * InputDimensions); read_leb_128<PSQTWeightType>(stream, psqtWeights, PSQTBuckets * InputDimensions);
permute_weights(inverse_order_packs); permute_weights();
scale_weights(true); scale_weights(true);
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) {
permute_weights(order_packs); unpermute_weights();
scale_weights(false); scale_weights(false);
write_leb_128<BiasType>(stream, biases, HalfDimensions); write_leb_128<BiasType>(stream, biases, HalfDimensions);
write_leb_128<WeightType>(stream, weights, HalfDimensions * InputDimensions); write_leb_128<WeightType>(stream, weights, HalfDimensions * InputDimensions);
write_leb_128<PSQTWeightType>(stream, psqtWeights, PSQTBuckets * InputDimensions); write_leb_128<PSQTWeightType>(stream, psqtWeights, PSQTBuckets * InputDimensions);
permute_weights(inverse_order_packs); permute_weights();
scale_weights(true); scale_weights(true);
return !stream.fail(); return !stream.fail();
} }
@@ -447,17 +470,16 @@ class FeatureTransformer {
void hint_common_access(const Position& pos, void hint_common_access(const Position& pos,
AccumulatorCaches::Cache<HalfDimensions>* cache) const { AccumulatorCaches::Cache<HalfDimensions>* cache) const {
hint_common_access_for_perspective<WHITE>(pos, cache); update_accumulator<WHITE>(pos, cache);
hint_common_access_for_perspective<BLACK>(pos, cache); update_accumulator<BLACK>(pos, cache);
} }
private: private:
template<Color Perspective> template<Color Perspective>
[[nodiscard]] std::pair<StateInfo*, StateInfo*> StateInfo* try_find_computed_accumulator(const Position& pos) const {
try_find_computed_accumulator(const Position& pos) const {
// Look for a usable accumulator of an earlier position. We keep track // Look for a usable accumulator of an earlier position. We keep track
// of the estimated gain in terms of features to be added/subtracted. // of the estimated gain in terms of features to be added/subtracted.
StateInfo *st = pos.state(), *next = nullptr; StateInfo* st = pos.state();
int gain = FeatureSet::refresh_cost(pos); int gain = FeatureSet::refresh_cost(pos);
while (st->previous && !(st->*accPtr).computed[Perspective]) while (st->previous && !(st->*accPtr).computed[Perspective])
{ {
@@ -466,239 +488,170 @@ class FeatureTransformer {
if (FeatureSet::requires_refresh(st, Perspective) if (FeatureSet::requires_refresh(st, Perspective)
|| (gain -= FeatureSet::update_cost(st) + 1) < 0) || (gain -= FeatureSet::update_cost(st) + 1) < 0)
break; break;
next = st; st = st->previous;
st = st->previous;
} }
return {st, next}; return st;
} }
// NOTE: The parameter states_to_update is an array of position states. // Given a computed accumulator, computes the accumulator of the next position.
// All states must be sequential, that is states_to_update[i] must template<Color Perspective>
// either be reachable by repeatedly applying ->previous from void update_accumulator_incremental(const Position& pos, StateInfo* computed) const {
// states_to_update[i+1], and computed_st must be reachable by assert((computed->*accPtr).computed[Perspective]);
// repeatedly applying ->previous on states_to_update[0]. assert(computed->next != nullptr);
template<Color Perspective, size_t N>
void update_accumulator_incremental(const Position& pos,
StateInfo* computed_st,
StateInfo* states_to_update[N]) const {
static_assert(N > 0);
assert([&]() {
for (size_t i = 0; i < N; ++i)
{
if (states_to_update[i] == nullptr)
return false;
}
return true;
}());
#ifdef VECTOR
// Gcc-10.2 unnecessarily spills AVX2 registers if this array
// is defined in the VECTOR code below, once in each branch.
vec_t acc[NumRegs];
psqt_vec_t psqt[NumPsqtRegs];
#endif
// Update incrementally going back through states_to_update.
// Gather all features to be updated.
const Square ksq = pos.square<KING>(Perspective); const Square ksq = pos.square<KING>(Perspective);
// The size must be enough to contain the largest possible update. // The size must be enough to contain the largest possible update.
// That might depend on the feature set and generally relies on the // That might depend on the feature set and generally relies on the
// feature set's update cost calculation to be correct and never allow // feature set's update cost calculation to be correct and never allow
// updates with more added/removed features than MaxActiveDimensions. // updates with more added/removed features than MaxActiveDimensions.
FeatureSet::IndexList removed[N], added[N]; // In this case, the maximum size of both feature addition and removal
// is 2, since we are incrementally updating one move at a time.
FeatureSet::IndexList removed, added;
FeatureSet::append_changed_indices<Perspective>(ksq, computed->next->dirtyPiece, removed,
added);
for (int i = N - 1; i >= 0; --i) StateInfo* next = computed->next;
assert(!(next->*accPtr).computed[Perspective]);
if (removed.size() == 0 && added.size() == 0)
{ {
(states_to_update[i]->*accPtr).computed[Perspective] = true; std::memcpy((next->*accPtr).accumulation[Perspective],
(computed->*accPtr).accumulation[Perspective],
const StateInfo* end_state = i == 0 ? computed_st : states_to_update[i - 1]; HalfDimensions * sizeof(BiasType));
std::memcpy((next->*accPtr).psqtAccumulation[Perspective],
for (StateInfo* st2 = states_to_update[i]; st2 != end_state; st2 = st2->previous) (computed->*accPtr).psqtAccumulation[Perspective],
FeatureSet::append_changed_indices<Perspective>(ksq, st2->dirtyPiece, removed[i], PSQTBuckets * sizeof(PSQTWeightType));
added[i]);
}
StateInfo* st = computed_st;
// Now update the accumulators listed in states_to_update[],
// where the last element is a sentinel.
#ifdef VECTOR
if (N == 1 && (removed[0].size() == 1 || removed[0].size() == 2) && added[0].size() == 1)
{
assert(states_to_update[0]);
auto accIn =
reinterpret_cast<const vec_t*>(&(st->*accPtr).accumulation[Perspective][0]);
auto accOut = reinterpret_cast<vec_t*>(
&(states_to_update[0]->*accPtr).accumulation[Perspective][0]);
const IndexType offsetR0 = HalfDimensions * removed[0][0];
auto columnR0 = reinterpret_cast<const vec_t*>(&weights[offsetR0]);
const IndexType offsetA = HalfDimensions * added[0][0];
auto columnA = reinterpret_cast<const vec_t*>(&weights[offsetA]);
if (removed[0].size() == 1)
{
for (IndexType k = 0; k < HalfDimensions * sizeof(std::int16_t) / sizeof(vec_t);
++k)
accOut[k] = vec_add_16(vec_sub_16(accIn[k], columnR0[k]), columnA[k]);
}
else
{
const IndexType offsetR1 = HalfDimensions * removed[0][1];
auto columnR1 = reinterpret_cast<const vec_t*>(&weights[offsetR1]);
for (IndexType k = 0; k < HalfDimensions * sizeof(std::int16_t) / sizeof(vec_t);
++k)
accOut[k] = vec_sub_16(vec_add_16(accIn[k], columnA[k]),
vec_add_16(columnR0[k], columnR1[k]));
}
auto accPsqtIn =
reinterpret_cast<const psqt_vec_t*>(&(st->*accPtr).psqtAccumulation[Perspective][0]);
auto accPsqtOut = reinterpret_cast<psqt_vec_t*>(
&(states_to_update[0]->*accPtr).psqtAccumulation[Perspective][0]);
const IndexType offsetPsqtR0 = PSQTBuckets * removed[0][0];
auto columnPsqtR0 = reinterpret_cast<const psqt_vec_t*>(&psqtWeights[offsetPsqtR0]);
const IndexType offsetPsqtA = PSQTBuckets * added[0][0];
auto columnPsqtA = reinterpret_cast<const psqt_vec_t*>(&psqtWeights[offsetPsqtA]);
if (removed[0].size() == 1)
{
for (std::size_t k = 0; k < PSQTBuckets * sizeof(std::int32_t) / sizeof(psqt_vec_t);
++k)
accPsqtOut[k] = vec_add_psqt_32(vec_sub_psqt_32(accPsqtIn[k], columnPsqtR0[k]),
columnPsqtA[k]);
}
else
{
const IndexType offsetPsqtR1 = PSQTBuckets * removed[0][1];
auto columnPsqtR1 = reinterpret_cast<const psqt_vec_t*>(&psqtWeights[offsetPsqtR1]);
for (std::size_t k = 0; k < PSQTBuckets * sizeof(std::int32_t) / sizeof(psqt_vec_t);
++k)
accPsqtOut[k] =
vec_sub_psqt_32(vec_add_psqt_32(accPsqtIn[k], columnPsqtA[k]),
vec_add_psqt_32(columnPsqtR0[k], columnPsqtR1[k]));
}
} }
else else
{ {
for (IndexType j = 0; j < HalfDimensions / TileHeight; ++j) assert(added.size() == 1 || added.size() == 2);
assert(removed.size() == 1 || removed.size() == 2);
assert(added.size() <= removed.size());
#ifdef VECTOR
auto* accIn =
reinterpret_cast<const vec_t*>(&(computed->*accPtr).accumulation[Perspective][0]);
auto* accOut = reinterpret_cast<vec_t*>(&(next->*accPtr).accumulation[Perspective][0]);
const IndexType offsetA0 = HalfDimensions * added[0];
auto* columnA0 = reinterpret_cast<const vec_t*>(&weights[offsetA0]);
const IndexType offsetR0 = HalfDimensions * removed[0];
auto* columnR0 = reinterpret_cast<const vec_t*>(&weights[offsetR0]);
if (removed.size() == 1)
{ {
// Load accumulator for (IndexType i = 0; i < HalfDimensions * sizeof(WeightType) / sizeof(vec_t); ++i)
auto accTileIn = reinterpret_cast<const vec_t*>( accOut[i] = vec_add_16(vec_sub_16(accIn[i], columnR0[i]), columnA0[i]);
&(st->*accPtr).accumulation[Perspective][j * TileHeight]); }
for (IndexType k = 0; k < NumRegs; ++k) else if (added.size() == 1)
acc[k] = vec_load(&accTileIn[k]); {
const IndexType offsetR1 = HalfDimensions * removed[1];
auto* columnR1 = reinterpret_cast<const vec_t*>(&weights[offsetR1]);
for (IndexType i = 0; i < N; ++i) for (IndexType i = 0; i < HalfDimensions * sizeof(WeightType) / sizeof(vec_t); ++i)
{ accOut[i] = vec_sub_16(vec_add_16(accIn[i], columnA0[i]),
// Difference calculation for the deactivated features vec_add_16(columnR0[i], columnR1[i]));
for (const auto index : removed[i]) }
{ else
const IndexType offset = HalfDimensions * index + j * TileHeight; {
auto column = reinterpret_cast<const vec_t*>(&weights[offset]); const IndexType offsetA1 = HalfDimensions * added[1];
for (IndexType k = 0; k < NumRegs; ++k) auto* columnA1 = reinterpret_cast<const vec_t*>(&weights[offsetA1]);
acc[k] = vec_sub_16(acc[k], column[k]); const IndexType offsetR1 = HalfDimensions * removed[1];
} auto* columnR1 = reinterpret_cast<const vec_t*>(&weights[offsetR1]);
// Difference calculation for the activated features for (IndexType i = 0; i < HalfDimensions * sizeof(WeightType) / sizeof(vec_t); ++i)
for (const auto index : added[i]) accOut[i] =
{ vec_add_16(accIn[i], vec_sub_16(vec_add_16(columnA0[i], columnA1[i]),
const IndexType offset = HalfDimensions * index + j * TileHeight; vec_add_16(columnR0[i], columnR1[i])));
auto column = reinterpret_cast<const vec_t*>(&weights[offset]);
for (IndexType k = 0; k < NumRegs; ++k)
acc[k] = vec_add_16(acc[k], column[k]);
}
// Store accumulator
auto accTileOut = reinterpret_cast<vec_t*>(
&(states_to_update[i]->*accPtr).accumulation[Perspective][j * TileHeight]);
for (IndexType k = 0; k < NumRegs; ++k)
vec_store(&accTileOut[k], acc[k]);
}
} }
for (IndexType j = 0; j < PSQTBuckets / PsqtTileHeight; ++j) auto* accPsqtIn = reinterpret_cast<const psqt_vec_t*>(
&(computed->*accPtr).psqtAccumulation[Perspective][0]);
auto* accPsqtOut =
reinterpret_cast<psqt_vec_t*>(&(next->*accPtr).psqtAccumulation[Perspective][0]);
const IndexType offsetPsqtA0 = PSQTBuckets * added[0];
auto* columnPsqtA0 = reinterpret_cast<const psqt_vec_t*>(&psqtWeights[offsetPsqtA0]);
const IndexType offsetPsqtR0 = PSQTBuckets * removed[0];
auto* columnPsqtR0 = reinterpret_cast<const psqt_vec_t*>(&psqtWeights[offsetPsqtR0]);
if (removed.size() == 1)
{ {
// Load accumulator for (std::size_t i = 0;
auto accTilePsqtIn = reinterpret_cast<const psqt_vec_t*>( i < PSQTBuckets * sizeof(PSQTWeightType) / sizeof(psqt_vec_t); ++i)
&(st->*accPtr).psqtAccumulation[Perspective][j * PsqtTileHeight]); accPsqtOut[i] = vec_add_psqt_32(vec_sub_psqt_32(accPsqtIn[i], columnPsqtR0[i]),
for (std::size_t k = 0; k < NumPsqtRegs; ++k) columnPsqtA0[i]);
psqt[k] = vec_load_psqt(&accTilePsqtIn[k]); }
else if (added.size() == 1)
for (IndexType i = 0; i < N; ++i) {
{ const IndexType offsetPsqtR1 = PSQTBuckets * removed[1];
// Difference calculation for the deactivated features auto* columnPsqtR1 =
for (const auto index : removed[i]) reinterpret_cast<const psqt_vec_t*>(&psqtWeights[offsetPsqtR1]);
{
const IndexType offset = PSQTBuckets * index + j * PsqtTileHeight; for (std::size_t i = 0;
auto columnPsqt = reinterpret_cast<const psqt_vec_t*>(&psqtWeights[offset]); i < PSQTBuckets * sizeof(PSQTWeightType) / sizeof(psqt_vec_t); ++i)
for (std::size_t k = 0; k < NumPsqtRegs; ++k) accPsqtOut[i] =
psqt[k] = vec_sub_psqt_32(psqt[k], columnPsqt[k]); vec_sub_psqt_32(vec_add_psqt_32(accPsqtIn[i], columnPsqtA0[i]),
} vec_add_psqt_32(columnPsqtR0[i], columnPsqtR1[i]));
}
// Difference calculation for the activated features else
for (const auto index : added[i]) {
{ const IndexType offsetPsqtA1 = PSQTBuckets * added[1];
const IndexType offset = PSQTBuckets * index + j * PsqtTileHeight; auto* columnPsqtA1 =
auto columnPsqt = reinterpret_cast<const psqt_vec_t*>(&psqtWeights[offset]); reinterpret_cast<const psqt_vec_t*>(&psqtWeights[offsetPsqtA1]);
for (std::size_t k = 0; k < NumPsqtRegs; ++k) const IndexType offsetPsqtR1 = PSQTBuckets * removed[1];
psqt[k] = vec_add_psqt_32(psqt[k], columnPsqt[k]); auto* columnPsqtR1 =
} reinterpret_cast<const psqt_vec_t*>(&psqtWeights[offsetPsqtR1]);
// Store accumulator for (std::size_t i = 0;
auto accTilePsqtOut = reinterpret_cast<psqt_vec_t*>( i < PSQTBuckets * sizeof(PSQTWeightType) / sizeof(psqt_vec_t); ++i)
&(states_to_update[i]->*accPtr) accPsqtOut[i] = vec_add_psqt_32(
.psqtAccumulation[Perspective][j * PsqtTileHeight]); accPsqtIn[i],
for (std::size_t k = 0; k < NumPsqtRegs; ++k) vec_sub_psqt_32(vec_add_psqt_32(columnPsqtA0[i], columnPsqtA1[i]),
vec_store_psqt(&accTilePsqtOut[k], psqt[k]); vec_add_psqt_32(columnPsqtR0[i], columnPsqtR1[i])));
}
} }
}
#else #else
for (IndexType i = 0; i < N; ++i) std::memcpy((next->*accPtr).accumulation[Perspective],
{ (computed->*accPtr).accumulation[Perspective],
std::memcpy((states_to_update[i]->*accPtr).accumulation[Perspective], HalfDimensions * sizeof(BiasType));
(st->*accPtr).accumulation[Perspective], HalfDimensions * sizeof(BiasType)); std::memcpy((next->*accPtr).psqtAccumulation[Perspective],
(computed->*accPtr).psqtAccumulation[Perspective],
for (std::size_t k = 0; k < PSQTBuckets; ++k) PSQTBuckets * sizeof(PSQTWeightType));
(states_to_update[i]->*accPtr).psqtAccumulation[Perspective][k] =
(st->*accPtr).psqtAccumulation[Perspective][k];
st = states_to_update[i];
// Difference calculation for the deactivated features // Difference calculation for the deactivated features
for (const auto index : removed[i]) for (const auto index : removed)
{ {
const IndexType offset = HalfDimensions * index; const IndexType offset = HalfDimensions * index;
for (IndexType j = 0; j < HalfDimensions; ++j) for (IndexType i = 0; i < HalfDimensions; ++i)
(st->*accPtr).accumulation[Perspective][j] -= weights[offset + j]; (next->*accPtr).accumulation[Perspective][i] -= weights[offset + i];
for (std::size_t k = 0; k < PSQTBuckets; ++k) for (std::size_t i = 0; i < PSQTBuckets; ++i)
(st->*accPtr).psqtAccumulation[Perspective][k] -= (next->*accPtr).psqtAccumulation[Perspective][i] -=
psqtWeights[index * PSQTBuckets + k]; psqtWeights[index * PSQTBuckets + i];
} }
// Difference calculation for the activated features // Difference calculation for the activated features
for (const auto index : added[i]) for (const auto index : added)
{ {
const IndexType offset = HalfDimensions * index; const IndexType offset = HalfDimensions * index;
for (IndexType j = 0; j < HalfDimensions; ++j) for (IndexType i = 0; i < HalfDimensions; ++i)
(st->*accPtr).accumulation[Perspective][j] += weights[offset + j]; (next->*accPtr).accumulation[Perspective][i] += weights[offset + i];
for (std::size_t k = 0; k < PSQTBuckets; ++k) for (std::size_t i = 0; i < PSQTBuckets; ++i)
(st->*accPtr).psqtAccumulation[Perspective][k] += (next->*accPtr).psqtAccumulation[Perspective][i] +=
psqtWeights[index * PSQTBuckets + k]; psqtWeights[index * PSQTBuckets + i];
} }
}
#endif #endif
}
(next->*accPtr).computed[Perspective] = true;
if (next != pos.state())
update_accumulator_incremental<Perspective>(pos, next);
} }
template<Color Perspective> template<Color Perspective>
void update_accumulator_refresh_cache(const Position& pos, void update_accumulator_refresh_cache(const Position& pos,
AccumulatorCaches::Cache<HalfDimensions>* cache) const { AccumulatorCaches::Cache<HalfDimensions>* cache) const {
@@ -735,88 +688,88 @@ class FeatureTransformer {
accumulator.computed[Perspective] = true; accumulator.computed[Perspective] = true;
#ifdef VECTOR #ifdef VECTOR
vec_t acc[NumRegs]; vec_t acc[Tiling::NumRegs];
psqt_vec_t psqt[NumPsqtRegs]; psqt_vec_t psqt[Tiling::NumPsqtRegs];
for (IndexType j = 0; j < HalfDimensions / TileHeight; ++j) for (IndexType j = 0; j < HalfDimensions / Tiling::TileHeight; ++j)
{ {
auto accTile = auto* accTile = reinterpret_cast<vec_t*>(
reinterpret_cast<vec_t*>(&accumulator.accumulation[Perspective][j * TileHeight]); &accumulator.accumulation[Perspective][j * Tiling::TileHeight]);
auto entryTile = reinterpret_cast<vec_t*>(&entry.accumulation[j * TileHeight]); auto* entryTile = reinterpret_cast<vec_t*>(&entry.accumulation[j * Tiling::TileHeight]);
for (IndexType k = 0; k < NumRegs; ++k) for (IndexType k = 0; k < Tiling::NumRegs; ++k)
acc[k] = entryTile[k]; acc[k] = entryTile[k];
int i = 0; std::size_t i = 0;
for (; i < int(std::min(removed.size(), added.size())); ++i) for (; i < std::min(removed.size(), added.size()); ++i)
{ {
IndexType indexR = removed[i]; IndexType indexR = removed[i];
const IndexType offsetR = HalfDimensions * indexR + j * TileHeight; const IndexType offsetR = HalfDimensions * indexR + j * Tiling::TileHeight;
auto columnR = reinterpret_cast<const vec_t*>(&weights[offsetR]); auto* columnR = reinterpret_cast<const vec_t*>(&weights[offsetR]);
IndexType indexA = added[i]; IndexType indexA = added[i];
const IndexType offsetA = HalfDimensions * indexA + j * TileHeight; const IndexType offsetA = HalfDimensions * indexA + j * Tiling::TileHeight;
auto columnA = reinterpret_cast<const vec_t*>(&weights[offsetA]); auto* columnA = reinterpret_cast<const vec_t*>(&weights[offsetA]);
for (unsigned k = 0; k < NumRegs; ++k) for (IndexType k = 0; k < Tiling::NumRegs; ++k)
acc[k] = vec_add_16(acc[k], vec_sub_16(columnA[k], columnR[k])); acc[k] = vec_add_16(acc[k], vec_sub_16(columnA[k], columnR[k]));
} }
for (; i < int(removed.size()); ++i) for (; i < removed.size(); ++i)
{ {
IndexType index = removed[i]; IndexType index = removed[i];
const IndexType offset = HalfDimensions * index + j * TileHeight; const IndexType offset = HalfDimensions * index + j * Tiling::TileHeight;
auto column = reinterpret_cast<const vec_t*>(&weights[offset]); auto* column = reinterpret_cast<const vec_t*>(&weights[offset]);
for (unsigned k = 0; k < NumRegs; ++k) for (IndexType k = 0; k < Tiling::NumRegs; ++k)
acc[k] = vec_sub_16(acc[k], column[k]); acc[k] = vec_sub_16(acc[k], column[k]);
} }
for (; i < int(added.size()); ++i) for (; i < added.size(); ++i)
{ {
IndexType index = added[i]; IndexType index = added[i];
const IndexType offset = HalfDimensions * index + j * TileHeight; const IndexType offset = HalfDimensions * index + j * Tiling::TileHeight;
auto column = reinterpret_cast<const vec_t*>(&weights[offset]); auto* column = reinterpret_cast<const vec_t*>(&weights[offset]);
for (unsigned k = 0; k < NumRegs; ++k) for (IndexType k = 0; k < Tiling::NumRegs; ++k)
acc[k] = vec_add_16(acc[k], column[k]); acc[k] = vec_add_16(acc[k], column[k]);
} }
for (IndexType k = 0; k < NumRegs; k++) for (IndexType k = 0; k < Tiling::NumRegs; k++)
vec_store(&entryTile[k], acc[k]); vec_store(&entryTile[k], acc[k]);
for (IndexType k = 0; k < NumRegs; k++) for (IndexType k = 0; k < Tiling::NumRegs; k++)
vec_store(&accTile[k], acc[k]); vec_store(&accTile[k], acc[k]);
} }
for (IndexType j = 0; j < PSQTBuckets / PsqtTileHeight; ++j) for (IndexType j = 0; j < PSQTBuckets / Tiling::PsqtTileHeight; ++j)
{ {
auto accTilePsqt = reinterpret_cast<psqt_vec_t*>( auto* accTilePsqt = reinterpret_cast<psqt_vec_t*>(
&accumulator.psqtAccumulation[Perspective][j * PsqtTileHeight]); &accumulator.psqtAccumulation[Perspective][j * Tiling::PsqtTileHeight]);
auto entryTilePsqt = auto* entryTilePsqt =
reinterpret_cast<psqt_vec_t*>(&entry.psqtAccumulation[j * PsqtTileHeight]); reinterpret_cast<psqt_vec_t*>(&entry.psqtAccumulation[j * Tiling::PsqtTileHeight]);
for (std::size_t k = 0; k < NumPsqtRegs; ++k) for (std::size_t k = 0; k < Tiling::NumPsqtRegs; ++k)
psqt[k] = entryTilePsqt[k]; psqt[k] = entryTilePsqt[k];
for (int i = 0; i < int(removed.size()); ++i) for (std::size_t i = 0; i < removed.size(); ++i)
{ {
IndexType index = removed[i]; IndexType index = removed[i];
const IndexType offset = PSQTBuckets * index + j * PsqtTileHeight; const IndexType offset = PSQTBuckets * index + j * Tiling::PsqtTileHeight;
auto columnPsqt = reinterpret_cast<const psqt_vec_t*>(&psqtWeights[offset]); auto* columnPsqt = reinterpret_cast<const psqt_vec_t*>(&psqtWeights[offset]);
for (std::size_t k = 0; k < NumPsqtRegs; ++k) for (std::size_t k = 0; k < Tiling::NumPsqtRegs; ++k)
psqt[k] = vec_sub_psqt_32(psqt[k], columnPsqt[k]); psqt[k] = vec_sub_psqt_32(psqt[k], columnPsqt[k]);
} }
for (int i = 0; i < int(added.size()); ++i) for (std::size_t i = 0; i < added.size(); ++i)
{ {
IndexType index = added[i]; IndexType index = added[i];
const IndexType offset = PSQTBuckets * index + j * PsqtTileHeight; const IndexType offset = PSQTBuckets * index + j * Tiling::PsqtTileHeight;
auto columnPsqt = reinterpret_cast<const psqt_vec_t*>(&psqtWeights[offset]); auto* columnPsqt = reinterpret_cast<const psqt_vec_t*>(&psqtWeights[offset]);
for (std::size_t k = 0; k < NumPsqtRegs; ++k) for (std::size_t k = 0; k < Tiling::NumPsqtRegs; ++k)
psqt[k] = vec_add_psqt_32(psqt[k], columnPsqt[k]); psqt[k] = vec_add_psqt_32(psqt[k], columnPsqt[k]);
} }
for (std::size_t k = 0; k < NumPsqtRegs; ++k) for (std::size_t k = 0; k < Tiling::NumPsqtRegs; ++k)
vec_store_psqt(&entryTilePsqt[k], psqt[k]); vec_store_psqt(&entryTilePsqt[k], psqt[k]);
for (std::size_t k = 0; k < NumPsqtRegs; ++k) for (std::size_t k = 0; k < Tiling::NumPsqtRegs; ++k)
vec_store_psqt(&accTilePsqt[k], psqt[k]); vec_store_psqt(&accTilePsqt[k], psqt[k]);
} }
@@ -858,60 +811,18 @@ class FeatureTransformer {
entry.byTypeBB[pt] = pos.pieces(pt); entry.byTypeBB[pt] = pos.pieces(pt);
} }
template<Color Perspective>
void hint_common_access_for_perspective(const Position& pos,
AccumulatorCaches::Cache<HalfDimensions>* cache) const {
// Works like update_accumulator, but performs less work.
// Updates ONLY the accumulator for pos.
// Look for a usable accumulator of an earlier position. We keep track
// of the estimated gain in terms of features to be added/subtracted.
// Fast early exit.
if ((pos.state()->*accPtr).computed[Perspective])
return;
auto [oldest_st, _] = try_find_computed_accumulator<Perspective>(pos);
if ((oldest_st->*accPtr).computed[Perspective])
{
// Only update current position accumulator to minimize work
StateInfo* states_to_update[1] = {pos.state()};
update_accumulator_incremental<Perspective, 1>(pos, oldest_st, states_to_update);
}
else
update_accumulator_refresh_cache<Perspective>(pos, cache);
}
template<Color Perspective> template<Color Perspective>
void update_accumulator(const Position& pos, void update_accumulator(const Position& pos,
AccumulatorCaches::Cache<HalfDimensions>* cache) const { AccumulatorCaches::Cache<HalfDimensions>* cache) const {
if ((pos.state()->*accPtr).computed[Perspective])
return;
StateInfo* oldest = try_find_computed_accumulator<Perspective>(pos);
auto [oldest_st, next] = try_find_computed_accumulator<Perspective>(pos); if ((oldest->*accPtr).computed[Perspective] && oldest != pos.state())
// Start from the oldest computed accumulator, update all the
if ((oldest_st->*accPtr).computed[Perspective]) // accumulators up to the current position.
{ update_accumulator_incremental<Perspective>(pos, oldest);
if (next == nullptr)
return;
// Now update the accumulators listed in states_to_update[], where
// the last element is a sentinel. Currently we update two accumulators:
// 1. for the current position
// 2. the next accumulator after the computed one
// The heuristic may change in the future.
if (next == pos.state())
{
StateInfo* states_to_update[1] = {next};
update_accumulator_incremental<Perspective, 1>(pos, oldest_st, states_to_update);
}
else
{
StateInfo* states_to_update[2] = {next, pos.state()};
update_accumulator_incremental<Perspective, 2>(pos, oldest_st, states_to_update);
}
}
else else
update_accumulator_refresh_cache<Perspective>(pos, cache); update_accumulator_refresh_cache<Perspective>(pos, cache);
} }
+2 -2
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-2024 The Stockfish developers (see AUTHORS file) Copyright (C) 2004-2025 The Stockfish developers (see AUTHORS file)
Stockfish is free software: you can redistribute it and/or modify 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
@@ -126,7 +126,7 @@ trace(Position& pos, const Eval::NNUE::Networks& networks, Eval::NNUE::Accumulat
board[y][x] = board[y][x + 8] = board[y + 3][x + 8] = board[y + 3][x] = '+'; board[y][x] = board[y][x + 8] = board[y + 3][x + 8] = board[y + 3][x] = '+';
if (pc != NO_PIECE) if (pc != NO_PIECE)
board[y + 1][x + 4] = PieceToChar[pc]; board[y + 1][x + 4] = PieceToChar[pc];
if (value != VALUE_NONE) if (is_valid(value))
format_cp_compact(value, &board[y + 2][x + 2], pos); format_cp_compact(value, &board[y + 2][x + 2], pos);
}; };
+1 -1
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-2024 The Stockfish developers (see AUTHORS file) Copyright (C) 2004-2025 The Stockfish developers (see AUTHORS file)
Stockfish is free software: you can redistribute it and/or modify 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
+7 -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-2024 The Stockfish developers (see AUTHORS file) Copyright (C) 2004-2025 The Stockfish developers (see AUTHORS file)
Stockfish is free software: you can redistribute it and/or modify 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,6 +23,7 @@
#include <atomic> #include <atomic>
#include <cstdint> #include <cstdint>
#include <cstdlib> #include <cstdlib>
#include <functional>
#include <iostream> #include <iostream>
#include <limits> #include <limits>
#include <map> #include <map>
@@ -653,7 +654,7 @@ class NumaConfig {
NumaIndex n = 0; NumaIndex n = 0;
for (auto&& nodeStr : split(s, ":")) for (auto&& nodeStr : split(s, ":"))
{ {
auto indices = indices_from_shortened_string(nodeStr); auto indices = indices_from_shortened_string(std::string(nodeStr));
if (!indices.empty()) if (!indices.empty())
{ {
for (auto idx : indices) for (auto idx : indices)
@@ -1015,7 +1016,7 @@ class NumaConfig {
if (s.empty()) if (s.empty())
return indices; return indices;
for (const std::string& ss : split(s, ",")) for (const auto& ss : split(s, ","))
{ {
if (ss.empty()) if (ss.empty())
continue; continue;
@@ -1023,13 +1024,13 @@ class NumaConfig {
auto parts = split(ss, "-"); auto parts = split(ss, "-");
if (parts.size() == 1) if (parts.size() == 1)
{ {
const CpuIndex c = CpuIndex{str_to_size_t(parts[0])}; const CpuIndex c = CpuIndex{str_to_size_t(std::string(parts[0]))};
indices.emplace_back(c); indices.emplace_back(c);
} }
else if (parts.size() == 2) else if (parts.size() == 2)
{ {
const CpuIndex cfirst = CpuIndex{str_to_size_t(parts[0])}; const CpuIndex cfirst = CpuIndex{str_to_size_t(std::string(parts[0]))};
const CpuIndex clast = CpuIndex{str_to_size_t(parts[1])}; const CpuIndex clast = CpuIndex{str_to_size_t(std::string(parts[1]))};
for (size_t c = cfirst; c <= clast; ++c) for (size_t c = cfirst; c <= clast; ++c)
{ {
indices.emplace_back(c); indices.emplace_back(c);
+1 -1
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-2024 The Stockfish developers (see AUTHORS file) Copyright (C) 2004-2025 The Stockfish developers (see AUTHORS file)
Stockfish is free software: you can redistribute it and/or modify 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
+89 -56
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-2024 The Stockfish developers (see AUTHORS file) Copyright (C) 2004-2025 The Stockfish developers (see AUTHORS file)
Stockfish is free software: you can redistribute it and/or modify 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
@@ -119,6 +119,9 @@ void Position::init() {
for (Piece pc : Pieces) for (Piece pc : Pieces)
for (Square s = SQ_A1; s <= SQ_H8; ++s) for (Square s = SQ_A1; s <= SQ_H8; ++s)
Zobrist::psq[pc][s] = rng.rand<Key>(); Zobrist::psq[pc][s] = rng.rand<Key>();
// pawns on these squares will promote
std::fill_n(Zobrist::psq[W_PAWN] + SQ_A8, 8, 0);
std::fill_n(Zobrist::psq[B_PAWN], 8, 0);
for (File f = FILE_A; f <= FILE_H; ++f) for (File f = FILE_A; f <= FILE_H; ++f)
Zobrist::enpassant[f] = rng.rand<Key>(); Zobrist::enpassant[f] = rng.rand<Key>();
@@ -334,8 +337,10 @@ void Position::set_check_info() const {
// The function is only used when a new position is set up // The function is only used when a new position is set up
void Position::set_state() const { void Position::set_state() const {
st->key = st->materialKey = 0; st->key = st->materialKey = 0;
st->pawnKey = Zobrist::noPawns; st->minorPieceKey = 0;
st->nonPawnKey[WHITE] = st->nonPawnKey[BLACK] = 0;
st->pawnKey = Zobrist::noPawns;
st->nonPawnMaterial[WHITE] = st->nonPawnMaterial[BLACK] = VALUE_ZERO; st->nonPawnMaterial[WHITE] = st->nonPawnMaterial[BLACK] = VALUE_ZERO;
st->checkersBB = attackers_to(square<KING>(sideToMove)) & pieces(~sideToMove); st->checkersBB = attackers_to(square<KING>(sideToMove)) & pieces(~sideToMove);
@@ -350,8 +355,18 @@ void Position::set_state() const {
if (type_of(pc) == PAWN) if (type_of(pc) == PAWN)
st->pawnKey ^= Zobrist::psq[pc][s]; st->pawnKey ^= Zobrist::psq[pc][s];
else if (type_of(pc) != KING) else
st->nonPawnMaterial[color_of(pc)] += PieceValue[pc]; {
st->nonPawnKey[color_of(pc)] ^= Zobrist::psq[pc][s];
if (type_of(pc) != KING)
{
st->nonPawnMaterial[color_of(pc)] += PieceValue[pc];
if (type_of(pc) <= BISHOP)
st->minorPieceKey ^= Zobrist::psq[pc][s];
}
}
} }
if (st->epSquare != SQ_NONE) if (st->epSquare != SQ_NONE)
@@ -364,7 +379,7 @@ void Position::set_state() const {
for (Piece pc : Pieces) for (Piece pc : Pieces)
for (int cnt = 0; cnt < pieceCount[pc]; ++cnt) for (int cnt = 0; cnt < pieceCount[pc]; ++cnt)
st->materialKey ^= Zobrist::psq[pc][cnt]; st->materialKey ^= Zobrist::psq[pc][8 + cnt];
} }
@@ -472,14 +487,23 @@ void Position::update_slider_blockers(Color c) const {
// Slider attacks use the occupied bitboard to indicate occupancy. // Slider attacks use the occupied bitboard to indicate occupancy.
Bitboard Position::attackers_to(Square s, Bitboard occupied) const { Bitboard Position::attackers_to(Square s, Bitboard occupied) const {
return (pawn_attacks_bb(BLACK, s) & pieces(WHITE, PAWN)) return (attacks_bb<ROOK>(s, occupied) & pieces(ROOK, QUEEN))
| (pawn_attacks_bb(WHITE, s) & pieces(BLACK, PAWN))
| (attacks_bb<KNIGHT>(s) & pieces(KNIGHT))
| (attacks_bb<ROOK>(s, occupied) & pieces(ROOK, QUEEN))
| (attacks_bb<BISHOP>(s, occupied) & pieces(BISHOP, QUEEN)) | (attacks_bb<BISHOP>(s, occupied) & pieces(BISHOP, QUEEN))
| (attacks_bb<KING>(s) & pieces(KING)); | (pawn_attacks_bb(BLACK, s) & pieces(WHITE, PAWN))
| (pawn_attacks_bb(WHITE, s) & pieces(BLACK, PAWN))
| (attacks_bb<KNIGHT>(s) & pieces(KNIGHT)) | (attacks_bb<KING>(s) & pieces(KING));
} }
bool Position::attackers_to_exist(Square s, Bitboard occupied, Color c) const {
return ((attacks_bb<ROOK>(s) & pieces(c, ROOK, QUEEN))
&& (attacks_bb<ROOK>(s, occupied) & pieces(c, ROOK, QUEEN)))
|| ((attacks_bb<BISHOP>(s) & pieces(c, BISHOP, QUEEN))
&& (attacks_bb<BISHOP>(s, occupied) & pieces(c, BISHOP, QUEEN)))
|| (((pawn_attacks_bb(~c, s) & pieces(PAWN)) | (attacks_bb<KNIGHT>(s) & pieces(KNIGHT))
| (attacks_bb<KING>(s) & pieces(KING)))
& pieces(c));
}
// Tests whether a pseudo-legal move is legal // Tests whether a pseudo-legal move is legal
bool Position::legal(Move m) const { bool Position::legal(Move m) const {
@@ -521,7 +545,7 @@ bool Position::legal(Move m) const {
Direction step = to > from ? WEST : EAST; Direction step = to > from ? WEST : EAST;
for (Square s = to; s != from; s += step) for (Square s = to; s != from; s += step)
if (attackers_to(s) & pieces(~us)) if (attackers_to_exist(s, pieces(), ~us))
return false; return false;
// In case of Chess960, verify if the Rook blocks some checks. // In case of Chess960, verify if the Rook blocks some checks.
@@ -532,7 +556,7 @@ bool Position::legal(Move m) const {
// If the moving piece is a king, check whether the destination square is // If the moving piece is a king, check whether the destination square is
// attacked by the opponent. // attacked by the opponent.
if (type_of(piece_on(from)) == KING) if (type_of(piece_on(from)) == KING)
return !(attackers_to(to, pieces() ^ from) & pieces(~us)); return !(attackers_to_exist(to, pieces() ^ from, ~us));
// A non-king move is legal if and only if it is not pinned or it // A non-king move is legal if and only if it is not pinned or it
// is moving along the ray towards or away from the king. // is moving along the ray towards or away from the king.
@@ -601,7 +625,7 @@ bool Position::pseudo_legal(const Move m) const {
} }
// In case of king moves under check we have to remove the king so as to catch // In case of king moves under check we have to remove the king so as to catch
// invalid moves like b1a1 when opposite queen is on c1. // invalid moves like b1a1 when opposite queen is on c1.
else if (attackers_to(to, pieces() ^ from) & pieces(~us)) else if (attackers_to_exist(to, pieces() ^ from, ~us))
return false; return false;
} }
@@ -659,7 +683,12 @@ bool Position::gives_check(Move m) const {
// Makes a move, and saves all information necessary // Makes a move, and saves all information necessary
// to a StateInfo object. The move is assumed to be legal. Pseudo-legal // to a StateInfo object. The move is assumed to be legal. Pseudo-legal
// moves should be filtered out before this function is called. // moves should be filtered out before this function is called.
void Position::do_move(Move m, StateInfo& newSt, bool givesCheck) { // If a pointer to the TT table is passed, the entry for the new position
// will be prefetched
void Position::do_move(Move m,
StateInfo& newSt,
bool givesCheck,
const TranspositionTable* tt = nullptr) {
assert(m.is_ok()); assert(m.is_ok());
assert(&newSt != st); assert(&newSt != st);
@@ -671,6 +700,7 @@ void Position::do_move(Move m, StateInfo& newSt, bool givesCheck) {
// our state pointer to point to the new (ready to be updated) state. // our state pointer to point to the new (ready to be updated) state.
std::memcpy(&newSt, st, offsetof(StateInfo, key)); std::memcpy(&newSt, st, offsetof(StateInfo, key));
newSt.previous = st; newSt.previous = st;
st->next = &newSt;
st = &newSt; st = &newSt;
// Increment ply counters. In particular, rule50 will be reset to zero later on // Increment ply counters. In particular, rule50 will be reset to zero later on
@@ -706,6 +736,7 @@ void Position::do_move(Move m, StateInfo& newSt, bool givesCheck) {
do_castling<true>(us, from, to, rfrom, rto); do_castling<true>(us, from, to, rfrom, rto);
k ^= Zobrist::psq[captured][rfrom] ^ Zobrist::psq[captured][rto]; k ^= Zobrist::psq[captured][rfrom] ^ Zobrist::psq[captured][rto];
st->nonPawnKey[us] ^= Zobrist::psq[captured][rfrom] ^ Zobrist::psq[captured][rto];
captured = NO_PIECE; captured = NO_PIECE;
} }
@@ -731,7 +762,13 @@ void Position::do_move(Move m, StateInfo& newSt, bool givesCheck) {
st->pawnKey ^= Zobrist::psq[captured][capsq]; st->pawnKey ^= Zobrist::psq[captured][capsq];
} }
else else
{
st->nonPawnMaterial[them] -= PieceValue[captured]; st->nonPawnMaterial[them] -= PieceValue[captured];
st->nonPawnKey[them] ^= Zobrist::psq[captured][capsq];
if (type_of(captured) <= BISHOP)
st->minorPieceKey ^= Zobrist::psq[captured][capsq];
}
dp.dirty_num = 2; // 1 piece moved, 1 piece captured dp.dirty_num = 2; // 1 piece moved, 1 piece captured
dp.piece[1] = captured; dp.piece[1] = captured;
@@ -742,7 +779,7 @@ void Position::do_move(Move m, StateInfo& newSt, bool givesCheck) {
remove_piece(capsq); remove_piece(capsq);
k ^= Zobrist::psq[captured][capsq]; k ^= Zobrist::psq[captured][capsq];
st->materialKey ^= Zobrist::psq[captured][pieceCount[captured]]; st->materialKey ^= Zobrist::psq[captured][8 + pieceCount[captured]];
// Reset rule 50 counter // Reset rule 50 counter
st->rule50 = 0; st->rule50 = 0;
@@ -789,7 +826,8 @@ void Position::do_move(Move m, StateInfo& newSt, bool givesCheck) {
else if (m.type_of() == PROMOTION) else if (m.type_of() == PROMOTION)
{ {
Piece promotion = make_piece(us, m.promotion_type()); Piece promotion = make_piece(us, m.promotion_type());
PieceType promotionType = type_of(promotion);
assert(relative_rank(us, to) == RANK_8); assert(relative_rank(us, to) == RANK_8);
assert(type_of(promotion) >= KNIGHT && type_of(promotion) <= QUEEN); assert(type_of(promotion) >= KNIGHT && type_of(promotion) <= QUEEN);
@@ -805,10 +843,13 @@ void Position::do_move(Move m, StateInfo& newSt, bool givesCheck) {
dp.dirty_num++; dp.dirty_num++;
// Update hash keys // Update hash keys
k ^= Zobrist::psq[pc][to] ^ Zobrist::psq[promotion][to]; // Zobrist::psq[pc][to] is zero, so we don't need to clear it
st->pawnKey ^= Zobrist::psq[pc][to]; k ^= Zobrist::psq[promotion][to];
st->materialKey ^= st->materialKey ^= Zobrist::psq[promotion][8 + pieceCount[promotion] - 1]
Zobrist::psq[promotion][pieceCount[promotion] - 1] ^ Zobrist::psq[pc][pieceCount[pc]]; ^ Zobrist::psq[pc][8 + pieceCount[pc]];
if (promotionType <= BISHOP)
st->minorPieceKey ^= Zobrist::psq[promotion][to];
// Update material // Update material
st->nonPawnMaterial[us] += PieceValue[promotion]; st->nonPawnMaterial[us] += PieceValue[promotion];
@@ -821,11 +862,21 @@ void Position::do_move(Move m, StateInfo& newSt, bool givesCheck) {
st->rule50 = 0; st->rule50 = 0;
} }
// Set capture piece else
st->capturedPiece = captured; {
st->nonPawnKey[us] ^= Zobrist::psq[pc][from] ^ Zobrist::psq[pc][to];
if (type_of(pc) <= BISHOP)
st->minorPieceKey ^= Zobrist::psq[pc][from] ^ Zobrist::psq[pc][to];
}
// Update the key with the final value // Update the key with the final value
st->key = k; st->key = k;
if (tt)
prefetch(tt->first_entry(key()));
// Set capture piece
st->capturedPiece = captured;
// Calculate checkers bitboard (if move gives check) // Calculate checkers bitboard (if move gives check)
st->checkersBB = givesCheck ? attackers_to(square<KING>(them)) & pieces(us) : 0; st->checkersBB = givesCheck ? attackers_to(square<KING>(them)) & pieces(us) : 0;
@@ -955,7 +1006,7 @@ void Position::do_castling(Color us, Square from, Square& to, Square& rfrom, Squ
// Used to do a "null move": it flips // Used to do a "null move": it flips
// the side to move without executing any move on the board. // the side to move without executing any move on the board.
void Position::do_null_move(StateInfo& newSt, TranspositionTable& tt) { void Position::do_null_move(StateInfo& newSt, const TranspositionTable& tt) {
assert(!checkers()); assert(!checkers());
assert(&newSt != st); assert(&newSt != st);
@@ -963,13 +1014,9 @@ void Position::do_null_move(StateInfo& newSt, TranspositionTable& tt) {
std::memcpy(&newSt, st, offsetof(StateInfo, accumulatorBig)); std::memcpy(&newSt, st, offsetof(StateInfo, accumulatorBig));
newSt.previous = st; newSt.previous = st;
st->next = &newSt;
st = &newSt; st = &newSt;
st->dirtyPiece.dirty_num = 0;
st->dirtyPiece.piece[0] = NO_PIECE; // Avoid checks in UpdateAccumulator()
st->accumulatorBig.computed[WHITE] = st->accumulatorBig.computed[BLACK] =
st->accumulatorSmall.computed[WHITE] = st->accumulatorSmall.computed[BLACK] = false;
if (st->epSquare != SQ_NONE) if (st->epSquare != SQ_NONE)
{ {
st->key ^= Zobrist::enpassant[file_of(st->epSquare)]; st->key ^= Zobrist::enpassant[file_of(st->epSquare)];
@@ -977,9 +1024,13 @@ void Position::do_null_move(StateInfo& newSt, TranspositionTable& tt) {
} }
st->key ^= Zobrist::side; st->key ^= Zobrist::side;
++st->rule50;
prefetch(tt.first_entry(key())); prefetch(tt.first_entry(key()));
st->dirtyPiece.dirty_num = 0;
st->dirtyPiece.piece[0] = NO_PIECE; // Avoid checks in UpdateAccumulator()
st->accumulatorBig.computed[WHITE] = st->accumulatorBig.computed[BLACK] =
st->accumulatorSmall.computed[WHITE] = st->accumulatorSmall.computed[BLACK] = false;
st->pliesFromNull = 0; st->pliesFromNull = 0;
sideToMove = ~sideToMove; sideToMove = ~sideToMove;
@@ -1002,26 +1053,6 @@ void Position::undo_null_move() {
} }
// Computes the new hash key after the given move. Needed
// for speculative prefetch. It doesn't recognize special moves like castling,
// en passant and promotions.
Key Position::key_after(Move m) const {
Square from = m.from_sq();
Square to = m.to_sq();
Piece pc = piece_on(from);
Piece captured = piece_on(to);
Key k = st->key ^ Zobrist::side;
if (captured)
k ^= Zobrist::psq[captured][to];
k ^= Zobrist::psq[pc][to] ^ Zobrist::psq[pc][from];
return (captured || type_of(pc) == PAWN) ? k : adjust_key50<true>(k);
}
// Tests if the SEE (Static Exchange Evaluation) // Tests if the SEE (Static Exchange Evaluation)
// value of move is greater or equal to the given threshold. We'll use an // value of move is greater or equal to the given threshold. We'll use an
// algorithm similar to alpha-beta pruning with a null window. // algorithm similar to alpha-beta pruning with a null window.
@@ -1109,8 +1140,9 @@ bool Position::see_ge(Move m, int threshold) const {
else if ((bb = stmAttackers & pieces(QUEEN))) else if ((bb = stmAttackers & pieces(QUEEN)))
{ {
if ((swap = QueenValue - swap) < res) swap = QueenValue - swap;
break; // implies that the previous recapture was done by a higher rated piece than a Queen (King is excluded)
assert(swap >= res);
occupied ^= least_significant_square_bb(bb); occupied ^= least_significant_square_bb(bb);
attackers |= (attacks_bb<BISHOP>(to, occupied) & pieces(BISHOP, QUEEN)) attackers |= (attacks_bb<BISHOP>(to, occupied) & pieces(BISHOP, QUEEN))
@@ -1133,11 +1165,12 @@ bool Position::is_draw(int ply) const {
if (st->rule50 > 99 && (!checkers() || MoveList<LEGAL>(*this).size())) if (st->rule50 > 99 && (!checkers() || MoveList<LEGAL>(*this).size()))
return true; return true;
// Return a draw score if a position repeats once earlier but strictly return is_repetition(ply);
// after the root, or repeats twice before or at the root.
return st->repetition && st->repetition < ply;
} }
// Return a draw score if a position repeats once earlier but strictly
// after the root, or repeats twice before or at the root.
bool Position::is_repetition(int ply) const { return st->repetition && st->repetition < ply; }
// Tests whether there has been at least one repetition // Tests whether there has been at least one repetition
// of positions since the last capture or pawn move. // of positions since the last capture or pawn move.
@@ -1253,7 +1286,7 @@ bool Position::pos_is_ok() const {
return true; return true;
if (pieceCount[W_KING] != 1 || pieceCount[B_KING] != 1 if (pieceCount[W_KING] != 1 || pieceCount[B_KING] != 1
|| attackers_to(square<KING>(~sideToMove)) & pieces(sideToMove)) || attackers_to_exist(square<KING>(~sideToMove), pieces(), sideToMove))
assert(0 && "pos_is_ok: Kings"); assert(0 && "pos_is_ok: Kings");
if ((pieces(PAWN) & (Rank1BB | Rank8BB)) || pieceCount[W_PAWN] > 8 || pieceCount[B_PAWN] > 8) if ((pieces(PAWN) & (Rank1BB | Rank8BB)) || pieceCount[W_PAWN] > 8 || pieceCount[B_PAWN] > 8)
+18 -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-2024 The Stockfish developers (see AUTHORS file) Copyright (C) 2004-2025 The Stockfish developers (see AUTHORS file)
Stockfish is free software: you can redistribute it and/or modify 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
@@ -43,6 +43,8 @@ struct StateInfo {
// Copied when making a move // Copied when making a move
Key materialKey; Key materialKey;
Key pawnKey; Key pawnKey;
Key minorPieceKey;
Key nonPawnKey[COLOR_NB];
Value nonPawnMaterial[COLOR_NB]; Value nonPawnMaterial[COLOR_NB];
int castlingRights; int castlingRights;
int rule50; int rule50;
@@ -53,6 +55,7 @@ struct StateInfo {
Key key; Key key;
Bitboard checkersBB; Bitboard checkersBB;
StateInfo* previous; StateInfo* previous;
StateInfo* next;
Bitboard blockersForKing[COLOR_NB]; Bitboard blockersForKing[COLOR_NB];
Bitboard pinners[COLOR_NB]; Bitboard pinners[COLOR_NB];
Bitboard checkSquares[PIECE_TYPE_NB]; Bitboard checkSquares[PIECE_TYPE_NB];
@@ -122,6 +125,7 @@ class Position {
// 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;
bool attackers_to_exist(Square s, Bitboard occupied, Color c) const;
void update_slider_blockers(Color c) const; void update_slider_blockers(Color c) const;
template<PieceType Pt> template<PieceType Pt>
Bitboard attacks_by(Color c) const; Bitboard attacks_by(Color c) const;
@@ -136,10 +140,10 @@ class Position {
Piece captured_piece() const; Piece captured_piece() const;
// Doing and undoing moves // Doing and undoing moves
void do_move(Move m, StateInfo& newSt); void do_move(Move m, StateInfo& newSt, const TranspositionTable* tt);
void do_move(Move m, StateInfo& newSt, bool givesCheck); void do_move(Move m, StateInfo& newSt, bool givesCheck, const TranspositionTable* tt);
void undo_move(Move m); void undo_move(Move m);
void do_null_move(StateInfo& newSt, TranspositionTable& tt); void do_null_move(StateInfo& newSt, const TranspositionTable& tt);
void undo_null_move(); void undo_null_move();
// Static Exchange Evaluation // Static Exchange Evaluation
@@ -147,15 +151,17 @@ class Position {
// Accessing hash keys // Accessing hash keys
Key key() const; Key key() const;
Key key_after(Move m) const;
Key material_key() const; Key material_key() const;
Key pawn_key() const; Key pawn_key() const;
Key minor_piece_key() const;
Key non_pawn_key(Color c) const;
// Other properties of the position // Other properties of the position
Color side_to_move() const; Color side_to_move() const;
int game_ply() const; int game_ply() const;
bool is_chess960() const; bool is_chess960() const;
bool is_draw(int ply) const; bool is_draw(int ply) const;
bool is_repetition(int ply) const;
bool upcoming_repetition(int ply) const; bool upcoming_repetition(int ply) const;
bool has_repeated() const; bool has_repeated() const;
int rule50_count() const; int rule50_count() const;
@@ -297,6 +303,10 @@ inline Key Position::pawn_key() const { return st->pawnKey; }
inline Key Position::material_key() const { return st->materialKey; } inline Key Position::material_key() const { return st->materialKey; }
inline Key Position::minor_piece_key() const { return st->minorPieceKey; }
inline Key Position::non_pawn_key(Color c) const { return st->nonPawnKey[c]; }
inline Value Position::non_pawn_material(Color c) const { return st->nonPawnMaterial[c]; } inline Value Position::non_pawn_material(Color c) const { return st->nonPawnMaterial[c]; }
inline Value Position::non_pawn_material() const { inline Value Position::non_pawn_material() const {
@@ -355,7 +365,9 @@ inline void Position::move_piece(Square from, Square to) {
board[to] = pc; board[to] = pc;
} }
inline void Position::do_move(Move m, StateInfo& newSt) { do_move(m, newSt, gives_check(m)); } inline void Position::do_move(Move m, StateInfo& newSt, const TranspositionTable* tt = nullptr) {
do_move(m, newSt, gives_check(m), tt);
}
inline StateInfo* Position::state() const { return st; } inline StateInfo* Position::state() const { return st; }
+2 -2
View File
@@ -1,6 +1,6 @@
/* /*
Stockfish, a UCI chess playing engine derived from Glaurung 2.1 Stockfish, a UCI chess playing engine derived from Glaurung 2.1
Copyright (C) 2004-2024 The Stockfish developers (see AUTHORS file) Copyright (C) 2004-2025 The Stockfish developers (see AUTHORS file)
Stockfish is free software: you can redistribute it and/or modify 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
@@ -29,7 +29,7 @@ namespace Stockfish {
Score::Score(Value v, const Position& pos) { Score::Score(Value v, const Position& pos) {
assert(-VALUE_INFINITE < v && v < VALUE_INFINITE); assert(-VALUE_INFINITE < v && v < VALUE_INFINITE);
if (std::abs(v) < VALUE_TB_WIN_IN_MAX_PLY) if (!is_decisive(v))
{ {
score = InternalUnits{UCIEngine::to_cp(v, pos)}; score = InternalUnits{UCIEngine::to_cp(v, pos)};
} }
+1 -1
View File
@@ -1,6 +1,6 @@
/* /*
Stockfish, a UCI chess playing engine derived from Glaurung 2.1 Stockfish, a UCI chess playing engine derived from Glaurung 2.1
Copyright (C) 2004-2024 The Stockfish developers (see AUTHORS file) Copyright (C) 2004-2025 The Stockfish developers (see AUTHORS file)
Stockfish is free software: you can redistribute it and/or modify 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
+401 -344
View File
File diff suppressed because it is too large Load Diff
+42 -26
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-2024 The Stockfish developers (see AUTHORS file) Copyright (C) 2004-2025 The Stockfish developers (see AUTHORS file)
Stockfish is free software: you can redistribute it and/or modify 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
@@ -31,8 +31,8 @@
#include <string_view> #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/network.h"
#include "nnue/nnue_accumulator.h" #include "nnue/nnue_accumulator.h"
#include "numa.h" #include "numa.h"
@@ -61,18 +61,21 @@ namespace Search {
// 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;
Value staticEval; Move excludedMove;
int statScore; Value staticEval;
int moveCount; int statScore;
bool inCheck; int moveCount;
bool ttPv; bool inCheck;
bool ttHit; bool ttPv;
int cutoffCnt; bool ttHit;
int cutoffCnt;
int reduction;
bool isTTMove;
}; };
@@ -90,15 +93,16 @@ struct RootMove {
return m.score != score ? m.score < score : m.previousScore < previousScore; return m.score != score ? m.score < score : m.previousScore < previousScore;
} }
uint64_t effort = 0; uint64_t effort = 0;
Value score = -VALUE_INFINITE; Value score = -VALUE_INFINITE;
Value previousScore = -VALUE_INFINITE; Value previousScore = -VALUE_INFINITE;
Value averageScore = -VALUE_INFINITE; Value averageScore = -VALUE_INFINITE;
Value uciScore = -VALUE_INFINITE; Value meanSquaredScore = -VALUE_INFINITE * VALUE_INFINITE;
bool scoreLowerbound = false; Value uciScore = -VALUE_INFINITE;
bool scoreUpperbound = false; bool scoreLowerbound = false;
int selDepth = 0; bool scoreUpperbound = false;
int tbRank = 0; int selDepth = 0;
int tbRank = 0;
Value tbScore; Value tbScore;
std::vector<Move> pv; std::vector<Move> pv;
}; };
@@ -124,7 +128,6 @@ struct LimitsType {
int movestogo, depth, mate, perft, infinite; int movestogo, depth, mate, perft, infinite;
uint64_t nodes; uint64_t nodes;
bool ponderMode; bool ponderMode;
Square capSq;
}; };
@@ -277,11 +280,17 @@ class Worker {
void ensure_network_replicated(); void ensure_network_replicated();
// Public because they need to be updatable by the stats // Public because they need to be updatable by the stats
ButterflyHistory mainHistory; ButterflyHistory mainHistory;
LowPlyHistory lowPlyHistory;
CapturePieceToHistory captureHistory; CapturePieceToHistory captureHistory;
ContinuationHistory continuationHistory[2][2]; ContinuationHistory continuationHistory[2][2];
PawnHistory pawnHistory; PawnHistory pawnHistory;
CorrectionHistory correctionHistory;
CorrectionHistory<Pawn> pawnCorrectionHistory;
CorrectionHistory<Minor> minorPieceCorrectionHistory;
CorrectionHistory<NonPawn> nonPawnCorrectionHistory[COLOR_NB];
CorrectionHistory<Continuation> continuationCorrectionHistory;
private: private:
void iterative_deepening(); void iterative_deepening();
@@ -305,6 +314,8 @@ class Worker {
TimePoint elapsed() const; TimePoint elapsed() const;
TimePoint elapsed_time() const; TimePoint elapsed_time() const;
Value evaluate(const Position&);
LimitsType limits; LimitsType limits;
size_t pvIdx, pvLast; size_t pvIdx, pvLast;
@@ -342,6 +353,11 @@ class Worker {
friend class SearchManager; friend class SearchManager;
}; };
struct ConthistBonus {
int index;
int weight;
};
} // namespace Search } // namespace Search
+2 -2
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-2024 The Stockfish developers (see AUTHORS file) Copyright (C) 2004-2025 The Stockfish developers (see AUTHORS file)
Stockfish is free software: you can redistribute it and/or modify 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
@@ -1620,7 +1620,7 @@ bool Tablebases::root_probe(Position& pos,
WDLScore wdl = -probe_wdl(pos, &result); WDLScore wdl = -probe_wdl(pos, &result);
dtz = dtz_before_zeroing(wdl); dtz = dtz_before_zeroing(wdl);
} }
else if (pos.is_draw(1)) else if ((rule50 && pos.is_draw(1)) || pos.is_repetition(1))
{ {
// In case a root move leads to a draw by repetition or 50-move rule, // In case a root move leads to a draw by repetition or 50-move rule,
// we set dtz to zero. Note: since we are only 1 ply from the root, // we set dtz to zero. Note: since we are only 1 ply from the root,
+1 -1
View File
@@ -1,6 +1,6 @@
/* /*
Stockfish, a UCI chess playing engine derived from Glaurung 2.1 Stockfish, a UCI chess playing engine derived from Glaurung 2.1
Copyright (C) 2004-2024 The Stockfish developers (see AUTHORS file) Copyright (C) 2004-2025 The Stockfish developers (see AUTHORS file)
Stockfish is free software: you can redistribute it and/or modify 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
+6 -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-2024 The Stockfish developers (see AUTHORS file) Copyright (C) 2004-2025 The Stockfish developers (see AUTHORS file)
Stockfish is free software: you can redistribute it and/or modify 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
@@ -329,13 +329,13 @@ Thread* ThreadPool::get_best_thread() const {
const auto bestThreadMoveVote = votes[bestThreadPV[0]]; const auto bestThreadMoveVote = votes[bestThreadPV[0]];
const auto newThreadMoveVote = votes[newThreadPV[0]]; const auto newThreadMoveVote = votes[newThreadPV[0]];
const bool bestThreadInProvenWin = bestThreadScore >= VALUE_TB_WIN_IN_MAX_PLY; const bool bestThreadInProvenWin = is_win(bestThreadScore);
const bool newThreadInProvenWin = newThreadScore >= VALUE_TB_WIN_IN_MAX_PLY; const bool newThreadInProvenWin = is_win(newThreadScore);
const bool bestThreadInProvenLoss = const bool bestThreadInProvenLoss =
bestThreadScore != -VALUE_INFINITE && bestThreadScore <= VALUE_TB_LOSS_IN_MAX_PLY; bestThreadScore != -VALUE_INFINITE && is_loss(bestThreadScore);
const bool newThreadInProvenLoss = const bool newThreadInProvenLoss =
newThreadScore != -VALUE_INFINITE && newThreadScore <= VALUE_TB_LOSS_IN_MAX_PLY; newThreadScore != -VALUE_INFINITE && is_loss(newThreadScore);
// We make sure not to pick a thread with truncated principal variation // We make sure not to pick a thread with truncated principal variation
const bool betterVotingValue = const bool betterVotingValue =
@@ -355,7 +355,7 @@ Thread* ThreadPool::get_best_thread() const {
bestThread = th.get(); bestThread = th.get();
} }
else if (newThreadInProvenWin || newThreadInProvenLoss else if (newThreadInProvenWin || newThreadInProvenLoss
|| (newThreadScore > VALUE_TB_LOSS_IN_MAX_PLY || (!is_loss(newThreadScore)
&& (newThreadMoveVote > bestThreadMoveVote && (newThreadMoveVote > bestThreadMoveVote
|| (newThreadMoveVote == bestThreadMoveVote && betterVotingValue)))) || (newThreadMoveVote == bestThreadMoveVote && betterVotingValue))))
bestThread = th.get(); bestThread = th.get();
+1 -1
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-2024 The Stockfish developers (see AUTHORS file) Copyright (C) 2004-2025 The Stockfish developers (see AUTHORS file)
Stockfish is free software: you can redistribute it and/or modify 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
+1 -1
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-2024 The Stockfish developers (see AUTHORS file) Copyright (C) 2004-2025 The Stockfish developers (see AUTHORS file)
Stockfish is free software: you can redistribute it and/or modify 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 -16
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-2024 The Stockfish developers (see AUTHORS file) Copyright (C) 2004-2025 The Stockfish developers (see AUTHORS file)
Stockfish is free software: you can redistribute it and/or modify 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
@@ -87,18 +87,20 @@ void TimeManagement::init(Search::LimitsType& limits,
const TimePoint scaledTime = limits.time[us] / scaleFactor; const TimePoint scaledTime = limits.time[us] / scaleFactor;
const TimePoint scaledInc = limits.inc[us] / scaleFactor; const TimePoint scaledInc = limits.inc[us] / scaleFactor;
// Maximum move horizon of 50 moves // Maximum move horizon
int mtg = limits.movestogo ? std::min(limits.movestogo, 50) : 50; int centiMTG = limits.movestogo ? std::min(limits.movestogo * 100, 5000) : 5051;
// If less than one second, gradually reduce mtg // If less than one second, gradually reduce mtg
if (scaledTime < 1000 && double(mtg) / scaledInc > 0.05) if (scaledTime < 1000 && double(centiMTG) / scaledInc > 5.051)
{ {
mtg = scaledTime * 0.05; centiMTG = scaledTime * 5.051;
} }
// Make sure timeLeft is > 0 since we may use it as a divisor // 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) TimePoint timeLeft =
- moveOverhead * (2 + mtg)); std::max(TimePoint(1),
limits.time[us]
+ (limits.inc[us] * (centiMTG - 100) - moveOverhead * (200 + centiMTG)) / 100);
// x basetime (+ z increment) // x basetime (+ z increment)
// If there is a healthy increment, timeLeft can exceed the actual available // If there is a healthy increment, timeLeft can exceed the actual available
@@ -107,31 +109,32 @@ void TimeManagement::init(Search::LimitsType& limits,
{ {
// Extra time according to timeLeft // Extra time according to timeLeft
if (originalTimeAdjust < 0) if (originalTimeAdjust < 0)
originalTimeAdjust = 0.3285 * std::log10(timeLeft) - 0.4830; originalTimeAdjust = 0.3128 * std::log10(timeLeft) - 0.4354;
// Calculate time constants based on current time left. // Calculate time constants based on current time left.
double logTimeInSec = std::log10(scaledTime / 1000.0); double logTimeInSec = std::log10(scaledTime / 1000.0);
double optConstant = std::min(0.00308 + 0.000319 * logTimeInSec, 0.00506); double optConstant = std::min(0.0032116 + 0.000321123 * logTimeInSec, 0.00508017);
double maxConstant = std::max(3.39 + 3.01 * logTimeInSec, 2.93); double maxConstant = std::max(3.3977 + 3.03950 * logTimeInSec, 2.94761);
optScale = std::min(0.0122 + std::pow(ply + 2.95, 0.462) * optConstant, optScale = std::min(0.0121431 + std::pow(ply + 2.94693, 0.461073) * optConstant,
0.213 * limits.time[us] / timeLeft) 0.213035 * limits.time[us] / timeLeft)
* originalTimeAdjust; * originalTimeAdjust;
maxScale = std::min(6.64, maxConstant + ply / 12.0); maxScale = std::min(6.67704, maxConstant + ply / 11.9847);
} }
// x moves in y seconds (+ z increment) // x moves in y seconds (+ z increment)
else else
{ {
optScale = std::min((0.88 + ply / 116.4) / mtg, 0.88 * limits.time[us] / timeLeft); optScale =
maxScale = std::min(6.3, 1.5 + 0.11 * mtg); 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 // Limit the maximum possible time for this move
optimumTime = TimePoint(optScale * timeLeft); optimumTime = TimePoint(optScale * timeLeft);
maximumTime = maximumTime =
TimePoint(std::min(0.825 * limits.time[us] - moveOverhead, maxScale * optimumTime)) - 10; TimePoint(std::min(0.825179 * limits.time[us] - moveOverhead, maxScale * optimumTime)) - 10;
if (options["Ponder"]) if (options["Ponder"])
optimumTime += optimumTime / 4; optimumTime += optimumTime / 4;
+1 -1
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-2024 The Stockfish developers (see AUTHORS file) Copyright (C) 2004-2025 The Stockfish developers (see AUTHORS file)
Stockfish is free software: you can redistribute it and/or modify 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
+8 -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-2024 The Stockfish developers (see AUTHORS file) Copyright (C) 2004-2025 The Stockfish developers (see AUTHORS file)
Stockfish is free software: you can redistribute it and/or modify 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
@@ -193,13 +193,13 @@ void TranspositionTable::clear(ThreadPool& threads) {
// Returns an approximation of the hashtable // Returns an approximation of the hashtable
// occupation during a search. The hash is x permill full, as per UCI protocol. // occupation during a search. The hash is x permill full, as per UCI protocol.
// Only counts entries which match the current generation. // Only counts entries which match the current generation.
int TranspositionTable::hashfull() const { int TranspositionTable::hashfull(int maxAge) const {
int maxAgeInternal = maxAge << GENERATION_BITS;
int cnt = 0; int cnt = 0;
for (int i = 0; i < 1000; ++i) for (int i = 0; i < 1000; ++i)
for (int j = 0; j < ClusterSize; ++j) for (int j = 0; j < ClusterSize; ++j)
cnt += table[i].entry[j].is_occupied() cnt += table[i].entry[j].is_occupied()
&& (table[i].entry[j].genBound8 & GENERATION_MASK) == generation8; && table[i].entry[j].relative_age(generation8) <= maxAgeInternal;
return cnt / ClusterSize; return cnt / ClusterSize;
} }
@@ -238,7 +238,9 @@ std::tuple<bool, TTData, TTWriter> TranspositionTable::probe(const Key key) cons
> tte[i].depth8 - tte[i].relative_age(generation8) * 2) > tte[i].depth8 - tte[i].relative_age(generation8) * 2)
replace = &tte[i]; replace = &tte[i];
return {false, TTData(), TTWriter(replace)}; return {false,
TTData{Move::none(), VALUE_NONE, VALUE_NONE, DEPTH_ENTRY_OFFSET, BOUND_NONE, false},
TTWriter(replace)};
} }
+14 -2
View File
@@ -1,6 +1,6 @@
/* /*
Stockfish, a UCI chess playing engine derived from Glaurung 2.1 Stockfish, a UCI chess playing engine derived from Glaurung 2.1
Copyright (C) 2004-2024 The Stockfish developers (see AUTHORS file) Copyright (C) 2004-2025 The Stockfish developers (see AUTHORS file)
Stockfish is free software: you can redistribute it and/or modify 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
@@ -51,6 +51,18 @@ struct TTData {
Depth depth; Depth depth;
Bound bound; Bound bound;
bool is_pv; bool is_pv;
TTData() = delete;
// clang-format off
TTData(Move m, Value v, Value ev, Depth d, Bound b, bool pv) :
move(m),
value(v),
eval(ev),
depth(d),
bound(b),
is_pv(pv) {};
// clang-format on
}; };
@@ -73,7 +85,7 @@ class TranspositionTable {
void resize(size_t mbSize, ThreadPool& threads); // Set TT size void resize(size_t mbSize, ThreadPool& threads); // Set TT size
void clear(ThreadPool& threads); // Re-initialize memory, multithreaded void clear(ThreadPool& threads); // Re-initialize memory, multithreaded
int hashfull() int hashfull(int maxAge = 0)
const; // Approximate what fraction of entries (permille) have been written to during this root search const; // Approximate what fraction of entries (permille) have been written to during this root search
void void
+2 -2
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-2024 The Stockfish developers (see AUTHORS file) Copyright (C) 2004-2025 The Stockfish developers (see AUTHORS file)
Stockfish is free software: you can redistribute it and/or modify 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
@@ -55,7 +55,7 @@ void Tune::make_option(OptionsMap* opts, const string& n, int v, const SetRange&
if (TuneResults.count(n)) if (TuneResults.count(n))
v = TuneResults[n]; v = TuneResults[n];
(*opts)[n] << Option(v, r(v).first, r(v).second, on_tune); opts->add(n, Option(v, r(v).first, r(v).second, on_tune));
LastOption = &((*opts)[n]); LastOption = &((*opts)[n]);
// Print formatted parameters, ready to be copy-pasted in Fishtest // Print formatted parameters, ready to be copy-pasted in Fishtest
+1 -1
View File
@@ -1,6 +1,6 @@
/* /*
Stockfish, a UCI chess playing engine derived from Glaurung 2.1 Stockfish, a UCI chess playing engine derived from Glaurung 2.1
Copyright (C) 2004-2024 The Stockfish developers (see AUTHORS file) Copyright (C) 2004-2025 The Stockfish developers (see AUTHORS file)
Stockfish is free software: you can redistribute it and/or modify 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 -1
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-2024 The Stockfish developers (see AUTHORS file) Copyright (C) 2004-2025 The Stockfish developers (see AUTHORS file)
Stockfish is free software: you can redistribute it and/or modify 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
@@ -155,6 +155,21 @@ constexpr Value VALUE_TB = VALUE_MATE_IN_MAX_PLY - 1;
constexpr Value VALUE_TB_WIN_IN_MAX_PLY = VALUE_TB - MAX_PLY; constexpr Value VALUE_TB_WIN_IN_MAX_PLY = VALUE_TB - MAX_PLY;
constexpr Value VALUE_TB_LOSS_IN_MAX_PLY = -VALUE_TB_WIN_IN_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 // In the code, we make the assumption that these values
// are such that non_pawn_material() can be used to uniquely // are such that non_pawn_material() can be used to uniquely
// identify the material on the board. // identify the material on the board.
+177 -3
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-2024 The Stockfish developers (see AUTHORS file) Copyright (C) 2004-2025 The Stockfish developers (see AUTHORS file)
Stockfish is free software: you can redistribute it and/or modify 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
@@ -22,6 +22,7 @@
#include <cctype> #include <cctype>
#include <cmath> #include <cmath>
#include <cstdint> #include <cstdint>
#include <iterator>
#include <optional> #include <optional>
#include <sstream> #include <sstream>
#include <string_view> #include <string_view>
@@ -30,6 +31,7 @@
#include "benchmark.h" #include "benchmark.h"
#include "engine.h" #include "engine.h"
#include "memory.h"
#include "movegen.h" #include "movegen.h"
#include "position.h" #include "position.h"
#include "score.h" #include "score.h"
@@ -39,6 +41,8 @@
namespace Stockfish { namespace Stockfish {
constexpr auto BenchmarkCommand = "speedtest";
constexpr auto StartFEN = "rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq - 0 1"; constexpr auto StartFEN = "rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq - 0 1";
template<typename... Ts> template<typename... Ts>
struct overload: Ts... { struct overload: Ts... {
@@ -48,7 +52,7 @@ struct overload: Ts... {
template<typename... Ts> template<typename... Ts>
overload(Ts...) -> overload<Ts...>; overload(Ts...) -> overload<Ts...>;
void UCIEngine::print_info_string(const std::string& str) { void UCIEngine::print_info_string(std::string_view str) {
sync_cout_start(); sync_cout_start();
for (auto& line : split(str, "\n")) for (auto& line : split(str, "\n"))
{ {
@@ -69,11 +73,16 @@ UCIEngine::UCIEngine(int argc, char** argv) :
print_info_string(*str); 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_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_no_moves([](const auto& i) { on_update_no_moves(i); });
engine.set_on_update_full( engine.set_on_update_full(
[this](const auto& i) { on_update_full(i, engine.get_options()["UCI_ShowWDL"]); }); [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_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() { void UCIEngine::loop() {
@@ -117,7 +126,7 @@ void UCIEngine::loop() {
{ {
// send info strings after the go command is sent for old GUIs and python-chess // 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.numa_config_information_as_string());
print_info_string(engine.thread_binding_information_as_string()); print_info_string(engine.thread_allocation_information_as_string());
go(is); go(is);
} }
else if (token == "position") else if (token == "position")
@@ -133,6 +142,8 @@ void UCIEngine::loop() {
engine.flip(); engine.flip();
else if (token == "bench") else if (token == "bench")
bench(is); bench(is);
else if (token == BenchmarkCommand)
benchmark(is);
else if (token == "d") else if (token == "d")
sync_cout << engine.visualize() << sync_endl; sync_cout << engine.visualize() << sync_endl;
else if (token == "eval") else if (token == "eval")
@@ -285,6 +296,169 @@ void UCIEngine::bench(std::istream& args) {
engine.set_on_update_full([&](const auto& i) { on_update_full(i, options["UCI_ShowWDL"]); }); 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) { void UCIEngine::setoption(std::istringstream& is) {
engine.wait_for_search_finished(); engine.wait_for_search_finished();
+5 -2
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-2024 The Stockfish developers (see AUTHORS file) Copyright (C) 2004-2025 The Stockfish developers (see AUTHORS file)
Stockfish is free software: you can redistribute it and/or modify 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
@@ -58,10 +58,11 @@ class UCIEngine {
Engine engine; Engine engine;
CommandLine cli; CommandLine cli;
static void print_info_string(const std::string& str); static void print_info_string(std::string_view str);
void go(std::istringstream& is); void go(std::istringstream& is);
void bench(std::istream& args); void bench(std::istream& args);
void benchmark(std::istream& args);
void position(std::istringstream& is); void position(std::istringstream& is);
void setoption(std::istringstream& is); void setoption(std::istringstream& is);
std::uint64_t perft(const Search::LimitsType&); std::uint64_t perft(const Search::LimitsType&);
@@ -70,6 +71,8 @@ class UCIEngine {
static void on_update_full(const Engine::InfoFull& info, bool showWDL); static void on_update_full(const Engine::InfoFull& info, bool showWDL);
static void on_iter(const Engine::InfoIter& info); static void on_iter(const Engine::InfoIter& info);
static void on_bestmove(std::string_view bestmove, std::string_view ponder); static void on_bestmove(std::string_view bestmove, std::string_view ponder);
void init_search_update_listeners();
}; };
} // namespace Stockfish } // namespace Stockfish
+22 -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-2024 The Stockfish developers (see AUTHORS file) Copyright (C) 2004-2025 The Stockfish developers (see AUTHORS file)
Stockfish is free software: you can redistribute it and/or modify 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,6 +21,7 @@
#include <algorithm> #include <algorithm>
#include <cassert> #include <cassert>
#include <cctype> #include <cctype>
#include <cstdlib>
#include <iostream> #include <iostream>
#include <sstream> #include <sstream>
#include <utility> #include <utility>
@@ -57,17 +58,31 @@ void OptionsMap::setoption(std::istringstream& is) {
sync_cout << "No such option: " << name << sync_endl; sync_cout << "No such option: " << name << sync_endl;
} }
Option OptionsMap::operator[](const std::string& name) const { const Option& OptionsMap::operator[](const std::string& name) const {
auto it = options_map.find(name); auto it = options_map.find(name);
return it != options_map.end() ? it->second : Option(this); assert(it != options_map.end());
return it->second;
} }
Option& OptionsMap::operator[](const std::string& name) { // Inits options and assigns idx in the correct printing order
void OptionsMap::add(const std::string& name, const Option& option) {
if (!options_map.count(name)) if (!options_map.count(name))
options_map[name] = Option(this); {
return options_map[name]; static size_t insert_order = 0;
options_map[name] = option;
options_map[name].parent = this;
options_map[name].idx = insert_order++;
}
else
{
std::cerr << "Option \"" << name << "\" was already added!" << std::endl;
std::exit(EXIT_FAILURE);
}
} }
std::size_t OptionsMap::count(const std::string& name) const { return options_map.count(name); } std::size_t OptionsMap::count(const std::string& name) const { return options_map.count(name); }
Option::Option(const OptionsMap* map) : Option::Option(const OptionsMap* map) :
@@ -130,19 +145,6 @@ bool Option::operator==(const char* s) const {
bool Option::operator!=(const char* s) const { return !(*this == s); } bool Option::operator!=(const char* s) const { return !(*this == s); }
// Inits options and assigns idx in the correct printing order
void Option::operator<<(const Option& o) {
static size_t insert_order = 0;
auto p = this->parent;
*this = o;
this->parent = p;
idx = insert_order++;
}
// Updates currentValue and triggers on_change() action. It's up to // 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 // 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. // from the user by console window, so let's check the bounds anyway.
@@ -161,7 +163,7 @@ Option& Option::operator=(const std::string& v) {
std::string token; std::string token;
std::istringstream ss(defaultValue); std::istringstream ss(defaultValue);
while (ss >> token) while (ss >> token)
comboMap[token] << Option(); comboMap.add(token, Option());
if (!comboMap.count(v) || v == "var") if (!comboMap.count(v) || v == "var")
return *this; return *this;
} }
+6 -4
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-2024 The Stockfish developers (see AUTHORS file) Copyright (C) 2004-2025 The Stockfish developers (see AUTHORS file)
Stockfish is free software: you can redistribute it and/or modify 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
@@ -54,12 +54,13 @@ class Option {
friend std::ostream& operator<<(std::ostream&, const OptionsMap&); friend std::ostream& operator<<(std::ostream&, const OptionsMap&);
int operator<<(const Option&) = delete;
private: private:
friend class OptionsMap; friend class OptionsMap;
friend class Engine; friend class Engine;
friend class Tune; friend class Tune;
void operator<<(const Option&);
std::string defaultValue, currentValue, type; std::string defaultValue, currentValue, type;
int min, max; int min, max;
@@ -82,8 +83,9 @@ class OptionsMap {
void setoption(std::istringstream&); void setoption(std::istringstream&);
Option operator[](const std::string&) const; const Option& operator[](const std::string&) const;
Option& operator[](const std::string&);
void add(const std::string&, const Option& option);
std::size_t count(const std::string&) const; std::size_t count(const std::string&) const;
+1
View File
@@ -0,0 +1 @@
*.sh text eol=lf
+520
View File
@@ -0,0 +1,520 @@
import argparse
import re
import sys
import subprocess
import pathlib
import os
from testing import (
EPD,
TSAN,
Stockfish as Engine,
MiniTestFramework,
OrderedClassMembers,
Valgrind,
Syzygy,
)
PATH = pathlib.Path(__file__).parent.resolve()
CWD = os.getcwd()
def get_prefix():
if args.valgrind:
return Valgrind.get_valgrind_command()
if args.valgrind_thread:
return Valgrind.get_valgrind_thread_command()
return []
def get_threads():
if args.valgrind_thread or args.sanitizer_thread:
return 2
return 1
def get_path():
return os.path.abspath(os.path.join(CWD, args.stockfish_path))
def postfix_check(output):
if args.sanitizer_undefined:
for idx, line in enumerate(output):
if "runtime error:" in line:
# print next possible 50 lines
for i in range(50):
debug_idx = idx + i
if debug_idx < len(output):
print(output[debug_idx])
return False
if args.sanitizer_thread:
for idx, line in enumerate(output):
if "WARNING: ThreadSanitizer:" in line:
# print next possible 50 lines
for i in range(50):
debug_idx = idx + i
if debug_idx < len(output):
print(output[debug_idx])
return False
return True
def Stockfish(*args, **kwargs):
return Engine(get_prefix(), get_path(), *args, **kwargs)
class TestCLI(metaclass=OrderedClassMembers):
def beforeAll(self):
pass
def afterAll(self):
pass
def beforeEach(self):
self.stockfish = None
def afterEach(self):
assert postfix_check(self.stockfish.get_output()) == True
self.stockfish.clear_output()
def test_eval(self):
self.stockfish = Stockfish("eval".split(" "), True)
assert self.stockfish.process.returncode == 0
def test_go_nodes_1000(self):
self.stockfish = Stockfish("go nodes 1000".split(" "), True)
assert self.stockfish.process.returncode == 0
def test_go_depth_10(self):
self.stockfish = Stockfish("go depth 10".split(" "), True)
assert self.stockfish.process.returncode == 0
def test_go_perft_4(self):
self.stockfish = Stockfish("go perft 4".split(" "), True)
assert self.stockfish.process.returncode == 0
def test_go_movetime_1000(self):
self.stockfish = Stockfish("go movetime 1000".split(" "), True)
assert self.stockfish.process.returncode == 0
def test_go_wtime_8000_btime_8000_winc_500_binc_500(self):
self.stockfish = Stockfish(
"go wtime 8000 btime 8000 winc 500 binc 500".split(" "),
True,
)
assert self.stockfish.process.returncode == 0
def test_go_wtime_1000_btime_1000_winc_0_binc_0(self):
self.stockfish = Stockfish(
"go wtime 1000 btime 1000 winc 0 binc 0".split(" "),
True,
)
assert self.stockfish.process.returncode == 0
def test_go_wtime_1000_btime_1000_winc_0_binc_0_movestogo_5(self):
self.stockfish = Stockfish(
"go wtime 1000 btime 1000 winc 0 binc 0 movestogo 5".split(" "),
True,
)
assert self.stockfish.process.returncode == 0
def test_go_movetime_200(self):
self.stockfish = Stockfish("go movetime 200".split(" "), True)
assert self.stockfish.process.returncode == 0
def test_go_nodes_20000_searchmoves_e2e4_d2d4(self):
self.stockfish = Stockfish(
"go nodes 20000 searchmoves e2e4 d2d4".split(" "), True
)
assert self.stockfish.process.returncode == 0
def test_bench_128_threads_8_default_depth(self):
self.stockfish = Stockfish(
f"bench 128 {get_threads()} 8 default depth".split(" "),
True,
)
assert self.stockfish.process.returncode == 0
def test_bench_128_threads_3_bench_tmp_epd_depth(self):
self.stockfish = Stockfish(
f"bench 128 {get_threads()} 3 {os.path.join(PATH,'bench_tmp.epd')} depth".split(
" "
),
True,
)
assert self.stockfish.process.returncode == 0
def test_d(self):
self.stockfish = Stockfish("d".split(" "), True)
assert self.stockfish.process.returncode == 0
def test_compiler(self):
self.stockfish = Stockfish("compiler".split(" "), True)
assert self.stockfish.process.returncode == 0
def test_license(self):
self.stockfish = Stockfish("license".split(" "), True)
assert self.stockfish.process.returncode == 0
def test_uci(self):
self.stockfish = Stockfish("uci".split(" "), True)
assert self.stockfish.process.returncode == 0
def test_export_net_verify_nnue(self):
current_path = os.path.abspath(os.getcwd())
self.stockfish = Stockfish(
f"export_net {os.path.join(current_path , 'verify.nnue')}".split(" "), True
)
assert self.stockfish.process.returncode == 0
# verify the generated net equals the base net
def test_network_equals_base(self):
self.stockfish = Stockfish(
["uci"],
True,
)
output = self.stockfish.process.stdout
# find line
for line in output.split("\n"):
if "option name EvalFile type string default" in line:
network = line.split(" ")[-1]
break
# find network file in src dir
network = os.path.join(PATH.parent.resolve(), "src", network)
if not os.path.exists(network):
print(
f"Network file {network} not found, please download the network file over the make command."
)
assert False
diff = subprocess.run(["diff", network, f"verify.nnue"])
assert diff.returncode == 0
class TestInteractive(metaclass=OrderedClassMembers):
def beforeAll(self):
self.stockfish = Stockfish()
def afterAll(self):
self.stockfish.quit()
assert self.stockfish.close() == 0
def afterEach(self):
assert postfix_check(self.stockfish.get_output()) == True
self.stockfish.clear_output()
def test_startup_output(self):
self.stockfish.starts_with("Stockfish")
def test_uci_command(self):
self.stockfish.send_command("uci")
self.stockfish.equals("uciok")
def test_set_threads_option(self):
self.stockfish.send_command(f"setoption name Threads value {get_threads()}")
def test_ucinewgame_and_startpos_nodes_1000(self):
self.stockfish.send_command("ucinewgame")
self.stockfish.send_command("position startpos")
self.stockfish.send_command("go nodes 1000")
self.stockfish.starts_with("bestmove")
def test_ucinewgame_and_startpos_moves(self):
self.stockfish.send_command("ucinewgame")
self.stockfish.send_command("position startpos moves e2e4 e7e6")
self.stockfish.send_command("go nodes 1000")
self.stockfish.starts_with("bestmove")
def test_fen_position_1(self):
self.stockfish.send_command("ucinewgame")
self.stockfish.send_command("position fen 5rk1/1K4p1/8/8/3B4/8/8/8 b - - 0 1")
self.stockfish.send_command("go nodes 1000")
self.stockfish.starts_with("bestmove")
def test_fen_position_2_flip(self):
self.stockfish.send_command("ucinewgame")
self.stockfish.send_command("position fen 5rk1/1K4p1/8/8/3B4/8/8/8 b - - 0 1")
self.stockfish.send_command("flip")
self.stockfish.send_command("go nodes 1000")
self.stockfish.starts_with("bestmove")
def test_depth_5_with_callback(self):
self.stockfish.send_command("ucinewgame")
self.stockfish.send_command("position startpos")
self.stockfish.send_command("go depth 5")
def callback(output):
regex = r"info depth \d+ seldepth \d+ multipv \d+ score cp \d+ nodes \d+ nps \d+ hashfull \d+ tbhits \d+ time \d+ pv"
if output.startswith("info depth") and not re.match(regex, output):
assert False
if output.startswith("bestmove"):
return True
return False
self.stockfish.check_output(callback)
def test_ucinewgame_and_go_depth_9(self):
self.stockfish.send_command("ucinewgame")
self.stockfish.send_command("setoption name UCI_ShowWDL value true")
self.stockfish.send_command("position startpos")
self.stockfish.send_command("go depth 9")
depth = 1
def callback(output):
nonlocal depth
regex = rf"info depth {depth} seldepth \d+ multipv \d+ score cp \d+ wdl \d+ \d+ \d+ nodes \d+ nps \d+ hashfull \d+ tbhits \d+ time \d+ pv"
if output.startswith("info depth"):
if not re.match(regex, output):
assert False
depth += 1
if output.startswith("bestmove"):
assert depth == 10
return True
return False
self.stockfish.check_output(callback)
def test_clear_hash(self):
self.stockfish.send_command("setoption name Clear Hash")
def test_fen_position_mate_1(self):
self.stockfish.send_command("ucinewgame")
self.stockfish.send_command(
"position fen 5K2/8/2qk4/2nPp3/3r4/6B1/B7/3R4 w - e6"
)
self.stockfish.send_command("go depth 18")
self.stockfish.expect("* score mate 1 * pv d5e6")
self.stockfish.equals("bestmove d5e6")
def test_fen_position_mate_minus_1(self):
self.stockfish.send_command("ucinewgame")
self.stockfish.send_command(
"position fen 2brrb2/8/p7/Q7/1p1kpPp1/1P1pN1K1/3P4/8 b - -"
)
self.stockfish.send_command("go depth 18")
self.stockfish.expect("* score mate -1 *")
self.stockfish.starts_with("bestmove")
def test_fen_position_fixed_node(self):
self.stockfish.send_command("ucinewgame")
self.stockfish.send_command(
"position fen 5K2/8/2P1P1Pk/6pP/3p2P1/1P6/3P4/8 w - - 0 1"
)
self.stockfish.send_command("go nodes 500000")
self.stockfish.starts_with("bestmove")
def test_fen_position_with_mate_go_depth(self):
self.stockfish.send_command("ucinewgame")
self.stockfish.send_command(
"position fen 8/5R2/2K1P3/4k3/8/b1PPpp1B/5p2/8 w - -"
)
self.stockfish.send_command("go depth 18 searchmoves c6d7")
self.stockfish.expect("* score mate 2 * pv c6d7 * f7f5")
self.stockfish.starts_with("bestmove")
def test_fen_position_with_mate_go_mate(self):
self.stockfish.send_command("ucinewgame")
self.stockfish.send_command(
"position fen 8/5R2/2K1P3/4k3/8/b1PPpp1B/5p2/8 w - -"
)
self.stockfish.send_command("go mate 2 searchmoves c6d7")
self.stockfish.expect("* score mate 2 * pv c6d7 *")
self.stockfish.starts_with("bestmove")
def test_fen_position_with_mate_go_nodes(self):
self.stockfish.send_command("ucinewgame")
self.stockfish.send_command(
"position fen 8/5R2/2K1P3/4k3/8/b1PPpp1B/5p2/8 w - -"
)
self.stockfish.send_command("go nodes 500000 searchmoves c6d7")
self.stockfish.expect("* score mate 2 * pv c6d7 * f7f5")
self.stockfish.starts_with("bestmove")
def test_fen_position_depth_27(self):
self.stockfish.send_command("ucinewgame")
self.stockfish.send_command(
"position fen r1b2r1k/pp1p2pp/2p5/2B1q3/8/8/P1PN2PP/R4RK1 w - - 0 18"
)
self.stockfish.send_command("go")
self.stockfish.contains("score mate 1")
self.stockfish.starts_with("bestmove")
def test_fen_position_with_mate_go_depth_and_promotion(self):
self.stockfish.send_command("ucinewgame")
self.stockfish.send_command(
"position fen 8/5R2/2K1P3/4k3/8/b1PPpp1B/5p2/8 w - - moves c6d7 f2f1q"
)
self.stockfish.send_command("go depth 18")
self.stockfish.expect("* score mate 1 * pv f7f5")
self.stockfish.starts_with("bestmove f7f5")
def test_fen_position_with_mate_go_depth_and_searchmoves(self):
self.stockfish.send_command("ucinewgame")
self.stockfish.send_command(
"position fen 8/5R2/2K1P3/4k3/8/b1PPpp1B/5p2/8 w - -"
)
self.stockfish.send_command("go depth 18 searchmoves c6d7")
self.stockfish.expect("* score mate 2 * pv c6d7 * f7f5")
self.stockfish.starts_with("bestmove c6d7")
def test_fen_position_with_moves_with_mate_go_depth_and_searchmoves(self):
self.stockfish.send_command("ucinewgame")
self.stockfish.send_command(
"position fen 8/5R2/2K1P3/4k3/8/b1PPpp1B/5p2/8 w - - moves c6d7"
)
self.stockfish.send_command("go depth 18 searchmoves e3e2")
self.stockfish.expect("* score mate -1 * pv e3e2 f7f5")
self.stockfish.starts_with("bestmove e3e2")
def test_verify_nnue_network(self):
current_path = os.path.abspath(os.getcwd())
Stockfish(
f"export_net {os.path.join(current_path , 'verify.nnue')}".split(" "), True
)
self.stockfish.send_command("setoption name EvalFile value verify.nnue")
self.stockfish.send_command("position startpos")
self.stockfish.send_command("go depth 5")
self.stockfish.starts_with("bestmove")
def test_multipv_setting(self):
self.stockfish.send_command("setoption name MultiPV value 4")
self.stockfish.send_command("position startpos")
self.stockfish.send_command("go depth 5")
self.stockfish.starts_with("bestmove")
def test_fen_position_with_skill_level(self):
self.stockfish.send_command("setoption name Skill Level value 10")
self.stockfish.send_command("position startpos")
self.stockfish.send_command("go depth 5")
self.stockfish.starts_with("bestmove")
self.stockfish.send_command("setoption name Skill Level value 20")
class TestSyzygy(metaclass=OrderedClassMembers):
def beforeAll(self):
self.stockfish = Stockfish()
def afterAll(self):
self.stockfish.quit()
assert self.stockfish.close() == 0
def afterEach(self):
assert postfix_check(self.stockfish.get_output()) == True
self.stockfish.clear_output()
def test_syzygy_setup(self):
self.stockfish.starts_with("Stockfish")
self.stockfish.send_command("uci")
self.stockfish.send_command(
f"setoption name SyzygyPath value {os.path.join(PATH, 'syzygy')}"
)
self.stockfish.expect(
"info string Found 35 WDL and 35 DTZ tablebase files (up to 4-man)."
)
def test_syzygy_bench(self):
self.stockfish.send_command("bench 128 1 8 default depth")
self.stockfish.expect("Nodes searched :*")
def test_syzygy_position(self):
self.stockfish.send_command("ucinewgame")
self.stockfish.send_command("position fen 4k3/PP6/8/8/8/8/8/4K3 w - - 0 1")
self.stockfish.send_command("go depth 5")
def check_output(output):
if "score cp 20000" in output or "score mate" in output:
return True
self.stockfish.check_output(check_output)
self.stockfish.expect("bestmove *")
def test_syzygy_position_2(self):
self.stockfish.send_command("ucinewgame")
self.stockfish.send_command("position fen 8/1P6/2B5/8/4K3/8/6k1/8 w - - 0 1")
self.stockfish.send_command("go depth 5")
def check_output(output):
if "score cp 20000" in output or "score mate" in output:
return True
self.stockfish.check_output(check_output)
self.stockfish.expect("bestmove *")
def test_syzygy_position_3(self):
self.stockfish.send_command("ucinewgame")
self.stockfish.send_command("position fen 8/1P6/2B5/8/4K3/8/6k1/8 b - - 0 1")
self.stockfish.send_command("go depth 5")
def check_output(output):
if "score cp -20000" in output or "score mate" in output:
return True
self.stockfish.check_output(check_output)
self.stockfish.expect("bestmove *")
def parse_args():
parser = argparse.ArgumentParser(description="Run Stockfish with testing options")
parser.add_argument("--valgrind", action="store_true", help="Run valgrind testing")
parser.add_argument(
"--valgrind-thread", action="store_true", help="Run valgrind-thread testing"
)
parser.add_argument(
"--sanitizer-undefined",
action="store_true",
help="Run sanitizer-undefined testing",
)
parser.add_argument(
"--sanitizer-thread", action="store_true", help="Run sanitizer-thread testing"
)
parser.add_argument(
"--none", action="store_true", help="Run without any testing options"
)
parser.add_argument("stockfish_path", type=str, help="Path to Stockfish binary")
return parser.parse_args()
if __name__ == "__main__":
args = parse_args()
EPD.create_bench_epd()
TSAN.set_tsan_option()
Syzygy.download_syzygy()
framework = MiniTestFramework()
# Each test suite will be ran inside a temporary directory
framework.run([TestCLI, TestInteractive, TestSyzygy])
EPD.delete_bench_epd()
TSAN.unset_tsan_option()
if framework.has_failed():
sys.exit(1)
sys.exit(0)
-301
View File
@@ -1,301 +0,0 @@
#!/bin/bash
# check for errors under Valgrind or sanitizers.
error()
{
echo "instrumented testing failed on line $1"
exit 1
}
trap 'error ${LINENO}' ERR
# define suitable post and prefixes for testing options
case $1 in
--valgrind)
echo "valgrind testing started"
prefix=''
exeprefix='valgrind --error-exitcode=42 --errors-for-leak-kinds=all --leak-check=full'
postfix=''
threads="1"
;;
--valgrind-thread)
echo "valgrind-thread testing started"
prefix=''
exeprefix='valgrind --fair-sched=try --error-exitcode=42'
postfix=''
threads="2"
;;
--sanitizer-undefined)
echo "sanitizer-undefined testing started"
prefix='!'
exeprefix=''
postfix='2>&1 | grep -A50 "runtime error:"'
threads="1"
;;
--sanitizer-thread)
echo "sanitizer-thread testing started"
prefix='!'
exeprefix=''
postfix='2>&1 | grep -A50 "WARNING: ThreadSanitizer:"'
threads="2"
cat << EOF > tsan.supp
race:Stockfish::TTEntry::read
race:Stockfish::TTEntry::save
race:Stockfish::TranspositionTable::probe
race:Stockfish::TranspositionTable::hashfull
EOF
export TSAN_OPTIONS="suppressions=./tsan.supp"
;;
*)
echo "unknown testing started"
prefix=''
exeprefix=''
postfix=''
threads="1"
;;
esac
cat << EOF > bench_tmp.epd
Rn6/1rbq1bk1/2p2n1p/2Bp1p2/3Pp1pP/1N2P1P1/2Q1NPB1/6K1 w - - 2 26
rnbqkb1r/ppp1pp2/5n1p/3p2p1/P2PP3/5P2/1PP3PP/RNBQKBNR w KQkq - 0 3
3qnrk1/4bp1p/1p2p1pP/p2bN3/1P1P1B2/P2BQ3/5PP1/4R1K1 w - - 9 28
r4rk1/1b2ppbp/pq4pn/2pp1PB1/1p2P3/1P1P1NN1/1PP3PP/R2Q1RK1 w - - 0 13
EOF
# simple command line testing
for args in "eval" \
"go nodes 1000" \
"go depth 10" \
"go perft 4" \
"go movetime 1000" \
"go wtime 8000 btime 8000 winc 500 binc 500" \
"go wtime 1000 btime 1000 winc 0 binc 0" \
"go wtime 1000 btime 1000 winc 0 binc 0" \
"go wtime 1000 btime 1000 winc 0 binc 0 movestogo 5" \
"go movetime 200" \
"go nodes 20000 searchmoves e2e4 d2d4" \
"bench 128 $threads 8 default depth" \
"bench 128 $threads 3 bench_tmp.epd depth" \
"export_net verify.nnue" \
"d" \
"compiler" \
"license" \
"uci"
do
echo "$prefix $exeprefix ./stockfish $args $postfix"
eval "$prefix $exeprefix ./stockfish $args $postfix"
done
# verify the generated net equals the base net
network=`./stockfish uci | grep 'option name EvalFile type string default' | awk '{print $NF}'`
echo "Comparing $network to the written verify.nnue"
diff $network verify.nnue
# more general testing, following an uci protocol exchange
cat << EOF > game.exp
set timeout 240
# to correctly catch eof we need the following line
# expect_before timeout { exit 2 } eof { exit 3 }
expect_before timeout { exit 2 }
spawn $exeprefix ./stockfish
expect "Stockfish"
send "uci\n"
expect "uciok"
# send "setoption name Debug Log File value debug.log\n"
send "setoption name Threads value $threads\n"
send "ucinewgame\n"
send "position startpos\n"
send "go nodes 1000\n"
expect "bestmove"
send "ucinewgame\n"
send "position startpos moves e2e4 e7e6\n"
send "go nodes 1000\n"
expect "bestmove"
send "ucinewgame\n"
send "position fen 5rk1/1K4p1/8/8/3B4/8/8/8 b - - 0 1\n"
send "go depth 10\n"
expect "bestmove"
send "ucinewgame\n"
send "position fen 5rk1/1K4p1/8/8/3B4/8/8/8 b - - 0 1\n"
send "flip\n"
send "go depth 10\n"
expect "bestmove"
send "ucinewgame\n"
send "position startpos\n"
send "go depth 5\n"
expect -re {info depth \d+ seldepth \d+ multipv \d+ score cp \d+ nodes \d+ nps \d+ hashfull \d+ tbhits \d+ time \d+ pv}
expect "bestmove"
send "ucinewgame\n"
send "setoption name UCI_ShowWDL value true\n"
send "position startpos\n"
send "go depth 9\n"
expect -re {info depth 1 seldepth \d+ multipv \d+ score cp \d+ wdl \d+ \d+ \d+ nodes \d+ nps \d+ hashfull \d+ tbhits \d+ time \d+ pv}
expect -re {info depth 2 seldepth \d+ multipv \d+ score cp \d+ wdl \d+ \d+ \d+ nodes \d+ nps \d+ hashfull \d+ tbhits \d+ time \d+ pv}
expect -re {info depth 3 seldepth \d+ multipv \d+ score cp \d+ wdl \d+ \d+ \d+ nodes \d+ nps \d+ hashfull \d+ tbhits \d+ time \d+ pv}
expect -re {info depth 4 seldepth \d+ multipv \d+ score cp \d+ wdl \d+ \d+ \d+ nodes \d+ nps \d+ hashfull \d+ tbhits \d+ time \d+ pv}
expect -re {info depth 5 seldepth \d+ multipv \d+ score cp \d+ wdl \d+ \d+ \d+ nodes \d+ nps \d+ hashfull \d+ tbhits \d+ time \d+ pv}
expect -re {info depth 6 seldepth \d+ multipv \d+ score cp \d+ wdl \d+ \d+ \d+ nodes \d+ nps \d+ hashfull \d+ tbhits \d+ time \d+ pv}
expect -re {info depth 7 seldepth \d+ multipv \d+ score cp \d+ wdl \d+ \d+ \d+ nodes \d+ nps \d+ hashfull \d+ tbhits \d+ time \d+ pv}
expect -re {info depth 8 seldepth \d+ multipv \d+ score cp \d+ wdl \d+ \d+ \d+ nodes \d+ nps \d+ hashfull \d+ tbhits \d+ time \d+ pv}
expect -re {info depth 9 seldepth \d+ multipv \d+ score cp \d+ wdl \d+ \d+ \d+ nodes \d+ nps \d+ hashfull \d+ tbhits \d+ time \d+ pv}
expect "bestmove"
send "setoption name Clear Hash\n"
send "ucinewgame\n"
send "position fen 5K2/8/2qk4/2nPp3/3r4/6B1/B7/3R4 w - e6\n"
send "go depth 18\n"
expect "score mate 1"
expect "pv d5e6"
expect "bestmove d5e6"
send "ucinewgame\n"
send "position fen 2brrb2/8/p7/Q7/1p1kpPp1/1P1pN1K1/3P4/8 b - -\n"
send "go depth 18\n"
expect "score mate -1"
expect "bestmove"
send "ucinewgame\n"
send "position fen 7K/P1p1p1p1/2P1P1Pk/6pP/3p2P1/1P6/3P4/8 w - - 0 1\n"
send "go nodes 500000\n"
expect "bestmove"
send "ucinewgame\n"
send "position fen 8/5R2/2K1P3/4k3/8/b1PPpp1B/5p2/8 w - -\n"
send "go depth 18 searchmoves c6d7\n"
expect "score mate 2 * pv c6d7 * f7f5"
expect "bestmove c6d7"
send "ucinewgame\n"
send "position fen 8/5R2/2K1P3/4k3/8/b1PPpp1B/5p2/8 w - -\n"
send "go mate 2 searchmoves c6d7\n"
expect "score mate 2 * pv c6d7"
expect "bestmove c6d7"
send "ucinewgame\n"
send "position fen 8/5R2/2K1P3/4k3/8/b1PPpp1B/5p2/8 w - -\n"
send "go nodes 500000 searchmoves c6d7\n"
expect "score mate 2 * pv c6d7 * f7f5"
expect "bestmove c6d7"
send "ucinewgame\n"
send "position fen 1NR2B2/5p2/5p2/1p1kpp2/1P2rp2/2P1pB2/2P1P1K1/8 b - - \n"
send "go depth 27\n"
expect "score mate -2"
expect "pv d5e6 c8d8"
expect "bestmove d5e6"
send "ucinewgame\n"
send "position fen 8/5R2/2K1P3/4k3/8/b1PPpp1B/5p2/8 w - - moves c6d7 f2f1q\n"
send "go depth 18\n"
expect "score mate 1 * pv f7f5"
expect "bestmove f7f5"
send "ucinewgame\n"
send "position fen 8/5R2/2K1P3/4k3/8/b1PPpp1B/5p2/8 w - -\n"
send "go depth 18 searchmoves c6d7\n"
expect "score mate 2 * pv c6d7 * f7f5"
expect "bestmove c6d7"
send "ucinewgame\n"
send "position fen 8/5R2/2K1P3/4k3/8/b1PPpp1B/5p2/8 w - - moves c6d7\n"
send "go depth 18 searchmoves e3e2\n"
expect "score mate -1 * pv e3e2 f7f5"
expect "bestmove e3e2"
send "setoption name EvalFile value verify.nnue\n"
send "position startpos\n"
send "go depth 5\n"
expect "bestmove"
send "setoption name MultiPV value 4\n"
send "position startpos\n"
send "go depth 5\n"
expect "bestmove"
send "setoption name Skill Level value 10\n"
send "position startpos\n"
send "go depth 5\n"
expect "bestmove"
send "setoption name Skill Level value 20\n"
send "quit\n"
expect eof
# return error code of the spawned program, useful for Valgrind
lassign [wait] pid spawnid os_error_flag value
exit \$value
EOF
#download TB as needed
if [ ! -d ../tests/syzygy ]; then
curl -sL https://api.github.com/repos/niklasf/python-chess/tarball/9b9aa13f9f36d08aadfabff872882f4ab1494e95 | tar -xzf -
mv niklasf-python-chess-9b9aa13 ../tests/syzygy
fi
cat << EOF > syzygy.exp
set timeout 240
# to correctly catch eof we need the following line
# expect_before timeout { exit 2 } eof { exit 3 }
expect_before timeout { exit 2 }
spawn $exeprefix ./stockfish
expect "Stockfish"
send "uci\n"
send "setoption name SyzygyPath value ../tests/syzygy/\n"
expect "info string Found 35 WDL and 35 DTZ tablebase files (up to 4-man)."
send "bench 128 1 8 default depth\n"
expect "Nodes searched :"
send "ucinewgame\n"
send "position fen 4k3/PP6/8/8/8/8/8/4K3 w - - 0 1\n"
send "go depth 5\n"
expect -re {score cp 20000|score mate}
expect "bestmove"
send "ucinewgame\n"
send "position fen 8/1P6/2B5/8/4K3/8/6k1/8 w - - 0 1\n"
send "go depth 5\n"
expect -re {score cp 20000|score mate}
expect "bestmove"
send "ucinewgame\n"
send "position fen 8/1P6/2B5/8/4K3/8/6k1/8 b - - 0 1\n"
send "go depth 5\n"
expect -re {score cp -20000|score mate}
expect "bestmove"
send "quit\n"
expect eof
# return error code of the spawned program, useful for Valgrind
lassign [wait] pid spawnid os_error_flag value
exit \$value
EOF
for exp in game.exp syzygy.exp
do
echo "======== $exp =============="
cat $exp
echo "============================"
echo "$prefix expect $exp $postfix"
eval "$prefix expect $exp $postfix"
rm $exp
done
rm -f tsan.supp bench_tmp.epd
echo "instrumented testing OK"
+1 -1
View File
@@ -1,5 +1,5 @@
#!/bin/bash #!/bin/bash
# verify perft numbers (positions from www.chessprogramming.org/Perft_Results) # verify perft numbers (positions from https://www.chessprogramming.org/Perft_Results)
error() error()
{ {
+400
View File
@@ -0,0 +1,400 @@
import subprocess
from typing import List
import os
import collections
import time
import sys
import traceback
import fnmatch
from functools import wraps
from contextlib import redirect_stdout
import io
import tarfile
import pathlib
import concurrent.futures
import tempfile
import shutil
import requests
CYAN_COLOR = "\033[36m"
GRAY_COLOR = "\033[2m"
RED_COLOR = "\033[31m"
GREEN_COLOR = "\033[32m"
RESET_COLOR = "\033[0m"
WHITE_BOLD = "\033[1m"
MAX_TIMEOUT = 60 * 5
PATH = pathlib.Path(__file__).parent.resolve()
class Valgrind:
@staticmethod
def get_valgrind_command():
return [
"valgrind",
"--error-exitcode=42",
"--errors-for-leak-kinds=all",
"--leak-check=full",
]
@staticmethod
def get_valgrind_thread_command():
return ["valgrind", "--error-exitcode=42", "--fair-sched=try"]
class TSAN:
@staticmethod
def set_tsan_option():
with open(f"tsan.supp", "w") as f:
f.write(
"""
race:Stockfish::TTEntry::read
race:Stockfish::TTEntry::save
race:Stockfish::TranspositionTable::probe
race:Stockfish::TranspositionTable::hashfull
"""
)
os.environ["TSAN_OPTIONS"] = "suppressions=./tsan.supp"
@staticmethod
def unset_tsan_option():
os.environ.pop("TSAN_OPTIONS", None)
os.remove(f"tsan.supp")
class EPD:
@staticmethod
def create_bench_epd():
with open(f"{os.path.join(PATH,'bench_tmp.epd')}", "w") as f:
f.write(
"""
Rn6/1rbq1bk1/2p2n1p/2Bp1p2/3Pp1pP/1N2P1P1/2Q1NPB1/6K1 w - - 2 26
rnbqkb1r/ppp1pp2/5n1p/3p2p1/P2PP3/5P2/1PP3PP/RNBQKBNR w KQkq - 0 3
3qnrk1/4bp1p/1p2p1pP/p2bN3/1P1P1B2/P2BQ3/5PP1/4R1K1 w - - 9 28
r4rk1/1b2ppbp/pq4pn/2pp1PB1/1p2P3/1P1P1NN1/1PP3PP/R2Q1RK1 w - - 0 13
"""
)
@staticmethod
def delete_bench_epd():
os.remove(f"{os.path.join(PATH,'bench_tmp.epd')}")
class Syzygy:
@staticmethod
def get_syzygy_path():
return os.path.abspath("syzygy")
@staticmethod
def download_syzygy():
if not os.path.isdir(os.path.join(PATH, "syzygy")):
url = "https://api.github.com/repos/niklasf/python-chess/tarball/9b9aa13f9f36d08aadfabff872882f4ab1494e95"
file = "niklasf-python-chess-9b9aa13"
with tempfile.TemporaryDirectory() as tmpdirname:
tarball_path = os.path.join(tmpdirname, f"{file}.tar.gz")
response = requests.get(url, stream=True)
with open(tarball_path, "wb") as f:
for chunk in response.iter_content(chunk_size=8192):
f.write(chunk)
with tarfile.open(tarball_path, "r:gz") as tar:
tar.extractall(tmpdirname)
shutil.move(
os.path.join(tmpdirname, file), os.path.join(PATH, "syzygy")
)
class OrderedClassMembers(type):
@classmethod
def __prepare__(self, name, bases):
return collections.OrderedDict()
def __new__(self, name, bases, classdict):
classdict["__ordered__"] = [
key for key in classdict.keys() if key not in ("__module__", "__qualname__")
]
return type.__new__(self, name, bases, classdict)
class TimeoutException(Exception):
def __init__(self, message: str, timeout: int):
self.message = message
self.timeout = timeout
def timeout_decorator(timeout: float):
def decorator(func):
@wraps(func)
def wrapper(*args, **kwargs):
with concurrent.futures.ThreadPoolExecutor() as executor:
future = executor.submit(func, *args, **kwargs)
try:
result = future.result(timeout=timeout)
except concurrent.futures.TimeoutError:
raise TimeoutException(
f"Function {func.__name__} timed out after {timeout} seconds",
timeout,
)
return result
return wrapper
return decorator
class MiniTestFramework:
def __init__(self):
self.passed_test_suites = 0
self.failed_test_suites = 0
self.passed_tests = 0
self.failed_tests = 0
self.stop_on_failure = True
def has_failed(self) -> bool:
return self.failed_test_suites > 0
def run(self, classes: List[type]) -> bool:
self.start_time = time.time()
for test_class in classes:
with tempfile.TemporaryDirectory() as tmpdirname:
original_cwd = os.getcwd()
os.chdir(tmpdirname)
try:
if self.__run(test_class):
self.failed_test_suites += 1
else:
self.passed_test_suites += 1
except Exception as e:
self.failed_test_suites += 1
print(f"\n{RED_COLOR}Error: {e}{RESET_COLOR}")
finally:
os.chdir(original_cwd)
self.__print_summary(round(time.time() - self.start_time, 2))
return self.has_failed()
def __run(self, test_class) -> bool:
test_instance = test_class()
test_name = test_instance.__class__.__name__
test_methods = [m for m in test_instance.__ordered__ if m.startswith("test_")]
print(f"\nTest Suite: {test_name}")
if hasattr(test_instance, "beforeAll"):
test_instance.beforeAll()
fails = 0
for method in test_methods:
fails += self.__run_test_method(test_instance, method)
if hasattr(test_instance, "afterAll"):
test_instance.afterAll()
self.failed_tests += fails
return fails > 0
def __run_test_method(self, test_instance, method: str) -> int:
print(f" Running {method}... \r", end="", flush=True)
buffer = io.StringIO()
fails = 0
try:
t0 = time.time()
with redirect_stdout(buffer):
if hasattr(test_instance, "beforeEach"):
test_instance.beforeEach()
getattr(test_instance, method)()
if hasattr(test_instance, "afterEach"):
test_instance.afterEach()
duration = time.time() - t0
self.print_success(f" {method} ({duration * 1000:.2f}ms)")
self.passed_tests += 1
except Exception as e:
if isinstance(e, TimeoutException):
self.print_failure(
f" {method} (hit execution limit of {e.timeout} seconds)"
)
if isinstance(e, AssertionError):
self.__handle_assertion_error(t0, method)
if self.stop_on_failure:
self.__print_buffer_output(buffer)
raise e
fails += 1
finally:
self.__print_buffer_output(buffer)
return fails
def __handle_assertion_error(self, start_time, method: str):
duration = time.time() - start_time
self.print_failure(f" {method} ({duration * 1000:.2f}ms)")
traceback_output = "".join(traceback.format_tb(sys.exc_info()[2]))
colored_traceback = "\n".join(
f" {CYAN_COLOR}{line}{RESET_COLOR}"
for line in traceback_output.splitlines()
)
print(colored_traceback)
def __print_buffer_output(self, buffer: io.StringIO):
output = buffer.getvalue()
if output:
indented_output = "\n".join(f" {line}" for line in output.splitlines())
print(f" {RED_COLOR}⎯⎯⎯⎯⎯OUTPUT⎯⎯⎯⎯⎯{RESET_COLOR}")
print(f"{GRAY_COLOR}{indented_output}{RESET_COLOR}")
print(f" {RED_COLOR}⎯⎯⎯⎯⎯OUTPUT⎯⎯⎯⎯⎯{RESET_COLOR}")
def __print_summary(self, duration: float):
print(f"\n{WHITE_BOLD}Test Summary{RESET_COLOR}\n")
print(
f" Test Suites: {GREEN_COLOR}{self.passed_test_suites} passed{RESET_COLOR}, {RED_COLOR}{self.failed_test_suites} failed{RESET_COLOR}, {self.passed_test_suites + self.failed_test_suites} total"
)
print(
f" Tests: {GREEN_COLOR}{self.passed_tests} passed{RESET_COLOR}, {RED_COLOR}{self.failed_tests} failed{RESET_COLOR}, {self.passed_tests + self.failed_tests} total"
)
print(f" Time: {duration}s\n")
def print_failure(self, add: str):
print(f" {RED_COLOR}{RESET_COLOR}{add}", flush=True)
def print_success(self, add: str):
print(f" {GREEN_COLOR}{RESET_COLOR}{add}", flush=True)
class Stockfish:
def __init__(
self,
prefix: List[str],
path: str,
args: List[str] = [],
cli: bool = False,
):
self.path = path
self.process = None
self.args = args
self.cli = cli
self.prefix = prefix
self.output = []
self.start()
def _check_process_alive(self):
if not self.process or self.process.poll() is not None:
print("\n".join(self.output))
raise RuntimeError("Stockfish process has terminated")
def start(self):
if self.cli:
self.process = subprocess.run(
self.prefix + [self.path] + self.args,
capture_output=True,
text=True,
)
if self.process.returncode != 0:
print(self.process.stdout)
print(self.process.stderr)
print(f"Process failed with return code {self.process.returncode}")
return
self.process = subprocess.Popen(
self.prefix + [self.path] + self.args,
stdin=subprocess.PIPE,
stdout=subprocess.PIPE,
stderr=subprocess.STDOUT,
universal_newlines=True,
bufsize=1,
)
def setoption(self, name: str, value: str):
self.send_command(f"setoption name {name} value {value}")
def send_command(self, command: str):
if not self.process:
raise RuntimeError("Stockfish process is not started")
self._check_process_alive()
self.process.stdin.write(command + "\n")
self.process.stdin.flush()
@timeout_decorator(MAX_TIMEOUT)
def equals(self, expected_output: str):
for line in self.readline():
if line == expected_output:
return
@timeout_decorator(MAX_TIMEOUT)
def expect(self, expected_output: str):
for line in self.readline():
if fnmatch.fnmatch(line, expected_output):
return
@timeout_decorator(MAX_TIMEOUT)
def contains(self, expected_output: str):
for line in self.readline():
if expected_output in line:
return
@timeout_decorator(MAX_TIMEOUT)
def starts_with(self, expected_output: str):
for line in self.readline():
if line.startswith(expected_output):
return
@timeout_decorator(MAX_TIMEOUT)
def check_output(self, callback):
if not callback:
raise ValueError("Callback function is required")
for line in self.readline():
if callback(line) == True:
return
def readline(self):
if not self.process:
raise RuntimeError("Stockfish process is not started")
while True:
self._check_process_alive()
line = self.process.stdout.readline().strip()
self.output.append(line)
yield line
def clear_output(self):
self.output = []
def get_output(self) -> List[str]:
return self.output
def quit(self):
self.send_command("quit")
def close(self):
if self.process:
self.process.stdin.close()
self.process.stdout.close()
return self.process.wait()
return 0