2323#include < cmath>
2424#include < cstdlib>
2525#include < fstream>
26+ #include < initializer_list>
2627#include < iomanip>
2728#include < iostream>
2829#include < sstream>
3132#include " incbin/incbin.h"
3233#include " misc.h"
3334#include " nnue/evaluate_nnue.h"
35+ #include " nnue/nnue_architecture.h"
3436#include " position.h"
3537#include " thread.h"
3638#include " types.h"
4446// const unsigned int gEmbeddedNNUESize; // the size of the embedded file
4547// Note that this does not work in Microsoft Visual Studio.
4648#if !defined(_MSC_VER) && !defined(NNUE_EMBEDDING_OFF)
47- INCBIN (EmbeddedNNUE, EvalFileDefaultName);
49+ INCBIN (EmbeddedNNUEBig, EvalFileDefaultNameBig);
50+ INCBIN (EmbeddedNNUESmall, EvalFileDefaultNameSmall);
4851#else
49- const unsigned char gEmbeddedNNUEData [1 ] = {0x0 };
50- const unsigned char * const gEmbeddedNNUEEnd = &gEmbeddedNNUEData [1 ];
51- const unsigned int gEmbeddedNNUESize = 1 ;
52+ const unsigned char gEmbeddedNNUEBigData [1 ] = {0x0 };
53+ const unsigned char * const gEmbeddedNNUEBigEnd = &gEmbeddedNNUEBigData [1 ];
54+ const unsigned int gEmbeddedNNUEBigSize = 1 ;
55+ const unsigned char gEmbeddedNNUESmallData [1 ] = {0x0 };
56+ const unsigned char * const gEmbeddedNNUESmallEnd = &gEmbeddedNNUESmallData [1 ];
57+ const unsigned int gEmbeddedNNUESmallSize = 1 ;
5258#endif
5359
5460
5561namespace Stockfish {
5662
5763namespace Eval {
5864
59- std::string currentEvalFileName = " None" ;
65+ std::string currentEvalFileName[2 ] = {" None" , " None" };
66+ const std::string EvFiles[2 ] = {" EvalFile" , " EvalFileSmall" };
67+ const std::string EvFileNames[2 ] = {EvalFileDefaultNameBig, EvalFileDefaultNameSmall};
6068
6169// Tries to load a NNUE network at startup time, or when the engine
6270// receives a UCI command "setoption name EvalFile value nn-[a-z0-9]{12}.nnue"
@@ -67,84 +75,96 @@ std::string currentEvalFileName = "None";
6775// variable to have the engine search in a special directory in their distro.
6876void NNUE::init () {
6977
70- std::string eval_file = std::string (Options[" EvalFile" ]);
71- if (eval_file.empty ())
72- eval_file = EvalFileDefaultName;
78+ for (NetSize netSize : {Big, Small})
79+ {
80+ // change after fishtest supports EvalFileSmall
81+ std::string eval_file =
82+ std::string (netSize == Small ? EvalFileDefaultNameSmall : Options[EvFiles[netSize]]);
83+ if (eval_file.empty ())
84+ eval_file = EvFileNames[netSize];
7385
7486#if defined(DEFAULT_NNUE_DIRECTORY)
75- std::vector<std::string> dirs = {" <internal>" , " " , CommandLine::binaryDirectory,
76- stringify (DEFAULT_NNUE_DIRECTORY)};
87+ std::vector<std::string> dirs = {" <internal>" , " " , CommandLine::binaryDirectory,
88+ stringify (DEFAULT_NNUE_DIRECTORY)};
7789#else
78- std::vector<std::string> dirs = {" <internal>" , " " , CommandLine::binaryDirectory};
90+ std::vector<std::string> dirs = {" <internal>" , " " , CommandLine::binaryDirectory};
7991#endif
8092
81- for (const std::string& directory : dirs)
82- if (currentEvalFileName != eval_file)
93+ for (const std::string& directory : dirs)
8394 {
84- if (directory != " <internal>" )
85- {
86- std::ifstream stream (directory + eval_file, std::ios::binary);
87- if (NNUE::load_eval (eval_file, stream))
88- currentEvalFileName = eval_file;
89- }
90-
91- if (directory == " <internal>" && eval_file == EvalFileDefaultName)
95+ if (currentEvalFileName[netSize] != eval_file)
9296 {
93- // C++ way to prepare a buffer for a memory stream
94- class MemoryBuffer : public std ::basic_streambuf<char > {
95- public:
96- MemoryBuffer (char * p, size_t n) {
97- setg (p, p, p + n);
98- setp (p, p + n);
99- }
100- };
101-
102- MemoryBuffer buffer (
103- const_cast <char *>(reinterpret_cast <const char *>(gEmbeddedNNUEData )),
104- size_t (gEmbeddedNNUESize ));
105- (void ) gEmbeddedNNUEEnd ; // Silence warning on unused variable
106-
107- std::istream stream (&buffer);
108- if (NNUE::load_eval (eval_file, stream))
109- currentEvalFileName = eval_file;
97+ if (directory != " <internal>" )
98+ {
99+ std::ifstream stream (directory + eval_file, std::ios::binary);
100+ if (NNUE::load_eval (eval_file, stream, netSize))
101+ currentEvalFileName[netSize] = eval_file;
102+ }
103+
104+ if (directory == " <internal>" && eval_file == EvFileNames[netSize])
105+ {
106+ // C++ way to prepare a buffer for a memory stream
107+ class MemoryBuffer : public std ::basic_streambuf<char > {
108+ public:
109+ MemoryBuffer (char * p, size_t n) {
110+ setg (p, p, p + n);
111+ setp (p, p + n);
112+ }
113+ };
114+
115+ MemoryBuffer buffer (
116+ const_cast <char *>(reinterpret_cast <const char *>(
117+ netSize == Small ? gEmbeddedNNUESmallData : gEmbeddedNNUEBigData )),
118+ size_t (netSize == Small ? gEmbeddedNNUESmallSize : gEmbeddedNNUEBigSize ));
119+ (void ) gEmbeddedNNUEBigEnd ; // Silence warning on unused variable
120+ (void ) gEmbeddedNNUESmallEnd ;
121+
122+ std::istream stream (&buffer);
123+ if (NNUE::load_eval (eval_file, stream, netSize))
124+ currentEvalFileName[netSize] = eval_file;
125+ }
110126 }
111127 }
128+ }
112129}
113130
114131// Verifies that the last net used was loaded successfully
115132void NNUE::verify () {
116133
117- std::string eval_file = std::string (Options[" EvalFile" ]);
118- if (eval_file.empty ())
119- eval_file = EvalFileDefaultName;
120-
121- if (currentEvalFileName != eval_file)
134+ for (NetSize netSize : {Big, Small})
122135 {
136+ // change after fishtest supports EvalFileSmall
137+ std::string eval_file =
138+ std::string (netSize == Small ? EvalFileDefaultNameSmall : Options[EvFiles[netSize]]);
139+ if (eval_file.empty ())
140+ eval_file = EvFileNames[netSize];
123141
124- std::string msg1 =
125- " Network evaluation parameters compatible with the engine must be available." ;
126- std::string msg2 = " The network file " + eval_file + " was not loaded successfully." ;
127- std::string msg3 = " The UCI option EvalFile might need to specify the full path, "
128- " including the directory name, to the network file." ;
129- std::string msg4 = " The default net can be downloaded from: "
130- " https://tests.stockfishchess.org/api/nn/"
131- + std::string (EvalFileDefaultName);
132- std::string msg5 = " The engine will be terminated now." ;
133-
134- sync_cout << " info string ERROR: " << msg1 << sync_endl;
135- sync_cout << " info string ERROR: " << msg2 << sync_endl;
136- sync_cout << " info string ERROR: " << msg3 << sync_endl;
137- sync_cout << " info string ERROR: " << msg4 << sync_endl;
138- sync_cout << " info string ERROR: " << msg5 << sync_endl;
139-
140- exit (EXIT_FAILURE);
141- }
142+ if (currentEvalFileName[netSize] != eval_file)
143+ {
144+ std::string msg1 =
145+ " Network evaluation parameters compatible with the engine must be available." ;
146+ std::string msg2 = " The network file " + eval_file + " was not loaded successfully." ;
147+ std::string msg3 = " The UCI option EvalFile might need to specify the full path, "
148+ " including the directory name, to the network file." ;
149+ std::string msg4 = " The default net can be downloaded from: "
150+ " https://tests.stockfishchess.org/api/nn/"
151+ + std::string (EvFileNames[netSize]);
152+ std::string msg5 = " The engine will be terminated now." ;
153+
154+ sync_cout << " info string ERROR: " << msg1 << sync_endl;
155+ sync_cout << " info string ERROR: " << msg2 << sync_endl;
156+ sync_cout << " info string ERROR: " << msg3 << sync_endl;
157+ sync_cout << " info string ERROR: " << msg4 << sync_endl;
158+ sync_cout << " info string ERROR: " << msg5 << sync_endl;
159+
160+ exit (EXIT_FAILURE);
161+ }
142162
143- sync_cout << " info string NNUE evaluation using " << eval_file << sync_endl;
163+ sync_cout << " info string NNUE evaluation using " << eval_file << sync_endl;
164+ }
144165}
145166}
146167
147-
148168// Returns a static, purely materialistic evaluation of the position from
149169// the point of view of the given color. It can be divided by PawnValue to get
150170// an approximation of the material advantage on the board in terms of pawns.
@@ -163,18 +183,19 @@ Value Eval::evaluate(const Position& pos) {
163183 int v;
164184 Color stm = pos.side_to_move ();
165185 int shuffling = pos.rule50_count ();
166- int simpleEval = simple_eval (pos, stm) + (int (pos.key () & 7 ) - 3 );
167-
168- bool lazy = std::abs (simpleEval) >= RookValue + KnightValue + 16 * shuffling * shuffling
169- + std::abs (pos.this_thread ()->bestValue )
170- + std::abs (pos.this_thread ()->rootSimpleEval );
186+ int simpleEval = simple_eval (pos, stm);
171187
188+ bool lazy = std::abs (simpleEval) > 2300 ;
172189 if (lazy)
173190 v = simpleEval;
174191 else
175192 {
176- int nnueComplexity;
177- Value nnue = NNUE::evaluate (pos, true , &nnueComplexity);
193+ bool smallNet = std::abs (simpleEval) > 1100 ;
194+
195+ int nnueComplexity;
196+
197+ Value nnue = smallNet ? NNUE::evaluate<NNUE::Small>(pos, true , &nnueComplexity)
198+ : NNUE::evaluate<NNUE::Big>(pos, true , &nnueComplexity);
178199
179200 int optimism = pos.this_thread ()->optimism [stm];
180201
@@ -217,7 +238,7 @@ std::string Eval::trace(Position& pos) {
217238 ss << std::showpoint << std::showpos << std::fixed << std::setprecision (2 ) << std::setw (15 );
218239
219240 Value v;
220- v = NNUE::evaluate (pos, false );
241+ v = NNUE::evaluate<NNUE::Big> (pos, false );
221242 v = pos.side_to_move () == WHITE ? v : -v;
222243 ss << " NNUE evaluation " << 0.01 * UCI::to_cp (v) << " (white side)\n " ;
223244
0 commit comments