closes https://github.com/official-stockfish/Stockfish/pull/3822
also adjusts readme as requested in https://github.com/official-stockfish/Stockfish/pull/3816
No functional change
The NNUE evaluation was first introduced in shogi, and ported to Stockfish afterward.
It can be evaluated efficiently on CPUs, and exploits the fact that only parts
of the neural network need to be updated after a typical chess move.
The NNUE evaluation was first introduced in shogi, and ported to Stockfish afterward.
It can be evaluated efficiently on CPUs, and exploits the fact that only parts
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. On CPUs supporting modern vector instructions
+[The nodchip repository](https://github.com/nodchip/Stockfish) provided the first version of
+the needed tools to train and develop the NNUE networks. Today, more advanced training tools are available
+in [the nnue-pytorch repository](https://github.com/glinscott/nnue-pytorch/), while data generation tools
+are available in [a dedicated branch](https://github.com/official-stockfish/Stockfish/tree/tools).
+
+On CPUs supporting modern vector instructions
(avx2 and similar), the NNUE evaluation 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).
(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).
// write_little_endian() is our utility to write an integer (signed or unsigned, any size)
// to a stream in little-endian order. We swap the byte order before the write if
// write_little_endian() is our utility to write an integer (signed or unsigned, any size)
// to a stream in little-endian order. We swap the byte order before the write if
- // necessary to always write in little endian order, independantly of the byte
+ // necessary to always write in little endian order, independently of the byte
// ordering of the compiling machine.
template <typename IntType>
inline void write_little_endian(std::ostream& stream, IntType value) {
// ordering of the compiling machine.
template <typename IntType>
inline void write_little_endian(std::ostream& stream, IntType value) {
goto encode_remaining; // With pawns we have finished special treatments
}
goto encode_remaining; // With pawns we have finished special treatments
}
- // In positions withouth pawns, we further flip the squares to ensure leading
+ // In positions without pawns, we further flip the squares to ensure leading
// piece is below RANK_5.
if (rank_of(squares[0]) > RANK_4)
for (int i = 0; i < size; ++i)
// piece is below RANK_5.
if (rank_of(squares[0]) > RANK_4)
for (int i = 0; i < size; ++i)
// Rs "together" in 62 * 61 / 2 ways (we divide by 2 because rooks can be
// swapped and still get the same position.)
//
// Rs "together" in 62 * 61 / 2 ways (we divide by 2 because rooks can be
// swapped and still get the same position.)
//
- // In case we have at least 3 unique pieces (inlcuded kings) we encode them
+ // In case we have at least 3 unique pieces (included kings) we encode them
// together.
if (entry->hasUniquePieces) {
// together.
if (entry->hasUniquePieces) {
+ (squares[1] - adjust1)) * 62
+ squares[2] - adjust2;
+ (squares[1] - adjust1)) * 62
+ squares[2] - adjust2;
- // First piece is on a1-h8 diagonal, second below: map this occurence to
+ // First piece is on a1-h8 diagonal, second below: map this occurrence to
// 6 to differentiate from the above case, rank_of() maps a1-d4 diagonal
// to 0...3 and finally MapB1H1H7[] maps the b1-h1-h7 triangle to 0..27.
else if (off_A1H8(squares[1]))
// 6 to differentiate from the above case, rank_of() maps a1-d4 diagonal
// to 0...3 and finally MapB1H1H7[] maps the b1-h1-h7 triangle to 0..27.
else if (off_A1H8(squares[1]))
idx *= d->groupIdx[0];
Square* groupSq = squares + d->groupLen[0];
idx *= d->groupIdx[0];
Square* groupSq = squares + d->groupLen[0];
- // Encode remainig pawns then pieces according to square, in ascending order
+ // Encode remaining pawns then pieces according to square, in ascending order
bool remainingPawns = entry->hasPawns && entry->pawnCount[1];
while (d->groupLen[++next])
bool remainingPawns = entry->hasPawns && entry->pawnCount[1];
while (d->groupLen[++next])
// Group together pieces that will be encoded together. The general rule is that
// a group contains pieces of same type and color. The exception is the leading
// Group together pieces that will be encoded together. The general rule is that
// a group contains pieces of same type and color. The exception is the leading
-// group that, in case of positions withouth pawns, can be formed by 3 different
+// group that, in case of positions without pawns, can be formed by 3 different
// pieces (default) or by the king pair when there is not a unique piece apart
// from the kings. When there are pawns, pawns are always first in pieces[].
//
// pieces (default) or by the king pair when there is not a unique piece apart
// from the kings. When there are pawns, pawns are always first in pieces[].
//
//
// This ensures unique encoding for the whole position. The order of the
// groups is a per-table parameter and could not follow the canonical leading
//
// This ensures unique encoding for the whole position. The order of the
// groups is a per-table parameter and could not follow the canonical leading
- // pawns/pieces -> remainig pawns -> remaining pieces. In particular the
+ // pawns/pieces -> remaining pawns -> remaining pieces. In particular the
// first group is at order[0] position and the remaining pawns, when present,
// are at order[1] position.
bool pp = e.hasPawns && e.pawnCount[1]; // Pawns on both sides
// first group is at order[0] position and the remaining pawns, when present,
// are at order[1] position.
bool pp = e.hasPawns && e.pawnCount[1]; // Pawns on both sides
d->groupIdx[1] = idx;
idx *= Binomial[d->groupLen[1]][48 - d->groupLen[0]];
}
d->groupIdx[1] = idx;
idx *= Binomial[d->groupLen[1]][48 - d->groupLen[0]];
}
- else // Remainig pieces
+ else // Remaining pieces
{
d->groupIdx[next] = idx;
idx *= Binomial[d->groupLen[next]][freeSquares];
{
d->groupIdx[next] = idx;
idx *= Binomial[d->groupLen[next]][freeSquares];
-// In Recursive Pairing each symbol represents a pair of childern symbols. So
+// In Recursive Pairing each symbol represents a pair of children symbols. So
// read d->btree[] symbols data and expand each one in his left and right child
// symbol until reaching the leafs that represent the symbol value.
uint8_t set_symlen(PairsData* d, Sym s, std::vector<bool>& visited) {
// read d->btree[] symbols data and expand each one in his left and right child
// symbol until reaching the leafs that represent the symbol value.
uint8_t set_symlen(PairsData* d, Sym s, std::vector<bool>& visited) {
for (auto p : bothOnDiagonal)
MapKK[p.first][p.second] = code++;
for (auto p : bothOnDiagonal)
MapKK[p.first][p.second] = code++;
- // Binomial[] stores the Binomial Coefficents using Pascal rule. There
+ // Binomial[] stores the Binomial Coefficients using Pascal rule. There
// are Binomial[k][n] ways to choose k elements from a set of n elements.
Binomial[0][0] = 1;
// are Binomial[k][n] ways to choose k elements from a set of n elements.
Binomial[0][0] = 1;
for (int leadPawnsCnt = 1; leadPawnsCnt <= 5; ++leadPawnsCnt)
for (File f = FILE_A; f <= FILE_D; ++f)
{
for (int leadPawnsCnt = 1; leadPawnsCnt <= 5; ++leadPawnsCnt)
for (File f = FILE_A; f <= FILE_D; ++f)
{
- // Restart the index at every file because TB table is splitted
+ // Restart the index at every file because TB table is split
// by file, so we can reuse the same index for different files.
int idx = 0;
// by file, so we can reuse the same index for different files.
int idx = 0;
// Possible states after a probing operation
enum ProbeState {
FAIL = 0, // Probe failed (missing file table)
// Possible states after a probing operation
enum ProbeState {
FAIL = 0, // Probe failed (missing file table)
- OK = 1, // Probe succesful
+ OK = 1, // Probe successful
CHANGE_STM = -1, // DTZ should check the other side
ZEROING_BEST_MOVE = 2 // Best move zeroes DTZ (capture or pawn move)
};
CHANGE_STM = -1, // DTZ should check the other side
ZEROING_BEST_MOVE = 2 // Best move zeroes DTZ (capture or pawn move)
};
static Tune& instance() { static Tune t; return t; } // Singleton
static Tune& instance() { static Tune t; return t; } // Singleton
- // Use polymorphism to accomodate Entry of different types in the same vector
+ // Use polymorphism to accommodate Entry of different types in the same vector
struct EntryBase {
virtual ~EntryBase() = default;
virtual void init_option() = 0;
struct EntryBase {
virtual ~EntryBase() = default;
virtual void init_option() = 0;
-# to increase the likelyhood of finding a non-reproducible case,
+# to increase the likelihood of finding a non-reproducible case,
# the allowed number of nodes are varied systematically
for i in `seq 1 20`
do
# the allowed number of nodes are varied systematically
for i in `seq 1 20`
do