diff --git a/src/net.h b/src/net.h index 8a5bc1f..89cccb2 100644 --- a/src/net.h +++ b/src/net.h @@ -93,7 +93,9 @@ #define ALIGN 64 #endif +#ifndef NO_EMBED_NET INCBIN(Net, EVALFILE); +#endif constexpr int KING_BUCKETS = 7; constexpr int INPUT_NEURONS = 768 * KING_BUCKETS; @@ -120,7 +122,46 @@ struct NNUE alignas(ALIGN) int16_t output_biases[OUTPUT_NEURONS]; }; +#ifdef NO_EMBED_NET +// Rama Chess patch: the net is not embedded, it is loaded at run time from the +// UCI option "EvalFile" (setoption name EvalFile value ). +alignas(ALIGN) static NNUE nnue_storage; // zero-filled until a net is loaded +const NNUE *nnue = &nnue_storage; +bool nnue_loaded = false; + +#include +#include +inline bool load_nnue_file(const std::string &path, std::string &err) +{ + FILE *f = std::fopen(path.c_str(), "rb"); + if (!f) + { + err = "cannot open file"; + return false; + } + std::fseek(f, 0, SEEK_END); + long size = std::ftell(f); + std::fseek(f, 0, SEEK_SET); + if (size != (long)sizeof(NNUE)) + { + std::fclose(f); + err = "wrong file size " + std::to_string(size) + ", expected " + std::to_string(sizeof(NNUE)); + return false; + } + size_t got = std::fread(&nnue_storage, 1, sizeof(NNUE), f); + std::fclose(f); + if (got != sizeof(NNUE)) + { + err = "read error"; + return false; + } + nnue_loaded = true; + return true; +} +#else alignas(ALIGN) const NNUE *nnue; +bool nnue_loaded = true; +#endif constexpr int get_king_bucket_cache_index(const Square king_sq, const bool side) { @@ -129,7 +170,9 @@ constexpr int get_king_bucket_cache_index(const Square king_sq, const bool side) void load_nnue_weights() { +#ifndef NO_EMBED_NET nnue = reinterpret_cast(gNetData); +#endif } inline reg_type reg_clamp(reg_type reg) @@ -177,6 +220,11 @@ class Network }; Network() + { + reset_cache(); + } + + void reset_cache() { hist_size = 0; for (auto c : {BLACK, WHITE}) diff --git a/src/search.h b/src/search.h index 8569821..5f96302 100644 --- a/src/search.h +++ b/src/search.h @@ -80,7 +80,7 @@ template int SearchThread::quiesce(int alpha, int beta, StackEntry } HistoricalState next_state; - const bool in_check = board.checkers() != 0; + const bool in_check = board.checkers() != 0ull; int futility_base; if (in_check) @@ -302,7 +302,7 @@ int SearchThread::search(int alpha, int beta, int depth, StackEntry *stack) } HistoricalState next_state; - const bool in_check = (board.checkers() != 0); + const bool in_check = (board.checkers() != 0ull); const bool enemy_has_no_threats = !board.threats().threatened_pieces; int raw_eval; @@ -630,7 +630,7 @@ int SearchThread::search(int alpha, int beta, int depth, StackEntry *stack) R -= LMRGrain * history / (is_quiet ? HistReductionDiv : CapHistReductionDiv); // reduce move based on history - R -= LMRGivesCheck * (board.checkers() != 0); // move gives check + R -= LMRGivesCheck * (board.checkers() != 0ull); // move gives check R += LMRWasNotPV * !was_pv; R += LMRGoodEval * (enemy_has_no_threats && !in_check && diff --git a/src/uci.h b/src/uci.h index 7ecbfe8..74b7171 100644 --- a/src/uci.h +++ b/src/uci.h @@ -119,6 +119,28 @@ class UCI iss >> value >> value; info.set_chess960(value == "true"); }}}, +#ifdef NO_EMBED_NET + {"EvalFile", + {"EvalFile", "string", "", "", "", + [&](std::istringstream &iss) { + std::string value, path; + iss >> value; + std::getline(iss >> std::ws, path); + while (!path.empty() && (path.back() == '\r' || path.back() == ' ')) + path.pop_back(); + std::string err; + thread_pool.wait_for_finish(); + if (load_nnue_file(path, err)) + { + NN.reset_cache(); + thread_pool.create_pool(std::max(1, thread_pool.get_num_threads())); + ucinewgame(); + std::cout << "info string EvalFile loaded: " << path << std::endl; + } + else + std::cout << "info string ERROR: EvalFile " << path << ": " << err << std::endl; + }}}, +#endif {"MinNodes", {"MinNodes", "check", "false", "", "", [&](std::istringstream &iss) { std::string value; iss >> value >> value; @@ -327,6 +349,12 @@ void UCI::ucinewgame() void UCI::go(std::istringstream &iss, Info &info) { + if (!nnue_loaded) + { + std::cout << "info string ERROR: no net loaded, send setoption name EvalFile value first" << std::endl; + std::cout << "bestmove 0000" << std::endl; + return; + } int depth = MAX_DEPTH, movetime = -1; int time = -1, inc = 0; int64_t nodes = -1, min_nodes = -1, max_nodes = -1; @@ -474,6 +502,11 @@ std::string benchPos[] = { void UCI::bench(int depth) { + if (!nnue_loaded) + { + std::cout << "info string ERROR: no net loaded, send setoption name EvalFile value first" << std::endl; + return; + } TT = std::make_unique(); info = Info();