The reason I say that is that the context of the time was programs searching 5-6-7 plies deep, whereas today programs are searching 4x that deep. That changes a lot.
Yes, I fully agree. The historical nature of the discussion is of differing value that its modern implementation.
And even with numbers like 36-40, counters overflow terribly at today's NPS. Even depth*depth becomes problematic and needs a 64 bit counter.
The "fix" to this in Rybka 3 and environs is to make adjustments be scalable (not exactly a sigmoid, but of the same flavour).
- Code: Select all
#define SHIFT 8
#define HISTORY_GOOD(move, depth) \
{ int sv = HISTORY_VALUE (POSITION , move); \
HISTORY_VALUE (POSITION, move) = sv + (( (0xff00 - sv) * depth) >> SHIFT); \ [...]
[...]
#define HISTORY_BAD(move, depth)
{ int sv = HISTORY_VALUE (POSITION, move); \
if (POS0->Value > VALUE - 50) \ # POS0->value is the positional evaluation
HISTORY_VALUE (POSITION, move) = sv - ((sv * depth) >> SHIFT); }
So IvanHoe subtracts
(depth/256) of the current history value when a move is bad. When a move is good, the "upper limit" is
0xff00 or 65280 [the "lower limit" being 0], and the difference of the current score to this is then scaled again by
(depth/256) before adding it. Since all modifications are "multiplicative" as a percentage of the current value [or 65280 minus it], no overflow can occur. Admittedly, this only keeps the original "counter" sense as a concept, though good moves will definitely get better scores. The start values in IvanHoe are
0x800, or 2048, which leaves plenty of room for increase, and a fair bit for decrease.
R3 is essentially the same, though the numerology differs (and there are two history tables for bad history moves depending on the comparison of the scout value to the positional evaluation -- GCP was wondering about this, and recently I found that just "strings <rybka3-executable>" might already tell you such:
history [0]: %d / (12*64) = %d and
history [1]: %d / (12*64) = %d).