mirror of
https://github.com/HChaZZY/Stockfish.git
synced 2025-12-24 02:57:11 +08:00
Post-merge fixes.
This commit is contained in:
121
src/evaluate.cpp
121
src/evaluate.cpp
@@ -38,8 +38,127 @@
|
||||
#include "uci.h"
|
||||
#include "incbin/incbin.h"
|
||||
|
||||
// Macro to embed the default efficiently updatable neural network (NNUE) file
|
||||
// data in the engine binary (using incbin.h, by Dale Weiler).
|
||||
// This macro invocation will declare the following three variables
|
||||
// const unsigned char gEmbeddedNNUEData[]; // a pointer to the embedded data
|
||||
// const unsigned char *const gEmbeddedNNUEEnd; // a marker to the end
|
||||
// const unsigned int gEmbeddedNNUESize; // the size of the embedded file
|
||||
// Note that this does not work in Microsoft Visual Studio.
|
||||
#if !defined(_MSC_VER) && !defined(NNUE_EMBEDDING_OFF)
|
||||
INCBIN(EmbeddedNNUE, EvalFileDefaultName);
|
||||
#else
|
||||
const unsigned char gEmbeddedNNUEData[1] = {0x0};
|
||||
const unsigned char *const gEmbeddedNNUEEnd = &gEmbeddedNNUEData[1];
|
||||
const unsigned int gEmbeddedNNUESize = 1;
|
||||
#endif
|
||||
|
||||
using namespace std;
|
||||
|
||||
namespace Stockfish {
|
||||
|
||||
namespace Eval {
|
||||
|
||||
namespace NNUE {
|
||||
string eval_file_loaded = "None";
|
||||
UseNNUEMode useNNUE;
|
||||
|
||||
/// 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.
|
||||
/// 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
|
||||
/// variable to have the engine search in a special directory in their distro.
|
||||
|
||||
static UseNNUEMode nnue_mode_from_option(const UCI::Option& mode)
|
||||
{
|
||||
if (mode == "false")
|
||||
return UseNNUEMode::False;
|
||||
else if (mode == "true")
|
||||
return UseNNUEMode::True;
|
||||
else if (mode == "pure")
|
||||
return UseNNUEMode::Pure;
|
||||
|
||||
return UseNNUEMode::False;
|
||||
}
|
||||
|
||||
void init() {
|
||||
|
||||
useNNUE = nnue_mode_from_option(Options["Use NNUE"]);
|
||||
if (useNNUE == UseNNUEMode::False)
|
||||
return;
|
||||
|
||||
string eval_file = string(Options["EvalFile"]);
|
||||
|
||||
#if defined(DEFAULT_NNUE_DIRECTORY)
|
||||
#define stringify2(x) #x
|
||||
#define stringify(x) stringify2(x)
|
||||
vector<string> dirs = { "<internal>" , "" , CommandLine::binaryDirectory , stringify(DEFAULT_NNUE_DIRECTORY) };
|
||||
#else
|
||||
vector<string> dirs = { "<internal>" , "" , CommandLine::binaryDirectory };
|
||||
#endif
|
||||
|
||||
for (string directory : dirs)
|
||||
if (eval_file_loaded != eval_file)
|
||||
{
|
||||
if (directory != "<internal>")
|
||||
{
|
||||
ifstream stream(directory + eval_file, ios::binary);
|
||||
if (load_eval(eval_file, stream))
|
||||
eval_file_loaded = eval_file;
|
||||
}
|
||||
|
||||
if (directory == "<internal>" && eval_file == EvalFileDefaultName)
|
||||
{
|
||||
// C++ way to prepare a buffer for a memory stream
|
||||
class MemoryBuffer : public basic_streambuf<char> {
|
||||
public: MemoryBuffer(char* p, size_t n) { setg(p, p, p + n); setp(p, p + n); }
|
||||
};
|
||||
|
||||
MemoryBuffer buffer(const_cast<char*>(reinterpret_cast<const char*>(gEmbeddedNNUEData)),
|
||||
size_t(gEmbeddedNNUESize));
|
||||
|
||||
istream stream(&buffer);
|
||||
if (load_eval(eval_file, stream))
|
||||
eval_file_loaded = eval_file;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// NNUE::verify() verifies that the last net used was loaded successfully
|
||||
void verify() {
|
||||
|
||||
string eval_file = string(Options["EvalFile"]);
|
||||
|
||||
if (useNNUE != UseNNUEMode::False && eval_file_loaded != eval_file)
|
||||
{
|
||||
UCI::OptionsMap defaults;
|
||||
UCI::init(defaults);
|
||||
|
||||
string msg1 = "If the UCI option \"Use NNUE\" is set to true, network evaluation parameters compatible with the engine must be available.";
|
||||
string msg2 = "The option is set to true, but the network file " + eval_file + " was not loaded successfully.";
|
||||
string msg3 = "The UCI option EvalFile might need to specify the full path, including the directory name, to the network file.";
|
||||
string msg4 = "The default net can be downloaded from: https://tests.stockfishchess.org/api/nn/" + string(defaults["EvalFile"]);
|
||||
string msg5 = "The engine will be terminated now.";
|
||||
|
||||
sync_cout << "info string ERROR: " << msg1 << sync_endl;
|
||||
sync_cout << "info string ERROR: " << msg2 << sync_endl;
|
||||
sync_cout << "info string ERROR: " << msg3 << sync_endl;
|
||||
sync_cout << "info string ERROR: " << msg4 << sync_endl;
|
||||
sync_cout << "info string ERROR: " << msg5 << sync_endl;
|
||||
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
if (useNNUE != UseNNUEMode::False)
|
||||
sync_cout << "info string NNUE evaluation using " << eval_file << " enabled" << sync_endl;
|
||||
else
|
||||
sync_cout << "info string classical evaluation enabled" << sync_endl;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
namespace Trace {
|
||||
|
||||
enum Tracing { NO_TRACE, TRACE };
|
||||
@@ -1021,7 +1140,7 @@ Value Eval::evaluate(const Position& pos) {
|
||||
bool lowPieceEndgame = pos.non_pawn_material() == BishopValueMg
|
||||
|| (pos.non_pawn_material() < 2 * RookValueMg && pos.count<PAWN>() < 2);
|
||||
|
||||
v = classical || lowPieceEndgame ? Evaluation<NO_TRACE>(pos).value()
|
||||
v = classical || lowPieceEndgame ? Evaluation<NO_TRACE>(pos).value()
|
||||
: adjusted_NNUE();
|
||||
|
||||
// If the classical eval is small and imbalance large, use NNUE nevertheless.
|
||||
|
||||
@@ -28,6 +28,7 @@ namespace Stockfish {
|
||||
class Position;
|
||||
|
||||
namespace Eval {
|
||||
|
||||
std::string trace(const Position& pos);
|
||||
Value evaluate(const Position& pos);
|
||||
|
||||
@@ -36,6 +37,23 @@ namespace Eval {
|
||||
// name of the macro, as it is used in the Makefile.
|
||||
#define EvalFileDefaultName "nn-62ef826d1a6d.nnue"
|
||||
|
||||
namespace NNUE {
|
||||
enum struct UseNNUEMode
|
||||
{
|
||||
False,
|
||||
True,
|
||||
Pure
|
||||
};
|
||||
|
||||
extern UseNNUEMode useNNUE;
|
||||
extern std::string eval_file_loaded;
|
||||
|
||||
Value evaluate(const Position& pos);
|
||||
bool load_eval(std::string name, std::istream& stream);
|
||||
void init();
|
||||
void verify();
|
||||
}
|
||||
|
||||
} // namespace Eval
|
||||
|
||||
} // namespace Stockfish
|
||||
|
||||
@@ -61,10 +61,10 @@ typedef bool(*fun3_t)(HANDLE, CONST GROUP_AFFINITY*, PGROUP_AFFINITY);
|
||||
|
||||
using namespace std;
|
||||
|
||||
SynchronizedRegionLogger sync_region_cout(std::cout);
|
||||
|
||||
namespace Stockfish {
|
||||
|
||||
SynchronizedRegionLogger sync_region_cout(std::cout);
|
||||
|
||||
namespace {
|
||||
|
||||
/// Version number. If Version is left empty, then compile date in the format
|
||||
|
||||
@@ -1,33 +1,21 @@
|
||||
/*
|
||||
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/>.
|
||||
*/
|
||||
|
||||
// Code for calculating NNUE evaluation function
|
||||
|
||||
#include "evaluate_nnue.h"
|
||||
|
||||
#include "position.h"
|
||||
#include "misc.h"
|
||||
#include "uci.h"
|
||||
#include "types.h"
|
||||
|
||||
#include <iostream>
|
||||
#include <string>
|
||||
#include <fstream>
|
||||
#include <set>
|
||||
|
||||
#include "../evaluate.h"
|
||||
@@ -49,36 +37,18 @@ namespace Stockfish::Eval::NNUE {
|
||||
// Evaluation function file name
|
||||
std::string fileName;
|
||||
|
||||
// Saved evaluation function file name
|
||||
std::string savedfileName = "nn.bin";
|
||||
|
||||
// Get a string that represents the structure of the evaluation function
|
||||
std::string get_architecture_string() {
|
||||
return "Features=" + FeatureTransformer::get_structure_string() +
|
||||
",Network=" + Network::get_structure_string();
|
||||
}
|
||||
|
||||
std::string get_layers_info() {
|
||||
return
|
||||
FeatureTransformer::get_layers_info()
|
||||
+ '\n' + Network::get_layers_info();
|
||||
}
|
||||
|
||||
UseNNUEMode useNNUE;
|
||||
std::string eval_file_loaded = "None";
|
||||
|
||||
namespace Detail {
|
||||
|
||||
// Initialize the evaluation function parameters
|
||||
template <typename T>
|
||||
void initialize(AlignedPtr<T>& pointer) {
|
||||
void Initialize(AlignedPtr<T>& pointer) {
|
||||
|
||||
pointer.reset(reinterpret_cast<T*>(std_aligned_alloc(alignof(T), sizeof(T))));
|
||||
std::memset(pointer.get(), 0, sizeof(T));
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
void initialize(LargePagePtr<T>& pointer) {
|
||||
void Initialize(LargePagePtr<T>& pointer) {
|
||||
|
||||
static_assert(alignof(T) <= 4096, "aligned_large_pages_alloc() may fail for such a big alignment requirement of T");
|
||||
pointer.reset(reinterpret_cast<T*>(aligned_large_pages_alloc(sizeof(T))));
|
||||
@@ -95,35 +65,17 @@ namespace Stockfish::Eval::NNUE {
|
||||
return reference.ReadParameters(stream);
|
||||
}
|
||||
|
||||
// write evaluation function parameters
|
||||
template <typename T>
|
||||
bool WriteParameters(std::ostream& stream, const AlignedPtr<T>& pointer) {
|
||||
constexpr std::uint32_t header = T::GetHashValue();
|
||||
|
||||
stream.write(reinterpret_cast<const char*>(&header), sizeof(header));
|
||||
|
||||
return pointer->WriteParameters(stream);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
bool WriteParameters(std::ostream& stream, const LargePagePtr<T>& pointer) {
|
||||
constexpr std::uint32_t header = T::GetHashValue();
|
||||
|
||||
stream.write(reinterpret_cast<const char*>(&header), sizeof(header));
|
||||
|
||||
return pointer->WriteParameters(stream);
|
||||
}
|
||||
} // namespace Detail
|
||||
|
||||
// Initialize the evaluation function parameters
|
||||
void initialize() {
|
||||
void Initialize() {
|
||||
|
||||
Detail::initialize(feature_transformer);
|
||||
Detail::initialize(network);
|
||||
Detail::Initialize(feature_transformer);
|
||||
Detail::Initialize(network);
|
||||
}
|
||||
|
||||
// Read network header
|
||||
bool read_header(std::istream& stream, std::uint32_t* hash_value, std::string* architecture)
|
||||
bool ReadHeader(std::istream& stream, std::uint32_t* hash_value, std::string* architecture)
|
||||
{
|
||||
std::uint32_t version, size;
|
||||
|
||||
@@ -136,48 +88,18 @@ namespace Stockfish::Eval::NNUE {
|
||||
return !stream.fail();
|
||||
}
|
||||
|
||||
// write the header
|
||||
bool write_header(std::ostream& stream,
|
||||
std::uint32_t hash_value, const std::string& architecture) {
|
||||
|
||||
stream.write(reinterpret_cast<const char*>(&kVersion), sizeof(kVersion));
|
||||
stream.write(reinterpret_cast<const char*>(&hash_value), sizeof(hash_value));
|
||||
|
||||
const std::uint32_t size = static_cast<std::uint32_t>(architecture.size());
|
||||
|
||||
stream.write(reinterpret_cast<const char*>(&size), sizeof(size));
|
||||
stream.write(architecture.data(), size);
|
||||
|
||||
return !stream.fail();
|
||||
}
|
||||
|
||||
// Read network parameters
|
||||
bool ReadParameters(std::istream& stream) {
|
||||
|
||||
std::uint32_t hash_value;
|
||||
std::string architecture;
|
||||
if (!read_header(stream, &hash_value, &architecture)) return false;
|
||||
if (!ReadHeader(stream, &hash_value, &architecture)) return false;
|
||||
if (hash_value != kHashValue) return false;
|
||||
if (!Detail::ReadParameters(stream, *feature_transformer)) return false;
|
||||
if (!Detail::ReadParameters(stream, *network)) return false;
|
||||
return stream && stream.peek() == std::ios::traits_type::eof();
|
||||
}
|
||||
|
||||
// write evaluation function parameters
|
||||
bool WriteParameters(std::ostream& stream) {
|
||||
|
||||
if (!write_header(stream, kHashValue, get_architecture_string()))
|
||||
return false;
|
||||
|
||||
if (!Detail::WriteParameters(stream, feature_transformer))
|
||||
return false;
|
||||
|
||||
if (!Detail::WriteParameters(stream, network))
|
||||
return false;
|
||||
|
||||
return !stream.fail();
|
||||
}
|
||||
|
||||
// Evaluation function. Perform differential calculation.
|
||||
Value evaluate(const Position& pos) {
|
||||
|
||||
@@ -211,65 +133,9 @@ namespace Stockfish::Eval::NNUE {
|
||||
// Load eval, from a file stream or a memory stream
|
||||
bool load_eval(std::string name, std::istream& stream) {
|
||||
|
||||
initialize();
|
||||
Initialize();
|
||||
fileName = name;
|
||||
return ReadParameters(stream);
|
||||
}
|
||||
|
||||
static UseNNUEMode nnue_mode_from_option(const UCI::Option& mode)
|
||||
{
|
||||
if (mode == "false")
|
||||
return UseNNUEMode::False;
|
||||
else if (mode == "true")
|
||||
return UseNNUEMode::True;
|
||||
else if (mode == "pure")
|
||||
return UseNNUEMode::Pure;
|
||||
|
||||
return UseNNUEMode::False;
|
||||
}
|
||||
|
||||
void init() {
|
||||
|
||||
useNNUE = nnue_mode_from_option(Options["Use NNUE"]);
|
||||
|
||||
if (Options["SkipLoadingEval"])
|
||||
{
|
||||
eval_file_loaded.clear();
|
||||
return;
|
||||
}
|
||||
|
||||
if (useNNUE == UseNNUEMode::False)
|
||||
{
|
||||
// Keep the eval file loaded. Useful for mixed bench.
|
||||
return;
|
||||
}
|
||||
|
||||
std::string eval_file = std::string(Options["EvalFile"]);
|
||||
|
||||
#if defined(DEFAULT_NNUE_DIRECTORY)
|
||||
#define stringify2(x) #x
|
||||
#define stringify(x) stringify2(x)
|
||||
std::vector<std::string> dirs = { "" , CommandLine::binaryDirectory , stringify(DEFAULT_NNUE_DIRECTORY) };
|
||||
#else
|
||||
std::vector<std::string> dirs = { "" , CommandLine::binaryDirectory };
|
||||
#endif
|
||||
|
||||
for (std::string directory : dirs)
|
||||
{
|
||||
if (eval_file_loaded != eval_file)
|
||||
{
|
||||
std::ifstream stream(directory + eval_file, std::ios::binary);
|
||||
if (load_eval(eval_file, stream))
|
||||
{
|
||||
sync_cout << "info string Loaded eval file " << directory + eval_file << sync_endl;
|
||||
eval_file_loaded = eval_file;
|
||||
}
|
||||
else
|
||||
{
|
||||
sync_cout << "info string ERROR: failed to load eval file " << directory + eval_file << sync_endl;
|
||||
eval_file_loaded.clear();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace Stockfish::Eval::NNUE
|
||||
} // namespace Stockfish::Eval::NNUE
|
||||
@@ -1,17 +1,14 @@
|
||||
/*
|
||||
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/>.
|
||||
*/
|
||||
@@ -23,19 +20,10 @@
|
||||
|
||||
#include "nnue_feature_transformer.h"
|
||||
|
||||
#include "misc.h"
|
||||
|
||||
#include <memory>
|
||||
|
||||
namespace Stockfish::Eval::NNUE {
|
||||
|
||||
enum struct UseNNUEMode
|
||||
{
|
||||
False,
|
||||
True,
|
||||
Pure
|
||||
};
|
||||
|
||||
// Hash value of evaluation function structure
|
||||
constexpr std::uint32_t kHashValue =
|
||||
FeatureTransformer::GetHashValue() ^ Network::GetHashValue();
|
||||
@@ -65,4 +53,4 @@ namespace Stockfish::Eval::NNUE {
|
||||
|
||||
} // namespace Stockfish::Eval::NNUE
|
||||
|
||||
#endif // #ifndef NNUE_EVALUATE_NNUE_H_INCLUDED
|
||||
#endif // #ifndef NNUE_EVALUATE_NNUE_H_INCLUDED
|
||||
@@ -1,17 +1,14 @@
|
||||
/*
|
||||
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/>.
|
||||
*/
|
||||
@@ -26,277 +23,44 @@
|
||||
|
||||
namespace Stockfish::Eval::NNUE::Features {
|
||||
|
||||
// Class template that represents a list of values
|
||||
template <typename T, T... Values>
|
||||
struct CompileTimeList;
|
||||
// Class template that represents a list of values
|
||||
template <typename T, T... Values>
|
||||
struct CompileTimeList;
|
||||
|
||||
template <typename T, T First, T... Remaining>
|
||||
struct CompileTimeList<T, First, Remaining...> {
|
||||
static constexpr bool contains(T value) {
|
||||
return value == First || CompileTimeList<T, Remaining...>::contains(value);
|
||||
}
|
||||
template <typename T, T First, T... Remaining>
|
||||
struct CompileTimeList<T, First, Remaining...> {
|
||||
static constexpr bool Contains(T value) {
|
||||
return value == First || CompileTimeList<T, Remaining...>::Contains(value);
|
||||
}
|
||||
static constexpr std::array<T, sizeof...(Remaining) + 1>
|
||||
kValues = {{First, Remaining...}};
|
||||
};
|
||||
|
||||
static constexpr std::array<T, sizeof...(Remaining) + 1>
|
||||
kValues = {{First, Remaining...}};
|
||||
};
|
||||
// Base class of feature set
|
||||
template <typename Derived>
|
||||
class FeatureSetBase {
|
||||
|
||||
template <typename T, T First, T... Remaining>
|
||||
constexpr std::array<T, sizeof...(Remaining) + 1>
|
||||
CompileTimeList<T, First, Remaining...>::kValues;
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
struct CompileTimeList<T> {
|
||||
static constexpr bool contains(T /*value*/) {
|
||||
return false;
|
||||
}
|
||||
static constexpr std::array<T, 0> kValues = { {} };
|
||||
};
|
||||
// Class template that represents the feature set
|
||||
template <typename FeatureType>
|
||||
class FeatureSet<FeatureType> : public FeatureSetBase<FeatureSet<FeatureType>> {
|
||||
|
||||
// Class template that adds to the beginning of the list
|
||||
template <typename T, typename ListType, T Value>
|
||||
struct AppendToList;
|
||||
public:
|
||||
// Hash value embedded in the evaluation file
|
||||
static constexpr std::uint32_t kHashValue = FeatureType::kHashValue;
|
||||
// Number of feature dimensions
|
||||
static constexpr IndexType kDimensions = FeatureType::kDimensions;
|
||||
// Maximum number of simultaneously active features
|
||||
static constexpr IndexType kMaxActiveDimensions =
|
||||
FeatureType::kMaxActiveDimensions;
|
||||
// Trigger for full calculation instead of difference calculation
|
||||
using SortedTriggerSet =
|
||||
CompileTimeList<TriggerEvent, FeatureType::kRefreshTrigger>;
|
||||
static constexpr auto kRefreshTriggers = SortedTriggerSet::kValues;
|
||||
|
||||
template <typename T, T... Values, T AnotherValue>
|
||||
struct AppendToList<T, CompileTimeList<T, Values...>, AnotherValue> {
|
||||
using Result = CompileTimeList<T, AnotherValue, Values...>;
|
||||
};
|
||||
|
||||
// Class template for adding to a sorted, unique list
|
||||
template <typename T, typename ListType, T Value>
|
||||
struct InsertToSet;
|
||||
|
||||
template <typename T, T First, T... Remaining, T AnotherValue>
|
||||
struct InsertToSet<T, CompileTimeList<T, First, Remaining...>, AnotherValue> {
|
||||
using Result =
|
||||
std::conditional_t<
|
||||
CompileTimeList<T, First, Remaining...>::contains(AnotherValue),
|
||||
CompileTimeList<T, First, Remaining...>,
|
||||
std::conditional_t<
|
||||
(AnotherValue < First),
|
||||
CompileTimeList<T, AnotherValue, First, Remaining...>,
|
||||
typename AppendToList<T, typename InsertToSet<
|
||||
T, CompileTimeList<T, Remaining...>, AnotherValue>::Result,
|
||||
First
|
||||
>::Result
|
||||
>
|
||||
>;
|
||||
};
|
||||
|
||||
template <typename T, T Value>
|
||||
struct InsertToSet<T, CompileTimeList<T>, Value> {
|
||||
using Result = CompileTimeList<T, Value>;
|
||||
};
|
||||
|
||||
// Base class of feature set
|
||||
template <typename Derived>
|
||||
class FeatureSetBase {
|
||||
|
||||
public:
|
||||
// Get a list of indices for active features
|
||||
template <typename IndexListType>
|
||||
static void append_active_indices(
|
||||
const Position& pos, TriggerEvent trigger, IndexListType active[2]) {
|
||||
|
||||
for (Color perspective : { WHITE, BLACK }) {
|
||||
Derived::collect_active_indices(
|
||||
pos, trigger, perspective, &active[perspective]);
|
||||
}
|
||||
}
|
||||
|
||||
// Get a list of indices for recently changed features
|
||||
template <typename PositionType, typename IndexListType>
|
||||
static void append_changed_indices(
|
||||
const PositionType& pos,
|
||||
TriggerEvent trigger,
|
||||
IndexListType removed[2],
|
||||
IndexListType added[2],
|
||||
bool reset[2]) {
|
||||
|
||||
const auto& dp = pos.state()->dirtyPiece;
|
||||
|
||||
for (Color perspective : { WHITE, BLACK }) {
|
||||
switch (trigger) {
|
||||
case TriggerEvent::kNone:
|
||||
break;
|
||||
case TriggerEvent::kFriendKingMoved:
|
||||
if (dp.dirty_num == 0) continue;
|
||||
reset[perspective] = dp.piece[0] == make_piece(perspective, KING);
|
||||
break;
|
||||
case TriggerEvent::kEnemyKingMoved:
|
||||
if (dp.dirty_num == 0) continue;
|
||||
reset[perspective] = dp.piece[0] == make_piece(~perspective, KING);
|
||||
break;
|
||||
case TriggerEvent::kAnyKingMoved:
|
||||
if (dp.dirty_num == 0) continue;
|
||||
reset[perspective] = type_of(dp.piece[0]) == KING;
|
||||
break;
|
||||
case TriggerEvent::kAnyPieceMoved:
|
||||
reset[perspective] = true;
|
||||
break;
|
||||
default:
|
||||
assert(false);
|
||||
break;
|
||||
}
|
||||
|
||||
if (reset[perspective]) {
|
||||
Derived::collect_active_indices(
|
||||
pos, trigger, perspective, &added[perspective]);
|
||||
} else {
|
||||
Derived::collect_changed_indices(
|
||||
pos, trigger, perspective,
|
||||
&removed[perspective], &added[perspective]);
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
// Class template that represents the feature set
|
||||
// do internal processing in reverse order of template arguments in order to linearize the amount of calculation at runtime
|
||||
template <typename FirstFeatureType, typename... RemainingFeatureTypes>
|
||||
class FeatureSet<FirstFeatureType, RemainingFeatureTypes...> :
|
||||
public FeatureSetBase<
|
||||
FeatureSet<FirstFeatureType, RemainingFeatureTypes...>
|
||||
> {
|
||||
|
||||
private:
|
||||
using Head = FirstFeatureType;
|
||||
using Tail = FeatureSet<RemainingFeatureTypes...>;
|
||||
|
||||
public:
|
||||
// Hash value embedded in the evaluation function file
|
||||
static constexpr std::uint32_t kHashValue =
|
||||
Head::kHashValue ^ (Tail::kHashValue << 1) ^ (Tail::kHashValue >> 31);
|
||||
|
||||
// number of feature dimensions
|
||||
static constexpr IndexType kDimensions =
|
||||
Head::kDimensions + Tail::kDimensions;
|
||||
|
||||
// The maximum value of the number of indexes whose value is 1 at the same time among the feature values
|
||||
static constexpr IndexType kMaxActiveDimensions =
|
||||
Head::kMaxActiveDimensions + Tail::kMaxActiveDimensions;
|
||||
|
||||
// List of timings to perform all calculations instead of difference calculation
|
||||
using SortedTriggerSet = typename InsertToSet<TriggerEvent,
|
||||
typename Tail::SortedTriggerSet, Head::kRefreshTrigger>::Result;
|
||||
|
||||
static constexpr auto kRefreshTriggers = SortedTriggerSet::kValues;
|
||||
|
||||
// Get the feature quantity name
|
||||
static std::string get_name() {
|
||||
return std::string(Head::kName) + "+" + Tail::get_name();
|
||||
}
|
||||
|
||||
private:
|
||||
// Get a list of indices with a value of 1 among the features
|
||||
template <typename IndexListType>
|
||||
static void collect_active_indices(
|
||||
const Position& pos,
|
||||
const TriggerEvent trigger,
|
||||
const Color perspective,
|
||||
IndexListType* const active) {
|
||||
|
||||
Tail::collect_active_indices(pos, trigger, perspective, active);
|
||||
if (Head::kRefreshTrigger == trigger) {
|
||||
const auto start = active->size();
|
||||
Head::append_active_indices(pos, perspective, active);
|
||||
|
||||
for (auto i = start; i < active->size(); ++i) {
|
||||
(*active)[i] += Tail::kDimensions;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Get a list of indices whose values have changed from the previous one in the feature quantity
|
||||
template <typename IndexListType>
|
||||
static void collect_changed_indices(
|
||||
const Position& pos,
|
||||
const TriggerEvent trigger,
|
||||
const Color perspective,
|
||||
IndexListType* const removed,
|
||||
IndexListType* const added) {
|
||||
|
||||
Tail::collect_changed_indices(pos, trigger, perspective, removed, added);
|
||||
if (Head::kRefreshTrigger == trigger) {
|
||||
const auto start_removed = removed->size();
|
||||
const auto start_added = added->size();
|
||||
Head::append_changed_indices(pos, perspective, removed, added);
|
||||
|
||||
for (auto i = start_removed; i < removed->size(); ++i) {
|
||||
(*removed)[i] += Tail::kDimensions;
|
||||
}
|
||||
|
||||
for (auto i = start_added; i < added->size(); ++i) {
|
||||
(*added)[i] += Tail::kDimensions;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Make the base class and the class template that recursively uses itself a friend
|
||||
friend class FeatureSetBase<FeatureSet>;
|
||||
|
||||
template <typename... FeatureTypes>
|
||||
friend class FeatureSet;
|
||||
};
|
||||
|
||||
// Class template that represents the feature set
|
||||
template <typename FeatureType>
|
||||
class FeatureSet<FeatureType> : public FeatureSetBase<FeatureSet<FeatureType>> {
|
||||
|
||||
public:
|
||||
// Hash value embedded in the evaluation file
|
||||
static constexpr std::uint32_t kHashValue = FeatureType::kHashValue;
|
||||
|
||||
// Number of feature dimensions
|
||||
static constexpr IndexType kDimensions = FeatureType::kDimensions;
|
||||
|
||||
// Maximum number of simultaneously active features
|
||||
static constexpr IndexType kMaxActiveDimensions =
|
||||
FeatureType::kMaxActiveDimensions;
|
||||
|
||||
// Trigger for full calculation instead of difference calculation
|
||||
using SortedTriggerSet =
|
||||
CompileTimeList<TriggerEvent, FeatureType::kRefreshTrigger>;
|
||||
|
||||
static constexpr auto kRefreshTriggers = SortedTriggerSet::kValues;
|
||||
|
||||
// Get the feature quantity name
|
||||
static std::string get_name() {
|
||||
return FeatureType::kName;
|
||||
}
|
||||
|
||||
private:
|
||||
// Get a list of indices for active features
|
||||
static void collect_active_indices(
|
||||
const Position& pos,
|
||||
const TriggerEvent trigger,
|
||||
const Color perspective,
|
||||
IndexList* const active) {
|
||||
|
||||
if (FeatureType::kRefreshTrigger == trigger) {
|
||||
FeatureType::append_active_indices(pos, perspective, active);
|
||||
}
|
||||
}
|
||||
|
||||
// Get a list of indices for recently changed features
|
||||
static void collect_changed_indices(
|
||||
const Position& pos,
|
||||
const TriggerEvent trigger,
|
||||
const Color perspective,
|
||||
IndexList* const removed,
|
||||
IndexList* const added) {
|
||||
|
||||
if (FeatureType::kRefreshTrigger == trigger) {
|
||||
FeatureType::append_changed_indices(pos, perspective, removed, added);
|
||||
}
|
||||
}
|
||||
|
||||
// Make the base class and the class template that recursively uses itself a friend
|
||||
friend class FeatureSetBase<FeatureSet>;
|
||||
|
||||
template <typename... FeatureTypes>
|
||||
friend class FeatureSet;
|
||||
};
|
||||
};
|
||||
|
||||
} // namespace Stockfish::Eval::NNUE::Features
|
||||
|
||||
#endif // #ifndef NNUE_FEATURE_SET_H_INCLUDED
|
||||
#endif // #ifndef NNUE_FEATURE_SET_H_INCLUDED
|
||||
@@ -33,16 +33,11 @@ namespace Stockfish::Eval::NNUE::Features {
|
||||
|
||||
// Trigger to perform full calculations instead of difference only
|
||||
enum class TriggerEvent {
|
||||
kNone, // Calculate the difference whenever possible
|
||||
kFriendKingMoved, // calculate full evaluation when own king moves
|
||||
kEnemyKingMoved, // calculate full evaluation when opponent king moves
|
||||
kAnyKingMoved, // calculate full evaluation when any king moves
|
||||
kAnyPieceMoved, // always calculate full evaluation
|
||||
kFriendKingMoved // calculate full evaluation when own king moves
|
||||
};
|
||||
|
||||
enum class Side {
|
||||
kFriend, // side to move
|
||||
kEnemy, // opponent
|
||||
kFriend // side to move
|
||||
};
|
||||
|
||||
} // namespace Stockfish::Eval::NNUE::Features
|
||||
|
||||
@@ -80,6 +80,7 @@ namespace Stockfish::Eval::NNUE::Features {
|
||||
if (dp.to[i] != SQ_NONE)
|
||||
added->push_back(make_index(perspective, dp.to[i], pc, ksq));
|
||||
}
|
||||
}
|
||||
|
||||
template class HalfKP<Side::kFriend>;
|
||||
|
||||
|
||||
@@ -1,17 +1,14 @@
|
||||
/*
|
||||
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/>.
|
||||
*/
|
||||
@@ -55,8 +52,6 @@ namespace Stockfish::Eval::NNUE::Layers {
|
||||
static constexpr std::size_t kBufferSize =
|
||||
PreviousLayer::kBufferSize + kSelfBufferSize;
|
||||
|
||||
static constexpr int kLayerIndex = PreviousLayer::kLayerIndex + 1;
|
||||
|
||||
// Hash value embedded in the evaluation file
|
||||
static constexpr std::uint32_t GetHashValue() {
|
||||
std::uint32_t hash_value = 0xCC03DAE4u;
|
||||
@@ -66,27 +61,6 @@ namespace Stockfish::Eval::NNUE::Layers {
|
||||
return hash_value;
|
||||
}
|
||||
|
||||
static std::string get_name() {
|
||||
return "AffineTransform[" +
|
||||
std::to_string(kOutputDimensions) + "<-" +
|
||||
std::to_string(kInputDimensions) + "]";
|
||||
}
|
||||
|
||||
// A string that represents the structure from the input layer to this layer
|
||||
static std::string get_structure_string() {
|
||||
return get_name() + "(" +
|
||||
PreviousLayer::get_structure_string() + ")";
|
||||
}
|
||||
|
||||
static std::string get_layers_info() {
|
||||
std::string info = PreviousLayer::get_layers_info();
|
||||
info += "\n - ";
|
||||
info += std::to_string(kLayerIndex);
|
||||
info += " - ";
|
||||
info += get_name();
|
||||
return info;
|
||||
}
|
||||
|
||||
// Read network parameters
|
||||
bool ReadParameters(std::istream& stream) {
|
||||
if (!previous_layer_.ReadParameters(stream)) return false;
|
||||
@@ -148,21 +122,6 @@ namespace Stockfish::Eval::NNUE::Layers {
|
||||
return !stream.fail();
|
||||
}
|
||||
|
||||
// write parameters
|
||||
bool WriteParameters(std::ostream& stream) const {
|
||||
if (!previous_layer_.WriteParameters(stream))
|
||||
return false;
|
||||
|
||||
stream.write(reinterpret_cast<const char*>(biases_),
|
||||
kOutputDimensions * sizeof(BiasType));
|
||||
|
||||
stream.write(reinterpret_cast<const char*>(weights_),
|
||||
kOutputDimensions * kPaddedInputDimensions *
|
||||
sizeof(WeightType));
|
||||
|
||||
return !stream.fail();
|
||||
}
|
||||
|
||||
// Forward propagation
|
||||
const OutputType* Propagate(
|
||||
const TransformedFeatureType* transformed_features, char* buffer) const {
|
||||
@@ -474,9 +433,6 @@ namespace Stockfish::Eval::NNUE::Layers {
|
||||
using BiasType = OutputType;
|
||||
using WeightType = std::int8_t;
|
||||
|
||||
// Make the learning class a friend
|
||||
friend class Trainer<AffineTransform>;
|
||||
|
||||
PreviousLayer previous_layer_;
|
||||
|
||||
alignas(kCacheLineSize) BiasType biases_[kOutputDimensions];
|
||||
@@ -502,4 +458,4 @@ namespace Stockfish::Eval::NNUE::Layers {
|
||||
|
||||
} // namespace Stockfish::Eval::NNUE::Layers
|
||||
|
||||
#endif // #ifndef NNUE_LAYERS_AFFINE_TRANSFORM_H_INCLUDED
|
||||
#endif // #ifndef NNUE_LAYERS_AFFINE_TRANSFORM_H_INCLUDED
|
||||
@@ -1,17 +1,14 @@
|
||||
/*
|
||||
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/>.
|
||||
*/
|
||||
@@ -25,12 +22,16 @@
|
||||
|
||||
namespace Stockfish::Eval::NNUE {
|
||||
|
||||
// The accumulator of a StateInfo without parent is set to the INIT state
|
||||
enum AccumulatorState { EMPTY, COMPUTED, INIT };
|
||||
|
||||
// Class that holds the result of affine transformation of input features
|
||||
struct alignas(kCacheLineSize) Accumulator {
|
||||
std::int16_t accumulation[2][kRefreshTriggers.size()][kTransformedFeatureDimensions];
|
||||
bool computed_accumulation;
|
||||
std::int16_t
|
||||
accumulation[2][kRefreshTriggers.size()][kTransformedFeatureDimensions];
|
||||
AccumulatorState state[2];
|
||||
};
|
||||
|
||||
} // namespace Stockfish::Eval::NNUE
|
||||
|
||||
#endif // NNUE_ACCUMULATOR_H_INCLUDED
|
||||
#endif // NNUE_ACCUMULATOR_H_INCLUDED
|
||||
@@ -1,17 +1,14 @@
|
||||
/*
|
||||
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/>.
|
||||
*/
|
||||
@@ -25,8 +22,7 @@
|
||||
#include "nnue_architecture.h"
|
||||
#include "features/index_list.h"
|
||||
|
||||
#include <cstring>
|
||||
#include <string>
|
||||
#include <cstring> // std::memset()
|
||||
|
||||
namespace Stockfish::Eval::NNUE {
|
||||
|
||||
@@ -41,7 +37,6 @@ namespace Stockfish::Eval::NNUE {
|
||||
#define vec_store(a,b) _mm512_store_si512(a,b)
|
||||
#define vec_add_16(a,b) _mm512_add_epi16(a,b)
|
||||
#define vec_sub_16(a,b) _mm512_sub_epi16(a,b)
|
||||
#define vec_zero _mm512_setzero_si512()
|
||||
static constexpr IndexType kNumRegs = 8; // only 8 are needed
|
||||
|
||||
#elif USE_AVX2
|
||||
@@ -50,7 +45,6 @@ namespace Stockfish::Eval::NNUE {
|
||||
#define vec_store(a,b) _mm256_store_si256(a,b)
|
||||
#define vec_add_16(a,b) _mm256_add_epi16(a,b)
|
||||
#define vec_sub_16(a,b) _mm256_sub_epi16(a,b)
|
||||
#define vec_zero _mm256_setzero_si256()
|
||||
static constexpr IndexType kNumRegs = 16;
|
||||
|
||||
#elif USE_SSE2
|
||||
@@ -59,7 +53,6 @@ namespace Stockfish::Eval::NNUE {
|
||||
#define vec_store(a,b) *(a)=(b)
|
||||
#define vec_add_16(a,b) _mm_add_epi16(a,b)
|
||||
#define vec_sub_16(a,b) _mm_sub_epi16(a,b)
|
||||
#define vec_zero _mm_setzero_si128()
|
||||
static constexpr IndexType kNumRegs = Is64Bit ? 16 : 8;
|
||||
|
||||
#elif USE_MMX
|
||||
@@ -68,7 +61,6 @@ namespace Stockfish::Eval::NNUE {
|
||||
#define vec_store(a,b) *(a)=(b)
|
||||
#define vec_add_16(a,b) _mm_add_pi16(a,b)
|
||||
#define vec_sub_16(a,b) _mm_sub_pi16(a,b)
|
||||
#define vec_zero _mm_setzero_si64()
|
||||
static constexpr IndexType kNumRegs = 8;
|
||||
|
||||
#elif USE_NEON
|
||||
@@ -77,7 +69,6 @@ namespace Stockfish::Eval::NNUE {
|
||||
#define vec_store(a,b) *(a)=(b)
|
||||
#define vec_add_16(a,b) vaddq_s16(a,b)
|
||||
#define vec_sub_16(a,b) vsubq_s16(a,b)
|
||||
#define vec_zero {0}
|
||||
static constexpr IndexType kNumRegs = 16;
|
||||
|
||||
#else
|
||||
@@ -109,33 +100,12 @@ namespace Stockfish::Eval::NNUE {
|
||||
static constexpr std::size_t kBufferSize =
|
||||
kOutputDimensions * sizeof(OutputType);
|
||||
|
||||
static constexpr int kLayerIndex = 0;
|
||||
|
||||
// Hash value embedded in the evaluation file
|
||||
static constexpr std::uint32_t GetHashValue() {
|
||||
|
||||
return RawFeatures::kHashValue ^ kOutputDimensions;
|
||||
}
|
||||
|
||||
static std::string get_name() {
|
||||
return RawFeatures::get_name() + "[" +
|
||||
std::to_string(kInputDimensions) + "->" +
|
||||
std::to_string(kHalfDimensions) + "x2]";
|
||||
}
|
||||
|
||||
// a string representing the structure
|
||||
static std::string get_structure_string() {
|
||||
return get_name();
|
||||
}
|
||||
|
||||
static std::string get_layers_info() {
|
||||
std::string info = " - ";
|
||||
info += std::to_string(kLayerIndex);
|
||||
info += " - ";
|
||||
info += get_name();
|
||||
return info;
|
||||
}
|
||||
|
||||
// Read network parameters
|
||||
bool ReadParameters(std::istream& stream) {
|
||||
|
||||
@@ -146,38 +116,11 @@ namespace Stockfish::Eval::NNUE {
|
||||
return !stream.fail();
|
||||
}
|
||||
|
||||
// write parameters
|
||||
bool WriteParameters(std::ostream& stream) const {
|
||||
stream.write(reinterpret_cast<const char*>(biases_),
|
||||
kHalfDimensions * sizeof(BiasType));
|
||||
|
||||
stream.write(reinterpret_cast<const char*>(weights_),
|
||||
kHalfDimensions * kInputDimensions * sizeof(WeightType));
|
||||
|
||||
return !stream.fail();
|
||||
}
|
||||
|
||||
// Proceed with the difference calculation if possible
|
||||
bool update_accumulator_if_possible(const Position& pos) const {
|
||||
|
||||
const auto now = pos.state();
|
||||
if (now->accumulator.computed_accumulation)
|
||||
return true;
|
||||
|
||||
const auto prev = now->previous;
|
||||
if (prev && prev->accumulator.computed_accumulation) {
|
||||
update_accumulator(pos);
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
// Convert input features
|
||||
void Transform(const Position& pos, OutputType* output) const {
|
||||
|
||||
if (!update_accumulator_if_possible(pos))
|
||||
refresh_accumulator(pos);
|
||||
UpdateAccumulator(pos, WHITE);
|
||||
UpdateAccumulator(pos, BLACK);
|
||||
|
||||
const auto& accumulation = pos.state()->accumulator.accumulation;
|
||||
|
||||
@@ -221,13 +164,6 @@ namespace Stockfish::Eval::NNUE {
|
||||
&reinterpret_cast<const __m512i*>(accumulation[perspectives[p]][0])[j * 2 + 0]);
|
||||
__m512i sum1 = _mm512_load_si512(
|
||||
&reinterpret_cast<const __m512i*>(accumulation[perspectives[p]][0])[j * 2 + 1]);
|
||||
for (IndexType i = 1; i < kRefreshTriggers.size(); ++i) {
|
||||
sum0 = _mm512_add_epi16(sum0, reinterpret_cast<const __m512i*>(
|
||||
accumulation[perspectives[p]][i])[j * 2 + 0]);
|
||||
sum1 = _mm512_add_epi16(sum1, reinterpret_cast<const __m512i*>(
|
||||
accumulation[perspectives[p]][i])[j * 2 + 1]);
|
||||
}
|
||||
|
||||
_mm512_store_si512(&out[j], _mm512_permutexvar_epi64(kControl,
|
||||
_mm512_max_epi8(_mm512_packs_epi16(sum0, sum1), kZero)));
|
||||
}
|
||||
@@ -239,13 +175,6 @@ namespace Stockfish::Eval::NNUE {
|
||||
&reinterpret_cast<const __m256i*>(accumulation[perspectives[p]][0])[j * 2 + 0]);
|
||||
__m256i sum1 = _mm256_load_si256(
|
||||
&reinterpret_cast<const __m256i*>(accumulation[perspectives[p]][0])[j * 2 + 1]);
|
||||
for (IndexType i = 1; i < kRefreshTriggers.size(); ++i) {
|
||||
sum0 = _mm256_add_epi16(sum0, reinterpret_cast<const __m256i*>(
|
||||
accumulation[perspectives[p]][i])[j * 2 + 0]);
|
||||
sum1 = _mm256_add_epi16(sum1, reinterpret_cast<const __m256i*>(
|
||||
accumulation[perspectives[p]][i])[j * 2 + 1]);
|
||||
}
|
||||
|
||||
_mm256_store_si256(&out[j], _mm256_permute4x64_epi64(_mm256_max_epi8(
|
||||
_mm256_packs_epi16(sum0, sum1), kZero), kControl));
|
||||
}
|
||||
@@ -257,13 +186,6 @@ namespace Stockfish::Eval::NNUE {
|
||||
accumulation[perspectives[p]][0])[j * 2 + 0]);
|
||||
__m128i sum1 = _mm_load_si128(&reinterpret_cast<const __m128i*>(
|
||||
accumulation[perspectives[p]][0])[j * 2 + 1]);
|
||||
for (IndexType i = 1; i < kRefreshTriggers.size(); ++i) {
|
||||
sum0 = _mm_add_epi16(sum0, reinterpret_cast<const __m128i*>(
|
||||
accumulation[perspectives[p]][i])[j * 2 + 0]);
|
||||
sum1 = _mm_add_epi16(sum1, reinterpret_cast<const __m128i*>(
|
||||
accumulation[perspectives[p]][i])[j * 2 + 1]);
|
||||
}
|
||||
|
||||
const __m128i packedbytes = _mm_packs_epi16(sum0, sum1);
|
||||
|
||||
_mm_store_si128(&out[j],
|
||||
@@ -284,13 +206,6 @@ namespace Stockfish::Eval::NNUE {
|
||||
accumulation[perspectives[p]][0])[j * 2 + 0]);
|
||||
__m64 sum1 = *(&reinterpret_cast<const __m64*>(
|
||||
accumulation[perspectives[p]][0])[j * 2 + 1]);
|
||||
for (IndexType i = 1; i < kRefreshTriggers.size(); ++i) {
|
||||
sum0 = _mm_add_pi16(sum0, reinterpret_cast<const __m64*>(
|
||||
accumulation[perspectives[p]][i])[j * 2 + 0]);
|
||||
sum1 = _mm_add_pi16(sum1, reinterpret_cast<const __m64*>(
|
||||
accumulation[perspectives[p]][i])[j * 2 + 1]);
|
||||
}
|
||||
|
||||
const __m64 packedbytes = _mm_packs_pi16(sum0, sum1);
|
||||
out[j] = _mm_subs_pi8(_mm_adds_pi8(packedbytes, k0x80s), k0x80s);
|
||||
}
|
||||
@@ -300,22 +215,12 @@ namespace Stockfish::Eval::NNUE {
|
||||
for (IndexType j = 0; j < kNumChunks; ++j) {
|
||||
int16x8_t sum = reinterpret_cast<const int16x8_t*>(
|
||||
accumulation[perspectives[p]][0])[j];
|
||||
|
||||
for (IndexType i = 1; i < kRefreshTriggers.size(); ++i) {
|
||||
sum = vaddq_s16(sum, reinterpret_cast<const int16x8_t*>(
|
||||
accumulation[perspectives[p]][i])[j]);
|
||||
}
|
||||
|
||||
out[j] = vmax_s8(vqmovn_s16(sum), kZero);
|
||||
}
|
||||
|
||||
#else
|
||||
for (IndexType j = 0; j < kHalfDimensions; ++j) {
|
||||
BiasType sum = accumulation[static_cast<int>(perspectives[p])][0][j];
|
||||
for (IndexType i = 1; i < kRefreshTriggers.size(); ++i) {
|
||||
sum += accumulation[static_cast<int>(perspectives[p])][i][j];
|
||||
}
|
||||
|
||||
output[offset + j] = static_cast<OutputType>(
|
||||
std::max<int>(0, std::min<int>(127, sum)));
|
||||
}
|
||||
@@ -328,183 +233,177 @@ namespace Stockfish::Eval::NNUE {
|
||||
}
|
||||
|
||||
private:
|
||||
// Calculate cumulative value without using difference calculation
|
||||
void refresh_accumulator(const Position& pos) const {
|
||||
void UpdateAccumulator(const Position& pos, const Color c) const {
|
||||
|
||||
#ifdef VECTOR
|
||||
// Gcc-10.2 unnecessarily spills AVX2 registers if this array
|
||||
// is defined in the VECTOR code below, once in each branch
|
||||
vec_t acc[kNumRegs];
|
||||
#endif
|
||||
auto& accumulator = pos.state()->accumulator;
|
||||
for (IndexType i = 0; i < kRefreshTriggers.size(); ++i) {
|
||||
Features::IndexList active_indices[2];
|
||||
RawFeatures::append_active_indices(pos, kRefreshTriggers[i],
|
||||
active_indices);
|
||||
for (Color perspective : { WHITE, BLACK }) {
|
||||
#ifdef VECTOR
|
||||
for (IndexType j = 0; j < kHalfDimensions / kTileHeight; ++j) {
|
||||
auto accTile = reinterpret_cast<vec_t*>(
|
||||
&accumulator.accumulation[perspective][i][j * kTileHeight]);
|
||||
|
||||
if (i == 0) {
|
||||
auto biasesTile = reinterpret_cast<const vec_t*>(
|
||||
&biases_[j * kTileHeight]);
|
||||
for (IndexType k = 0; k < kNumRegs; ++k)
|
||||
acc[k] = biasesTile[k];
|
||||
} else {
|
||||
for (IndexType k = 0; k < kNumRegs; ++k)
|
||||
acc[k] = vec_zero;
|
||||
}
|
||||
// Look for a usable accumulator of an earlier position. We keep track
|
||||
// of the estimated gain in terms of features to be added/subtracted.
|
||||
StateInfo *st = pos.state(), *next = nullptr;
|
||||
int gain = pos.count<ALL_PIECES>() - 2;
|
||||
while (st->accumulator.state[c] == EMPTY)
|
||||
{
|
||||
auto& dp = st->dirtyPiece;
|
||||
// The first condition tests whether an incremental update is
|
||||
// possible at all: if this side's king has moved, it is not possible.
|
||||
static_assert(std::is_same_v<RawFeatures::SortedTriggerSet,
|
||||
Features::CompileTimeList<Features::TriggerEvent, Features::TriggerEvent::kFriendKingMoved>>,
|
||||
"Current code assumes that only kFriendlyKingMoved refresh trigger is being used.");
|
||||
if ( dp.piece[0] == make_piece(c, KING)
|
||||
|| (gain -= dp.dirty_num + 1) < 0)
|
||||
break;
|
||||
next = st;
|
||||
st = st->previous;
|
||||
}
|
||||
|
||||
for (const auto index : active_indices[perspective]) {
|
||||
const IndexType offset = kHalfDimensions * index + j * kTileHeight;
|
||||
auto column = reinterpret_cast<const vec_t*>(&weights_[offset]);
|
||||
if (st->accumulator.state[c] == COMPUTED)
|
||||
{
|
||||
if (next == nullptr)
|
||||
return;
|
||||
|
||||
for (IndexType k = 0; k < kNumRegs; ++k)
|
||||
acc[k] = vec_add_16(acc[k], column[k]);
|
||||
}
|
||||
// Update incrementally in two steps. First, we update the "next"
|
||||
// accumulator. Then, we update the current accumulator (pos.state()).
|
||||
|
||||
for (IndexType k = 0; k < kNumRegs; k++)
|
||||
vec_store(&accTile[k], acc[k]);
|
||||
}
|
||||
#else
|
||||
if (i == 0) {
|
||||
std::memcpy(accumulator.accumulation[perspective][i], biases_,
|
||||
kHalfDimensions * sizeof(BiasType));
|
||||
} else {
|
||||
std::memset(accumulator.accumulation[perspective][i], 0,
|
||||
kHalfDimensions * sizeof(BiasType));
|
||||
}
|
||||
// Gather all features to be updated. This code assumes HalfKP features
|
||||
// only and doesn't support refresh triggers.
|
||||
static_assert(std::is_same_v<Features::FeatureSet<Features::HalfKP<Features::Side::kFriend>>,
|
||||
RawFeatures>);
|
||||
Features::IndexList removed[2], added[2];
|
||||
Features::HalfKP<Features::Side::kFriend>::AppendChangedIndices(pos,
|
||||
next->dirtyPiece, c, &removed[0], &added[0]);
|
||||
for (StateInfo *st2 = pos.state(); st2 != next; st2 = st2->previous)
|
||||
Features::HalfKP<Features::Side::kFriend>::AppendChangedIndices(pos,
|
||||
st2->dirtyPiece, c, &removed[1], &added[1]);
|
||||
|
||||
for (const auto index : active_indices[perspective]) {
|
||||
const IndexType offset = kHalfDimensions * index;
|
||||
|
||||
for (IndexType j = 0; j < kHalfDimensions; ++j)
|
||||
accumulator.accumulation[perspective][i][j] += weights_[offset + j];
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#if defined(USE_MMX)
|
||||
_mm_empty();
|
||||
#endif
|
||||
|
||||
accumulator.computed_accumulation = true;
|
||||
}
|
||||
|
||||
// Calculate cumulative value using difference calculation
|
||||
void update_accumulator(const Position& pos) const {
|
||||
// Mark the accumulators as computed.
|
||||
next->accumulator.state[c] = COMPUTED;
|
||||
pos.state()->accumulator.state[c] = COMPUTED;
|
||||
|
||||
// Now update the accumulators listed in info[], where the last element is a sentinel.
|
||||
StateInfo *info[3] =
|
||||
{ next, next == pos.state() ? nullptr : pos.state(), nullptr };
|
||||
#ifdef VECTOR
|
||||
// Gcc-10.2 unnecessarily spills AVX2 registers if this array
|
||||
// is defined in the VECTOR code below, once in each branch
|
||||
vec_t acc[kNumRegs];
|
||||
#endif
|
||||
const auto& prev_accumulator = pos.state()->previous->accumulator;
|
||||
auto& accumulator = pos.state()->accumulator;
|
||||
for (IndexType i = 0; i < kRefreshTriggers.size(); ++i) {
|
||||
Features::IndexList removed_indices[2], added_indices[2];
|
||||
bool reset[2] = { false, false };
|
||||
RawFeatures::append_changed_indices(pos, kRefreshTriggers[i],
|
||||
removed_indices, added_indices, reset);
|
||||
|
||||
#ifdef VECTOR
|
||||
for (IndexType j = 0; j < kHalfDimensions / kTileHeight; ++j) {
|
||||
for (Color perspective : { WHITE, BLACK }) {
|
||||
for (IndexType j = 0; j < kHalfDimensions / kTileHeight; ++j)
|
||||
{
|
||||
// Load accumulator
|
||||
auto accTile = reinterpret_cast<vec_t*>(
|
||||
&accumulator.accumulation[perspective][i][j * kTileHeight]);
|
||||
|
||||
if (reset[perspective]) {
|
||||
if (i == 0) {
|
||||
auto biasesTile = reinterpret_cast<const vec_t*>(
|
||||
&biases_[j * kTileHeight]);
|
||||
for (IndexType k = 0; k < kNumRegs; ++k)
|
||||
acc[k] = biasesTile[k];
|
||||
} else {
|
||||
for (IndexType k = 0; k < kNumRegs; ++k)
|
||||
acc[k] = vec_zero;
|
||||
}
|
||||
} else {
|
||||
auto prevAccTile = reinterpret_cast<const vec_t*>(
|
||||
&prev_accumulator.accumulation[perspective][i][j * kTileHeight]);
|
||||
|
||||
for (IndexType k = 0; k < kNumRegs; ++k)
|
||||
acc[k] = vec_load(&prevAccTile[k]);
|
||||
&st->accumulator.accumulation[c][0][j * kTileHeight]);
|
||||
for (IndexType k = 0; k < kNumRegs; ++k)
|
||||
acc[k] = vec_load(&accTile[k]);
|
||||
|
||||
for (IndexType i = 0; info[i]; ++i)
|
||||
{
|
||||
// Difference calculation for the deactivated features
|
||||
for (const auto index : removed_indices[perspective]) {
|
||||
for (const auto index : removed[i])
|
||||
{
|
||||
const IndexType offset = kHalfDimensions * index + j * kTileHeight;
|
||||
auto column = reinterpret_cast<const vec_t*>(&weights_[offset]);
|
||||
|
||||
for (IndexType k = 0; k < kNumRegs; ++k)
|
||||
acc[k] = vec_sub_16(acc[k], column[k]);
|
||||
}
|
||||
}
|
||||
|
||||
{ // Difference calculation for the activated features
|
||||
for (const auto index : added_indices[perspective]) {
|
||||
// Difference calculation for the activated features
|
||||
for (const auto index : added[i])
|
||||
{
|
||||
const IndexType offset = kHalfDimensions * index + j * kTileHeight;
|
||||
auto column = reinterpret_cast<const vec_t*>(&weights_[offset]);
|
||||
|
||||
for (IndexType k = 0; k < kNumRegs; ++k)
|
||||
acc[k] = vec_add_16(acc[k], column[k]);
|
||||
}
|
||||
|
||||
// Store accumulator
|
||||
accTile = reinterpret_cast<vec_t*>(
|
||||
&info[i]->accumulator.accumulation[c][0][j * kTileHeight]);
|
||||
for (IndexType k = 0; k < kNumRegs; ++k)
|
||||
vec_store(&accTile[k], acc[k]);
|
||||
}
|
||||
}
|
||||
|
||||
#else
|
||||
for (IndexType i = 0; info[i]; ++i)
|
||||
{
|
||||
std::memcpy(info[i]->accumulator.accumulation[c][0],
|
||||
st->accumulator.accumulation[c][0],
|
||||
kHalfDimensions * sizeof(BiasType));
|
||||
st = info[i];
|
||||
|
||||
// Difference calculation for the deactivated features
|
||||
for (const auto index : removed[i])
|
||||
{
|
||||
const IndexType offset = kHalfDimensions * index;
|
||||
|
||||
for (IndexType j = 0; j < kHalfDimensions; ++j)
|
||||
st->accumulator.accumulation[c][0][j] -= weights_[offset + j];
|
||||
}
|
||||
|
||||
// Difference calculation for the activated features
|
||||
for (const auto index : added[i])
|
||||
{
|
||||
const IndexType offset = kHalfDimensions * index;
|
||||
|
||||
for (IndexType j = 0; j < kHalfDimensions; ++j)
|
||||
st->accumulator.accumulation[c][0][j] += weights_[offset + j];
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
else
|
||||
{
|
||||
// Refresh the accumulator
|
||||
auto& accumulator = pos.state()->accumulator;
|
||||
accumulator.state[c] = COMPUTED;
|
||||
Features::IndexList active;
|
||||
Features::HalfKP<Features::Side::kFriend>::AppendActiveIndices(pos, c, &active);
|
||||
|
||||
#ifdef VECTOR
|
||||
for (IndexType j = 0; j < kHalfDimensions / kTileHeight; ++j)
|
||||
{
|
||||
auto biasesTile = reinterpret_cast<const vec_t*>(
|
||||
&biases_[j * kTileHeight]);
|
||||
for (IndexType k = 0; k < kNumRegs; ++k)
|
||||
acc[k] = biasesTile[k];
|
||||
|
||||
for (const auto index : active)
|
||||
{
|
||||
const IndexType offset = kHalfDimensions * index + j * kTileHeight;
|
||||
auto column = reinterpret_cast<const vec_t*>(&weights_[offset]);
|
||||
|
||||
for (unsigned k = 0; k < kNumRegs; ++k)
|
||||
acc[k] = vec_add_16(acc[k], column[k]);
|
||||
}
|
||||
|
||||
auto accTile = reinterpret_cast<vec_t*>(
|
||||
&accumulator.accumulation[c][0][j * kTileHeight]);
|
||||
for (unsigned k = 0; k < kNumRegs; k++)
|
||||
vec_store(&accTile[k], acc[k]);
|
||||
}
|
||||
|
||||
#else
|
||||
std::memcpy(accumulator.accumulation[c][0], biases_,
|
||||
kHalfDimensions * sizeof(BiasType));
|
||||
|
||||
for (const auto index : active)
|
||||
{
|
||||
const IndexType offset = kHalfDimensions * index;
|
||||
|
||||
for (IndexType j = 0; j < kHalfDimensions; ++j)
|
||||
accumulator.accumulation[c][0][j] += weights_[offset + j];
|
||||
}
|
||||
#endif
|
||||
}
|
||||
#if defined(USE_MMX)
|
||||
|
||||
#if defined(USE_MMX)
|
||||
_mm_empty();
|
||||
#endif
|
||||
|
||||
#else
|
||||
for (Color perspective : { WHITE, BLACK }) {
|
||||
|
||||
if (reset[perspective]) {
|
||||
if (i == 0) {
|
||||
std::memcpy(accumulator.accumulation[perspective][i], biases_,
|
||||
kHalfDimensions * sizeof(BiasType));
|
||||
} else {
|
||||
std::memset(accumulator.accumulation[perspective][i], 0,
|
||||
kHalfDimensions * sizeof(BiasType));
|
||||
}
|
||||
} else {
|
||||
std::memcpy(accumulator.accumulation[perspective][i],
|
||||
prev_accumulator.accumulation[perspective][i],
|
||||
kHalfDimensions * sizeof(BiasType));
|
||||
// Difference calculation for the deactivated features
|
||||
for (const auto index : removed_indices[perspective]) {
|
||||
const IndexType offset = kHalfDimensions * index;
|
||||
|
||||
for (IndexType j = 0; j < kHalfDimensions; ++j)
|
||||
accumulator.accumulation[perspective][i][j] -= weights_[offset + j];
|
||||
}
|
||||
}
|
||||
{ // Difference calculation for the activated features
|
||||
for (const auto index : added_indices[perspective]) {
|
||||
const IndexType offset = kHalfDimensions * index;
|
||||
|
||||
for (IndexType j = 0; j < kHalfDimensions; ++j)
|
||||
accumulator.accumulation[perspective][i][j] += weights_[offset + j];
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
accumulator.computed_accumulation = true;
|
||||
#endif
|
||||
}
|
||||
|
||||
using BiasType = std::int16_t;
|
||||
using WeightType = std::int16_t;
|
||||
|
||||
// Make the learning class a friend
|
||||
friend class Trainer<FeatureTransformer>;
|
||||
|
||||
alignas(kCacheLineSize) BiasType biases_[kHalfDimensions];
|
||||
alignas(kCacheLineSize)
|
||||
WeightType weights_[kHalfDimensions * kInputDimensions];
|
||||
@@ -512,4 +411,4 @@ namespace Stockfish::Eval::NNUE {
|
||||
|
||||
} // namespace Stockfish::Eval::NNUE
|
||||
|
||||
#endif // #ifndef NNUE_FEATURE_TRANSFORMER_H_INCLUDED
|
||||
#endif // #ifndef NNUE_FEATURE_TRANSFORMER_H_INCLUDED
|
||||
@@ -707,7 +707,8 @@ void Position::do_move(Move m, StateInfo& newSt, bool givesCheck) {
|
||||
++st->pliesFromNull;
|
||||
|
||||
// Used by NNUE
|
||||
st->accumulator.computed_accumulation = false;
|
||||
st->accumulator.state[WHITE] = Eval::NNUE::EMPTY;
|
||||
st->accumulator.state[BLACK] = Eval::NNUE::EMPTY;
|
||||
auto& dp = st->dirtyPiece;
|
||||
dp.dirty_num = 1;
|
||||
|
||||
@@ -1006,7 +1007,8 @@ void Position::do_null_move(StateInfo& newSt) {
|
||||
st = &newSt;
|
||||
|
||||
// Used by NNUE
|
||||
st->accumulator.computed_accumulation = false;
|
||||
st->accumulator.state[WHITE] = Eval::NNUE::EMPTY;
|
||||
st->accumulator.state[BLACK] = Eval::NNUE::EMPTY;
|
||||
auto& dp = st->dirtyPiece;
|
||||
dp.dirty_num = 0;
|
||||
|
||||
|
||||
@@ -197,7 +197,7 @@ public:
|
||||
//static std::string sfen_from_rawdata(Piece board[81], Hand hands[2], Color turn, int gamePly);
|
||||
|
||||
// Returns the position of the ball on the c side.
|
||||
Square king_square(Color c) const { return pieceList[make_piece(c, KING)][0]; }
|
||||
Square king_square(Color c) const { return lsb(pieces(c, KING)); }
|
||||
|
||||
private:
|
||||
// Initialization helpers (used while setting up a position)
|
||||
@@ -445,6 +445,8 @@ inline StateInfo* Position::state() const {
|
||||
return st;
|
||||
}
|
||||
|
||||
static const char* const StartFEN = "rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq - 0 1";
|
||||
|
||||
} // namespace Stockfish
|
||||
|
||||
#endif // #ifndef POSITION_H_INCLUDED
|
||||
|
||||
@@ -222,7 +222,7 @@ void MainThread::search() {
|
||||
Time.init(Limits, us, rootPos.game_ply());
|
||||
TT.new_search();
|
||||
|
||||
Eval::NNUE::verify_eval_file_loaded();
|
||||
Eval::NNUE::verify();
|
||||
|
||||
if (rootMoves.empty())
|
||||
{
|
||||
@@ -2143,7 +2143,7 @@ namespace Search
|
||||
return { mated_in(/*ss->ply*/ 0 + 1), {} };
|
||||
}
|
||||
|
||||
auto bestValue = ::qsearch<PV>(pos, ss, -VALUE_INFINITE, VALUE_INFINITE, 0);
|
||||
auto bestValue = Stockfish::qsearch<PV>(pos, ss, -VALUE_INFINITE, VALUE_INFINITE, 0);
|
||||
|
||||
// Returns the PV obtained.
|
||||
std::vector<Move> pvs;
|
||||
@@ -2249,7 +2249,7 @@ namespace Search
|
||||
while (true)
|
||||
{
|
||||
Depth adjustedDepth = std::max(1, rootDepth);
|
||||
bestValue = ::search<PV>(pos, ss, alpha, beta, adjustedDepth, false);
|
||||
bestValue = Stockfish::search<PV>(pos, ss, alpha, beta, adjustedDepth, false);
|
||||
|
||||
stable_sort(rootMoves.begin() + pvIdx, rootMoves.end());
|
||||
//my_stable_sort(pos.this_thread()->thread_id(),&rootMoves[0] + pvIdx, rootMoves.size() - pvIdx);
|
||||
|
||||
@@ -28,7 +28,7 @@
|
||||
|
||||
using namespace std;
|
||||
|
||||
namespace Tools
|
||||
namespace Stockfish::Tools
|
||||
{
|
||||
bool fen_is_ok(Position& pos, std::string input_fen) {
|
||||
std::string pos_fen = pos.fen();
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
#include <string>
|
||||
#include <sstream>
|
||||
|
||||
namespace Tools {
|
||||
namespace Stockfish::Tools {
|
||||
void convert(std::istringstream& is);
|
||||
|
||||
void convert_bin_from_pgn_extract(std::istringstream& is);
|
||||
|
||||
@@ -34,7 +34,7 @@
|
||||
|
||||
using namespace std;
|
||||
|
||||
namespace Tools
|
||||
namespace Stockfish::Tools
|
||||
{
|
||||
// Class to generate sfen with multiple threads
|
||||
struct Gensfen
|
||||
@@ -962,7 +962,7 @@ namespace Tools
|
||||
<< " - draw by insuff. mat. = " << params.detect_draw_by_insufficient_mating_material << endl;
|
||||
|
||||
// Show if the training data generator uses NNUE.
|
||||
Eval::NNUE::verify_eval_file_loaded();
|
||||
Eval::NNUE::verify();
|
||||
|
||||
Threads.main()->ponder = false;
|
||||
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
|
||||
#include <sstream>
|
||||
|
||||
namespace Tools {
|
||||
namespace Stockfish::Tools {
|
||||
|
||||
// Automatic generation of teacher position
|
||||
void gensfen(std::istringstream& is);
|
||||
|
||||
@@ -34,7 +34,7 @@
|
||||
|
||||
using namespace std;
|
||||
|
||||
namespace Tools
|
||||
namespace Stockfish::Tools
|
||||
{
|
||||
// Class to generate sfen with multiple threads
|
||||
struct GensfenNonPv
|
||||
@@ -476,7 +476,7 @@ namespace Tools
|
||||
<< " - count = " << count << endl;
|
||||
|
||||
// Show if the training data generator uses NNUE.
|
||||
Eval::NNUE::verify_eval_file_loaded();
|
||||
Eval::NNUE::verify();
|
||||
|
||||
Threads.main()->ponder = false;
|
||||
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
|
||||
#include <sstream>
|
||||
|
||||
namespace Tools {
|
||||
namespace Stockfish::Tools {
|
||||
|
||||
// Automatic generation of teacher position
|
||||
void gensfen_nonpv(std::istringstream& is);
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
#include <fstream>
|
||||
|
||||
namespace Tools {
|
||||
namespace Stockfish::Tools {
|
||||
|
||||
EpdOpeningBook::EpdOpeningBook(const std::string& file, PRNG& prng) :
|
||||
OpeningBook(file)
|
||||
|
||||
@@ -13,7 +13,7 @@
|
||||
#include <memory>
|
||||
#include <mutex>
|
||||
|
||||
namespace Tools {
|
||||
namespace Stockfish::Tools {
|
||||
|
||||
struct OpeningBook {
|
||||
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
#include <vector>
|
||||
#include <cstdint>
|
||||
|
||||
namespace Tools {
|
||||
namespace Stockfish::Tools {
|
||||
|
||||
// packed sfen
|
||||
struct PackedSfen { std::uint8_t data[32]; };
|
||||
|
||||
@@ -11,7 +11,7 @@
|
||||
|
||||
using namespace std;
|
||||
|
||||
namespace Tools {
|
||||
namespace Stockfish::Tools {
|
||||
|
||||
// Class that handles bitstream
|
||||
// useful when doing aspect encoding
|
||||
@@ -260,15 +260,11 @@ namespace Tools {
|
||||
|
||||
pos.clear();
|
||||
std::memset(si, 0, sizeof(StateInfo));
|
||||
std::fill_n(&pos.pieceList[0][0], sizeof(pos.pieceList) / sizeof(Square), SQ_NONE);
|
||||
pos.st = si;
|
||||
|
||||
// Active color
|
||||
pos.sideToMove = (Color)stream.read_one_bit();
|
||||
|
||||
pos.pieceList[W_KING][0] = SQUARE_NB;
|
||||
pos.pieceList[B_KING][0] = SQUARE_NB;
|
||||
|
||||
// First the position of the ball
|
||||
for (auto c : Colors)
|
||||
pos.board[stream.read_n_bit(6)] = make_piece(c, KING);
|
||||
|
||||
@@ -7,11 +7,13 @@
|
||||
|
||||
#include <cstdint>
|
||||
|
||||
class Position;
|
||||
struct StateInfo;
|
||||
class Thread;
|
||||
namespace Stockfish {
|
||||
class Position;
|
||||
struct StateInfo;
|
||||
class Thread;
|
||||
}
|
||||
|
||||
namespace Tools {
|
||||
namespace Stockfish::Tools {
|
||||
|
||||
int set_from_packed_sfen(Position& pos, const PackedSfen& sfen, StateInfo* si, Thread* th);
|
||||
PackedSfen sfen_pack(Position& pos);
|
||||
|
||||
@@ -17,7 +17,7 @@
|
||||
#include <thread>
|
||||
#include <functional>
|
||||
|
||||
namespace Tools{
|
||||
namespace Stockfish::Tools{
|
||||
|
||||
enum struct SfenReaderMode
|
||||
{
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
#include <string>
|
||||
#include <memory>
|
||||
|
||||
namespace Tools {
|
||||
namespace Stockfish::Tools {
|
||||
|
||||
enum struct SfenOutputType
|
||||
{
|
||||
|
||||
@@ -17,9 +17,7 @@
|
||||
#include <thread>
|
||||
#include <atomic>
|
||||
|
||||
using namespace std;
|
||||
|
||||
namespace Tools {
|
||||
namespace Stockfish::Tools {
|
||||
|
||||
// Helper class for exporting Sfen
|
||||
struct SfenWriter
|
||||
@@ -28,13 +26,13 @@ namespace Tools {
|
||||
static constexpr size_t SFEN_WRITE_SIZE = 5000;
|
||||
|
||||
// File name to write and number of threads to create
|
||||
SfenWriter(string filename_, int thread_num, uint64_t save_count, SfenOutputType sfen_output_type)
|
||||
SfenWriter(std::string filename_, int thread_num, uint64_t save_count, SfenOutputType sfen_output_type)
|
||||
{
|
||||
sfen_buffers_pool.reserve((size_t)thread_num * 10);
|
||||
sfen_buffers.resize(thread_num);
|
||||
|
||||
auto out = sync_region_cout.new_region();
|
||||
out << "INFO (sfen_writer): Creating new data file at " << filename_ << endl;
|
||||
out << "INFO (sfen_writer): Creating new data file at " << filename_ << std::endl;
|
||||
|
||||
sfen_format = sfen_output_type;
|
||||
output_file_stream = create_new_sfen_output(filename_, sfen_format);
|
||||
@@ -121,7 +119,7 @@ namespace Tools {
|
||||
{
|
||||
while (!finished || sfen_buffers_pool.size())
|
||||
{
|
||||
vector<std::unique_ptr<PSVector>> buffers;
|
||||
std::vector<std::unique_ptr<PSVector>> buffers;
|
||||
{
|
||||
std::unique_lock<std::mutex> lk(mutex);
|
||||
|
||||
@@ -157,11 +155,11 @@ namespace Tools {
|
||||
// Rename the file and open it again.
|
||||
// Add ios::app in consideration of overwriting.
|
||||
// (Depending on the operation, it may not be necessary.)
|
||||
string new_filename = filename + "_" + std::to_string(n);
|
||||
std::string new_filename = filename + "_" + std::to_string(n);
|
||||
output_file_stream = create_new_sfen_output(new_filename, sfen_format);
|
||||
|
||||
auto out = sync_region_cout.new_region();
|
||||
out << "INFO (sfen_writer): Creating new data file at " << new_filename << endl;
|
||||
out << "INFO (sfen_writer): Creating new data file at " << new_filename << std::endl;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -182,7 +180,7 @@ namespace Tools {
|
||||
std::thread file_worker_thread;
|
||||
|
||||
// Flag that all threads have finished
|
||||
atomic<bool> finished;
|
||||
std::atomic<bool> finished;
|
||||
|
||||
SfenOutputType sfen_format;
|
||||
|
||||
|
||||
@@ -25,7 +25,7 @@
|
||||
#include <mutex>
|
||||
#include <optional>
|
||||
|
||||
namespace Tools::Stats
|
||||
namespace Stockfish::Tools::Stats
|
||||
{
|
||||
struct StatisticGathererBase
|
||||
{
|
||||
@@ -398,7 +398,7 @@ namespace Tools::Stats
|
||||
m_castling += 1;
|
||||
else if (type_of(move) == PROMOTION)
|
||||
m_promotion += 1;
|
||||
else if (type_of(move) == ENPASSANT)
|
||||
else if (type_of(move) == EN_PASSANT)
|
||||
m_enpassant += 1;
|
||||
else if (type_of(move) == NORMAL)
|
||||
m_normal += 1;
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
|
||||
#include <sstream>
|
||||
|
||||
namespace Tools::Stats {
|
||||
namespace Stockfish::Tools::Stats {
|
||||
|
||||
void gather_statistics(std::istringstream& is);
|
||||
|
||||
|
||||
@@ -21,7 +21,7 @@
|
||||
#include <mutex>
|
||||
#include <optional>
|
||||
|
||||
namespace Tools
|
||||
namespace Stockfish::Tools
|
||||
{
|
||||
using CommandFunc = void(*)(std::istringstream&);
|
||||
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
|
||||
#include <sstream>
|
||||
|
||||
namespace Tools {
|
||||
namespace Stockfish::Tools {
|
||||
|
||||
void transform(std::istringstream& is);
|
||||
|
||||
|
||||
@@ -45,9 +45,6 @@ namespace Stockfish {
|
||||
|
||||
extern vector<string> setup_bench(const Position&, istream&);
|
||||
|
||||
// FEN string of the initial position, normal chess
|
||||
const char* StartFEN = "rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq - 0 1";
|
||||
|
||||
namespace {
|
||||
|
||||
// position() is called when engine receives the "position" UCI command.
|
||||
@@ -93,7 +90,7 @@ namespace {
|
||||
Position p;
|
||||
p.set(pos.fen(), Options["UCI_Chess960"], &states->back(), Threads.main());
|
||||
|
||||
Eval::NNUE::verify_eval_file_loaded();
|
||||
Eval::NNUE::verify();
|
||||
|
||||
sync_cout << "\n" << Eval::trace(p) << sync_endl;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user