diff --git a/include/engine/uci.h b/include/engine/uci.h index 6704667..3f18d54 100644 --- a/include/engine/uci.h +++ b/include/engine/uci.h @@ -43,6 +43,7 @@ struct uci { chess::board position = chess::board::start_pos(); nnue::quantized_weights weights_{}; + bool weights_loaded_{false}; search::worker_orchestrator orchestrator_; std::atomic_bool ponder_{false}; diff --git a/include/nnue/embedded_weights.h b/include/nnue/embedded_weights.h index 39261d6..10c2eee 100644 --- a/include/nnue/embedded_weights.h +++ b/include/nnue/embedded_weights.h @@ -23,8 +23,10 @@ namespace nnue::embed { +#ifndef SEER_NO_EMBED_NET extern "C" { INCBIN(weights_file, EVALFILE); } +#endif } // namespace nnue::embed \ No newline at end of file diff --git a/include/nnue/simd.h b/include/nnue/simd.h index b02c969..460b1ef 100644 --- a/include/nnue/simd.h +++ b/include/nnue/simd.h @@ -17,7 +17,17 @@ #pragma once +#if defined(__x86_64__) || defined(__i386__) #include +#elif defined(SEER_SIMDE_SSSE3) +// Rama Chess Android arm64 build: the SSSE3 code path is mapped to NEON by SIMDe (MIT) +#define SIMDE_ENABLE_NATIVE_ALIASES +#include +// SIMDe aliases are macros; template commas inside the argument break them, so use a real function +#undef _mm_load_ps +static inline simde__m128 _mm_load_ps(const float* p) { return simde_mm_load_ps(p); } +#define __SSSE3__ 1 +#endif #include #include diff --git a/src/engine/uci.cc b/src/engine/uci.cc index 003995d..ade2842 100644 --- a/src/engine/uci.cc +++ b/src/engine/uci.cc @@ -34,10 +34,27 @@ namespace engine { auto uci::options() noexcept { auto quantized_weight_path = option_callback(string_option("QuantizedWeights", std::string(embedded_weight_path)), [this](const std::string& path) { if (path == std::string(embedded_weight_path)) { +#ifndef SEER_NO_EMBED_NET nnue::embedded_weight_streamer embedded(nnue::embed::weights_file_data); weights_.load(embedded); + weights_loaded_ = true; +#else + return; +#endif } else { - weights_.load(path); + // Rama Chess Android build: check the file before trusting it + weights_loaded_ = false; + nnue::weights_streamer streamer(path); + if (!streamer.reader.is_open()) { + os << "info string ERROR: QuantizedWeights " << path << ": cannot open file" << std::endl; + return; + } + weights_.load(streamer); + if (!streamer.reader.good() || streamer.reader.peek() != std::char_traits::eof()) { + os << "info string ERROR: QuantizedWeights " << path << ": wrong file size, not a Seer quantized net" << std::endl; + return; + } + weights_loaded_ = true; } weights_info_string(); @@ -50,6 +67,7 @@ auto uci::options() noexcept { raw_weights.load(path); weights_ = raw_weights.to(); + weights_loaded_ = true; weights_info_string(); }); @@ -128,6 +146,11 @@ void uci::init_time_manager(Ts&&... args) noexcept { void uci::go() noexcept { std::lock_guard lock(mutex_); if (orchestrator_.is_searching()) { return; } + if (!weights_loaded_) { + os << "info string ERROR: no network loaded, use setoption name QuantizedWeights value " << std::endl; + os << "bestmove 0000" << std::endl; + return; + } timer_.lap(); orchestrator_.go(history, position); @@ -174,6 +197,10 @@ void uci::id_info() noexcept { void uci::bench() noexcept { std::lock_guard lock(mutex_); if (orchestrator_.is_searching()) { return; } + if (!weights_loaded_) { + os << "info string ERROR: no network loaded, use setoption name QuantizedWeights value " << std::endl; + return; + } os << get_bench_info(weights_) << std::endl; } @@ -301,8 +328,11 @@ uci::uci() noexcept [this](const auto& worker) { if (manager_.should_stop_on_update(update_info{worker.nodes()})) { stop(); } }) { +#ifndef SEER_NO_EMBED_NET nnue::embedded_weight_streamer embedded(nnue::embed::weights_file_data); weights_.load(embedded); + weights_loaded_ = true; +#endif orchestrator_.resize(default_thread_count); }