+#include "timeman.h"
+#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 {
+
+ bool useNNUE;
+ string eval_file_loaded = "None";
+
+ /// 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.
+
+ void NNUE::init() {
+
+ useNNUE = Options["Use NNUE"];
+ if (!useNNUE)
+ 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::export_net() exports the currently loaded network to a file
+ void NNUE::export_net(const std::optional<std::string>& filename) {
+ std::string actualFilename;
+
+ if (filename.has_value())
+ actualFilename = filename.value();
+ else
+ {
+ if (eval_file_loaded != EvalFileDefaultName)
+ {
+ sync_cout << "Failed to export a net. A non-embedded net can only be saved if the filename is specified." << sync_endl;
+ return;
+ }
+ actualFilename = EvalFileDefaultName;
+ }
+
+ ofstream stream(actualFilename, std::ios_base::binary);
+
+ if (save_eval(stream))
+ sync_cout << "Network saved successfully to " << actualFilename << "." << sync_endl;
+ else
+ sync_cout << "Failed to export a net." << sync_endl;
+ }
+
+ /// NNUE::verify() verifies that the last net used was loaded successfully
+ void NNUE::verify() {
+
+ string eval_file = string(Options["EvalFile"]);
+
+ if (useNNUE && 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)
+ sync_cout << "info string NNUE evaluation using " << eval_file << " enabled" << sync_endl;
+ else
+ sync_cout << "info string classical evaluation enabled" << sync_endl;
+ }
+}