--- /dev/null
+# Files from build
+**/*.o
+**/*.s
+src/.depend
+
+# Built binary
+src/stockfish*
+src/-lstdc++.res
+
+# Neural network for the NNUE evaluation
+**/*.nnue
+
Andrew Grant (AndyGrant)
Andrey Neporada (nepal)
Andy Duplain
+Antoine Champion (antoinechampion)
Aram Tumanian (atumanian)
Arjun Temurnikar
Auguste Pop
Bojun Guo (noobpwnftw, Nooby)
braich
Brian Sheppard (SapphireBrand, briansheppard-toast)
+Bruno de Melo Costa (BM123499)
Bryan Cross (crossbr)
candirufish
Chess13234
David Zar
Daylen Yang (daylen)
Deshawn Mohan-Smith (GoldenRare)
+Dieter Dobbelaere (ddobbelaere)
DiscanX
Dominik Schlösser (domschl)
double-beep
kinderchocolate
Kiran Panditrao (Krgp)
Kojirion
+Krystian Kuzniarek (kuzkry)
Leonardo Ljubičić (ICCF World Champion)
Leonid Pechenik (lp--)
Linus Arver (listx)
Malcolm Campbell (xoto10)
Mark Tenzer (31m059)
marotear
+Matt Ginsberg (mattginsberg)
Matthew Lai (matthewlai)
Matthew Sullivan (Matt14916)
Maxim Molchanov (Maxim)
sf-x
Shane Booth (shane31)
Shawn Varghese (xXH4CKST3RXx)
+Siad Daboul (Topologist)
Stefan Geschwentner (locutus2)
Stefano Cardanobile (Stefano80)
Steinar Gunderson (sesse)
* Readme.md, the file you are currently reading.
* Copying.txt, a text file containing the GNU General Public License version 3.
+
+ * AUTHORS, a text file with the list of authors for the project
* src, a subdirectory containing the full source code, including a Makefile
that can be used to compile Stockfish on Unix-like systems.
* a file with the .nnue extension, storing the neural network for the NNUE
evaluation. Binary distributions will have this file embedded.
-Note: to use the NNUE evaluation, the additional data file with neural network parameters
-needs to be available. Normally, this file is already embedded in the binary or it can be downloaded.
-The filename for the default (recommended) net can be found as the default
-value of the `EvalFile` UCI option, with the format `nn-[SHA256 first 12 digits].nnue`
-(for instance, `nn-c157e0a5755b.nnue`). This file can be downloaded from
-```
-https://tests.stockfishchess.org/api/nn/[filename]
-```
-replacing `[filename]` as needed.
-
-
## UCI options
Currently, Stockfish has the following UCI options:
* #### Hash
The size of the hash table in MB. It is recommended to set Hash after setting Threads.
+ * #### Clear Hash
+ Clear the hash table.
+
* #### Ponder
Let Stockfish ponder its next move while the opponent is thinking.
* #### SyzygyProbeDepth
Minimum remaining search depth for which a position is probed. Set this option
to a higher value to probe less aggressively if you experience too much slowdown
- (in terms of nps) due to TB probing.
+ (in terms of nps) due to tablebase probing.
* #### Syzygy50MoveRule
Disable to let fifty-move rule draws detected by Syzygy tablebase probes count
Tells the engine to use nodes searched instead of wall time to account for
elapsed time. Useful for engine testing.
- * #### Clear Hash
- Clear the hash table.
-
* #### Debug Log File
Write all communication to and from the engine into a text file.
-## A note on classical and NNUE evaluation
+## A note on classical evaluation versus NNUE evaluation
Both approaches assign a value to a position that is used in alpha-beta (PVS) search
to find the best move. The classical evaluation computes this value as a function
It can be evaluated efficiently on CPUs, and exploits the fact that only parts
of the neural network need to be updated after a typical chess move.
[The nodchip repository](https://github.com/nodchip/Stockfish) provides additional
-tools to train and develop the NNUE networks.
+tools to train and develop the NNUE networks. On CPUs supporting modern vector instructions
+(avx2 and similar), the NNUE evaluation results in much stronger playing strength, even
+if the nodes per second computed by the engine is somewhat lower (roughly 80% of nps
+is typical).
-On CPUs supporting modern vector instructions (avx2 and similar), the NNUE evaluation
-results in stronger playing strength, even if the nodes per second computed by the engine
-is somewhat lower (roughly 60% of nps is typical).
+Notes:
-Note that the NNUE evaluation depends on the Stockfish binary and the network parameter
-file (see EvalFile). Not every parameter file is compatible with a given Stockfish binary.
-The default value of the EvalFile UCI option is the name of a network that is guaranteed
-to be compatible with that binary.
+1) the NNUE evaluation depends on the Stockfish binary and the network parameter
+file (see the EvalFile UCI option). Not every parameter file is compatible with a given
+Stockfish binary, but the default value of the EvalFile UCI option is the name of a network
+that is guaranteed to be compatible with that binary.
+
+2) to use the NNUE evaluation, the additional data file with neural network parameters
+needs to be available. Normally, this file is already embedded in the binary or it
+can be downloaded. The filename for the default (recommended) net can be found as the default
+value of the `EvalFile` UCI option, with the format `nn-[SHA256 first 12 digits].nnue`
+(for instance, `nn-c157e0a5755b.nnue`). This file can be downloaded from
+```
+https://tests.stockfishchess.org/api/nn/[filename]
+```
+replacing `[filename]` as needed.
-## What to expect from Syzygybases?
+## What to expect from the Syzygy tablebases?
If the engine is searching a position that is not in the tablebases (e.g.
a position with 8 pieces), it will access the tablebases during the search.
It is therefore clear that this behaviour is not identical to what one might
be used to with Nalimov tablebases. There are technical reasons for this
difference, the main technical reason being that Nalimov tablebases use the
-DTM metric (distance-to-mate), while Syzygybases use a variation of the
+DTM metric (distance-to-mate), while the Syzygy tablebases use a variation of the
DTZ metric (distance-to-zero, zero meaning any move that resets the 50-move
-counter). This special metric is one of the reasons that Syzygybases are
+counter). This special metric is one of the reasons that the Syzygy tablebases are
more compact than Nalimov tablebases, while still storing all information
needed for optimal play and in addition being able to take into account
the 50-move rule.
Nevertheless, a helpful resource.
* The latest source can always be found on [GitHub](https://github.com/official-stockfish/Stockfish).
-Discussions about Stockfish take place in the [FishCooking](https://groups.google.com/forum/#!forum/fishcooking)
-group and engine testing is done on [Fishtest](https://tests.stockfishchess.org/tests).
+Discussions about Stockfish take place these days mainly in the [FishCooking](https://groups.google.com/forum/#!forum/fishcooking)
+group and on the [Stockfish Discord channel](https://discord.gg/nv8gDtt).
+The engine testing is done on [Fishtest](https://tests.stockfishchess.org/tests).
If you want to help improve Stockfish, please read this [guideline](https://github.com/glinscott/fishtest/wiki/Creating-my-first-test)
first, where the basics of Stockfish development are explained.
using it as the starting point for a software project of your own.
The only real limitation is that whenever you distribute Stockfish in
-some way, you must always include the full source code, or a pointer
-to where the source code can be found. If you make any changes to the
-source code, these changes must also be made available under the GPL.
+some way, you MUST always include the full source code, or a pointer
+to where the source code can be found, to generate the exact binary
+you are distributing. If you make any changes to the source code,
+these changes must also be made available under the GPL.
For full details, read the copy of the GPL v3 found in the file named
*Copying.txt*.
-Contributors with >10,000 CPU hours as of Sept 2, 2020
+Contributors to Fishtest with >10,000 CPU hours, as of Feb 15, 2021.
Thank you!
-Username CPU Hours Games played
---------------------------------------------------
-noobpwnftw 19352969 1231459677
-mlang 957168 61657446
-dew 949885 56893432
-mibere 703817 46865007
-crunchy 427035 27344275
-cw 416006 27521077
-JojoM 415904 24479564
-fastgm 404873 23953472
-CSU_Dynasty 335774 22850550
-tvijlbrief 335199 21871270
-Fisherman 325053 21786603
-gvreuls 311480 20751516
-ctoks 275877 18710423
-velislav 241267 15596372
-glinscott 217799 13780820
-nordlandia 211692 13484886
-bcross 206213 14934233
-bking_US 198894 11876016
-leszek 189170 11446821
-mgrabiak 183896 11778092
-drabel 181408 12489478
-TueRens 181349 12192000
-Thanar 179852 12365359
-vdv 175171 9881246
-robal 166948 10702862
-spams 157128 10319326
-marrco 149947 9376421
-sqrt2 147963 9724586
-vdbergh 137041 8926915
-CoffeeOne 136294 5004100
-malala 136182 8002293
-mhoram 128934 8177193
-davar 122092 7960001
-dsmith 122059 7570238
-xoto 119696 8222144
-grandphish2 116481 7582197
-Data 113305 8220352
-BrunoBanani 112960 7436849
-ElbertoOne 99028 7023771
-MaZePallas 98571 6362619
-brabos 92118 6186135
-psk 89957 5984901
-sunu 88463 6007033
-sterni1971 86948 5613788
-Vizvezdenec 83752 5343724
-BRAVONE 81239 5054681
-nssy 76497 5259388
-teddybaer 75125 5407666
-Pking_cda 73776 5293873
-jromang 70695 4940891
-solarlight 70517 5028306
-dv8silencer 70287 3883992
-Bobo1239 68515 4652287
-racerschmacer 67468 4935996
-manap 66273 4121774
-tinker 63458 4213726
-linrock 59082 4516053
-robnjr 57262 4053117
-Freja 56938 3733019
-ttruscott 56005 3679485
-renouve 53811 3501516
-cuistot 52532 3014920
-finfish 51360 3370515
-eva42 51272 3599691
-rkl 50759 3840947
-rap 49985 3219146
-pb00067 49727 3298270
-ronaldjerum 47654 3240695
-bigpen0r 47278 3291647
-biffhero 46564 3111352
-VoyagerOne 45386 3445881
-speedycpu 43842 3003273
-jbwiebe 43305 2805433
-Antihistamine 41788 2761312
-mhunt 41735 2691355
-eastorwest 40387 2812173
-homyur 39893 2850481
-gri 39871 2515779
-oryx 38228 2941656
-0x3C33 37773 2529097
-SC 37290 2731014
-csnodgrass 36207 2688994
-jmdana 36108 2205261
-strelock 34716 2074055
-Garf 33800 2747562
-EthanOConnor 33370 2090311
-slakovv 32915 2021889
-Spprtr 32591 2139601
-Prcuvu 30377 2170122
-anst 30301 2190091
-jkiiski 30136 1904470
-hyperbolic.tom 29840 2017394
-Pyafue 29650 1902349
-OuaisBla 27629 1578000
-chriswk 26902 1868317
-achambord 26582 1767323
-Patrick_G 26276 1801617
-yorkman 26193 1992080
-SFTUser 25182 1675689
-nabildanial 24942 1519409
-Sharaf_DG 24765 1786697
-ncfish1 24411 1520927
-agg177 23890 1395014
-JanErik 23408 1703875
-Isidor 23388 1680691
-Norabor 22976 1587862
-cisco2015 22880 1759669
-Zirie 22542 1472937
-team-oh 22272 1636708
-MazeOfGalious 21978 1629593
-sg4032 21945 1643065
-ianh2105 21725 1632562
-xor12 21628 1680365
-dex 21612 1467203
-nesoneg 21494 1463031
-horst.prack 20878 1465656
-0xB00B1ES 20590 1208666
-j3corre 20405 941444
-Adrian.Schmidt123 20316 1281436
-wei 19973 1745989
-rstoesser 19569 1293588
-eudhan 19274 1283717
-Ente 19070 1373058
-jundery 18445 1115855
-iisiraider 18247 1101015
-ville 17883 1384026
-chris 17698 1487385
-purplefishies 17595 1092533
-DragonLord 17014 1162790
-dju 16515 929427
-IgorLeMasson 16064 1147232
-ako027ako 15671 1173203
-Nikolay.IT 15154 1068349
-Andrew Grant 15114 895539
-yurikvelo 15027 1165616
-OssumOpossum 14857 1007129
-enedene 14476 905279
-bpfliegel 14298 884523
-jpulman 13982 870599
-joster 13794 950160
-Nesa92 13786 1114691
-Dark_wizzie 13422 1007152
-Hjax 13350 900887
-Fifis 13313 965473
-mabichito 12903 749391
-thijsk 12886 722107
-crocogoat 12876 1048802
-AdrianSA 12860 804972
-Flopzee 12698 894821
-fatmurphy 12547 853210
-SapphireBrand 12416 969604
-modolief 12386 896470
-scuzzi 12362 833465
-pgontarz 12151 848794
-stocky 11954 699440
-mschmidt 11941 803401
-infinity 11470 727027
-torbjo 11387 728873
-Thomas A. Anderson 11372 732094
-snicolet 11106 869170
-amicic 10779 733593
-rpngn 10712 688203
-d64 10680 771144
-basepi 10637 744851
-jjoshua2 10559 670905
-dzjp 10343 732529
-ols 10259 570669
-lbraesch 10252 647825
+Username CPU Hours Games played
+----------------------------------------------------
+noobpwnftw 23930906 1560559941
+dew 1169948 70333008
+mlang 957168 61657446
+mibere 703840 46867607
+tvijlbrief 517888 33379462
+JojoM 515404 30334272
+cw 443276 29385549
+crunchy 427035 27344275
+grandphish2 425794 26347253
+fastgm 414133 24519696
+gvreuls 377843 24708884
+CSU_Dynasty 338718 23030006
+Fisherman 326795 21820747
+TueRens 313730 19490246
+ctoks 298442 20052551
+velislav 270519 17355456
+bcross 241064 17196165
+glinscott 217799 13780820
+nordlandia 211692 13484886
+bking_US 198894 11876016
+drabel 191096 13129722
+leszek 189170 11446821
+mgrabiak 187153 12013300
+robal 181389 11539242
+Thanar 179852 12365359
+vdv 175274 9889046
+spams 157128 10319326
+marrco 150292 9401741
+sqrt2 147963 9724586
+CoffeeOne 137086 5022516
+vdbergh 137041 8926915
+malala 136182 8002293
+mhoram 132780 8398229
+xoto 124729 8652088
+davar 122092 7960001
+dsmith 122059 7570238
+Data 113305 8220352
+BrunoBanani 112960 7436849
+pemo 109598 5036441
+Dantist 106768 6431396
+MaZePallas 102741 6630419
+ElbertoOne 99028 7023771
+brabos 92118 6186135
+linrock 90903 6708639
+psk 89957 5984901
+sunu 88614 6020673
+sterni1971 86948 5613788
+Vizvezdenec 83761 5344740
+BRAVONE 81239 5054681
+nssy 76497 5259388
+cuistot 76366 4370584
+racerschmacer 75753 5442626
+teddybaer 75125 5407666
+Pking_cda 73776 5293873
+0x3C33 73133 4670293
+jromang 72117 5054915
+solarlight 70517 5028306
+dv8silencer 70287 3883992
+Bobo1239 68515 4652287
+manap 66273 4121774
+tinker 64321 4268390
+robnjr 57262 4053117
+Freja 56938 3733019
+ttruscott 56010 3680085
+rkl 54986 4150767
+renouve 53811 3501516
+finfish 51360 3370515
+eva42 51272 3599691
+rap 49985 3219146
+pb00067 49727 3298270
+amicic 49691 3042481
+ronaldjerum 47654 3240695
+bigpen0r 47278 3291647
+biffhero 46564 3111352
+VoyagerOne 45476 3452465
+eastorwest 45033 3071805
+speedycpu 43842 3003273
+jbwiebe 43305 2805433
+Antihistamine 41788 2761312
+mhunt 41735 2691355
+homyur 39893 2850481
+gri 39871 2515779
+oryx 38282 2944400
+Spprtr 38157 2470529
+SC 37290 2731014
+csnodgrass 36207 2688994
+jmdana 36157 2210661
+strelock 34716 2074055
+Garf 33800 2747562
+skiminki 33515 2055584
+EthanOConnor 33370 2090311
+slakovv 32915 2021889
+yurikvelo 32600 2255966
+Prcuvu 30377 2170122
+manapbk 30326 1770143
+anst 30301 2190091
+jkiiski 30136 1904470
+hyperbolic.tom 29840 2017394
+Pyafue 29650 1902349
+qurashee 27758 1509620
+OuaisBla 27636 1578800
+chriswk 26902 1868317
+achambord 26582 1767323
+Fifis 26376 1776853
+Patrick_G 26276 1801617
+yorkman 26193 1992080
+SFTUser 25182 1675689
+nabildanial 24942 1519409
+Sharaf_DG 24765 1786697
+ncfish1 24411 1520927
+agg177 23890 1395014
+JanErik 23408 1703875
+Isidor 23388 1680691
+Norabor 23164 1591830
+cisco2015 22895 1762069
+Zirie 22542 1472937
+team-oh 22272 1636708
+MazeOfGalious 21978 1629593
+sg4032 21945 1643065
+ianh2105 21725 1632562
+xor12 21628 1680365
+dex 21612 1467203
+nesoneg 21494 1463031
+jjoshua2 20997 1422689
+horst.prack 20878 1465656
+0xB00B1ES 20590 1208666
+sphinx 20515 1352368
+j3corre 20405 941444
+Adrian.Schmidt123 20316 1281436
+Ente 20017 1432602
+wei 19973 1745989
+rstoesser 19569 1293588
+eudhan 19274 1283717
+jundery 18445 1115855
+iisiraider 18247 1101015
+ville 17883 1384026
+chris 17698 1487385
+purplefishies 17595 1092533
+DMBK 17357 1279152
+DragonLord 17014 1162790
+dju 16515 929427
+IgorLeMasson 16064 1147232
+ako027ako 15671 1173203
+Nikolay.IT 15154 1068349
+Andrew Grant 15114 895539
+OssumOpossum 14857 1007129
+enedene 14476 905279
+bpfliegel 14298 884523
+jpulman 13982 870599
+joster 13794 950160
+Nesa92 13786 1114691
+crocogoat 13753 1114622
+Hjax 13535 915487
+Dark_wizzie 13422 1007152
+mpx86 12941 693640
+mabichito 12903 749391
+thijsk 12886 722107
+AdrianSA 12860 804972
+Flopzee 12698 894821
+fatmurphy 12547 853210
+scuzzi 12511 845761
+Karby 12429 735880
+SapphireBrand 12416 969604
+modolief 12386 896470
+pgontarz 12151 848794
+stocky 11954 699440
+mschmidt 11941 803401
+infinity 11470 727027
+torbjo 11395 729145
+Thomas A. Anderson 11372 732094
+d64 11263 789184
+Maxim 11129 804704
+snicolet 11106 869170
+MooTheCow 11008 694942
+savage84 10965 641068
+Rudolphous 10915 741268
+Wolfgang 10809 580032
+rpngn 10712 688203
+basepi 10637 744851
+michaelrpg 10409 735127
+dzjp 10343 732529
+ali-al-zhrani 10324 726502
+ols 10259 570669
+lbraesch 10252 647825
# Stockfish, a UCI chess playing engine derived from Glaurung 2.1
-# Copyright (C) 2004-2008 Tord Romstad (Glaurung author)
-# Copyright (C) 2008-2015 Marco Costalba, Joona Kiiski, Tord Romstad
-# Copyright (C) 2015-2019 Marco Costalba, Joona Kiiski, Gary Linscott, Tord Romstad
+# Copyright (C) 2004-2021 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
ifneq ($(KERNEL),Darwin)
ifneq ($(KERNEL),OpenBSD)
+ ifneq ($(KERNEL),FreeBSD)
LDFLAGS += -latomic
endif
endif
+ endif
ifeq ($(arch),$(filter $(arch),armv7 armv8))
ifeq ($(OS),Android)
CXXFLAGS += -mdynamic-no-pic
endif
endif
+
+ ifeq ($(comp),clang)
+ CXXFLAGS += -fexperimental-new-pass-manager
+ endif
endif
### 3.4 Bits
ifeq ($(optimize),yes)
ifeq ($(debug), no)
ifeq ($(comp),clang)
- CXXFLAGS += -flto=thin
+ CXXFLAGS += -flto
ifneq ($(findstring MINGW,$(KERNEL)),)
CXXFLAGS += -fuse-ld=lld
else ifneq ($(findstring MSYS,$(KERNEL)),)
LDFLAGS += -save-temps
endif
else
- CXXFLAGS += -flto=thin
+ CXXFLAGS += -flto
LDFLAGS += $(CXXFLAGS)
endif
/*
Stockfish, a UCI chess playing engine derived from Glaurung 2.1
- Copyright (C) 2004-2020 The Stockfish developers (see AUTHORS file)
+ Copyright (C) 2004-2021 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
} // namespace
+namespace Stockfish {
+
/// setup_bench() builds a list of UCI commands to be run by bench. There
/// are five parameters: TT size in MB, number of search threads that
/// should be used, the limit value spent for each position, a file name
return list;
}
+
+} // namespace Stockfish
/*
Stockfish, a UCI chess playing engine derived from Glaurung 2.1
- Copyright (C) 2004-2020 The Stockfish developers (see AUTHORS file)
+ Copyright (C) 2004-2021 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
#include "bitboard.h"
#include "types.h"
+namespace Stockfish {
+
namespace {
// There are 24 possible pawn squares: files A to D and ranks from 2 to 7.
} // namespace
-
bool Bitbases::probe(Square wksq, Square wpsq, Square bksq, Color stm) {
assert(file_of(wpsq) <= FILE_D);
KPKBitbase.set(idx);
}
-
namespace {
KPKPosition::KPKPosition(unsigned idx) {
}
} // namespace
+
+} // namespace Stockfish
/*
Stockfish, a UCI chess playing engine derived from Glaurung 2.1
- Copyright (C) 2004-2020 The Stockfish developers (see AUTHORS file)
+ Copyright (C) 2004-2021 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
#include "bitboard.h"
#include "misc.h"
+namespace Stockfish {
+
uint8_t PopCnt16[1 << 16];
uint8_t SquareDistance[SQUARE_NB][SQUARE_NB];
}
-
/// safe_destination() returns the bitboard of target square for the given step
/// from the given square. If the step is off the board, returns empty bitboard.
/// Bitboards::pretty() returns an ASCII representation of a bitboard suitable
/// to be printed to standard output. Useful for debugging.
-const std::string Bitboards::pretty(Bitboard b) {
+std::string Bitboards::pretty(Bitboard b) {
std::string s = "+---+---+---+---+---+---+---+---+\n";
}
}
-
namespace {
Bitboard sliding_attack(PieceType pt, Square sq, Bitboard occupied) {
}
}
}
+
+} // namespace Stockfish
/*
Stockfish, a UCI chess playing engine derived from Glaurung 2.1
- Copyright (C) 2004-2020 The Stockfish developers (see AUTHORS file)
+ Copyright (C) 2004-2021 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
#include "types.h"
+namespace Stockfish {
+
namespace Bitbases {
void init();
bool probe(Square wksq, Square wpsq, Square bksq, Color us);
-}
+} // namespace Stockfish::Bitbases
namespace Bitboards {
void init();
-const std::string pretty(Bitboard b);
+std::string pretty(Bitboard b);
-}
+} // namespace Stockfish::Bitboards
constexpr Bitboard AllSquares = ~Bitboard(0);
constexpr Bitboard DarkSquares = 0xAA55AA55AA55AA55ULL;
return c == WHITE ? msb(b) : lsb(b);
}
+} // namespace Stockfish
+
#endif // #ifndef BITBOARD_H_INCLUDED
/*
Stockfish, a UCI chess playing engine derived from Glaurung 2.1
- Copyright (C) 2004-2020 The Stockfish developers (see AUTHORS file)
+ Copyright (C) 2004-2021 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
#include "endgame.h"
#include "movegen.h"
+namespace Stockfish {
+
namespace {
// Used to drive the king towards the edge of the board
// it's probably at least a draw even with the pawn.
return Bitbases::probe(strongKing, strongPawn, weakKing, us) ? SCALE_FACTOR_NONE : SCALE_FACTOR_DRAW;
}
+
+} // namespace Stockfish
/*
Stockfish, a UCI chess playing engine derived from Glaurung 2.1
- Copyright (C) 2004-2020 The Stockfish developers (see AUTHORS file)
+ Copyright (C) 2004-2021 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
#include "position.h"
#include "types.h"
+namespace Stockfish {
/// EndgameCode lists all supported endgame functions by corresponding codes
}
}
+} // namespace Stockfish
+
#endif // #ifndef ENDGAME_H_INCLUDED
/*
Stockfish, a UCI chess playing engine derived from Glaurung 2.1
- Copyright (C) 2004-2020 The Stockfish developers (see AUTHORS file)
+ Copyright (C) 2004-2021 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
#include "incbin/incbin.h"
-// Macro to embed the default NNUE file data in the engine binary (using incbin.h, by Dale Weiler).
+// Macro to embed the default efficiently updatable neural network (NNUE) file
+// data in the engine binary (using incbin.h, by Dale Weiler).
// This macro invocation will declare the following three variables
// const unsigned char gEmbeddedNNUEData[]; // a pointer to the embedded data
// const unsigned char *const gEmbeddedNNUEEnd; // a marker to the end
// const unsigned int gEmbeddedNNUESize; // the size of the embedded file
-// Note that this does not work in Microsof Visual Studio.
+// Note that this does not work in Microsoft Visual Studio.
#if !defined(_MSC_VER) && !defined(NNUE_EMBEDDING_OFF)
INCBIN(EmbeddedNNUE, EvalFileDefaultName);
#else
using namespace std;
-using namespace Eval::NNUE;
+using namespace Stockfish::Eval::NNUE;
+
+namespace Stockfish {
namespace Eval {
bool useNNUE;
string eval_file_loaded = "None";
- /// NNUE::init() tries to load a nnue network at startup time, or when the engine
+ /// NNUE::init() tries to load a NNUE network at startup time, or when the engine
/// receives a UCI command "setoption name EvalFile value nn-[a-z0-9]{12}.nnue"
- /// The name of the nnue network is always retrieved from the EvalFile option.
+ /// The name of the NNUE network is always retrieved from the EvalFile option.
/// We search the given network in three locations: internally (the default
/// network may be embedded in the binary), in the active working directory and
/// in the engine directory. Distro packagers may define the DEFAULT_NNUE_DIRECTORY
// BishopPawns[distance from edge] contains a file-dependent penalty for pawns on
// squares of the same color as our bishop.
constexpr Score BishopPawns[int(FILE_NB) / 2] = {
- S(3, 8), S(3, 9), S(1, 8), S(3, 7)
+ S(3, 8), S(3, 9), S(2, 8), S(3, 8)
};
// KingProtector[knight/bishop] contains penalty for each distance unit to own king
// Outpost[knight/bishop] contains bonuses for each knight or bishop occupying a
// pawn protected square on rank 4 to 6 which is also safe from a pawn attack.
- constexpr Score Outpost[] = { S(56, 34), S(31, 23) };
+ constexpr Score Outpost[] = { S(57, 38), S(31, 24) };
// PassedRank[Rank] contains a bonus according to the rank of a passed pawn
constexpr Score PassedRank[RANK_NB] = {
};
// Assorted bonuses and penalties
- constexpr Score BadOutpost = S( -7, 36);
+ constexpr Score UncontestedOutpost = S( 1, 10);
constexpr Score BishopOnKingRing = S( 24, 0);
constexpr Score BishopXRayPawns = S( 4, 5);
constexpr Score CorneredBishop = S( 50, 50);
score += BishopOnKingRing;
int mob = popcount(b & mobilityArea[Us]);
-
mobility[Us] += MobilityBonus[Pt - 2][mob];
if (Pt == BISHOP || Pt == KNIGHT)
{
// Bonus if the piece is on an outpost square or can reach one
- // Reduced bonus for knights (BadOutpost) if few relevant targets
+ // Bonus for knights (UncontestedOutpost) if few relevant targets
bb = OutpostRanks & (attackedBy[Us][PAWN] | shift<Down>(pos.pieces(PAWN)))
& ~pe->pawn_attacks_span(Them);
Bitboard targets = pos.pieces(Them) & ~pos.pieces(PAWN);
&& bb & s & ~CenterFiles // on a side outpost
&& !(b & targets) // no relevant attacks
&& (!more_than_one(targets & (s & QueenSide ? QueenSide : KingSide))))
- score += BadOutpost;
+ score += UncontestedOutpost * popcount(pos.pieces(PAWN) & (s & QueenSide ? QueenSide : KingSide));
else if (bb & s)
score += Outpost[Pt == BISHOP];
else if (Pt == KNIGHT && bb & b & ~pos.pieces(Us))
// Penalty if the piece is far from the king
score -= KingProtector[Pt == BISHOP] * distance(pos.square<KING>(Us), s);
- if (Pt == BISHOP)
+ if constexpr (Pt == BISHOP)
{
// Penalty according to the number of our pawns on the same color square as the
// bishop, bigger when the center files are blocked with pawns and smaller
}
}
- if (Pt == ROOK)
+ if constexpr (Pt == ROOK)
{
// Bonuses for rook on a (semi-)open or closed file
if (pos.is_on_semiopen_file(Us, s))
}
}
- if (Pt == QUEEN)
+ if constexpr (Pt == QUEEN)
{
// Penalty if any relative pin or discovered attack against the queen
Bitboard queenPinners;
score -= WeakQueen;
}
}
- if (T)
+ if constexpr (T)
Trace::add(Pt, Us, score);
return score;
// Penalty if king flank is under attack, potentially moving toward the king
score -= FlankAttacks * kingFlankAttack;
- if (T)
+ if constexpr (T)
Trace::add(KING, Us, score);
return score;
score += SliderOnQueen * popcount(b & safe & attackedBy2[Us]) * (1 + queenImbalance);
}
- if (T)
+ if constexpr (T)
Trace::add(THREAT, Us, score);
return score;
score += bonus - PassedFile * edge_distance(file_of(s));
}
- if (T)
+ if constexpr (T)
Trace::add(PASSED, Us, score);
return score;
int weight = pos.count<ALL_PIECES>(Us) - 3 + std::min(pe->blocked_count(), 9);
Score score = make_score(bonus * weight * weight / 16, 0);
- if (T)
+ if constexpr (T)
Trace::add(SPACE, Us, score);
return score;
+ eg * int(PHASE_MIDGAME - me->game_phase()) * ScaleFactor(sf) / SCALE_FACTOR_NORMAL;
v /= PHASE_MIDGAME;
- if (T)
+ if constexpr (T)
{
Trace::add(WINNABLE, make_score(u, eg * ScaleFactor(sf) / SCALE_FACTOR_NORMAL - eg_value(score)));
Trace::add(TOTAL, make_score(mg, eg * ScaleFactor(sf) / SCALE_FACTOR_NORMAL));
Value v = winnable(score);
// In case of tracing add all remaining individual evaluation terms
- if (T)
+ if constexpr (T)
{
Trace::add(MATERIAL, pos.psq_score());
Trace::add(IMBALANCE, me->imbalance());
{
// Scale and shift NNUE for compatibility with search and classical evaluation
auto adjusted_NNUE = [&](){
- int mat = pos.non_pawn_material() + PawnValueMg * pos.count<PAWN>();
- return NNUE::evaluate(pos) * (679 + mat / 32) / 1024 + Tempo;
+ int mat = pos.non_pawn_material() + 2 * PawnValueMg * pos.count<PAWN>();
+ return NNUE::evaluate(pos) * (641 + mat / 32 - 4 * pos.rule50_count()) / 1024 + Tempo;
};
// If there is PSQ imbalance use classical eval, with small probability if it is small
return ss.str();
}
+
+} // namespace Stockfish
/*
Stockfish, a UCI chess playing engine derived from Glaurung 2.1
- Copyright (C) 2004-2020 The Stockfish developers (see AUTHORS file)
+ Copyright (C) 2004-2021 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
#include "types.h"
+namespace Stockfish {
+
class Position;
namespace Eval {
} // namespace Eval
+} // namespace Stockfish
+
#endif // #ifndef EVALUATE_H_INCLUDED
/*
Stockfish, a UCI chess playing engine derived from Glaurung 2.1
- Copyright (C) 2004-2020 The Stockfish developers (see AUTHORS file)
+ Copyright (C) 2004-2021 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
#include "bitboard.h"
#include "endgame.h"
#include "position.h"
+#include "psqt.h"
#include "search.h"
+#include "syzygy/tbprobe.h"
#include "thread.h"
#include "tt.h"
#include "uci.h"
-#include "syzygy/tbprobe.h"
#include <grpc/grpc.h>
#include <grpc++/server.h>
void init();
}
+using namespace Stockfish;
+
int main(int argc, char* argv[]) {
std::cout << engine_info() << std::endl;
/*
Stockfish, a UCI chess playing engine derived from Glaurung 2.1
- Copyright (C) 2004-2020 The Stockfish developers (see AUTHORS file)
+ Copyright (C) 2004-2021 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
using namespace std;
+namespace Stockfish {
+
namespace {
#define S(mg, eg) make_score(mg, eg)
// Polynomial material imbalance parameters
+ // One Score parameter for each pair (our piece, another of our pieces)
constexpr Score QuadraticOurs[][PIECE_TYPE_NB] = {
- // OUR PIECES
- // pair pawn knight bishop rook queen
+ // OUR PIECE 2
+ // bishop pair pawn knight bishop rook queen
{S(1419, 1455) }, // Bishop pair
{S( 101, 28), S( 37, 39) }, // Pawn
- {S( 57, 64), S(249, 187), S(-49, -62) }, // Knight OUR PIECES
+ {S( 57, 64), S(249, 187), S(-49, -62) }, // Knight OUR PIECE 1
{S( 0, 0), S(118, 137), S( 10, 27), S( 0, 0) }, // Bishop
{S( -63, -68), S( -5, 3), S(100, 81), S(132, 118), S(-246, -244) }, // Rook
{S(-210, -211), S( 37, 14), S(147, 141), S(161, 105), S(-158, -174), S(-9,-31) } // Queen
};
+ // One Score parameter for each pair (our piece, their piece)
constexpr Score QuadraticTheirs[][PIECE_TYPE_NB] = {
- // THEIR PIECES
- // pair pawn knight bishop rook queen
+ // THEIR PIECE
+ // bishop pair pawn knight bishop rook queen
{ }, // Bishop pair
{S( 33, 30) }, // Pawn
- {S( 46, 18), S(106, 84) }, // Knight OUR PIECES
+ {S( 46, 18), S(106, 84) }, // Knight OUR PIECE
{S( 75, 35), S( 59, 44), S( 60, 15) }, // Bishop
{S( 26, 35), S( 6, 22), S( 38, 39), S(-12, -2) }, // Rook
{S( 97, 93), S(100, 163), S(-58, -91), S(112, 192), S(276, 225) } // Queen
}
} // namespace Material
+
+} // namespace Stockfish
/*
Stockfish, a UCI chess playing engine derived from Glaurung 2.1
- Copyright (C) 2004-2020 The Stockfish developers (see AUTHORS file)
+ Copyright (C) 2004-2021 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
#include "position.h"
#include "types.h"
-namespace Material {
+namespace Stockfish::Material {
/// Material::Entry contains various information about a material configuration.
/// It contains a material imbalance evaluation, a function pointer to a special
Entry* probe(const Position& pos);
-} // namespace Material
+} // namespace Stockfish::Material
#endif // #ifndef MATERIAL_H_INCLUDED
/*
Stockfish, a UCI chess playing engine derived from Glaurung 2.1
- Copyright (C) 2004-2020 The Stockfish developers (see AUTHORS file)
+ Copyright (C) 2004-2021 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
using namespace std;
+namespace Stockfish {
+
namespace {
/// Version number. If Version is left empty, then compile date in the format
/// the program was compiled) or "Stockfish <Version>", depending on whether
/// Version is empty.
-const string engine_info(bool to_uci) {
+string engine_info(bool to_uci) {
const string months("Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec");
string month, day, year;
/// compiler_info() returns a string trying to describe the compiler we use
-const std::string compiler_info() {
+std::string compiler_info() {
#define stringify2(x) #x
#define stringify(x) stringify2(x)
/// aligned_large_pages_alloc() will return suitably aligned memory, if possible using large pages.
#if defined(_WIN32)
-
+#if defined(_WIN64)
static void* aligned_large_pages_alloc_win(size_t allocSize) {
HANDLE hProcessToken { };
return mem;
}
+#endif
void* aligned_large_pages_alloc(size_t allocSize) {
+#if defined(_WIN64)
// Try to allocate large pages
void* mem = aligned_large_pages_alloc_win(allocSize);
// Fall back to regular, page aligned, allocation if necessary
if (!mem)
mem = VirtualAlloc(NULL, allocSize, MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE);
+#else
+ void* mem = VirtualAlloc(NULL, allocSize, MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE);
+#endif
return mem;
}
} // namespace CommandLine
+
+} // namespace Stockfish
/*
Stockfish, a UCI chess playing engine derived from Glaurung 2.1
- Copyright (C) 2004-2020 The Stockfish developers (see AUTHORS file)
+ Copyright (C) 2004-2021 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
#include "types.h"
-const std::string engine_info(bool to_uci = false);
-const std::string compiler_info();
+namespace Stockfish {
+
+std::string engine_info(bool to_uci = false);
+std::string compiler_info();
void prefetch(void* addr);
void start_logger(const std::string& fname);
void* std_aligned_alloc(size_t alignment, size_t size);
extern std::string workingDirectory; // path of the working directory
}
+} // namespace Stockfish
+
#endif // #ifndef MISC_H_INCLUDED
/*
Stockfish, a UCI chess playing engine derived from Glaurung 2.1
- Copyright (C) 2004-2020 The Stockfish developers (see AUTHORS file)
+ Copyright (C) 2004-2021 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
#include "movegen.h"
#include "position.h"
+namespace Stockfish {
+
namespace {
template<GenType Type, Direction D>
// Add pawn pushes which give discovered check. This is possible only
// if the pawn is not on the same file as the enemy king, because we
- // don't generate captures. Note that a possible discovery check
+ // don't generate captures. Note that a possible discovered check
// promotion has been already generated amongst the captures.
Bitboard dcCandidateQuiets = pos.blockers_for_king(Them) & pawnsNotOn7;
if (dcCandidateQuiets)
moveList = make_promotions<Type, Up >(moveList, pop_lsb(&b3), ksq);
}
- // Standard and en-passant captures
+ // Standard and en passant captures
if (Type == CAPTURES || Type == EVASIONS || Type == NON_EVASIONS)
{
Bitboard b1 = shift<UpRight>(pawnsNotOn7) & enemies;
{
assert(rank_of(pos.ep_square()) == relative_rank(Us, RANK_6));
- // An en passant capture can be an evasion only if the checking piece
- // is the double pushed pawn and so is in the target. Otherwise this
- // is a discovery check and we are forced to do otherwise.
- if (Type == EVASIONS && !(target & (pos.ep_square() - Up)))
+ // An en passant capture cannot resolve a discovered check.
+ if (Type == EVASIONS && (target & (pos.ep_square() + Up)))
return moveList;
b1 = pawnsNotOn7 & pawn_attacks_bb(Them, pos.ep_square());
assert(b1);
while (b1)
- *moveList++ = make<ENPASSANT>(pop_lsb(&b1), pos.ep_square());
+ *moveList++ = make<EN_PASSANT>(pop_lsb(&b1), pos.ep_square());
}
}
}
- template<Color Us, PieceType Pt, bool Checks>
- ExtMove* generate_moves(const Position& pos, ExtMove* moveList, Bitboard target) {
+ template<PieceType Pt, bool Checks>
+ ExtMove* generate_moves(const Position& pos, ExtMove* moveList, Bitboard piecesToMove, Bitboard target) {
static_assert(Pt != KING && Pt != PAWN, "Unsupported piece type in generate_moves()");
- Bitboard bb = pos.pieces(Us, Pt);
+ Bitboard bb = piecesToMove & pos.pieces(Pt);
- while (bb) {
- Square from = pop_lsb(&bb);
+ if (!bb)
+ return moveList;
- if (Checks)
- {
- if ( (Pt == BISHOP || Pt == ROOK || Pt == QUEEN)
- && !(attacks_bb<Pt>(from) & target & pos.check_squares(Pt)))
- continue;
+ [[maybe_unused]] const Bitboard checkSquares = pos.check_squares(Pt);
- if (pos.blockers_for_king(~Us) & from)
- continue;
- }
+ while (bb) {
+ Square from = pop_lsb(&bb);
Bitboard b = attacks_bb<Pt>(from, pos.pieces()) & target;
-
- if (Checks)
- b &= pos.check_squares(Pt);
+ if constexpr (Checks)
+ b &= checkSquares;
while (b)
*moveList++ = make_move(from, pop_lsb(&b));
template<Color Us, GenType Type>
ExtMove* generate_all(const Position& pos, ExtMove* moveList) {
- constexpr bool Checks = Type == QUIET_CHECKS; // Reduce template instantations
- Bitboard target;
+
+ static_assert(Type != LEGAL, "Unsupported type in generate_all()");
+
+ constexpr bool Checks = Type == QUIET_CHECKS; // Reduce template instantiations
+ Bitboard target, piecesToMove = pos.pieces(Us);
+
+ if(Type == QUIET_CHECKS)
+ piecesToMove &= ~pos.blockers_for_king(~Us);
switch (Type)
{
target = ~pos.pieces();
break;
case EVASIONS:
- {
- Square checksq = lsb(pos.checkers());
- target = between_bb(pos.square<KING>(Us), checksq) | checksq;
+ target = between_bb(pos.square<KING>(Us), lsb(pos.checkers())) | pos.checkers();
break;
- }
case NON_EVASIONS:
target = ~pos.pieces(Us);
break;
- default:
- static_assert(true, "Unsupported type in generate_all()");
}
moveList = generate_pawn_moves<Us, Type>(pos, moveList, target);
- moveList = generate_moves<Us, KNIGHT, Checks>(pos, moveList, target);
- moveList = generate_moves<Us, BISHOP, Checks>(pos, moveList, target);
- moveList = generate_moves<Us, ROOK, Checks>(pos, moveList, target);
- moveList = generate_moves<Us, QUEEN, Checks>(pos, moveList, target);
+ moveList = generate_moves<KNIGHT, Checks>(pos, moveList, piecesToMove, target);
+ moveList = generate_moves<BISHOP, Checks>(pos, moveList, piecesToMove, target);
+ moveList = generate_moves< ROOK, Checks>(pos, moveList, piecesToMove, target);
+ moveList = generate_moves< QUEEN, Checks>(pos, moveList, piecesToMove, target);
if (Type != QUIET_CHECKS && Type != EVASIONS)
{
/// <CAPTURES> Generates all pseudo-legal captures plus queen and checking knight promotions
-/// <QUIETS> Generates all pseudo-legal non-captures and underpromotions(except checking knight)
+/// <QUIETS> Generates all pseudo-legal non-captures and underpromotions (except checking knight)
/// <NON_EVASIONS> Generates all pseudo-legal captures and non-captures
///
/// Returns a pointer to the end of the move list.
template ExtMove* generate<NON_EVASIONS>(const Position&, ExtMove*);
-/// generate<QUIET_CHECKS> generates all pseudo-legal non-captures.
-/// Returns a pointer to the end of the move list.
+/// generate<QUIET_CHECKS> generates all pseudo-legal non-captures giving check,
+/// except castling. Returns a pointer to the end of the move list.
template<>
ExtMove* generate<QUIET_CHECKS>(const Position& pos, ExtMove* moveList) {
moveList = pos.checkers() ? generate<EVASIONS >(pos, moveList)
: generate<NON_EVASIONS>(pos, moveList);
while (cur != moveList)
- if ( (pinned || from_sq(*cur) == ksq || type_of(*cur) == ENPASSANT)
+ if ( ((pinned && pinned & from_sq(*cur)) || from_sq(*cur) == ksq || type_of(*cur) == EN_PASSANT)
&& !pos.legal(*cur))
*cur = (--moveList)->move;
else
return moveList;
}
+
+} // namespace Stockfish
/*
Stockfish, a UCI chess playing engine derived from Glaurung 2.1
- Copyright (C) 2004-2020 The Stockfish developers (see AUTHORS file)
+ Copyright (C) 2004-2021 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
#include "types.h"
+namespace Stockfish {
+
class Position;
enum GenType {
ExtMove moveList[MAX_MOVES], *last;
};
+} // namespace Stockfish
+
#endif // #ifndef MOVEGEN_H_INCLUDED
/*
Stockfish, a UCI chess playing engine derived from Glaurung 2.1
- Copyright (C) 2004-2020 The Stockfish developers (see AUTHORS file)
+ Copyright (C) 2004-2021 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
#include "movepick.h"
+namespace Stockfish {
+
namespace {
enum Stages {
static_assert(Type == CAPTURES || Type == QUIETS || Type == EVASIONS, "Wrong type");
for (auto& m : *this)
- if (Type == CAPTURES)
+ if constexpr (Type == CAPTURES)
m.value = int(PieceValue[MG][pos.piece_on(to_sq(m))]) * 6
+ (*captureHistory)[pos.moved_piece(m)][to_sq(m)][type_of(pos.piece_on(to_sq(m)))];
- else if (Type == QUIETS)
+ else if constexpr (Type == QUIETS)
m.value = (*mainHistory)[pos.side_to_move()][from_to(m)]
+ 2 * (*continuationHistory[0])[pos.moved_piece(m)][to_sq(m)]
- + 2 * (*continuationHistory[1])[pos.moved_piece(m)][to_sq(m)]
- + 2 * (*continuationHistory[3])[pos.moved_piece(m)][to_sq(m)]
+ + (*continuationHistory[1])[pos.moved_piece(m)][to_sq(m)]
+ + (*continuationHistory[3])[pos.moved_piece(m)][to_sq(m)]
+ (*continuationHistory[5])[pos.moved_piece(m)][to_sq(m)]
+ (ply < MAX_LPH ? std::min(4, depth / 3) * (*lowPlyHistory)[ply][from_to(m)] : 0);
m.value = PieceValue[MG][pos.piece_on(to_sq(m))]
- Value(type_of(pos.moved_piece(m)));
else
- m.value = (*mainHistory)[pos.side_to_move()][from_to(m)]
- + (*continuationHistory[0])[pos.moved_piece(m)][to_sq(m)]
+ m.value = (*mainHistory)[pos.side_to_move()][from_to(m)]
+ + 2 * (*continuationHistory[0])[pos.moved_piece(m)][to_sq(m)]
- (1 << 28);
}
}
}
/// MovePicker::next_move() is the most important method of the MovePicker class. It
-/// returns a new pseudo legal move every time it is called until there are no more
+/// returns a new pseudo-legal move every time it is called until there are no more
/// moves left, picking the move with the highest score from a list of generated moves.
Move MovePicker::next_move(bool skipQuiets) {
assert(false);
return MOVE_NONE; // Silence warning
}
+
+} // namespace Stockfish
/*
Stockfish, a UCI chess playing engine derived from Glaurung 2.1
- Copyright (C) 2004-2020 The Stockfish developers (see AUTHORS file)
+ Copyright (C) 2004-2021 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
#include "position.h"
#include "types.h"
+namespace Stockfish {
+
/// 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 naked value
/// to directly call history update operator<<() on the entry so to use stats
/// 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
-typedef Stats<int16_t, 10692, COLOR_NB, int(SQUARE_NB) * int(SQUARE_NB)> ButterflyHistory;
+typedef Stats<int16_t, 13365, COLOR_NB, int(SQUARE_NB) * int(SQUARE_NB)> ButterflyHistory;
/// At higher depths LowPlyHistory records successful quiet moves near the root
/// and quiet moves which are/were in the PV (ttPv). It is cleared with each new
typedef Stats<PieceToHistory, NOT_USED, PIECE_NB, SQUARE_NB> ContinuationHistory;
-/// MovePicker class is used to pick one pseudo legal move at a time from 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 returns a
-/// new pseudo legal move each time it is called, until there are no moves left,
-/// when MOVE_NONE is returned. In order to improve the efficiency of the alpha
-/// beta algorithm, MovePicker attempts to return the moves which are most likely
-/// to get a cut-off first.
+/// new pseudo-legal move each time it is called, until there are no moves left,
+/// when MOVE_NONE is returned. In order to improve the efficiency of the
+/// alpha-beta algorithm, MovePicker attempts to return the moves which are most
+/// likely to get a cut-off first.
class MovePicker {
enum PickType { Next, Best };
ExtMove moves[MAX_MOVES];
};
+} // namespace Stockfish
+
#endif // #ifndef MOVEPICK_H_INCLUDED
/*
Stockfish, a UCI chess playing engine derived from Glaurung 2.1
- Copyright (C) 2004-2020 The Stockfish developers (see AUTHORS file)
+ Copyright (C) 2004-2021 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
#include "../layers/affine_transform.h"
#include "../layers/clipped_relu.h"
-namespace Eval::NNUE {
+namespace Stockfish::Eval::NNUE {
// Input features used in evaluation function
using RawFeatures = Features::FeatureSet<
using Network = Layers::OutputLayer;
-} // namespace Eval::NNUE
+} // namespace Stockfish::Eval::NNUE
#endif // #ifndef NNUE_HALFKP_256X2_32_32_H_INCLUDED
/*
Stockfish, a UCI chess playing engine derived from Glaurung 2.1
- Copyright (C) 2004-2020 The Stockfish developers (see AUTHORS file)
+ Copyright (C) 2004-2021 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
#include "evaluate_nnue.h"
-namespace Eval::NNUE {
+namespace Stockfish::Eval::NNUE {
// Input feature converter
LargePagePtr<FeatureTransformer> feature_transformer;
return ReadParameters(stream);
}
-} // namespace Eval::NNUE
+} // namespace Stockfish::Eval::NNUE
/*
Stockfish, a UCI chess playing engine derived from Glaurung 2.1
- Copyright (C) 2004-2020 The Stockfish developers (see AUTHORS file)
+ Copyright (C) 2004-2021 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
#include <memory>
-namespace Eval::NNUE {
+namespace Stockfish::Eval::NNUE {
// Hash value of evaluation function structure
constexpr std::uint32_t kHashValue =
template <typename T>
using LargePagePtr = std::unique_ptr<T, LargePageDeleter<T>>;
-} // namespace Eval::NNUE
+} // namespace Stockfish::Eval::NNUE
#endif // #ifndef NNUE_EVALUATE_NNUE_H_INCLUDED
/*
Stockfish, a UCI chess playing engine derived from Glaurung 2.1
- Copyright (C) 2004-2020 The Stockfish developers (see AUTHORS file)
+ Copyright (C) 2004-2021 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
#include "features_common.h"
#include <array>
-namespace Eval::NNUE::Features {
+namespace Stockfish::Eval::NNUE::Features {
// Class template that represents a list of values
template <typename T, T... Values>
};
-} // namespace Eval::NNUE::Features
+} // namespace Stockfish::Eval::NNUE::Features
#endif // #ifndef NNUE_FEATURE_SET_H_INCLUDED
/*
Stockfish, a UCI chess playing engine derived from Glaurung 2.1
- Copyright (C) 2004-2020 The Stockfish developers (see AUTHORS file)
+ Copyright (C) 2004-2021 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
#include "../../evaluate.h"
#include "../nnue_common.h"
-namespace Eval::NNUE::Features {
+namespace Stockfish::Eval::NNUE::Features {
class IndexList;
kFriend // side to move
};
-} // namespace Eval::NNUE::Features
+} // namespace Stockfish::Eval::NNUE::Features
#endif // #ifndef NNUE_FEATURES_COMMON_H_INCLUDED
/*
Stockfish, a UCI chess playing engine derived from Glaurung 2.1
- Copyright (C) 2004-2020 The Stockfish developers (see AUTHORS file)
+ Copyright (C) 2004-2021 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
#include "half_kp.h"
#include "index_list.h"
-namespace Eval::NNUE::Features {
+namespace Stockfish::Eval::NNUE::Features {
// Orient a square according to perspective (rotates by 180 for black)
inline Square orient(Color perspective, Square s) {
template class HalfKP<Side::kFriend>;
-} // namespace Eval::NNUE::Features
+} // namespace Stockfish::Eval::NNUE::Features
/*
Stockfish, a UCI chess playing engine derived from Glaurung 2.1
- Copyright (C) 2004-2020 The Stockfish developers (see AUTHORS file)
+ Copyright (C) 2004-2021 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
#include "../../evaluate.h"
#include "features_common.h"
-namespace Eval::NNUE::Features {
+namespace Stockfish::Eval::NNUE::Features {
// Feature HalfKP: Combination of the position of own king
// and the position of pieces other than kings
IndexList* removed, IndexList* added);
};
-} // namespace Eval::NNUE::Features
+} // namespace Stockfish::Eval::NNUE::Features
#endif // #ifndef NNUE_FEATURES_HALF_KP_H_INCLUDED
/*
Stockfish, a UCI chess playing engine derived from Glaurung 2.1
- Copyright (C) 2004-2020 The Stockfish developers (see AUTHORS file)
+ Copyright (C) 2004-2021 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
#include "../../position.h"
#include "../nnue_architecture.h"
-namespace Eval::NNUE::Features {
+namespace Stockfish::Eval::NNUE::Features {
// Class template used for feature index list
template <typename T, std::size_t MaxSize>
: public ValueList<IndexType, RawFeatures::kMaxActiveDimensions> {
};
-} // namespace Eval::NNUE::Features
+} // namespace Stockfish::Eval::NNUE::Features
#endif // NNUE_FEATURES_INDEX_LIST_H_INCLUDED
/*
Stockfish, a UCI chess playing engine derived from Glaurung 2.1
- Copyright (C) 2004-2020 The Stockfish developers (see AUTHORS file)
+ Copyright (C) 2004-2021 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
#include <iostream>
#include "../nnue_common.h"
-namespace Eval::NNUE::Layers {
+namespace Stockfish::Eval::NNUE::Layers {
// Affine transformation layer
template <typename PreviousLayer, IndexType OutputDimensions>
static constexpr IndexType kOutputDimensions = OutputDimensions;
static constexpr IndexType kPaddedInputDimensions =
CeilToMultiple<IndexType>(kInputDimensions, kMaxSimdWidth);
+#if defined (USE_AVX512)
+ static constexpr const IndexType kOutputSimdWidth = kSimdWidth / 2;
+#elif defined (USE_SSSE3)
+ static constexpr const IndexType kOutputSimdWidth = kSimdWidth / 4;
+#endif
// Size of forward propagation buffer used in this layer
static constexpr std::size_t kSelfBufferSize =
for (std::size_t i = 0; i < kOutputDimensions; ++i)
biases_[i] = read_little_endian<BiasType>(stream);
for (std::size_t i = 0; i < kOutputDimensions * kPaddedInputDimensions; ++i)
+#if !defined (USE_SSSE3)
weights_[i] = read_little_endian<WeightType>(stream);
+#else
+ weights_[
+ (i / 4) % (kPaddedInputDimensions / 4) * kOutputDimensions * 4 +
+ i / kPaddedInputDimensions * 4 +
+ i % 4
+ ] = read_little_endian<WeightType>(stream);
-#if defined (USE_SSSE3)
- // Determine if quadruplets of weight and input products can be summed using 16bits
+ // Determine if eights of weight and input products can be summed using 16bits
// without saturation. We assume worst case combinations of 0 and 127 for all inputs.
- if (!stream.fail())
+ if (kOutputDimensions > 1 && !stream.fail())
{
- auto can_saturate = [](const WeightType* w, int idx[4]) {
- int pSum = 0, nSum = 0;
- for (int p = 0; p < 4; ++p)
- if (w[idx[p]] > 0)
- pSum += w[idx[p]];
- else
- nSum += w[idx[p]];
-
- return pSum > 258 || nSum < -258;
- };
-
- for (IndexType i = 0; i < kOutputDimensions; ++i)
- {
- canSaturate16[i] = false;
- const WeightType* w = &weights_[i * kPaddedInputDimensions];
-#if defined (USE_AVX512)
- for (IndexType j = 0; j < (kPaddedInputDimensions & ~127) && !canSaturate16[i]; j += 128)
- for (int k = 0; k < 64 && !canSaturate16[i]; k += 2)
- {
- int spacing[4] = { 0, 1, 64, 65 };
- canSaturate16[i] = can_saturate(&w[j + k], spacing);
- }
-#elif defined (USE_AVX2)
- for (IndexType j = 0; j < (kPaddedInputDimensions & ~63) && !canSaturate16[i]; j += 64)
- for (int k = 0; k < 32 && !canSaturate16[i]; k += 2)
+ canSaturate16.count = 0;
+#if !defined(USE_VNNI)
+ for (IndexType i = 0; i < kPaddedInputDimensions; i += 16)
+ for (IndexType j = 0; j < kOutputDimensions; ++j)
+ for (int x = 0; x < 2; ++x)
{
- int spacing[4] = { 0, 1, 32, 33 };
- canSaturate16[i] = can_saturate(&w[j + k], spacing);
- }
-#elif defined (USE_SSSE3)
- for (IndexType j = 0; j < (kPaddedInputDimensions & ~31) && !canSaturate16[i]; j += 32)
- for (int k = 0; k < 16 && !canSaturate16[i]; k += 2)
- {
- int spacing[4] = { 0, 1, 16, 17 };
- canSaturate16[i] = can_saturate(&w[j + k], spacing);
+ WeightType* w = &weights_[i * kOutputDimensions + j * 4 + x * 2];
+ int sum[2] = {0, 0};
+ for (int k = 0; k < 8; ++k)
+ {
+ IndexType idx = k / 2 * kOutputDimensions * 4 + k % 2;
+ sum[w[idx] < 0] += w[idx];
+ }
+ for (int sign : {-1, 1})
+ while (sign * sum[sign == -1] > 258)
+ {
+ int maxK = 0, maxW = 0;
+ for (int k = 0; k < 8; ++k)
+ {
+ IndexType idx = k / 2 * kOutputDimensions * 4 + k % 2;
+ if (maxW < sign * w[idx])
+ maxK = k, maxW = sign * w[idx];
+ }
+
+ IndexType idx = maxK / 2 * kOutputDimensions * 4 + maxK % 2;
+ sum[sign == -1] -= w[idx];
+ canSaturate16.add(j, i + maxK / 2 * 4 + maxK % 2 + x * 2, w[idx]);
+ w[idx] = 0;
+ }
}
+
+ // Non functional optimization for faster more linear access
+ std::sort(canSaturate16.ids, canSaturate16.ids + canSaturate16.count,
+ [](const typename CanSaturate::Entry& e1, const typename CanSaturate::Entry& e2)
+ { return e1.in == e2.in ? e1.out < e2.out : e1.in < e2.in; });
#endif
- }
}
#endif
return _mm512_reduce_add_epi32(sum) + bias;
};
- // This function takes
- // sum0 = [xmm0a, xmm0b, xmm0c, xmm0d]
- // sum1 = [xmm1a, xmm1b, xmm1c, xmm1d]
- // sum2 = [xmm2a, xmm2b, xmm2c, xmm2d]
- // sum3 = [xmm3a, xmm3b, xmm3c, xmm3d]
- // and returns
- // ret = [
- // reduce_add_epi32(xmm0a), reduce_add_epi32(xmm1a), reduce_add_epi32(xmm2a), reduce_add_epi32(xmm3a),
- // reduce_add_epi32(xmm0b), reduce_add_epi32(xmm1b), reduce_add_epi32(xmm2b), reduce_add_epi32(xmm3b),
- // reduce_add_epi32(xmm0c), reduce_add_epi32(xmm1c), reduce_add_epi32(xmm2c), reduce_add_epi32(xmm3c),
- // reduce_add_epi32(xmm0d), reduce_add_epi32(xmm1d), reduce_add_epi32(xmm2d), reduce_add_epi32(xmm3d)
- // ]
- [[maybe_unused]] auto m512_hadd128x16_interleave = [](
- __m512i sum0, __m512i sum1, __m512i sum2, __m512i sum3) -> __m512i {
-
- __m512i sum01a = _mm512_unpacklo_epi32(sum0, sum1);
- __m512i sum01b = _mm512_unpackhi_epi32(sum0, sum1);
-
- __m512i sum23a = _mm512_unpacklo_epi32(sum2, sum3);
- __m512i sum23b = _mm512_unpackhi_epi32(sum2, sum3);
-
- __m512i sum01 = _mm512_add_epi32(sum01a, sum01b);
- __m512i sum23 = _mm512_add_epi32(sum23a, sum23b);
-
- __m512i sum0123a = _mm512_unpacklo_epi64(sum01, sum23);
- __m512i sum0123b = _mm512_unpackhi_epi64(sum01, sum23);
-
- return _mm512_add_epi32(sum0123a, sum0123b);
- };
-
- [[maybe_unused]] auto m512_haddx4 = [m512_hadd128x16_interleave](
- __m512i sum0, __m512i sum1, __m512i sum2, __m512i sum3, __m128i bias) -> __m128i {
-
- __m512i sum = m512_hadd128x16_interleave(sum0, sum1, sum2, sum3);
-
- __m256i sum256lo = _mm512_castsi512_si256(sum);
- __m256i sum256hi = _mm512_extracti64x4_epi64(sum, 1);
-
- sum256lo = _mm256_add_epi32(sum256lo, sum256hi);
-
- __m128i sum128lo = _mm256_castsi256_si128(sum256lo);
- __m128i sum128hi = _mm256_extracti128_si256(sum256lo, 1);
-
- return _mm_add_epi32(_mm_add_epi32(sum128lo, sum128hi), bias);
- };
-
- [[maybe_unused]] auto m512_haddx8 = [m512_hadd128x16_interleave](
- __m512i sum0, __m512i sum1, __m512i sum2, __m512i sum3,
- __m512i sum4, __m512i sum5, __m512i sum6, __m512i sum7, __m256i bias) -> __m256i {
-
- __m512i suma = m512_hadd128x16_interleave(sum0, sum1, sum2, sum3);
- __m512i sumb = m512_hadd128x16_interleave(sum4, sum5, sum6, sum7);
-
- __m512i indices0 = _mm512_setr_epi64(0, 1, 8, 9, 4, 5, 12, 13);
- __m512i indices1 = _mm512_setr_epi64(2, 3, 10, 11, 6, 7, 14, 15);
- __m512i x = _mm512_add_epi32(
- _mm512_permutex2var_epi64(suma, indices0, sumb),
- _mm512_permutex2var_epi64(suma, indices1, sumb));
-
- __m256i sum256lo = _mm512_castsi512_si256(x);
- __m256i sum256hi = _mm512_extracti64x4_epi64(x, 1);
-
- return _mm256_add_epi32(_mm256_add_epi32(sum256lo, sum256hi), bias);
- };
-
- [[maybe_unused]] auto m512_hadd256x8 =[m512_hadd128x16_interleave](
- __m512i sum0, __m512i sum1, __m512i sum2, __m512i sum3, __m256i bias) -> __m256i {
-
- __m512i sum = m512_hadd128x16_interleave(sum0, sum1, sum2, sum3);
-
- __m512i indices = _mm512_setr_epi32(
- 0, 4, 8, 12, 2, 6, 10, 14,
- 1, 5, 9, 13, 3, 7, 11, 15);
- sum = _mm512_permutexvar_epi32(indices, sum);
-
- __m256i sum256lo = _mm512_castsi512_si256(sum);
- __m256i sum256hi = _mm512_extracti64x4_epi64(sum, 1);
-
- return _mm256_add_epi32(_mm256_hadd_epi32(sum256lo, sum256hi), bias);
- };
-
- [[maybe_unused]] auto m512_hadd256x16 = [m512_hadd128x16_interleave](
- __m512i sum0, __m512i sum1, __m512i sum2, __m512i sum3,
- __m512i sum4, __m512i sum5, __m512i sum6, __m512i sum7, __m512i bias) -> __m512i {
-
- __m512i suma = m512_hadd128x16_interleave(sum0, sum1, sum2, sum3);
- __m512i sumb = m512_hadd128x16_interleave(sum4, sum5, sum6, sum7);
-
- __m512i indices0 = _mm512_setr_epi64(0, 1, 8, 9, 4, 5, 12, 13);
- __m512i indices1 = _mm512_setr_epi64(2, 3, 10, 11, 6, 7, 14, 15);
- __m512i x = _mm512_add_epi32(
- _mm512_permutex2var_epi64(suma, indices0, sumb),
- _mm512_permutex2var_epi64(suma, indices1, sumb));
-
- __m512i indices = _mm512_setr_epi32(0, 8, 1, 9, 2, 10, 3, 11, 4, 12, 5, 13, 6, 14, 7, 15);
- return _mm512_add_epi32(_mm512_permutexvar_epi32(indices, x), bias);
- };
-
[[maybe_unused]] auto m512_add_dpbusd_epi32 = [=](__m512i& acc, __m512i a, __m512i b) {
#if defined (USE_VNNI)
acc = _mm512_dpbusd_epi32(acc, a, b);
#endif
};
- [[maybe_unused]] auto m512_add_dpbusd_epi32x2 = [=](__m512i& acc, __m512i a0, __m512i b0, __m512i a1, __m512i b1) {
+ [[maybe_unused]] auto m512_add_dpbusd_epi32x4 = [=](__m512i& acc, __m512i a0, __m512i b0, __m512i a1, __m512i b1,
+ __m512i a2, __m512i b2, __m512i a3, __m512i b3) {
#if defined (USE_VNNI)
acc = _mm512_dpbusd_epi32(acc, a0, b0);
acc = _mm512_dpbusd_epi32(acc, a1, b1);
+ acc = _mm512_dpbusd_epi32(acc, a2, b2);
+ acc = _mm512_dpbusd_epi32(acc, a3, b3);
#else
__m512i product0 = _mm512_maddubs_epi16(a0, b0);
__m512i product1 = _mm512_maddubs_epi16(a1, b1);
- product0 = _mm512_adds_epi16(product0, product1);
+ __m512i product2 = _mm512_maddubs_epi16(a2, b2);
+ __m512i product3 = _mm512_maddubs_epi16(a3, b3);
+ product0 = _mm512_add_epi16(product0, product1);
+ product2 = _mm512_add_epi16(product2, product3);
+ product0 = _mm512_add_epi16(product0, product2);
product0 = _mm512_madd_epi16(product0, kOnes512);
acc = _mm512_add_epi32(acc, product0);
#endif
return _mm_cvtsi128_si32(sum128) + bias;
};
- [[maybe_unused]] auto m256_haddx4 = [](__m256i sum0, __m256i sum1, __m256i sum2, __m256i sum3, __m128i bias) -> __m128i {
- sum0 = _mm256_hadd_epi32(sum0, sum1);
- sum2 = _mm256_hadd_epi32(sum2, sum3);
-
- sum0 = _mm256_hadd_epi32(sum0, sum2);
-
- __m128i sum128lo = _mm256_castsi256_si128(sum0);
- __m128i sum128hi = _mm256_extracti128_si256(sum0, 1);
-
- return _mm_add_epi32(_mm_add_epi32(sum128lo, sum128hi), bias);
- };
-
[[maybe_unused]] auto m256_add_dpbusd_epi32 = [=](__m256i& acc, __m256i a, __m256i b) {
#if defined (USE_VNNI)
acc = _mm256_dpbusd_epi32(acc, a, b);
#endif
};
- [[maybe_unused]] auto m256_add_dpbusd_epi32x2 = [=](__m256i& acc, __m256i a0, __m256i b0, __m256i a1, __m256i b1) {
+ [[maybe_unused]] auto m256_add_dpbusd_epi32x4 = [=](__m256i& acc, __m256i a0, __m256i b0, __m256i a1, __m256i b1,
+ __m256i a2, __m256i b2, __m256i a3, __m256i b3) {
#if defined (USE_VNNI)
acc = _mm256_dpbusd_epi32(acc, a0, b0);
acc = _mm256_dpbusd_epi32(acc, a1, b1);
+ acc = _mm256_dpbusd_epi32(acc, a2, b2);
+ acc = _mm256_dpbusd_epi32(acc, a3, b3);
#else
__m256i product0 = _mm256_maddubs_epi16(a0, b0);
__m256i product1 = _mm256_maddubs_epi16(a1, b1);
- product0 = _mm256_adds_epi16(product0, product1);
+ __m256i product2 = _mm256_maddubs_epi16(a2, b2);
+ __m256i product3 = _mm256_maddubs_epi16(a3, b3);
+ product0 = _mm256_add_epi16(product0, product1);
+ product2 = _mm256_add_epi16(product2, product3);
+ product0 = _mm256_add_epi16(product0, product2);
product0 = _mm256_madd_epi16(product0, kOnes256);
acc = _mm256_add_epi32(acc, product0);
#endif
};
#endif
-
#if defined (USE_SSSE3)
[[maybe_unused]] const __m128i kOnes128 = _mm_set1_epi16(1);
return _mm_cvtsi128_si32(sum) + bias;
};
- [[maybe_unused]] auto m128_haddx4 = [](__m128i sum0, __m128i sum1, __m128i sum2, __m128i sum3, __m128i bias) -> __m128i {
- sum0 = _mm_hadd_epi32(sum0, sum1);
- sum2 = _mm_hadd_epi32(sum2, sum3);
-
- sum0 = _mm_hadd_epi32(sum0, sum2);
-
- return _mm_add_epi32(sum0, bias);
- };
-
[[maybe_unused]] auto m128_add_dpbusd_epi32 = [=](__m128i& acc, __m128i a, __m128i b) {
__m128i product0 = _mm_maddubs_epi16(a, b);
product0 = _mm_madd_epi16(product0, kOnes128);
acc = _mm_add_epi32(acc, product0);
};
- [[maybe_unused]] auto m128_add_dpbusd_epi32x2 = [=](__m128i& acc, __m128i a0, __m128i b0, __m128i a1, __m128i b1) {
+ [[maybe_unused]] auto m128_add_dpbusd_epi32x4 = [=](__m128i& acc, __m128i a0, __m128i b0, __m128i a1, __m128i b1,
+ __m128i a2, __m128i b2, __m128i a3, __m128i b3) {
__m128i product0 = _mm_maddubs_epi16(a0, b0);
__m128i product1 = _mm_maddubs_epi16(a1, b1);
+ __m128i product2 = _mm_maddubs_epi16(a2, b2);
+ __m128i product3 = _mm_maddubs_epi16(a3, b3);
product0 = _mm_adds_epi16(product0, product1);
+ product2 = _mm_adds_epi16(product2, product3);
+ product0 = _mm_adds_epi16(product0, product2);
product0 = _mm_madd_epi16(product0, kOnes128);
acc = _mm_add_epi32(acc, product0);
};
#endif
#if defined (USE_AVX512)
+ using vec_t = __m512i;
+ #define vec_setzero _mm512_setzero_si512
+ #define vec_set_32 _mm512_set1_epi32
+ auto& vec_add_dpbusd_32 = m512_add_dpbusd_epi32;
+ auto& vec_add_dpbusd_32x4 = m512_add_dpbusd_epi32x4;
+ auto& vec_hadd = m512_hadd;
+#elif defined (USE_AVX2)
+ using vec_t = __m256i;
+ #define vec_setzero _mm256_setzero_si256
+ #define vec_set_32 _mm256_set1_epi32
+ auto& vec_add_dpbusd_32 = m256_add_dpbusd_epi32;
+ auto& vec_add_dpbusd_32x4 = m256_add_dpbusd_epi32x4;
+ auto& vec_hadd = m256_hadd;
+#elif defined (USE_SSSE3)
+ using vec_t = __m128i;
+ #define vec_setzero _mm_setzero_si128
+ #define vec_set_32 _mm_set1_epi32
+ auto& vec_add_dpbusd_32 = m128_add_dpbusd_epi32;
+ auto& vec_add_dpbusd_32x4 = m128_add_dpbusd_epi32x4;
+ auto& vec_hadd = m128_hadd;
+#endif
- constexpr IndexType kNumChunks512 = kPaddedInputDimensions / (kSimdWidth * 2);
- constexpr IndexType kNumChunks256 = kPaddedInputDimensions / kSimdWidth;
+#if defined (USE_SSSE3)
const auto output = reinterpret_cast<OutputType*>(buffer);
+ const auto input_vector = reinterpret_cast<const vec_t*>(input);
- // Since to saturate a zmm register it takes 64 bytes we
- // cannot use AVX512 for the smaller affine transforms.
- // Instead we fallback to a AVX2 implementation if the
- // kInputDimensions isn't a multiple of 64.
- // Note that this means that for example for
- // kInputDimensions of 96 we fallback to AVX2 even though
- // the first 64 elements could be processed with AVX512.
- // This is caused by mixing the __m256 and __m512 variables
- // required to better handle that case and it would
- // require handling more cases statically not to lose performance.
- // This should be revisited if such input dimensions are to be considered.
- [[maybe_unused]] const auto input_vector512 = reinterpret_cast<const __m512i*>(input);
- [[maybe_unused]] const auto input_vector256 = reinterpret_cast<const __m256i*>(input);
+ static_assert(kOutputDimensions % kOutputSimdWidth == 0 || kOutputDimensions == 1);
// kOutputDimensions is either 1 or a multiple of kSimdWidth
// because then it is also an input dimension.
- if constexpr (kOutputDimensions % 16 == 0 && kNumChunks256 == 1)
+ if constexpr (kOutputDimensions % kOutputSimdWidth == 0)
{
- for (IndexType i = 0; i < kOutputDimensions; i += 16)
- {
- const IndexType offset01a = (i + 0) * kPaddedInputDimensions;
- const IndexType offset23a = (i + 2) * kPaddedInputDimensions;
- const IndexType offset45a = (i + 4) * kPaddedInputDimensions;
- const IndexType offset67a = (i + 6) * kPaddedInputDimensions;
- const IndexType offset01b = (i + 8) * kPaddedInputDimensions;
- const IndexType offset23b = (i + 10) * kPaddedInputDimensions;
- const IndexType offset45b = (i + 12) * kPaddedInputDimensions;
- const IndexType offset67b = (i + 14) * kPaddedInputDimensions;
-
- const __m512i bias = *reinterpret_cast<const __m512i*>(&biases_[i]);
- __m512i* outptr = reinterpret_cast<__m512i*>(&output[i]);
-
- __m512i sum01a = _mm512_setzero_si512();
- __m512i sum23a = _mm512_setzero_si512();
- __m512i sum45a = _mm512_setzero_si512();
- __m512i sum67a = _mm512_setzero_si512();
- __m512i sum01b = _mm512_setzero_si512();
- __m512i sum23b = _mm512_setzero_si512();
- __m512i sum45b = _mm512_setzero_si512();
- __m512i sum67b = _mm512_setzero_si512();
-
- const auto row01a = *reinterpret_cast<const __m512i*>(&weights_[offset01a]);
- const auto row23a = *reinterpret_cast<const __m512i*>(&weights_[offset23a]);
- const auto row45a = *reinterpret_cast<const __m512i*>(&weights_[offset45a]);
- const auto row67a = *reinterpret_cast<const __m512i*>(&weights_[offset67a]);
- const auto row01b = *reinterpret_cast<const __m512i*>(&weights_[offset01b]);
- const auto row23b = *reinterpret_cast<const __m512i*>(&weights_[offset23b]);
- const auto row45b = *reinterpret_cast<const __m512i*>(&weights_[offset45b]);
- const auto row67b = *reinterpret_cast<const __m512i*>(&weights_[offset67b]);
-
- const __m256i in256 = input_vector256[0];
- const __m512i in = _mm512_inserti64x4(_mm512_castsi256_si512(in256), in256, 1);
-
- m512_add_dpbusd_epi32(sum01a, in, row01a);
- m512_add_dpbusd_epi32(sum23a, in, row23a);
- m512_add_dpbusd_epi32(sum45a, in, row45a);
- m512_add_dpbusd_epi32(sum67a, in, row67a);
- m512_add_dpbusd_epi32(sum01b, in, row01b);
- m512_add_dpbusd_epi32(sum23b, in, row23b);
- m512_add_dpbusd_epi32(sum45b, in, row45b);
- m512_add_dpbusd_epi32(sum67b, in, row67b);
-
- *outptr = m512_hadd256x16(
- sum01a, sum23a, sum45a, sum67a,
- sum01b, sum23b, sum45b, sum67b, bias);
- }
- }
- else if constexpr (kOutputDimensions % 4 == 0)
- {
- for (IndexType i = 0; i < kOutputDimensions; i += 4)
- {
- const IndexType offset0 = (i + 0) * kPaddedInputDimensions;
- const IndexType offset1 = (i + 1) * kPaddedInputDimensions;
- const IndexType offset2 = (i + 2) * kPaddedInputDimensions;
- const IndexType offset3 = (i + 3) * kPaddedInputDimensions;
+ constexpr IndexType kNumChunks = kPaddedInputDimensions / 4;
- const __m128i bias = *reinterpret_cast<const __m128i*>(&biases_[i]);
- __m128i* outptr = reinterpret_cast<__m128i*>(&output[i]);
+ const auto input32 = reinterpret_cast<const std::int32_t*>(input);
+ vec_t* outptr = reinterpret_cast<vec_t*>(output);
+ std::memcpy(output, biases_, kOutputDimensions * sizeof(OutputType));
- if constexpr (kPaddedInputDimensions % (kSimdWidth * 2) == 0)
+ for (int i = 0; i < (int)kNumChunks - 3; i += 4)
{
- __m512i sum0 = _mm512_setzero_si512();
- __m512i sum1 = _mm512_setzero_si512();
- __m512i sum2 = _mm512_setzero_si512();
- __m512i sum3 = _mm512_setzero_si512();
-
- const auto row0 = reinterpret_cast<const __m512i*>(&weights_[offset0]);
- const auto row1 = reinterpret_cast<const __m512i*>(&weights_[offset1]);
- const auto row2 = reinterpret_cast<const __m512i*>(&weights_[offset2]);
- const auto row3 = reinterpret_cast<const __m512i*>(&weights_[offset3]);
-
- int j = 0;
- if (!canSaturate16x4[i / 4])
- {
- for (; j < (int)kNumChunks512 - 1; j += 2)
- {
- const __m512i in0 = input_vector512[j];
- const __m512i in1 = input_vector512[j + 1];
-
- m512_add_dpbusd_epi32x2(sum0, in0, row0[j], in1, row0[j + 1]);
- m512_add_dpbusd_epi32x2(sum1, in0, row1[j], in1, row1[j + 1]);
- m512_add_dpbusd_epi32x2(sum2, in0, row2[j], in1, row2[j + 1]);
- m512_add_dpbusd_epi32x2(sum3, in0, row3[j], in1, row3[j + 1]);
- }
- }
- for (; j < (int)kNumChunks512; ++j)
- {
- const __m512i in = input_vector512[j];
-
- m512_add_dpbusd_epi32(sum0, in, row0[j]);
- m512_add_dpbusd_epi32(sum1, in, row1[j]);
- m512_add_dpbusd_epi32(sum2, in, row2[j]);
- m512_add_dpbusd_epi32(sum3, in, row3[j]);
- }
-
- *outptr = m512_haddx4(sum0, sum1, sum2, sum3, bias);
+ const vec_t in0 = vec_set_32(input32[i + 0]);
+ const vec_t in1 = vec_set_32(input32[i + 1]);
+ const vec_t in2 = vec_set_32(input32[i + 2]);
+ const vec_t in3 = vec_set_32(input32[i + 3]);
+ const auto col0 = reinterpret_cast<const vec_t*>(&weights_[(i + 0) * kOutputDimensions * 4]);
+ const auto col1 = reinterpret_cast<const vec_t*>(&weights_[(i + 1) * kOutputDimensions * 4]);
+ const auto col2 = reinterpret_cast<const vec_t*>(&weights_[(i + 2) * kOutputDimensions * 4]);
+ const auto col3 = reinterpret_cast<const vec_t*>(&weights_[(i + 3) * kOutputDimensions * 4]);
+ for (int j = 0; j * kOutputSimdWidth < kOutputDimensions; ++j)
+ vec_add_dpbusd_32x4(outptr[j], in0, col0[j], in1, col1[j], in2, col2[j], in3, col3[j]);
}
- else
- {
- __m256i sum0 = _mm256_setzero_si256();
- __m256i sum1 = _mm256_setzero_si256();
- __m256i sum2 = _mm256_setzero_si256();
- __m256i sum3 = _mm256_setzero_si256();
-
- const auto row0 = reinterpret_cast<const __m256i*>(&weights_[offset0]);
- const auto row1 = reinterpret_cast<const __m256i*>(&weights_[offset1]);
- const auto row2 = reinterpret_cast<const __m256i*>(&weights_[offset2]);
- const auto row3 = reinterpret_cast<const __m256i*>(&weights_[offset3]);
-
- for (IndexType j = 0; j < kNumChunks256; ++j)
- {
- const __m256i in = input_vector256[j];
-
- m256_add_dpbusd_epi32(sum0, in, row0[j]);
- m256_add_dpbusd_epi32(sum1, in, row1[j]);
- m256_add_dpbusd_epi32(sum2, in, row2[j]);
- m256_add_dpbusd_epi32(sum3, in, row3[j]);
- }
-
- *outptr = m256_haddx4(sum0, sum1, sum2, sum3, bias);
- }
- }
+ for (int i = 0; i < canSaturate16.count; ++i)
+ output[canSaturate16.ids[i].out] += input[canSaturate16.ids[i].in] * canSaturate16.ids[i].w;
}
else if constexpr (kOutputDimensions == 1)
{
- if constexpr (kPaddedInputDimensions % (kSimdWidth * 2) == 0)
- {
- __m512i sum0 = _mm512_setzero_si512();
-
- const auto row0 = reinterpret_cast<const __m512i*>(&weights_[0]);
-
- for (IndexType j = 0; j < kNumChunks512; ++j)
- {
- const __m512i in = input_vector512[j];
-
- m512_add_dpbusd_epi32(sum0, in, row0[j]);
- }
-
- output[0] = m512_hadd(sum0, biases_[0]);
- }
- else
- {
- __m256i sum0 = _mm256_setzero_si256();
-
- const auto row0 = reinterpret_cast<const __m256i*>(&weights_[0]);
-
- for (IndexType j = 0; j < kNumChunks256; ++j)
+#if defined (USE_AVX512)
+ if constexpr (kPaddedInputDimensions % (kSimdWidth * 2) != 0)
{
- const __m256i in = input_vector256[j];
-
- m256_add_dpbusd_epi32(sum0, in, row0[j]);
- }
-
- output[0] = m256_hadd(sum0, biases_[0]);
- }
- }
- else
- {
- // This case can never happen because kOutputDimensions
- // is always 1 or a multiple of kSimdWidth.
- assert(false);
- }
-
-#elif defined (USE_AVX2)
+ constexpr IndexType kNumChunks = kPaddedInputDimensions / kSimdWidth;
+ const auto input_vector256 = reinterpret_cast<const __m256i*>(input);
- constexpr IndexType kNumChunks = kPaddedInputDimensions / kSimdWidth;
+ __m256i sum0 = _mm256_setzero_si256();
+ const auto row0 = reinterpret_cast<const __m256i*>(&weights_[0]);
- const auto output = reinterpret_cast<OutputType*>(buffer);
- const auto input_vector = reinterpret_cast<const __m256i*>(input);
-
- // kOutputDimensions is either 1 or a multiple of kSimdWidth
- // because then it is also an input dimension.
- if constexpr (kOutputDimensions % 4 == 0)
- {
- for (IndexType i = 0; i < kOutputDimensions; i += 4)
- {
- const IndexType offset0 = (i + 0) * kPaddedInputDimensions;
- const IndexType offset1 = (i + 1) * kPaddedInputDimensions;
- const IndexType offset2 = (i + 2) * kPaddedInputDimensions;
- const IndexType offset3 = (i + 3) * kPaddedInputDimensions;
-
- const __m128i bias = *reinterpret_cast<const __m128i*>(&biases_[i]);
- __m128i* outptr = reinterpret_cast<__m128i*>(&output[i]);
-
- __m256i sum0 = _mm256_setzero_si256();
- __m256i sum1 = _mm256_setzero_si256();
- __m256i sum2 = _mm256_setzero_si256();
- __m256i sum3 = _mm256_setzero_si256();
-
- const auto row0 = reinterpret_cast<const __m256i*>(&weights_[offset0]);
- const auto row1 = reinterpret_cast<const __m256i*>(&weights_[offset1]);
- const auto row2 = reinterpret_cast<const __m256i*>(&weights_[offset2]);
- const auto row3 = reinterpret_cast<const __m256i*>(&weights_[offset3]);
-
- int j = 0;
- if (!canSaturate16x4[i / 4])
- {
- for (; j < (int)kNumChunks - 1; j += 2)
+ for (int j = 0; j < (int)kNumChunks; ++j)
{
- const __m256i in0 = input_vector[j];
- const __m256i in1 = input_vector[j + 1];
-
- m256_add_dpbusd_epi32x2(sum0, in0, row0[j], in1, row0[j + 1]);
- m256_add_dpbusd_epi32x2(sum1, in0, row1[j], in1, row1[j + 1]);
- m256_add_dpbusd_epi32x2(sum2, in0, row2[j], in1, row2[j + 1]);
- m256_add_dpbusd_epi32x2(sum3, in0, row3[j], in1, row3[j + 1]);
+ const __m256i in = input_vector256[j];
+ m256_add_dpbusd_epi32(sum0, in, row0[j]);
}
+ output[0] = m256_hadd(sum0, biases_[0]);
}
- for (; j < (int)kNumChunks; ++j)
+ else
+#endif
{
- const __m256i in = input_vector[j];
-
- m256_add_dpbusd_epi32(sum0, in, row0[j]);
- m256_add_dpbusd_epi32(sum1, in, row1[j]);
- m256_add_dpbusd_epi32(sum2, in, row2[j]);
- m256_add_dpbusd_epi32(sum3, in, row3[j]);
- }
-
- *outptr = m256_haddx4(sum0, sum1, sum2, sum3, bias);
- }
- }
- else if constexpr (kOutputDimensions == 1)
- {
- __m256i sum0 = _mm256_setzero_si256();
-
- const auto row0 = reinterpret_cast<const __m256i*>(&weights_[0]);
-
- for (IndexType j = 0; j < kNumChunks; ++j)
- {
- const __m256i in = input_vector[j];
-
- m256_add_dpbusd_epi32(sum0, in, row0[j]);
- }
-
- output[0] = m256_hadd(sum0, biases_[0]);
- }
- else
- {
- // This case can never happen because kOutputDimensions
- // is always 1 or a multiple of kSimdWidth.
- assert(false);
- }
-
-#elif defined (USE_SSSE3)
-
- constexpr IndexType kNumChunks = kPaddedInputDimensions / kSimdWidth;
-
- auto output = reinterpret_cast<OutputType*>(buffer);
- const auto input_vector = reinterpret_cast<const __m128i*>(input);
+#if defined (USE_AVX512)
+ constexpr IndexType kNumChunks = kPaddedInputDimensions / (kSimdWidth * 2);
+#else
+ constexpr IndexType kNumChunks = kPaddedInputDimensions / kSimdWidth;
+#endif
+ vec_t sum0 = vec_setzero();
+ const auto row0 = reinterpret_cast<const vec_t*>(&weights_[0]);
- // kOutputDimensions is either 1 or a multiple of kSimdWidth
- // because then it is also an input dimension.
- if constexpr (kOutputDimensions % 4 == 0)
- {
- for (IndexType i = 0; i < kOutputDimensions; i += 4)
- {
- const IndexType offset0 = (i + 0) * kPaddedInputDimensions;
- const IndexType offset1 = (i + 1) * kPaddedInputDimensions;
- const IndexType offset2 = (i + 2) * kPaddedInputDimensions;
- const IndexType offset3 = (i + 3) * kPaddedInputDimensions;
-
- const __m128i bias = *reinterpret_cast<const __m128i*>(&biases_[i]);
- __m128i* outptr = reinterpret_cast<__m128i*>(&output[i]);
-
- __m128i sum0 = _mm_setzero_si128();
- __m128i sum1 = _mm_setzero_si128();
- __m128i sum2 = _mm_setzero_si128();
- __m128i sum3 = _mm_setzero_si128();
-
- const auto row0 = reinterpret_cast<const __m128i*>(&weights_[offset0]);
- const auto row1 = reinterpret_cast<const __m128i*>(&weights_[offset1]);
- const auto row2 = reinterpret_cast<const __m128i*>(&weights_[offset2]);
- const auto row3 = reinterpret_cast<const __m128i*>(&weights_[offset3]);
-
- int j = 0;
- if (!canSaturate16x4[i / 4])
- {
- for (; j < (int)kNumChunks - 1; j += 2)
+ for (int j = 0; j < (int)kNumChunks; ++j)
{
- const __m128i in0 = input_vector[j];
- const __m128i in1 = input_vector[j + 1];
-
- m128_add_dpbusd_epi32x2(sum0, in0, row0[j], in1, row0[j + 1]);
- m128_add_dpbusd_epi32x2(sum1, in0, row1[j], in1, row1[j + 1]);
- m128_add_dpbusd_epi32x2(sum2, in0, row2[j], in1, row2[j + 1]);
- m128_add_dpbusd_epi32x2(sum3, in0, row3[j], in1, row3[j + 1]);
+ const vec_t in = input_vector[j];
+ vec_add_dpbusd_32(sum0, in, row0[j]);
}
+ output[0] = vec_hadd(sum0, biases_[0]);
}
- for (; j < (int)kNumChunks; ++j)
- {
- const __m128i in = input_vector[j];
-
- m128_add_dpbusd_epi32(sum0, in, row0[j]);
- m128_add_dpbusd_epi32(sum1, in, row1[j]);
- m128_add_dpbusd_epi32(sum2, in, row2[j]);
- m128_add_dpbusd_epi32(sum3, in, row3[j]);
- }
-
- *outptr = m128_haddx4(sum0, sum1, sum2, sum3, bias);
- }
- }
- else if constexpr (kOutputDimensions == 1)
- {
- __m128i sum0 = _mm_setzero_si128();
-
- const auto row0 = reinterpret_cast<const __m128i*>(&weights_[0]);
-
- for (int j = 0; j < (int)kNumChunks; ++j)
- {
- const __m128i in = input_vector[j];
-
- m128_add_dpbusd_epi32(sum0, in, row0[j]);
- }
-
- output[0] = m128_hadd(sum0, biases_[0]);
- }
- else
- {
- // This case can never happen because kOutputDimensions
- // is always 1 or a multiple of kSimdWidth.
- assert(false);
}
#else
#if defined(USE_SSE2)
constexpr IndexType kNumChunks = kPaddedInputDimensions / kSimdWidth;
-#ifndef USE_SSSE3
const __m128i kZeros = _mm_setzero_si128();
-#else
- const __m128i kOnes = _mm_set1_epi16(1);
-#endif
const auto input_vector = reinterpret_cast<const __m128i*>(input);
#elif defined(USE_MMX)
alignas(kCacheLineSize) BiasType biases_[kOutputDimensions];
alignas(kCacheLineSize) WeightType weights_[kOutputDimensions * kPaddedInputDimensions];
- union {
- uint32_t canSaturate16x4[(kOutputDimensions + 3) / 4];
- bool canSaturate16[kOutputDimensions];
- };
+#if defined (USE_SSSE3)
+ struct CanSaturate {
+ int count;
+ struct Entry {
+ uint16_t out;
+ uint16_t in;
+ int8_t w;
+ } ids[kPaddedInputDimensions * kOutputDimensions * 3 / 4];
+
+ void add(int i, int j, int8_t w) {
+ ids[count].out = i;
+ ids[count].in = j;
+ ids[count].w = w;
+ ++count;
+ }
+ } canSaturate16;
+#endif
};
-} // namespace Eval::NNUE::Layers
+} // namespace Stockfish::Eval::NNUE::Layers
#endif // #ifndef NNUE_LAYERS_AFFINE_TRANSFORM_H_INCLUDED
/*
Stockfish, a UCI chess playing engine derived from Glaurung 2.1
- Copyright (C) 2004-2020 The Stockfish developers (see AUTHORS file)
+ Copyright (C) 2004-2021 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
#include "../nnue_common.h"
-namespace Eval::NNUE::Layers {
+namespace Stockfish::Eval::NNUE::Layers {
// Clipped ReLU
template <typename PreviousLayer>
PreviousLayer previous_layer_;
};
-} // namespace Eval::NNUE::Layers
+} // namespace Stockfish::Eval::NNUE::Layers
#endif // NNUE_LAYERS_CLIPPED_RELU_H_INCLUDED
/*
Stockfish, a UCI chess playing engine derived from Glaurung 2.1
- Copyright (C) 2004-2020 The Stockfish developers (see AUTHORS file)
+ Copyright (C) 2004-2021 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
#include "../nnue_common.h"
-namespace Eval::NNUE::Layers {
+namespace Stockfish::Eval::NNUE::Layers {
// Input layer
template <IndexType OutputDimensions, IndexType Offset = 0>
private:
};
-} // namespace Layers
+} // namespace Stockfish::Eval::NNUE::Layers
#endif // #ifndef NNUE_LAYERS_INPUT_SLICE_H_INCLUDED
/*
Stockfish, a UCI chess playing engine derived from Glaurung 2.1
- Copyright (C) 2004-2020 The Stockfish developers (see AUTHORS file)
+ Copyright (C) 2004-2021 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
#include "nnue_architecture.h"
-namespace Eval::NNUE {
+namespace Stockfish::Eval::NNUE {
// The accumulator of a StateInfo without parent is set to the INIT state
enum AccumulatorState { EMPTY, COMPUTED, INIT };
AccumulatorState state[2];
};
-} // namespace Eval::NNUE
+} // namespace Stockfish::Eval::NNUE
#endif // NNUE_ACCUMULATOR_H_INCLUDED
/*
Stockfish, a UCI chess playing engine derived from Glaurung 2.1
- Copyright (C) 2004-2020 The Stockfish developers (see AUTHORS file)
+ Copyright (C) 2004-2021 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
// Defines the network structure
#include "architectures/halfkp_256x2-32-32.h"
-namespace Eval::NNUE {
+namespace Stockfish::Eval::NNUE {
static_assert(kTransformedFeatureDimensions % kMaxSimdWidth == 0, "");
static_assert(Network::kOutputDimensions == 1, "");
// Trigger for full calculation instead of difference calculation
constexpr auto kRefreshTriggers = RawFeatures::kRefreshTriggers;
-} // namespace Eval::NNUE
+} // namespace Stockfish::Eval::NNUE
#endif // #ifndef NNUE_ARCHITECTURE_H_INCLUDED
/*
Stockfish, a UCI chess playing engine derived from Glaurung 2.1
- Copyright (C) 2004-2020 The Stockfish developers (see AUTHORS file)
+ Copyright (C) 2004-2021 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
#include <arm_neon.h>
#endif
-namespace Eval::NNUE {
+namespace Stockfish::Eval::NNUE {
// Version of the evaluation file
constexpr std::uint32_t kVersion = 0x7AF32F16u;
return result;
}
-} // namespace Eval::NNUE
+} // namespace Stockfish::Eval::NNUE
#endif // #ifndef NNUE_COMMON_H_INCLUDED
/*
Stockfish, a UCI chess playing engine derived from Glaurung 2.1
- Copyright (C) 2004-2020 The Stockfish developers (see AUTHORS file)
+ Copyright (C) 2004-2021 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
#include <cstring> // std::memset()
-namespace Eval::NNUE {
+namespace Stockfish::Eval::NNUE {
// If vector instructions are enabled, we update and refresh the
// accumulator tile by tile such that each tile fits in the CPU's
WeightType weights_[kHalfDimensions * kInputDimensions];
};
-} // namespace Eval::NNUE
+} // namespace Stockfish::Eval::NNUE
#endif // #ifndef NNUE_FEATURE_TRANSFORMER_H_INCLUDED
/*
Stockfish, a UCI chess playing engine derived from Glaurung 2.1
- Copyright (C) 2004-2020 The Stockfish developers (see AUTHORS file)
+ Copyright (C) 2004-2021 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
#include "position.h"
#include "thread.h"
+namespace Stockfish {
+
namespace {
#define V Value
#define S(mg, eg) make_score(mg, eg)
// Pawn penalties
- constexpr Score Backward = S( 8, 25);
- constexpr Score Doubled = S(10, 55);
+ constexpr Score Backward = S( 9, 22);
+ constexpr Score Doubled = S(13, 51);
+ constexpr Score DoubledEarly = S(20, 7);
constexpr Score Isolated = S( 3, 15);
- constexpr Score WeakLever = S( 3, 55);
- constexpr Score WeakUnopposed = S(13, 25);
+ constexpr Score WeakLever = S( 4, 58);
+ constexpr Score WeakUnopposed = S(13, 24);
// Bonus for blocked pawns at 5th or 6th rank
- constexpr Score BlockedPawn[2] = { S(-15, -3), S(-6, 3) };
+ constexpr Score BlockedPawn[2] = { S(-17, -6), S(-9, 2) };
constexpr Score BlockedStorm[RANK_NB] = {
S(0, 0), S(0, 0), S(75, 78), S(-8, 16), S(-6, 10), S(-6, 6), S(0, 2)
};
// Connected pawn bonus
- constexpr int Connected[RANK_NB] = { 0, 5, 7, 11, 24, 48, 86 };
+ constexpr int Connected[RANK_NB] = { 0, 5, 7, 11, 23, 48, 87 };
// Strength of pawn shelter for our king by [distance from edge][rank].
// RANK_1 = 0 is used for files where we have no pawn, or pawn is behind our king.
// KingOnFile[semi-open Us][semi-open Them] contains bonuses/penalties
// for king when the king is on a semi-open or open file.
- constexpr Score KingOnFile[2][2] = {{ S(-19,12), S(-6, 7) },
- { S( 0, 2), S( 6,-5) }};
+ constexpr Score KingOnFile[2][2] = {{ S(-21,10), S(-7, 1) },
+ { S( 0,-3), S( 9,-4) }};
#undef S
#undef V
constexpr Color Them = ~Us;
constexpr Direction Up = pawn_push(Us);
+ constexpr Direction Down = -Up;
Bitboard neighbours, stoppers, support, phalanx, opposed;
Bitboard lever, leverPush, blocked;
phalanx = neighbours & rank_bb(s);
support = neighbours & rank_bb(s - Up);
+ if (doubled)
+ {
+ // Additional doubled penalty if none of their pawns is fixed
+ if (!(ourPawns & shift<Down>(theirPawns | pawn_attacks_bb<Them>(theirPawns))))
+ score -= DoubledEarly;
+ }
+
// A pawn is backward when it is behind all pawns of the same color on
// the adjacent files and cannot safely advance.
backward = !(neighbours & forward_ranks_bb(Them, s + Up))
else if (backward)
score -= Backward
- + WeakUnopposed * !opposed;
+ + WeakUnopposed * !opposed * bool(~(FileABB | FileHBB) & s);
if (!support)
score -= Doubled * doubled
template Score Entry::do_king_safety<BLACK>(const Position& pos);
} // namespace Pawns
+
+} // namespace Stockfish
/*
Stockfish, a UCI chess playing engine derived from Glaurung 2.1
- Copyright (C) 2004-2020 The Stockfish developers (see AUTHORS file)
+ Copyright (C) 2004-2021 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
#include "position.h"
#include "types.h"
-namespace Pawns {
+namespace Stockfish::Pawns {
/// Pawns::Entry contains various information about a pawn structure. A lookup
/// to the pawn hash table (performed by calling the probe function) returns a
Entry* probe(const Position& pos);
-} // namespace Pawns
+} // namespace Stockfish::Pawns
#endif // #ifndef PAWNS_H_INCLUDED
/*
Stockfish, a UCI chess playing engine derived from Glaurung 2.1
- Copyright (C) 2004-2020 The Stockfish developers (see AUTHORS file)
+ Copyright (C) 2004-2021 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
using std::string;
+namespace Stockfish {
+
namespace Zobrist {
Key psq[PIECE_NB][SQUARE_NB];
set_castling_right(c, rsq);
}
+ set_state(st);
+
// 4. En passant square.
// Ignore if square is invalid or not on side to move relative rank 6.
bool enpassant = false;
// a) side to move have a pawn threatening epSquare
// b) there is an enemy pawn in front of epSquare
// c) there is no piece on epSquare or behind epSquare
+ // d) enemy pawn didn't block a check of its own color by moving forward
enpassant = pawn_attacks_bb(~sideToMove, st->epSquare) & pieces(sideToMove, PAWN)
&& (pieces(~sideToMove, PAWN) & (st->epSquare + pawn_push(~sideToMove)))
- && !(pieces() & (st->epSquare | (st->epSquare + pawn_push(sideToMove))));
+ && !(pieces() & (st->epSquare | (st->epSquare + pawn_push(sideToMove))))
+ && ( file_of(square<KING>(sideToMove)) == file_of(st->epSquare)
+ || !(blockers_for_king(sideToMove) & (st->epSquare + pawn_push(~sideToMove))));
}
- if (!enpassant)
+ // It's necessary for st->previous to be intialized in this way because legality check relies on its existence
+ if (enpassant) {
+ st->previous = new StateInfo();
+ remove_piece(st->epSquare - pawn_push(sideToMove));
+ st->previous->checkersBB = attackers_to(square<KING>(~sideToMove)) & pieces(sideToMove);
+ st->previous->blockersForKing[WHITE] = slider_blockers(pieces(BLACK), square<KING>(WHITE), st->previous->pinners[BLACK]);
+ st->previous->blockersForKing[BLACK] = slider_blockers(pieces(WHITE), square<KING>(BLACK), st->previous->pinners[WHITE]);
+ put_piece(make_piece(~sideToMove, PAWN), st->epSquare - pawn_push(sideToMove));
+ }
+ else
st->epSquare = SQ_NONE;
// 5-6. Halfmove clock and fullmove number
chess960 = isChess960;
thisThread = th;
- set_state(st);
st->accumulator.state[WHITE] = Eval::NNUE::INIT;
st->accumulator.state[BLACK] = Eval::NNUE::INIT;
/// Position::fen() returns a FEN representation of the position. In case of
/// Chess960 the Shredder-FEN notation is used. This is mainly a debugging function.
-const string Position::fen() const {
+string Position::fen() const {
int emptyCnt;
std::ostringstream ss;
assert(color_of(moved_piece(m)) == us);
assert(piece_on(square<KING>(us)) == make_piece(us, KING));
- // En passant captures are a tricky special case. Because they are rather
- // uncommon, we do it simply by testing whether the king is attacked after
- // the move is made.
- if (type_of(m) == ENPASSANT)
- {
- Square ksq = square<KING>(us);
- Square capsq = to - pawn_push(us);
- Bitboard occupied = (pieces() ^ from ^ capsq) | to;
-
- assert(to == ep_square());
- assert(moved_piece(m) == make_piece(us, PAWN));
- assert(piece_on(capsq) == make_piece(~us, PAWN));
- assert(piece_on(to) == NO_PIECE);
-
- return !(attacks_bb< ROOK>(ksq, occupied) & pieces(~us, QUEEN, ROOK))
- && !(attacks_bb<BISHOP>(ksq, occupied) & pieces(~us, QUEEN, BISHOP));
- }
+ // st->previous->blockersForKing consider capsq as empty.
+ // If pinned, it has to move along the king ray.
+ if (type_of(m) == EN_PASSANT)
+ return !(st->previous->blockersForKing[sideToMove] & from)
+ || aligned(from, to, square<KING>(us));
// Castling moves generation does not check if the castling path is clear of
// enemy attacks, it is delayed at a later time: now!
if (attackers_to(s) & pieces(~us))
return false;
- // In case of Chess960, verify that when moving the castling rook we do
- // not discover some hidden checker.
+ // In case of Chess960, verify if the Rook blocks some checks
// For instance an enemy queen in SQ_A1 when castling rook is in SQ_B1.
- return !chess960
- || !(attacks_bb<ROOK>(to, pieces() ^ to_sq(m)) & pieces(~us, ROOK, QUEEN));
+ return !chess960 || !(blockers_for_king(us) & to_sq(m));
}
// If the moving piece is a king, check whether the destination square is
// A non-king move is legal if and only if it is not pinned or it
// is moving along the ray towards or away from the king.
- return !(blockers_for_king(us) & from)
- || aligned(from, to, square<KING>(us));
+ return !(blockers_for_king(us) & from)
+ || aligned(from, to, square<KING>(us));
}
Piece pc = moved_piece(m);
// Use a slower but simpler function for uncommon cases
+ // yet we skip the legality check of MoveList<LEGAL>().
if (type_of(m) != NORMAL)
- return MoveList<LEGAL>(*this).contains(m);
+ return checkers() ? MoveList< EVASIONS>(*this).contains(m)
+ : MoveList<NON_EVASIONS>(*this).contains(m);
// Is not a promotion, so promotion piece must be empty
if (promotion_type(m) - KNIGHT != NO_PIECE_TYPE)
case PROMOTION:
return attacks_bb(promotion_type(m), to, pieces() ^ from) & square<KING>(~sideToMove);
- // En passant capture with check? We have already handled the case
- // of direct checks and ordinary discovered check, so the only case we
- // need to handle is the unusual case of a discovered check through
- // the captured pawn.
- case ENPASSANT:
- {
- Square capsq = make_square(file_of(to), rank_of(from));
- Bitboard b = (pieces() ^ from ^ capsq) | to;
+ // The double-pushed pawn blocked a check? En Passant will remove the blocker.
+ // The only discovery check that wasn't handle is through capsq and fromsq
+ // So the King must be in the same rank as fromsq to consider this possibility.
+ // st->previous->blockersForKing consider capsq as empty.
+ case EN_PASSANT:
+ return st->previous->checkersBB
+ || ( rank_of(square<KING>(~sideToMove)) == rank_of(from)
+ && st->previous->blockersForKing[~sideToMove] & from);
- return (attacks_bb< ROOK>(square<KING>(~sideToMove), b) & pieces(sideToMove, QUEEN, ROOK))
- | (attacks_bb<BISHOP>(square<KING>(~sideToMove), b) & pieces(sideToMove, QUEEN, BISHOP));
- }
- case CASTLING:
+ default: //CASTLING
{
- Square kfrom = from;
- Square rfrom = to; // Castling is encoded as 'king captures the rook'
- Square kto = relative_square(sideToMove, rfrom > kfrom ? SQ_G1 : SQ_C1);
- Square rto = relative_square(sideToMove, rfrom > kfrom ? SQ_F1 : SQ_D1);
+ // Castling is encoded as 'king captures the rook'
+ Square ksq = square<KING>(~sideToMove);
+ Square rto = relative_square(sideToMove, to > from ? SQ_F1 : SQ_D1);
- return (attacks_bb<ROOK>(rto) & square<KING>(~sideToMove))
- && (attacks_bb<ROOK>(rto, (pieces() ^ kfrom ^ rfrom) | rto | kto) & square<KING>(~sideToMove));
+ return (attacks_bb<ROOK>(rto) & ksq)
+ && (attacks_bb<ROOK>(rto, pieces() ^ from ^ to) & ksq);
}
- default:
- assert(false);
- return false;
}
}
Square from = from_sq(m);
Square to = to_sq(m);
Piece pc = piece_on(from);
- Piece captured = type_of(m) == ENPASSANT ? make_piece(them, PAWN) : piece_on(to);
+ Piece captured = type_of(m) == EN_PASSANT ? make_piece(them, PAWN) : piece_on(to);
assert(color_of(pc) == us);
assert(captured == NO_PIECE || color_of(captured) == (type_of(m) != CASTLING ? them : us));
// update non-pawn material.
if (type_of(captured) == PAWN)
{
- if (type_of(m) == ENPASSANT)
+ if (type_of(m) == EN_PASSANT)
{
capsq -= pawn_push(us);
// Update board and piece lists
remove_piece(capsq);
- if (type_of(m) == ENPASSANT)
+ if (type_of(m) == EN_PASSANT)
board[capsq] = NO_PIECE;
// Update material hash key and prefetch access to materialTable
// If the moving piece is a pawn do some special extra work
if (type_of(pc) == PAWN)
{
- // Set en-passant square if the moved pawn can be captured
+ // Set en passant square if the moved pawn can be captured
if ( (int(to) ^ int(from)) == 16
&& (pawn_attacks_bb(us, to - pawn_push(us)) & pieces(them, PAWN)))
{
{
Square capsq = to;
- if (type_of(m) == ENPASSANT)
+ if (type_of(m) == EN_PASSANT)
{
capsq -= pawn_push(us);
}
st->key ^= Zobrist::side;
- prefetch(TT.first_entry(st->key));
+ prefetch(TT.first_entry(key()));
++st->rule50;
st->pliesFromNull = 0;
/// Position::key_after() 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.
+/// en passant and promotions.
Key Position::key_after(Move m) const {
assert(is_ok(m));
- // Only deal with normal moves, assume others pass a simple see
+ // Only deal with normal moves, assume others pass a simple SEE
if (type_of(m) != NORMAL)
return VALUE_ZERO >= threshold;
return true;
}
+
+} // namespace Stockfish
/*
Stockfish, a UCI chess playing engine derived from Glaurung 2.1
- Copyright (C) 2004-2020 The Stockfish developers (see AUTHORS file)
+ Copyright (C) 2004-2021 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
#include "bitboard.h"
#include "evaluate.h"
+#include "psqt.h"
#include "types.h"
#include "nnue/nnue_accumulator.h"
+namespace Stockfish {
/// StateInfo struct stores information needed to restore a Position object to
/// its previous state when we retract a move. Whenever a move is made on the
// FEN string input/output
Position& set(const std::string& fenStr, bool isChess960, StateInfo* si, Thread* th);
Position& set(const std::string& code, Color c, StateInfo* si);
- const std::string fen() const;
+ std::string fen() const;
// Position representation
Bitboard pieces(PieceType pt) const;
Bitboard blockers_for_king(Color c) const;
Bitboard check_squares(PieceType pt) const;
Bitboard pinners(Color c) const;
- bool is_discovery_check_on_king(Color c, Move m) const;
+ bool is_discovered_check_on_king(Color c, Move m) const;
// Attacks to/from a given square
Bitboard attackers_to(Square s) const;
bool chess960;
};
-namespace PSQT {
- extern Score psq[PIECE_NB][SQUARE_NB];
-}
-
extern std::ostream& operator<<(std::ostream& os, const Position& pos);
inline Color Position::side_to_move() const {
return st->checkSquares[pt];
}
-inline bool Position::is_discovery_check_on_king(Color c, Move m) const {
+inline bool Position::is_discovered_check_on_king(Color c, Move m) const {
return st->blockersForKing[c] & from_sq(m);
}
inline bool Position::advanced_pawn_push(Move m) const {
return type_of(moved_piece(m)) == PAWN
- && relative_rank(sideToMove, to_sq(m)) > RANK_5;
+ && relative_rank(sideToMove, to_sq(m)) > RANK_6;
}
inline int Position::pawns_on_same_color_squares(Color c, Square s) const {
}
inline Key Position::key() const {
- return st->key;
+ return st->rule50 < 14 ? st->key
+ : st->key ^ make_key((st->rule50 - 14) / 8);
}
inline Key Position::pawn_key() const {
inline bool Position::capture(Move m) const {
assert(is_ok(m));
// Castling is encoded as "king captures rook"
- return (!empty(to_sq(m)) && type_of(m) != CASTLING) || type_of(m) == ENPASSANT;
+ return (!empty(to_sq(m)) && type_of(m) != CASTLING) || type_of(m) == EN_PASSANT;
}
inline Piece Position::captured_piece() const {
return st;
}
+} // namespace Stockfish
+
#endif // #ifndef POSITION_H_INCLUDED
/*
Stockfish, a UCI chess playing engine derived from Glaurung 2.1
- Copyright (C) 2004-2020 The Stockfish developers (see AUTHORS file)
+ Copyright (C) 2004-2021 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
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
+
+#include "psqt.h"
+
#include <algorithm>
-#include "types.h"
#include "bitboard.h"
+#include "types.h"
+
+namespace Stockfish {
-namespace PSQT {
+namespace
+{
-#define S(mg, eg) make_score(mg, eg)
+auto constexpr S = make_score;
-// Bonus[PieceType][Square / 2] contains Piece-Square scores. For each piece
-// type on a given square a (middlegame, endgame) score pair is assigned. Table
-// is defined for files A..D and white side: it is symmetric for black side and
-// second half of the files.
+// 'Bonus' contains Piece-Square parameters.
+// Scores are explicit for files A to D, implicitly mirrored for E to H.
constexpr Score Bonus[][RANK_NB][int(FILE_NB) / 2] = {
{ },
{ },
{ S(-201,-100), S(-83,-88), S(-56,-56), S(-26,-17) }
},
{ // Bishop
- { S(-53,-57), S( -5,-30), S( -8,-37), S(-23,-12) },
- { S(-15,-37), S( 8,-13), S( 19,-17), S( 4, 1) },
- { S( -7,-16), S( 21, -1), S( -5, -2), S( 17, 10) },
- { S( -5,-20), S( 11, -6), S( 25, 0), S( 39, 17) },
- { S(-12,-17), S( 29, -1), S( 22,-14), S( 31, 15) },
- { S(-16,-30), S( 6, 6), S( 1, 4), S( 11, 6) },
- { S(-17,-31), S(-14,-20), S( 5, -1), S( 0, 1) },
- { S(-48,-46), S( 1,-42), S(-14,-37), S(-23,-24) }
+ { S(-37,-40), S(-4 ,-21), S( -6,-26), S(-16, -8) },
+ { S(-11,-26), S( 6, -9), S( 13,-12), S( 3, 1) },
+ { S(-5 ,-11), S( 15, -1), S( -4, -1), S( 12, 7) },
+ { S(-4 ,-14), S( 8, -4), S( 18, 0), S( 27, 12) },
+ { S(-8 ,-12), S( 20, -1), S( 15,-10), S( 22, 11) },
+ { S(-11,-21), S( 4, 4), S( 1, 3), S( 8, 4) },
+ { S(-12,-22), S(-10,-14), S( 4, -1), S( 0, 1) },
+ { S(-34,-32), S( 1,-29), S(-10,-26), S(-16,-17) }
},
{ // Rook
{ S(-31, -9), S(-20,-13), S(-14,-10), S(-5, -9) },
},
{ // Queen
{ S( 3,-69), S(-5,-57), S(-5,-47), S( 4,-26) },
- { S(-3,-55), S( 5,-31), S( 8,-22), S(12, -4) },
+ { S(-3,-54), S( 5,-31), S( 8,-22), S(12, -4) },
{ S(-3,-39), S( 6,-18), S(13, -9), S( 7, 3) },
{ S( 4,-23), S( 5, -3), S( 9, 13), S( 8, 24) },
{ S( 0,-29), S(14, -6), S(12, 9), S( 5, 21) },
- { S(-4,-38), S(10,-18), S( 6,-12), S( 8, 1) },
+ { S(-4,-38), S(10,-18), S( 6,-11), S( 8, 1) },
{ S(-5,-50), S( 6,-27), S(10,-24), S( 8, -8) },
- { S(-2,-75), S(-2,-52), S( 1,-43), S(-2,-36) }
+ { S(-2,-74), S(-2,-52), S( 1,-43), S(-2,-34) }
},
{ // King
{ S(271, 1), S(327, 45), S(271, 85), S(198, 76) },
constexpr Score PBonus[RANK_NB][FILE_NB] =
{ // Pawn (asymmetric distribution)
{ },
- { S( 3,-10), S( 3, -6), S( 10, 10), S( 19, 0), S( 16, 14), S( 19, 7), S( 7, -5), S( -5,-19) },
- { S( -9,-10), S(-15,-10), S( 11,-10), S( 15, 4), S( 32, 4), S( 22, 3), S( 5, -6), S(-22, -4) },
- { S( -4, 6), S(-23, -2), S( 6, -8), S( 20, -4), S( 40,-13), S( 17,-12), S( 4,-10), S( -8, -9) },
- { S( 13, 10), S( 0, 5), S(-13, 4), S( 1, -5), S( 11, -5), S( -2, -5), S(-13, 14), S( 5, 9) },
- { S( 5, 28), S(-12, 20), S( -7, 21), S( 22, 28), S( -8, 30), S( -5, 7), S(-15, 6), S( -8, 13) },
- { S( -7, 0), S( 7,-11), S( -3, 12), S(-13, 21), S( 5, 25), S(-16, 19), S( 10, 4), S( -8, 7) }
+ { S( 2, -8), S( 4, -6), S( 11, 9), S( 18, 5), S( 16, 16), S( 21, 6), S( 9, -6), S( -3,-18) },
+ { S( -9, -9), S(-15, -7), S( 11,-10), S( 15, 5), S( 31, 2), S( 23, 3), S( 6, -8), S(-20, -5) },
+ { S( -3, 7), S(-20, 1), S( 8, -8), S( 19, -2), S( 39,-14), S( 17,-13), S( 2,-11), S( -5, -6) },
+ { S( 11, 12), S( -4, 6), S(-11, 2), S( 2, -6), S( 11, -5), S( 0, -4), S(-12, 14), S( 5, 9) },
+ { S( 3, 27), S(-11, 18), S( -6, 19), S( 22, 29), S( -8, 30), S( -5, 9), S(-14, 8), S(-11, 14) },
+ { S( -7, -1), S( 6,-14), S( -2, 13), S(-11, 22), S( 4, 24), S(-14, 17), S( 10, 7), S( -9, 7) }
};
-#undef S
+} // namespace
-Score psq[PIECE_NB][SQUARE_NB];
+namespace PSQT
+{
+
+Score psq[PIECE_NB][SQUARE_NB];
// PSQT::init() initializes piece-square tables: the white halves of the tables are
// copied from Bonus[] and PBonus[], adding the piece value, then the black halves of
for (Piece pc : {W_PAWN, W_KNIGHT, W_BISHOP, W_ROOK, W_QUEEN, W_KING})
{
- Score score = make_score(PieceValue[MG][pc], PieceValue[EG][pc]);
-
- for (Square s = SQ_A1; s <= SQ_H8; ++s)
- {
- File f = File(edge_distance(file_of(s)));
- psq[ pc][s] = score + (type_of(pc) == PAWN ? PBonus[rank_of(s)][file_of(s)]
- : Bonus[pc][rank_of(s)][f]);
- psq[~pc][flip_rank(s)] = -psq[pc][s];
- }
+ Score score = make_score(PieceValue[MG][pc], PieceValue[EG][pc]);
+
+ for (Square s = SQ_A1; s <= SQ_H8; ++s)
+ {
+ File f = File(edge_distance(file_of(s)));
+ psq[ pc][s] = score + (type_of(pc) == PAWN ? PBonus[rank_of(s)][file_of(s)]
+ : Bonus[pc][rank_of(s)][f]);
+ psq[~pc][flip_rank(s)] = -psq[pc][s];
+ }
}
}
} // namespace PSQT
+
+} // namespace Stockfish
--- /dev/null
+/*
+ Stockfish, a UCI chess playing engine derived from Glaurung 2.1
+ Copyright (C) 2004-2021 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 PSQT_H_INCLUDED
+#define PSQT_H_INCLUDED
+
+
+#include "types.h"
+
+
+namespace Stockfish::PSQT
+{
+
+extern Score psq[PIECE_NB][SQUARE_NB];
+
+// Fill psqt array from a set of internally linked parameters
+extern void init();
+
+} // namespace Stockfish::PSQT
+
+
+#endif // PSQT_H_INCLUDED
/*
Stockfish, a UCI chess playing engine derived from Glaurung 2.1
- Copyright (C) 2004-2020 The Stockfish developers (see AUTHORS file)
+ Copyright (C) 2004-2021 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
#include "uci.h"
#include "syzygy/tbprobe.h"
+namespace Stockfish {
+
namespace Search {
LimitsType Limits;
constexpr uint64_t TtHitAverageWindow = 4096;
constexpr uint64_t TtHitAverageResolution = 1024;
- // Razor and futility margins
- constexpr int RazorMargin = 510;
+ // Futility margin
Value futility_margin(Depth d, bool improving) {
return Value(234 * (d - improving));
}
// History and stats update bonus, based on depth
int stat_bonus(Depth d) {
- return d > 13 ? 29 : 17 * d * d + 134 * d - 134;
+ return d > 14 ? 66 : 6 * d * d + 231 * d - 206;
}
- // Add a small random component to draw evaluations to avoid 3fold-blindness
+ // Add a small random component to draw evaluations to avoid 3-fold blindness
Value value_draw(Thread* thisThread) {
return VALUE_DRAW + Value(2 * (thisThread->nodes & 1) - 1);
}
while (true)
{
Depth adjustedDepth = std::max(1, rootDepth - failedHighCnt - searchAgainCounter);
- bestValue = ::search<PV>(rootPos, ss, alpha, beta, adjustedDepth, false);
+ bestValue = Stockfish::search<PV>(rootPos, ss, alpha, beta, adjustedDepth, false);
// Bring the best move to the front. It is critical that sorting
// is done with a stable algorithm because all the values but the
moveCount = captureCount = quietCount = ss->moveCount = 0;
bestValue = -VALUE_INFINITE;
maxValue = VALUE_INFINITE;
+ ss->distanceFromPv = (PvNode ? 0 : ss->distanceFromPv);
// Check for the available remaining time
if (thisThread == Threads.main())
thisThread->mainHistory[~us][from_to((ss-1)->currentMove)] << bonus;
}
- // Step 7. Razoring (~1 Elo)
- if ( !rootNode // The required rootNode PV handling is not available in qsearch
- && depth == 1
- && eval <= alpha - RazorMargin)
- return qsearch<NT>(pos, ss, alpha, beta);
-
// Set up improving flag that is used in various pruning heuristics
// We define position as improving if static evaluation of position is better
// Than the previous static evaluation at our turn
? ss->staticEval > (ss-4)->staticEval || (ss-4)->staticEval == VALUE_NONE
: ss->staticEval > (ss-2)->staticEval;
- // Step 8. Futility pruning: child node (~50 Elo)
+ // Step 7. Futility pruning: child node (~50 Elo)
if ( !PvNode
- && depth < 8
+ && depth < 9
&& eval - futility_margin(depth, improving) >= beta
&& eval < VALUE_KNOWN_WIN) // Do not return unproven wins
return eval;
- // Step 9. Null move search with verification search (~40 Elo)
+ // Step 8. Null move search with verification search (~40 Elo)
if ( !PvNode
&& (ss-1)->currentMove != MOVE_NULL
- && (ss-1)->statScore < 22977
+ && (ss-1)->statScore < 24185
&& eval >= beta
&& eval >= ss->staticEval
- && ss->staticEval >= beta - 30 * depth - 28 * improving + 84 * ss->ttPv + 168
+ && ss->staticEval >= beta - 24 * depth - 34 * improving + 162 * ss->ttPv + 159
&& !excludedMove
&& pos.non_pawn_material(us)
&& (ss->ply >= thisThread->nmpMinPly || us != thisThread->nmpColor))
assert(eval - beta >= 0);
// Null move dynamic reduction based on depth and value
- Depth R = (1015 + 85 * depth) / 256 + std::min(int(eval - beta) / 191, 3);
+ Depth R = (1062 + 68 * depth) / 256 + std::min(int(eval - beta) / 190, 3);
ss->currentMove = MOVE_NULL;
ss->continuationHistory = &thisThread->continuationHistory[0][0][NO_PIECE][0];
}
}
- probCutBeta = beta + 183 - 49 * improving;
+ probCutBeta = beta + 209 - 44 * improving;
- // Step 10. ProbCut (~10 Elo)
+ // Step 9. ProbCut (~10 Elo)
// If we have a good enough capture and a reduced search returns a value
// much above beta, we can (almost) safely prune the previous move.
if ( !PvNode
ss->ttPv = ttPv;
}
- // Step 11. If the position is not in TT, decrease depth by 2
+ // Step 10. If the position is not in TT, decrease depth by 2
if ( PvNode
&& depth >= 6
&& !ttMove)
moves_loop: // When in check, search starts from here
+ ttCapture = ttMove && pos.capture_or_promotion(ttMove);
+
+ // Step 11. A small Probcut idea, when we are in check
+ probCutBeta = beta + 400;
+ if ( ss->inCheck
+ && !PvNode
+ && depth >= 4
+ && ttCapture
+ && (tte->bound() & BOUND_LOWER)
+ && tte->depth() >= depth - 3
+ && ttValue >= probCutBeta
+ && abs(ttValue) <= VALUE_KNOWN_WIN
+ && abs(beta) <= VALUE_KNOWN_WIN
+ )
+ return probCutBeta;
+
+
const PieceToHistory* contHist[] = { (ss-1)->continuationHistory, (ss-2)->continuationHistory,
nullptr , (ss-4)->continuationHistory,
nullptr , (ss-6)->continuationHistory };
value = bestValue;
singularQuietLMR = moveCountPruning = false;
- ttCapture = ttMove && pos.capture_or_promotion(ttMove);
// Mark this node as being searched
ThreadHolding th(thisThread, posKey, ss->ply);
movedPiece = pos.moved_piece(move);
givesCheck = pos.gives_check(move);
+ // Indicate PvNodes that will probably fail low if node was searched with non-PV search
+ // at depth equal or greater to current depth and result of this search was far below alpha
+ bool likelyFailLow = PvNode
+ && ttMove
+ && (tte->bound() & BOUND_UPPER)
+ && ttValue < alpha + 200 + 100 * depth
+ && tte->depth() >= depth;
+
// Calculate new depth for this move
newDepth = depth - 1;
// Reduced depth of the next LMR search
int lmrDepth = std::max(newDepth - reduction(improving, depth, moveCount), 0);
- if ( !captureOrPromotion
- && !givesCheck)
+ if ( captureOrPromotion
+ || givesCheck)
+ {
+ // Capture history based pruning when the move doesn't give check
+ if ( !givesCheck
+ && lmrDepth < 1
+ && captureHistory[movedPiece][to_sq(move)][type_of(pos.piece_on(to_sq(move)))] < 0)
+ continue;
+
+ // SEE based pruning
+ if (!pos.see_ge(move, Value(-218) * depth)) // (~25 Elo)
+ continue;
+ }
+ else
{
// Countermoves based pruning (~20 Elo)
if ( lmrDepth < 4 + ((ss-1)->statScore > 0 || (ss-1)->moveCount == 1)
// Futility pruning: parent node (~5 Elo)
if ( lmrDepth < 7
&& !ss->inCheck
- && ss->staticEval + 266 + 170 * lmrDepth <= alpha
+ && ss->staticEval + 174 + 157 * lmrDepth <= alpha
&& (*contHist[0])[movedPiece][to_sq(move)]
+ (*contHist[1])[movedPiece][to_sq(move)]
+ (*contHist[3])[movedPiece][to_sq(move)]
- + (*contHist[5])[movedPiece][to_sq(move)] / 2 < 27376)
+ + (*contHist[5])[movedPiece][to_sq(move)] / 3 < 28255)
continue;
// Prune moves with negative SEE (~20 Elo)
if (!pos.see_ge(move, Value(-(30 - std::min(lmrDepth, 18)) * lmrDepth * lmrDepth)))
continue;
}
- else
- {
- // Capture history based pruning when the move doesn't give check
- if ( !givesCheck
- && lmrDepth < 1
- && captureHistory[movedPiece][to_sq(move)][type_of(pos.piece_on(to_sq(move)))] < 0)
- continue;
-
- // SEE based pruning
- if (!pos.see_ge(move, Value(-213) * depth)) // (~25 Elo)
- continue;
- }
}
// Step 14. Extensions (~75 Elo)
// Check extension (~2 Elo)
else if ( givesCheck
- && (pos.is_discovery_check_on_king(~us, move) || pos.see_ge(move)))
+ && (pos.is_discovered_check_on_king(~us, move) || pos.see_ge(move)))
extension = 1;
// Last captures extension
&& pos.non_pawn_material() <= 2 * RookValueMg)
extension = 1;
- // Late irreversible move extension
- if ( move == ttMove
- && pos.rule50_count() > 80
- && (captureOrPromotion || type_of(movedPiece) == PAWN))
- extension = 2;
-
// Add extension to new depth
newDepth += extension;
// Step 15. Make the move
pos.do_move(move, st, givesCheck);
- // Step 16. Reduced depth search (LMR, ~200 Elo). If the move fails high it will be
- // re-searched at full depth.
+ (ss+1)->distanceFromPv = ss->distanceFromPv + moveCount - 1;
+
+ // Step 16. Late moves reduction / extension (LMR, ~200 Elo)
+ // We use various heuristics for the sons of a node after the first son has
+ // been searched. In general we would like to reduce them, but there are many
+ // cases where we extend a son if it has good chances to be "interesting".
if ( depth >= 3
&& moveCount > 1 + 2 * rootNode
&& ( !captureOrPromotion
|| moveCountPruning
|| ss->staticEval + PieceValue[EG][pos.captured_piece()] <= alpha
|| cutNode
- || (!PvNode && !formerPv)
+ || (!PvNode && !formerPv && captureHistory[movedPiece][to_sq(move)][type_of(pos.captured_piece())] < 3678)
|| thisThread->ttHitAverage < 432 * TtHitAverageResolution * TtHitAverageWindow / 1024))
{
Depth r = reduction(improving, depth, moveCount);
if (th.marked())
r++;
- // Decrease reduction if position is or has been on the PV (~10 Elo)
- if (ss->ttPv)
+ // Decrease reduction if position is or has been on the PV
+ // and node is not likely to fail low. (~10 Elo)
+ if (ss->ttPv && !likelyFailLow)
r -= 2;
// Increase reduction at root and non-PV nodes when the best move does not change frequently
if (singularQuietLMR)
r--;
- if (!captureOrPromotion)
+ if (captureOrPromotion)
+ {
+ // Unless giving check, this capture is likely bad
+ if ( !givesCheck
+ && ss->staticEval + PieceValue[EG][pos.captured_piece()] + 210 * depth <= alpha)
+ r++;
+ }
+ else
{
// Increase reduction if ttMove is a capture (~5 Elo)
if (ttCapture)
+ (*contHist[0])[movedPiece][to_sq(move)]
+ (*contHist[1])[movedPiece][to_sq(move)]
+ (*contHist[3])[movedPiece][to_sq(move)]
- - 5287;
+ - 4741;
// Decrease/increase reduction by comparing opponent's stat score (~10 Elo)
- if (ss->statScore >= -105 && (ss-1)->statScore < -103)
+ if (ss->statScore >= -89 && (ss-1)->statScore < -116)
r--;
- else if ((ss-1)->statScore >= -122 && ss->statScore < -129)
+ else if ((ss-1)->statScore >= -112 && ss->statScore < -100)
r++;
// Decrease/increase reduction for moves with a good/bad history (~30 Elo)
- r -= ss->statScore / 14884;
- }
- else
- {
- // Unless giving check, this capture is likely bad
- if ( !givesCheck
- && ss->staticEval + PieceValue[EG][pos.captured_piece()] + 210 * depth <= alpha)
- r++;
+ // If we are not in check use statScore, but if we are in check we use
+ // the sum of main history and first continuation history with an offset.
+ if (ss->inCheck)
+ r -= (thisThread->mainHistory[us][from_to(move)]
+ + (*contHist[0])[movedPiece][to_sq(move)] - 3833) / 16384;
+ else
+ r -= ss->statScore / 14790;
}
- Depth d = std::clamp(newDepth - r, 1, newDepth);
+ // In general we want to cap the LMR depth search at newDepth. But for nodes
+ // close to the principal variation the cap is at (newDepth + 1), which will
+ // allow these nodes to be searched deeper than the pv (up to 4 plies deeper).
+ Depth d = std::clamp(newDepth - r, 1, newDepth + ((ss+1)->distanceFromPv <= 4));
value = -search<NonPV>(pos, ss+1, -(alpha+1), -alpha, d, true);
- doFullDepthSearch = value > alpha && d != newDepth;
-
+ // If the son is reduced and fails high it will be re-searched at full depth
+ doFullDepthSearch = value > alpha && d < newDepth;
didLMR = true;
}
else
{
doFullDepthSearch = !PvNode || moveCount > 1;
-
didLMR = false;
}
moveCount++;
- // Futility pruning
+ // Futility pruning and moveCount pruning
if ( bestValue > VALUE_TB_LOSS_IN_MAX_PLY
&& !givesCheck
&& futilityBase > -VALUE_KNOWN_WIN
&& !pos.advanced_pawn_push(move))
{
- assert(type_of(move) != ENPASSANT); // Due to !pos.advanced_pawn_push
- // moveCount pruning
if (moveCount > 2)
continue;
PieceType captured = type_of(pos.piece_on(to_sq(bestMove)));
bonus1 = stat_bonus(depth + 1);
- bonus2 = bestValue > beta + PawnValueMg ? bonus1 // larger bonus
- : stat_bonus(depth); // smaller bonus
+ bonus2 = bestValue > beta + PawnValueMg ? bonus1 // larger bonus
+ : std::min(bonus1, stat_bonus(depth)); // smaller bonus
if (!pos.capture_or_promotion(bestMove))
{
m.tbRank = 0;
}
}
+
+} // namespace Stockfish
/*
Stockfish, a UCI chess playing engine derived from Glaurung 2.1
- Copyright (C) 2004-2020 The Stockfish developers (see AUTHORS file)
+ Copyright (C) 2004-2021 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
#include "movepick.h"
#include "types.h"
+namespace Stockfish {
+
class Position;
namespace Search {
Value staticEval;
int statScore;
int moveCount;
+ int distanceFromPv;
bool inCheck;
bool ttPv;
bool ttHit;
} // namespace Search
+} // namespace Stockfish
+
#endif // #ifndef SEARCH_H_INCLUDED
/*
Stockfish, a UCI chess playing engine derived from Glaurung 2.1
- Copyright (C) 2004-2020 The Stockfish developers (see AUTHORS file)
+ Copyright (C) 2004-2021 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
#include <windows.h>
#endif
-using namespace Tablebases;
+using namespace Stockfish::Tablebases;
-int Tablebases::MaxCardinality;
+int Stockfish::Tablebases::MaxCardinality;
+
+namespace Stockfish {
namespace {
// so that d->lowestSym[i] >= d->lowestSym[i+1] (when read as LittleEndian).
// Starting from this we compute a base64[] table indexed by symbol length
// and containing 64 bit values so that d->base64[i] >= d->base64[i+1].
- // See http://www.eecs.harvard.edu/~michaelm/E210/huffman.pdf
+ // See https://en.wikipedia.org/wiki/Huffman_coding
for (int i = d->base64.size() - 2; i >= 0; --i) {
d->base64[i] = (d->base64[i + 1] + number<Sym, LittleEndian>(&d->lowestSym[i])
- number<Sym, LittleEndian>(&d->lowestSym[i + 1])) / 2;
if (e.ready.load(std::memory_order_acquire))
return e.baseAddress; // Could be nullptr if file does not exist
- std::unique_lock<std::mutex> lk(mutex);
+ std::scoped_lock<std::mutex> lk(mutex);
if (e.ready.load(std::memory_order_relaxed)) // Recheck under lock
return e.baseAddress;
// If n = 100 immediately after a capture or pawn move, then the position
// is also certainly a win, and during the whole phase until the next
// capture or pawn move, the inequality to be preserved is
-// dtz + 50-movecounter <= 100.
+// dtz + 50-move-counter <= 100.
//
// In short, if a move is available resulting in dtz + 50-move-counter <= 99,
// then do not accept moves leading to dtz + 50-move-counter == 100.
return true;
}
+
+} // namespace Stockfish
/*
Stockfish, a UCI chess playing engine derived from Glaurung 2.1
- Copyright (C) 2004-2020 The Stockfish developers (see AUTHORS file)
+ Copyright (C) 2004-2021 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
#include "../search.h"
-namespace Tablebases {
+namespace Stockfish::Tablebases {
enum WDLScore {
WDLLoss = -2, // Loss
return os;
}
-}
+} // namespace Stockfish::Tablebases
#endif
/*
Stockfish, a UCI chess playing engine derived from Glaurung 2.1
- Copyright (C) 2004-2020 The Stockfish developers (see AUTHORS file)
+ Copyright (C) 2004-2021 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
#include "syzygy/tbprobe.h"
#include "tt.h"
+namespace Stockfish {
+
ThreadPool Threads; // Global object
if (th != front())
th->wait_for_search_finished();
}
+
+} // namespace Stockfish
/*
Stockfish, a UCI chess playing engine derived from Glaurung 2.1
- Copyright (C) 2004-2020 The Stockfish developers (see AUTHORS file)
+ Copyright (C) 2004-2021 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
#include "search.h"
#include "thread_win32_osx.h"
+namespace Stockfish {
/// Thread class keeps together all the thread-related stuff. We use
/// per-thread pawn and material hash tables so that once we get a
extern ThreadPool Threads;
+} // namespace Stockfish
+
#endif // #ifndef THREAD_H_INCLUDED
/*
Stockfish, a UCI chess playing engine derived from Glaurung 2.1
- Copyright (C) 2004-2020 The Stockfish developers (see AUTHORS file)
+ Copyright (C) 2004-2021 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
#include <pthread.h>
+namespace Stockfish {
+
static const size_t TH_STACK_SIZE = 8 * 1024 * 1024;
template <class T, class P = std::pair<T*, void(T::*)()>>
void join() { pthread_join(thread, NULL); }
};
+} // namespace Stockfish
+
#else // Default case: use STL classes
+namespace Stockfish {
+
typedef std::thread NativeThread;
+} // namespace Stockfish
+
#endif
#endif // #ifndef THREAD_WIN32_OSX_H_INCLUDED
/*
Stockfish, a UCI chess playing engine derived from Glaurung 2.1
- Copyright (C) 2004-2020 The Stockfish developers (see AUTHORS file)
+ Copyright (C) 2004-2021 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
#include "timeman.h"
#include "uci.h"
+namespace Stockfish {
+
TimeManagement Time; // Our global time management object
if (Options["Ponder"])
optimumTime += optimumTime / 4;
}
+
+} // namespace Stockfish
/*
Stockfish, a UCI chess playing engine derived from Glaurung 2.1
- Copyright (C) 2004-2020 The Stockfish developers (see AUTHORS file)
+ Copyright (C) 2004-2021 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
#include "search.h"
#include "thread.h"
+namespace Stockfish {
+
/// The TimeManagement class computes the optimal time to think depending on
/// the maximum available time, the game move number and other parameters.
extern TimeManagement Time;
+} // namespace Stockfish
+
#endif // #ifndef TIMEMAN_H_INCLUDED
/*
Stockfish, a UCI chess playing engine derived from Glaurung 2.1
- Copyright (C) 2004-2020 The Stockfish developers (see AUTHORS file)
+ Copyright (C) 2004-2021 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
#include "tt.h"
#include "uci.h"
+namespace Stockfish {
+
TranspositionTable TT; // Our global transposition table
/// TTEntry::save() populates the TTEntry with a new node's data, possibly
for (int i = 0; i < ClusterSize; ++i)
if (tte[i].key16 == key16 || !tte[i].depth8)
{
- tte[i].genBound8 = uint8_t(generation8 | (tte[i].genBound8 & 0x7)); // Refresh
+ tte[i].genBound8 = uint8_t(generation8 | (tte[i].genBound8 & (GENERATION_DELTA - 1))); // Refresh
return found = (bool)tte[i].depth8, &tte[i];
}
TTEntry* replace = tte;
for (int i = 1; i < ClusterSize; ++i)
// Due to our packed storage format for generation and its cyclic
- // nature we add 263 (256 is the modulus plus 7 to keep the unrelated
- // lowest three bits from affecting the result) to calculate the entry
- // age correctly even after generation8 overflows into the next cycle.
- if ( replace->depth8 - ((263 + generation8 - replace->genBound8) & 0xF8)
- > tte[i].depth8 - ((263 + generation8 - tte[i].genBound8) & 0xF8))
+ // nature we add GENERATION_CYCLE (256 is the modulus, plus what
+ // is needed to keep the unrelated lowest n bits from affecting
+ // the result) to calculate the entry age correctly even after
+ // generation8 overflows into the next cycle.
+ if ( replace->depth8 - ((GENERATION_CYCLE + generation8 - replace->genBound8) & GENERATION_MASK)
+ > tte[i].depth8 - ((GENERATION_CYCLE + generation8 - tte[i].genBound8) & GENERATION_MASK))
replace = &tte[i];
return found = false, replace;
int cnt = 0;
for (int i = 0; i < 1000; ++i)
for (int j = 0; j < ClusterSize; ++j)
- cnt += table[i].entry[j].depth8 && (table[i].entry[j].genBound8 & 0xF8) == generation8;
+ cnt += table[i].entry[j].depth8 && (table[i].entry[j].genBound8 & GENERATION_MASK) == generation8;
return cnt / ClusterSize;
}
+
+} // namespace Stockfish
/*
Stockfish, a UCI chess playing engine derived from Glaurung 2.1
- Copyright (C) 2004-2020 The Stockfish developers (see AUTHORS file)
+ Copyright (C) 2004-2021 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
#include "misc.h"
#include "types.h"
+namespace Stockfish {
+
/// TTEntry struct is the 10 bytes transposition table entry, defined as below:
///
/// key 16 bit
static_assert(sizeof(Cluster) == 32, "Unexpected Cluster size");
+ // Constants used to refresh the hash table periodically
+ static constexpr unsigned GENERATION_BITS = 3; // nb of bits reserved for other things
+ static constexpr int GENERATION_DELTA = (1 << GENERATION_BITS); // increment for generation field
+ static constexpr int GENERATION_CYCLE = 255 + (1 << GENERATION_BITS); // cycle length
+ static constexpr int GENERATION_MASK = (0xFF << GENERATION_BITS) & 0xFF; // mask to pull out generation number
+
public:
~TranspositionTable() { aligned_large_pages_free(table); }
- void new_search() { generation8 += 8; } // Lower 3 bits are used by PV flag and Bound
+ void new_search() { generation8 += GENERATION_DELTA; } // Lower bits are used for other things
TTEntry* probe(const Key key, bool& found) const;
int hashfull() const;
void resize(size_t mbSize);
extern TranspositionTable TT;
+} // namespace Stockfish
+
#endif // #ifndef TT_H_INCLUDED
/*
Stockfish, a UCI chess playing engine derived from Glaurung 2.1
- Copyright (C) 2004-2020 The Stockfish developers (see AUTHORS file)
+ Copyright (C) 2004-2021 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
using std::string;
+namespace Stockfish {
+
bool Tune::update_on_last;
const UCI::Option* LastOption = nullptr;
BoolConditions Conditions;
sync_cout << binary[i] << sync_endl;
}
+} // namespace Stockfish
+
// Init options with tuning session results instead of default values. Useful to
// get correct bench signature after a tuning session or to test tuned values.
#include <cmath>
+namespace Stockfish {
+
void Tune::read_results() {
/* ...insert your values here... */
}
+
+} // namespace Stockfish
/*
Stockfish, a UCI chess playing engine derived from Glaurung 2.1
- Copyright (C) 2004-2020 The Stockfish developers (see AUTHORS file)
+ Copyright (C) 2004-2021 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
#include <type_traits>
#include <vector>
+namespace Stockfish {
+
typedef std::pair<int, int> Range; // Option's min-max values
typedef Range (RangeFun) (int);
SetRange range;
};
- // Our facilty to fill the container, each Entry corresponds to a parameter to tune.
- // We use variadic templates to deal with an unspecified number of entries, each one
- // of a possible different type.
+ // Our facility to fill the container, each Entry corresponds to a parameter
+ // to tune. We use variadic templates to deal with an unspecified number of
+ // entries, each one of a possible different type.
static std::string next(std::string& names, bool pop = true);
int add(const SetRange&, std::string&&) { return 0; }
#define TUNE_CONDITIONS() int UNIQUE(c, __LINE__) = (Conditions.init(__COUNTER__), 0); \
TUNE(Conditions, set_conditions)
+} // namespace Stockfish
+
#endif // #ifndef TUNE_H_INCLUDED
/*
Stockfish, a UCI chess playing engine derived from Glaurung 2.1
- Copyright (C) 2004-2020 The Stockfish developers (see AUTHORS file)
+ Copyright (C) 2004-2021 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
# define pext(b, m) 0
#endif
+namespace Stockfish {
+
#ifdef USE_POPCNT
constexpr bool HasPopCnt = true;
#else
/// bit 6-11: origin square (from 0 to 63)
/// bit 12-13: promotion piece type - 2 (from KNIGHT-2 to QUEEN-2)
/// bit 14-15: special move flag: promotion (1), en passant (2), castling (3)
-/// NOTE: EN-PASSANT bit is set only when a pawn can be captured
+/// NOTE: en passant bit is set only when a pawn can be captured
///
/// Special cases are MOVE_NONE and MOVE_NULL. We can sneak these in because in
/// any normal move destination square is always different from origin square
enum MoveType {
NORMAL,
PROMOTION = 1 << 14,
- ENPASSANT = 2 << 14,
+ EN_PASSANT = 2 << 14,
CASTLING = 3 << 14
};
return seed * 6364136223846793005ULL + 1442695040888963407ULL;
}
+} // namespace Stockfish
+
#endif // #ifndef TYPES_H_INCLUDED
#include "tune.h" // Global visibility to tuning setup
/*
Stockfish, a UCI chess playing engine derived from Glaurung 2.1
- Copyright (C) 2004-2020 The Stockfish developers (see AUTHORS file)
+ Copyright (C) 2004-2021 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
using namespace std;
+namespace Stockfish {
+
extern vector<string> setup_bench(const Position&, istream&);
namespace {
else if (token == "d") sync_cout << pos << sync_endl;
else if (token == "eval") trace_eval(pos);
else if (token == "compiler") sync_cout << compiler_info() << sync_endl;
- else
+ else if (!token.empty() && token[0] != '#')
sync_cout << "Unknown command: " << cmd << sync_endl;
} while (token != "quit" && argc == 1); // Command line args are one-shot
return MOVE_NONE;
}
+
+} // namespace Stockfish
/*
Stockfish, a UCI chess playing engine derived from Glaurung 2.1
- Copyright (C) 2004-2020 The Stockfish developers (see AUTHORS file)
+ Copyright (C) 2004-2021 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
#include "types.h"
+namespace Stockfish {
+
class Position;
namespace UCI {
extern UCI::OptionsMap Options;
+} // namespace Stockfish
+
#endif // #ifndef UCI_H_INCLUDED
/*
Stockfish, a UCI chess playing engine derived from Glaurung 2.1
- Copyright (C) 2004-2020 The Stockfish developers (see AUTHORS file)
+ Copyright (C) 2004-2021 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
using std::string;
+namespace Stockfish {
+
UCI::OptionsMap Options; // Global object
std::unique_ptr<HashProbeThread> hash_probe_thread;
}
} // namespace UCI
+
+} // namespace Stockfish
threads="2"
cat << EOF > tsan.supp
-race:TTEntry::move
-race:TTEntry::depth
-race:TTEntry::bound
-race:TTEntry::save
-race:TTEntry::value
-race:TTEntry::eval
-race:TTEntry::is_pv
-
-race:TranspositionTable::probe
-race:TranspositionTable::hashfull
+race:Stockfish::TTEntry::move
+race:Stockfish::TTEntry::depth
+race:Stockfish::TTEntry::bound
+race:Stockfish::TTEntry::save
+race:Stockfish::TTEntry::value
+race:Stockfish::TTEntry::eval
+race:Stockfish::TTEntry::is_pv
+
+race:Stockfish::TranspositionTable::probe
+race:Stockfish::TranspositionTable::hashfull
EOF