/* Stockfish, a UCI chess playing engine derived from Glaurung 2.1 Copyright (C) 2004-2008 Tord Romstad (Glaurung author) Copyright (C) 2008-2015 Marco Costalba, Joona Kiiski, Tord Romstad Copyright (C) 2015-2019 Marco Costalba, Joona Kiiski, Gary Linscott, Tord Romstad 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 . */ #ifndef MISC_H_INCLUDED #define MISC_H_INCLUDED #include #include #include #include #include #include #include #include "types.h" #include "thread_win32_osx.h" const std::string engine_info(bool to_uci = false); void prefetch(void* addr); void start_logger(const std::string& fname); void dbg_hit_on(bool b); void dbg_hit_on(bool c, bool b); void dbg_mean_of(int v); void dbg_print(); typedef std::chrono::milliseconds::rep TimePoint; // A value in milliseconds static_assert(sizeof(TimePoint) == sizeof(int64_t), "TimePoint should be 64 bits"); inline TimePoint now() { return std::chrono::duration_cast (std::chrono::steady_clock::now().time_since_epoch()).count(); } template struct HashTable { Entry* operator[](Key key) { return &table[(uint32_t)key & (Size - 1)]; } private: std::vector table = std::vector(Size); // Allocate on the heap }; enum SyncCout { IO_LOCK, IO_UNLOCK }; std::ostream& operator<<(std::ostream&, SyncCout); #define sync_cout std::cout << IO_LOCK #define sync_endl std::endl << IO_UNLOCK /// xorshift64star Pseudo-Random Number Generator /// This class is based on original code written and dedicated /// to the public domain by Sebastiano Vigna (2014). /// It has the following characteristics: /// /// - Outputs 64-bit numbers /// - Passes Dieharder and SmallCrush test batteries /// - Does not require warm-up, no zeroland to escape /// - Internal state is a single 64-bit integer /// - Period is 2^64 - 1 /// - Speed: 1.60 ns/call (Core i7 @3.40GHz) /// /// For further analysis see /// class PRNG { uint64_t s; uint64_t rand64() { s ^= s >> 12, s ^= s << 25, s ^= s >> 27; return s * 2685821657736338717LL; } public: PRNG(uint64_t seed) : s(seed) { assert(seed); } template T rand() { return T(rand64()); } /// Special generator used to fast init magic numbers. /// Output values only have 1/8th of their bits set on average. template T sparse_rand() { return T(rand64() & rand64() & rand64()); } // 0からn-1までの乱数を返す。(一様分布ではないが現実的にはこれで十分) uint64_t rand(uint64_t n) { return rand() % n; } // 内部で使用している乱数seedを返す。 uint64_t get_seed() const { return s; } }; // 乱数のseedを表示する。(デバッグ用) inline std::ostream& operator<<(std::ostream& os, PRNG& prng) { os << "PRNG::seed = " << std::hex << prng.get_seed() << std::dec; return os; } /// Under Windows it is not possible for a process to run on more than one /// logical processor group. This usually means to be limited to use max 64 /// cores. To overcome this, some special platform specific API should be /// called to set group affinity for each thread. Original code from Texel by /// Peter Österlund. namespace WinProcGroup { void bindThisThread(size_t idx); } // 指定されたミリ秒だけsleepする。 extern void sleep(int ms); // 現在時刻を文字列化したもを返す。(評価関数の学習時などにログ出力のために用いる) std::string now_string(); // 途中での終了処理のためのwrapper static void my_exit() { sleep(3000); // エラーメッセージが出力される前に終了するのはまずいのでwaitを入れておく。 exit(EXIT_FAILURE); } // msys2、Windows Subsystem for Linuxなどのgcc/clangでコンパイルした場合、 // C++のstd::ifstreamで::read()は、一発で2GB以上のファイルの読み書きが出来ないのでそのためのwrapperである。 // // read_file_to_memory()の引数のcallback_funcは、ファイルがオープン出来た時点でそのファイルサイズを引数として // callbackされるので、バッファを確保して、その先頭ポインタを返す関数を渡すと、そこに読み込んでくれる。 // これらの関数は、ファイルが見つからないときなどエラーの際には非0を返す。 // // また、callbackされた関数のなかでバッファが確保できなかった場合や、想定していたファイルサイズと異なった場合は、 // nullptrを返せば良い。このとき、read_file_to_memory()は、読み込みを中断し、エラーリターンする。 int read_file_to_memory(std::string filename, std::function callback_func); int write_memory_to_file(std::string filename, void* ptr, uint64_t size); // -------------------- // PRNGのasync版 // -------------------- // PRNGのasync版 struct AsyncPRNG { AsyncPRNG(uint64_t seed) : prng(seed) { assert(seed); } // [ASYNC] 乱数を一つ取り出す。 template T rand() { std::unique_lock lk(mutex); return prng.rand(); } // [ASYNC] 0からn-1までの乱数を返す。(一様分布ではないが現実的にはこれで十分) uint64_t rand(uint64_t n) { std::unique_lock lk(mutex); return prng.rand(n); } // 内部で使用している乱数seedを返す。 uint64_t get_seed() const { return prng.get_seed(); } protected: Mutex mutex; PRNG prng; }; // 乱数のseedを表示する。(デバッグ用) inline std::ostream& operator<<(std::ostream& os, AsyncPRNG& prng) { os << "AsyncPRNG::seed = " << std::hex << prng.get_seed() << std::dec; return os; } // -------------------- // Math // -------------------- // 進行度の計算や学習で用いる数学的な関数 namespace Math { // シグモイド関数 // = 1.0 / (1.0 + std::exp(-x)) double sigmoid(double x); // シグモイド関数の微分 // = sigmoid(x) * (1.0 - sigmoid(x)) double dsigmoid(double x); // vを[lo,hi]の間に収まるようにクリップする。 // ※ Stockfishではこの関数、bitboard.hに書いてある。 template constexpr const T& clamp(const T& v, const T& lo, const T& hi) { return v < lo ? lo : v > hi ? hi : v; } } // -------------------- // Path // -------------------- // C#にあるPathクラス的なもの。ファイル名の操作。 // C#のメソッド名に合わせておく。 struct Path { // path名とファイル名を結合して、それを返す。 // folder名のほうは空文字列でないときに、末尾に'/'か'\\'がなければそれを付与する。 static std::string Combine(const std::string& folder, const std::string& filename) { if (folder.length() >= 1 && *folder.rbegin() != '/' && *folder.rbegin() != '\\') return folder + "/" + filename; return folder + filename; } // full path表現から、(フォルダ名を除いた)ファイル名の部分を取得する。 static std::string GetFileName(const std::string& path) { // "\"か"/"か、どちらを使ってあるかはわからない。 auto path_index1 = path.find_last_of("\\") + 1; auto path_index2 = path.find_last_of("/") + 1; auto path_index = std::max(path_index1, path_index2); return path.substr(path_index); } }; extern void* aligned_malloc(size_t size, size_t align); static void aligned_free(void* ptr) { _mm_free(ptr); } // alignasを指定しているのにnewのときに無視される&STLのコンテナがメモリ確保するときに無視するので、 // そのために用いるカスタムアロケーター。 template class AlignedAllocator { public: using value_type = T; AlignedAllocator() {} AlignedAllocator(const AlignedAllocator&) {} AlignedAllocator(AlignedAllocator&&) {} template AlignedAllocator(const AlignedAllocator&) {} T* allocate(std::size_t n) { return (T*)aligned_malloc(n * sizeof(T), alignof(T)); } void deallocate(T* p, std::size_t n) { aligned_free(p); } }; // -------------------- // Dependency Wrapper // -------------------- namespace Dependency { // Linux環境ではgetline()したときにテキストファイルが'\r\n'だと // '\r'が末尾に残るのでこの'\r'を除去するためにwrapperを書く。 // そのため、fstreamに対してgetline()を呼び出すときは、 // std::getline()ではなく単にgetline()と書いて、この関数を使うべき。 extern bool getline(std::ifstream& fs, std::string& s); // フォルダを作成する。 // カレントフォルダ相対で指定する。dir_nameに日本語は使っていないものとする。 // 成功すれば0、失敗すれば非0が返る。 extern int mkdir(std::string dir_name); } #endif // #ifndef MISC_H_INCLUDED