Line data Source code
1 : #pragma once
2 :
3 : #include "definition.hpp"
4 : #include "logging.hpp"
5 :
6 : struct Position;
7 :
8 : #ifdef DEBUG_EVALSYM
9 : [[nodiscard]] FORCE_FINLINE float fiftyMoveRuleScaling(const uint8_t ){
10 : return 1;
11 : }
12 : [[nodiscard]] FORCE_FINLINE float fiftyMoveRuleUnScaling(const uint8_t ){
13 : return 1;
14 : }
15 : #else
16 : [[nodiscard]] constexpr float fiftyMoveRuleScaling(const uint8_t fifty){
17 5848870 : return 1.f - std::max(0, fifty*fifty) / 10000.f;
18 : }
19 : #endif
20 :
21 : [[nodiscard]] FORCE_FINLINE ScoreType fiftyScale(const ScoreType s, uint8_t fifty){
22 4452073 : return static_cast<ScoreType>(s * fiftyMoveRuleScaling(fifty));
23 : }
24 :
25 : ///@todo use that to store TT entry independant of fifty scaling
26 : [[nodiscard]] FORCE_FINLINE ScoreType fiftyUnScale(const ScoreType s, uint8_t fifty){
27 : return static_cast<ScoreType>(s / fiftyMoveRuleScaling(fifty));
28 : }
29 :
30 : // Stockfish trick (two short in one int) is not compatible with evaluation tuning !
31 : #ifndef WITH_EVALSCORE_AS_INT
32 : struct EvalScore {
33 : array1d<ScoreType, GP_MAX> sc = {0};
34 112351465 : EvalScore(const ScoreType mg, const ScoreType eg): sc {mg, eg} {}
35 212358242 : EvalScore(const ScoreType s): sc {s, s} {}
36 23352273 : EvalScore(): sc {0, 0} {}
37 11748185726 : EvalScore(const EvalScore& e): sc {e.sc[MG], e.sc[EG]} {}
38 : ~EvalScore() = default;
39 :
40 18978289886 : FORCE_FINLINE ScoreType& operator[](const GamePhase g) { return sc[g]; }
41 9594295432 : FORCE_FINLINE const ScoreType& operator[](const GamePhase g) const { return sc[g]; }
42 :
43 : EvalScore& operator*=(const EvalScore& s) {
44 : for (GamePhase g = MG; g < GP_MAX; ++g) sc[g] *= s[g];
45 : return *this;
46 : }
47 : EvalScore& operator/=(const EvalScore& s) {
48 : for (GamePhase g = MG; g < GP_MAX; ++g) sc[g] /= s[g];
49 : return *this;
50 : }
51 46457655 : EvalScore& operator+=(const EvalScore& s) {
52 7081851315 : for (GamePhase g = MG; g < GP_MAX; ++g) sc[g] += s[g];
53 46457655 : return *this;
54 : }
55 21828903 : EvalScore& operator-=(const EvalScore& s) {
56 65486709 : for (GamePhase g = MG; g < GP_MAX; ++g) sc[g] -= s[g];
57 21828903 : return *this;
58 : }
59 : EvalScore operator*(const EvalScore& s) const {
60 : EvalScore e(*this);
61 : for (GamePhase g = MG; g < GP_MAX; ++g) e[g] *= s[g];
62 : return e;
63 : }
64 : EvalScore operator/(const EvalScore& s) const {
65 : EvalScore e(*this);
66 : for (GamePhase g = MG; g < GP_MAX; ++g) e[g] /= s[g];
67 : return e;
68 : }
69 2314245873 : EvalScore operator+(const EvalScore& s) const {
70 : EvalScore e(*this);
71 6947811432 : for (GamePhase g = MG; g < GP_MAX; ++g) e[g] += s[g];
72 2314245873 : return e;
73 : }
74 26950231 : EvalScore operator-(const EvalScore& s) const {
75 : EvalScore e(*this);
76 90414309 : for (GamePhase g = MG; g < GP_MAX; ++g) e[g] -= s[g];
77 26950231 : return e;
78 : }
79 : EvalScore & operator=(const EvalScore& s) {
80 344008275 : for (GamePhase g = MG; g < GP_MAX; ++g) { sc[g] = s[g]; }
81 : return *this;
82 : }
83 :
84 : EvalScore& operator*=(const ScoreType& s) {
85 : for (GamePhase g = MG; g < GP_MAX; ++g) sc[g] *= s;
86 : return *this;
87 : }
88 : EvalScore& operator/=(const ScoreType& s) {
89 : for (GamePhase g = MG; g < GP_MAX; ++g) sc[g] /= s;
90 : return *this;
91 : }
92 : EvalScore& operator+=(const ScoreType& s) {
93 6825 : for (GamePhase g = MG; g < GP_MAX; ++g) sc[g] += s;
94 : return *this;
95 : }
96 : EvalScore& operator-=(const ScoreType& s) {
97 : for (GamePhase g = MG; g < GP_MAX; ++g) sc[g] -= s;
98 : return *this;
99 : }
100 9188880226 : EvalScore operator*(const ScoreType& s) const {
101 : EvalScore e(*this);
102 27736319068 : for (GamePhase g = MG; g < GP_MAX; ++g) e[g] *= s;
103 9188880226 : return e;
104 : }
105 210450636 : EvalScore operator/(const ScoreType& s) const {
106 : EvalScore e(*this);
107 636133716 : for (GamePhase g = MG; g < GP_MAX; ++g) e[g] /= s;
108 210450636 : return e;
109 : }
110 : EvalScore operator+(const ScoreType& s) const {
111 : EvalScore e(*this);
112 : for (GamePhase g = MG; g < GP_MAX; ++g) e[g] += s;
113 : return e;
114 : }
115 : EvalScore operator-(const ScoreType& s) const {
116 : EvalScore e(*this);
117 : for (GamePhase g = MG; g < GP_MAX; ++g) e[g] -= s;
118 : return e;
119 : }
120 : EvalScore & operator=(const ScoreType& s) {
121 : for (GamePhase g = MG; g < GP_MAX; ++g) { sc[g] = s; }
122 : return *this;
123 : }
124 :
125 : [[nodiscard]] EvalScore scale(float s_mg, float s_eg) const {
126 : EvalScore e(*this);
127 5578776 : e[MG] = ScoreType(s_mg * e[MG]);
128 5578776 : e[EG] = ScoreType(s_eg * e[EG]);
129 : return e;
130 : }
131 : };
132 :
133 : #else
134 :
135 : constexpr auto MakeScore(mg, eg) { return (int)((unsigned int)(eg) << 16) + (mg);}
136 : constexpr auto MGScore(s) { return (int16_t)((uint16_t)((unsigned)((s))));}
137 : constexpr auto EGScore(s) { return (int16_t)((uint16_t)((unsigned)((s) + 0x8000) >> 16));}
138 :
139 : struct EvalScore {
140 : int sc = 0;
141 : EvalScore(const ScoreType mg, const ScoreType eg): sc {MakeScore(mg, eg)} {}
142 : EvalScore(const ScoreType s): sc {MakeScore(s, s)} {}
143 : EvalScore(): sc {0} {}
144 : EvalScore(const EvalScore& s): sc {s.sc} {}
145 : ~EvalScore() = default;
146 :
147 : FORCE_FINLINE ScoreType operator[](GamePhase g) const { return g == MG ? MGScore(sc) : EGScore(sc); }
148 :
149 : EvalScore& operator*=(const EvalScore& s) {
150 : sc = MakeScore(MGScore(sc) * MGScore(s.sc), EGScore(sc) * EGScore(s.sc));
151 : return *this;
152 : }
153 : EvalScore& operator/=(const EvalScore& s) {
154 : sc = MakeScore(MGScore(sc) / MGScore(s.sc), EGScore(sc) / EGScore(s.sc));
155 : return *this;
156 : }
157 : EvalScore& operator+=(const EvalScore& s) {
158 : sc = MakeScore(MGScore(sc) + MGScore(s.sc), EGScore(sc) + EGScore(s.sc));
159 : return *this;
160 : }
161 : EvalScore& operator-=(const EvalScore& s) {
162 : sc = MakeScore(MGScore(sc) - MGScore(s.sc), EGScore(sc) - EGScore(s.sc));
163 : return *this;
164 : }
165 : EvalScore operator*(const EvalScore& s) const { return MakeScore(MGScore(sc) * MGScore(s.sc), EGScore(sc) * EGScore(s.sc)); }
166 : EvalScore operator/(const EvalScore& s) const { return MakeScore(MGScore(sc) / MGScore(s.sc), EGScore(sc) / EGScore(s.sc)); }
167 : EvalScore operator+(const EvalScore& s) const { return MakeScore(MGScore(sc) + MGScore(s.sc), EGScore(sc) + EGScore(s.sc)); }
168 : EvalScore operator-(const EvalScore& s) const { return MakeScore(MGScore(sc) - MGScore(s.sc), EGScore(sc) - EGScore(s.sc)); }
169 : EvalScore& operator=(const EvalScore& s) { sc = s.sc; return *this; }
170 :
171 : EvalScore& operator*=(const ScoreType& s) {
172 : sc = MakeScore(MGScore(sc) * s, EGScore(sc) * s);
173 : return *this;
174 : }
175 : EvalScore& operator/=(const ScoreType& s) {
176 : sc = MakeScore(MGScore(sc) / s, EGScore(sc) / s);
177 : return *this;
178 : }
179 : EvalScore& operator+=(const ScoreType& s) {
180 : sc = MakeScore(MGScore(sc) + s, EGScore(sc) + s);
181 : return *this;
182 : }
183 : EvalScore& operator-=(const ScoreType& s) {
184 : sc = MakeScore(MGScore(sc) - s, EGScore(sc) - s);
185 : return *this;
186 : }
187 : EvalScore operator*(const ScoreType& s) const { return MakeScore(MGScore(sc) * s, EGScore(sc) * s); }
188 : EvalScore operator/(const ScoreType& s) const { return MakeScore(MGScore(sc) / s, EGScore(sc) / s); }
189 : EvalScore operator+(const ScoreType& s) const { return MakeScore(MGScore(sc) + s, EGScore(sc) + s); }
190 : EvalScore operator-(const ScoreType& s) const { return MakeScore(MGScore(sc) - s, EGScore(sc) - s); }
191 : EvalScore& operator=(const ScoreType& s) { sc = MakeScore(s, s); return *this; }
192 :
193 : [[nodiscard]] EvalScore scale(float s_mg, float s_eg) const { return EvalScore(ScoreType(MGScore(sc) * s_mg), ScoreType(EGScore(sc) * s_eg)); }
194 : };
195 : #endif
196 :
197 1100 : inline std::ostream& operator<<(std::ostream& of, const EvalScore& s) {
198 2200 : of << s[MG] << " " << s[EG];
199 1100 : return of;
200 : }
201 :
202 : enum Feature : uint8_t { F_material = 0, F_positional, F_development, F_mobility, F_attack, F_pawnStruct, F_complexity, F_max };
203 : FORCE_FINLINE Feature operator++(Feature& f) {
204 : f = Feature(f + 1);
205 : return f;
206 : }
207 2919045 : struct EvalFeatures {
208 : array1d<EvalScore, F_max> scores; // EvalScore is 0 initialized
209 : float scalingFactor = 1.f; // only used in end-game !
210 : EvalScore SumUp() const;
211 : static void callBack();
212 : };
213 :
214 : /*
215 : inline std::ostream & operator<<(std::ostream & of, const EvalFeatures & features){
216 : for (size_t k = 0 ; k < F_max; ++k) of << features.scores[k] << " ";
217 : of << features.scalingFactor << " ";
218 : return of;
219 : }
220 : */
221 :
222 : [[nodiscard]] FORCE_FINLINE ScoreType ScaleScore(const EvalScore s, const float gp, const float scalingFactorEG = 1.f) {
223 29874666 : return static_cast<ScoreType>(gp * s[MG] + (1.f - gp) * scalingFactorEG * s[EG]);
224 : }
225 :
226 : /* Evaluation is returning the score of course, but also fill this little structure to provide
227 : * additionnal usefull information, such as game phase and current danger. Things that are
228 : * possibly used in search later.
229 : */
230 : struct EvalData {
231 : float gp = 0;
232 : colored<ScoreType> danger = {0, 0};
233 : colored<uint16_t> mobility = {0, 0};
234 : colored<bool> haveThreats = {false, false};
235 : colored<bool> goodThreats = {false, false};
236 : bool evalDone = false; // will tell if phase, danger and mobility are filleds or not
237 : };
238 :
239 : // used for easy move detection
240 : struct RootScores {
241 : Move m;
242 : ScoreType s;
243 : };
244 :
245 : // used for multiPV stuff
246 789 : struct MultiPVScores {
247 : Move m;
248 : ScoreType s;
249 : PVList pv;
250 : DepthType seldepth;
251 : };
252 :
253 : void displayEval(const EvalData& data, const EvalFeatures& features);
254 :
255 : // idea from Stockfish
256 : namespace WDL {
257 : // Coefficients of a 3rd order polynomial fit based on Minic test data (from CCRL, CEGT, FGRL)
258 : constexpr array1d<double, 4> as {-13.65744616, 94.04894005, -95.05180396, 84.853482690};
259 : constexpr array1d<double, 4> bs {-10.78187987, 77.22626799, -132.72201029, 122.54185402};
260 : } // namespace WDL
261 :
262 : [[nodiscard]] FORCE_FINLINE ScoreType shiftArmageddon(const ScoreType v, const unsigned int ply, const Color c) {
263 : // limit input ply and rescale
264 0 : const double m = std::min(256u, ply) / 64.0; // care! here ply not move
265 0 : const double a = (((WDL::as[0] * m + WDL::as[1]) * m + WDL::as[2]) * m) + WDL::as[3];
266 0 : if (c == Co_White) return static_cast<ScoreType>(v - 2 * a);
267 : else
268 0 : return static_cast<ScoreType>(v + 2 * a);
269 : }
270 :
271 : [[nodiscard]] FORCE_FINLINE double toWDLModel(const ScoreType v, const unsigned int ply) {
272 : // limit input ply and rescale
273 0 : const double m = std::min(256u, ply) / 64.0; // care! here ply not move
274 0 : const double a = (((WDL::as[0] * m + WDL::as[1]) * m + WDL::as[2]) * m) + WDL::as[3];
275 0 : const double b = (((WDL::bs[0] * m + WDL::bs[1]) * m + WDL::bs[2]) * m) + WDL::bs[3];
276 : // clamp score
277 0 : const double x = std::clamp(double((a - v) / b), -600.0, 600.0);
278 : // win probability from 0 to 1000
279 0 : return 1000. / (1. + std::exp(x));
280 : }
281 :
282 : /*
283 : FORCE_FINLINE ScoreType fromWDLModel(const double w, const unsigned int ply) {
284 : // limit input ply and rescale
285 : const double m = std::min(256u, ply) / 32.0;
286 : const double a = (((WDL::as[0] * m + WDL::as[1]) * m + WDL::as[2]) * m) + WDL::as[3];
287 : const double b = (((WDL::bs[0] * m + WDL::bs[1]) * m + WDL::bs[2]) * m) + WDL::bs[3];
288 : const double s = a - b * std::log(1000./(std::max(w,std::numeric_limits<double>::epsilon())) - 1. + std::numeric_limits<double>::epsilon());
289 : return static_cast<ScoreType>(std::clamp(s, static_cast<double>matedScore(ply) , static_cast<double>(matingScore(ply - 1)) );
290 : }
291 : */
|