]> git.sesse.net Git - stockfish/blob - src/tune.h
Remove all references to Score type
[stockfish] / src / tune.h
1 /*
2   Stockfish, a UCI chess playing engine derived from Glaurung 2.1
3   Copyright (C) 2004-2023 The Stockfish developers (see AUTHORS file)
4
5   Stockfish is free software: you can redistribute it and/or modify
6   it under the terms of the GNU General Public License as published by
7   the Free Software Foundation, either version 3 of the License, or
8   (at your option) any later version.
9
10   Stockfish is distributed in the hope that it will be useful,
11   but WITHOUT ANY WARRANTY; without even the implied warranty of
12   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13   GNU General Public License for more details.
14
15   You should have received a copy of the GNU General Public License
16   along with this program.  If not, see <http://www.gnu.org/licenses/>.
17 */
18
19 #ifndef TUNE_H_INCLUDED
20 #define TUNE_H_INCLUDED
21
22 #include <memory>
23 #include <string>
24 #include <type_traits>
25 #include <vector>
26
27 namespace Stockfish {
28
29 using Range = std::pair<int, int>; // Option's min-max values
30 using RangeFun = Range (int);
31
32 // Default Range function, to calculate Option's min-max values
33 inline Range default_range(int v) {
34   return v > 0 ? Range(0, 2 * v) : Range(2 * v, 0);
35 }
36
37 struct SetRange {
38   explicit SetRange(RangeFun f) : fun(f) {}
39   SetRange(int min, int max) : fun(nullptr), range(min, max) {}
40   Range operator()(int v) const { return fun ? fun(v) : range; }
41
42   RangeFun* fun;
43   Range range;
44 };
45
46 #define SetDefaultRange SetRange(default_range)
47
48
49 /// Tune class implements the 'magic' code that makes the setup of a fishtest
50 /// tuning session as easy as it can be. Mainly you have just to remove const
51 /// qualifiers from the variables you want to tune and flag them for tuning, so
52 /// if you have:
53 ///
54 ///   const Value myValue[][2] = { { V(100), V(20) }, { V(7), V(78) } };
55 ///
56 /// If you have a my_post_update() function to run after values have been updated,
57 /// and a my_range() function to set custom Option's min-max values, then you just
58 /// remove the 'const' qualifiers and write somewhere below in the file:
59 ///
60 ///   TUNE(SetRange(my_range), myValue, my_post_update);
61 ///
62 /// You can also set the range directly, and restore the default at the end
63 ///
64 ///   TUNE(SetRange(-100, 100), myValue, SetDefaultRange);
65 ///
66 /// In case update function is slow and you have many parameters, you can add:
67 ///
68 ///   UPDATE_ON_LAST();
69 ///
70 /// And the values update, including post update function call, will be done only
71 /// once, after the engine receives the last UCI option, that is the one defined
72 /// and created as the last one, so the GUI should send the options in the same
73 /// order in which have been defined.
74
75 class Tune {
76
77   using PostUpdate = void (); // Post-update function
78
79   Tune() { read_results(); }
80   Tune(const Tune&) = delete;
81   void operator=(const Tune&) = delete;
82   void read_results();
83
84   static Tune& instance() { static Tune t; return t; } // Singleton
85
86   // Use polymorphism to accommodate Entry of different types in the same vector
87   struct EntryBase {
88     virtual ~EntryBase() = default;
89     virtual void init_option() = 0;
90     virtual void read_option() = 0;
91   };
92
93   template<typename T>
94   struct Entry : public EntryBase {
95
96     static_assert(!std::is_const<T>::value, "Parameter cannot be const!");
97
98     static_assert(   std::is_same<T,   int>::value
99                   || std::is_same<T, Value>::value
100                   || std::is_same<T, PostUpdate>::value, "Parameter type not supported!");
101
102     Entry(const std::string& n, T& v, const SetRange& r) : name(n), value(v), range(r) {}
103     void operator=(const Entry&) = delete; // Because 'value' is a reference
104     void init_option() override;
105     void read_option() override;
106
107     std::string name;
108     T& value;
109     SetRange range;
110   };
111
112   // Our facility to fill the container, each Entry corresponds to a parameter
113   // to tune. We use variadic templates to deal with an unspecified number of
114   // entries, each one of a possible different type.
115   static std::string next(std::string& names, bool pop = true);
116
117   int add(const SetRange&, std::string&&) { return 0; }
118
119   template<typename T, typename... Args>
120   int add(const SetRange& range, std::string&& names, T& value, Args&&... args) {
121     list.push_back(std::unique_ptr<EntryBase>(new Entry<T>(next(names), value, range)));
122     return add(range, std::move(names), args...);
123   }
124
125   // Template specialization for arrays: recursively handle multi-dimensional arrays
126   template<typename T, size_t N, typename... Args>
127   int add(const SetRange& range, std::string&& names, T (&value)[N], Args&&... args) {
128     for (size_t i = 0; i < N; i++)
129         add(range, next(names, i == N - 1) + "[" + std::to_string(i) + "]", value[i]);
130     return add(range, std::move(names), args...);
131   }
132
133   // Template specialization for SetRange
134   template<typename... Args>
135   int add(const SetRange&, std::string&& names, SetRange& value, Args&&... args) {
136     return add(value, (next(names), std::move(names)), args...);
137   }
138
139   std::vector<std::unique_ptr<EntryBase>> list;
140
141 public:
142   template<typename... Args>
143   static int add(const std::string& names, Args&&... args) {
144     return instance().add(SetDefaultRange, names.substr(1, names.size() - 2), args...); // Remove trailing parenthesis
145   }
146   static void init() { for (auto& e : instance().list) e->init_option(); read_options(); } // Deferred, due to UCI::Options access
147   static void read_options() { for (auto& e : instance().list) e->read_option(); }
148   static bool update_on_last;
149 };
150
151 // Some macro magic :-) we define a dummy int variable that compiler initializes calling Tune::add()
152 #define STRINGIFY(x) #x
153 #define UNIQUE2(x, y) x ## y
154 #define UNIQUE(x, y) UNIQUE2(x, y) // Two indirection levels to expand __LINE__
155 #define TUNE(...) int UNIQUE(p, __LINE__) = Tune::add(STRINGIFY((__VA_ARGS__)), __VA_ARGS__)
156
157 #define UPDATE_ON_LAST() bool UNIQUE(p, __LINE__) = Tune::update_on_last = true
158
159 } // namespace Stockfish
160
161 #endif // #ifndef TUNE_H_INCLUDED