lucasart wrote:* lookup the TT. At PV nodes only use it for move ordering, but don't return the TT score (because of draw by 3/50 move rules or mate situations).
I have heard claims that this hurts the engine very much in positions like Fine #70. How long does it take your engine to solve that?
Spandrel gives these results for Fine #70. They show no hurt.
Reading from TT:
No adjustment.
Saving in TT:
if ( score > MATESCORE - MAXPLIES )
{
if ( scoreType == UPPERBOUND ) return; // don't save
score = MATESCORE - MAXPLIES;
scoreType = LOWERBOUND;
}
else if ( score < -MATESCORE + MAXPLIES )
{
if ( scoreType == LOWERBOUND ) return; // don't save
score = -MATESCORE + MAXPLIES;
scoreType = UPPERBOUND;
}
... save score and scoreType in TT...
The puzzle is that in my engine the nonstandard option #2 is much stronger (around 100 Elo) than #1.
It seems implausible that option #2 is "really" better, because in that case everyone would be using it.
More likely I have a bug (perhaps relating to scoreType for mate scores) that is rendered harmless by option #2. I am however, unable to see such a bug and would welcome ideas/suggestions how to proceed.
Robert P.
TTable are subtile. I coded a chess engine, so I know the hurdles. After many failures, I realised that this is the right way to proceed:
* lookup the TT. At PV nodes only use it for move ordering, but don't return the TT score (because of draw by 3/50 move rules or mate situations).
* At non PV nodes, return the TT score if you know it creates a cutoff (using the info of score exact lboudn or ubound and the current window alpha,alpha+1=beta)
* when you've found the best move, save it in the TT, and put the info about whether the score is exact lbound or ubound.
Have a look at Fruit 2.1 source code for a good source code that is relatively simple to understand.
This is not the "right way" to do this. It is _a_ way. And not the best way. Why not store mate scores and then use them? If not using them on PV nodes is better, why not turn off _all_ hashing on PV nodes?
The concept makes no sense and generally suggests that there is an implementation bug/issue that needs to be hid.
It is easy to adjust the mate scores. Programs have been doing this for 30+ years with no problems at all..
You can't store a "best move" when all you have is an upper bound. There is, by definition, no best move at an ALL node...
lucasart wrote:
TTable are subtile. I coded a chess engine, so I know the hurdles. After many failures, I realised that this is the right way to proceed:
* lookup the TT. At PV nodes only use it for move ordering, but don't return the TT score (because of draw by 3/50 move rules or mate situations).
* At non PV nodes, return the TT score if you know it creates a cutoff (using the info of score exact lboudn or ubound and the current window alpha,alpha+1=beta)
* when you've found the best move, save it in the TT, and put the info about whether the score is exact lbound or ubound.
Have a look at Fruit 2.1 source code for a good source code that is relatively simple to understand.
This is not the "right way" to do this. It is _a_ way. And not the best way. Why not store mate scores and then use them? If not using them on PV nodes is better, why not turn off _all_ hashing on PV nodes?
The concept makes no sense and generally suggests that there is an implementation bug/issue that needs to be hid.
// At PV nodes, we don't use the TT for pruning, but only for move ordering.
// This is to avoid problems in the following areas:
//
// * Repetition draw detection
// * Fifty move rule detection
// * Searching for a mate
// * Printing of full PV line
if (!PvNode && tte && ok_to_use_TT(tte, depth, beta, ply))
{
TT.refresh(tte);
ss->bestMove = ttMove; // Can be MOVE_NONE
return value_from_tt(tte->value(), ply);
}
Fruit does the same, but without comment.
Robert P.
Whether it is better or not no doubt depends on the engine. Some engines furthermore do this not because it makes them stronger, but because it gives nicer (longer) PVs as output. (For which Crafty has another system.)
Bob has a point though, when he says it should absolutely not matter for the root move and score whether you hash-cut PV nodes or not. If it matters you have a bug somewhere, and all you can say is that this helps to mask it. There is no guarantee that it will completely mask the bug, and that there aren't any situations where it comes back to bite you.
I also find the ouputs you present for fine #70 with and without PV hash cuts very suspect. It seems that without using the score you see the +2 one ply earlier. But when you don't use the score, you cannot have any grafting,so you would only see things that are truly within the horizon. And if a +2 is within the horizon, how come you don't see it at 25 ply when you do use the hash cuts?
lucasart wrote:* At non PV nodes, return the TT score if you know it creates a cutoff [...]
As I already wrote in a different thread today, I do not see the point of applying this restriction: "if you know it creates a cutoff". If the TT contains sufficient information (i.e., sufficient draft, matching type of score) to avoid the search then avoid it, and return the TT value, no matter how it relates to "beta". TT cutoff is not the same as beta cutoff, it is just saving time after finding a "transposition".
lucasart wrote:
TTable are subtile. I coded a chess engine, so I know the hurdles. After many failures, I realised that this is the right way to proceed:
* lookup the TT. At PV nodes only use it for move ordering, but don't return the TT score (because of draw by 3/50 move rules or mate situations).
* At non PV nodes, return the TT score if you know it creates a cutoff (using the info of score exact lboudn or ubound and the current window alpha,alpha+1=beta)
* when you've found the best move, save it in the TT, and put the info about whether the score is exact lbound or ubound.
Have a look at Fruit 2.1 source code for a good source code that is relatively simple to understand.
This is not the "right way" to do this. It is _a_ way. And not the best way. Why not store mate scores and then use them? If not using them on PV nodes is better, why not turn off _all_ hashing on PV nodes?
The concept makes no sense and generally suggests that there is an implementation bug/issue that needs to be hid.
// At PV nodes, we don't use the TT for pruning, but only for move ordering.
// This is to avoid problems in the following areas:
//
// * Repetition draw detection
// * Fifty move rule detection
// * Searching for a mate
// * Printing of full PV line
if (!PvNode && tte && ok_to_use_TT(tte, depth, beta, ply))
{
TT.refresh(tte);
ss->bestMove = ttMove; // Can be MOVE_NONE
return value_from_tt(tte->value(), ply);
}
Fruit does the same, but without comment.
Robert P.
lucasart wrote:* lookup the TT. At PV nodes only use it for move ordering, but don't return the TT score (because of draw by 3/50 move rules or mate situations).
I have heard claims that this hurts the engine very much in positions like Fine #70. How long does it take your engine to solve that?
Spandrel gives these results for Fine #70. They show no hurt.
Use TT score at non-PV nodes only:
20 1.40 13 kn 0.003 s Kb2
21 1.40 15 kn 0.004 s Kb2
22 1.38 21 kn 0.005 s Kb2
23 1.38 28 kn 0.007 s Kb2
24 1.14 43 kn 0.010 s Kb2
25 2.03 60 kn 0.014 s Kb1
26 2.72 75 kn 0.019 s Kb1
27 2.88 80 kn 0.020 s Kb1
28 2.88 83 kn 0.020 s Kb1
29 2.72 91 kn 0.022 s Kb1
30 2.84 103 kn 0.025 s Kb1
31 2.94 112 kn 0.027 s Kb1
32 2.94 121 kn 0.028 s Kb1
33 3.18 130 kn 0.031 s Kb1
34 2.94 156 kn 0.036 s Kb1
35 3.17 166 kn 0.038 s Kb1
36 3.04 171 kn 0.039 s Kb1
37 3.17 182 kn 0.041 s Kb1
38 2.84 218 kn 0.050 s Kb1
39 2.92 237 kn 0.054 s Kb1
40 2.92 247 kn 0.055 s Kb1
...
Always use TT score:
20 1.40 12 kn 0.005 s Kb2
21 1.40 14 kn 0.005 s Kb2
22 1.22 22 kn 0.008 s Kb2
23 1.22 28 kn 0.010 s Kb2
24 1.22 36 kn 0.012 s Kb2
25 1.24 46 kn 0.015 s Kb1
26 2.52 63 kn 0.021 s Kb1
27 2.52 66 kn 0.022 s Kb1
28 2.52 69 kn 0.023 s Kb1
29 2.72 78 kn 0.026 s Kb1
30 2.72 82 kn 0.027 s Kb1
31 2.72 89 kn 0.029 s Kb1
32 2.68 95 kn 0.031 s Kb1
33 2.79 107 kn 0.035 s Kb1
34 2.94 118 kn 0.039 s Kb1
35 3.02 132 kn 0.043 s Kb1
36 3.17 146 kn 0.049 s Kb1
37 3.04 156 kn 0.052 s Kb1
38 3.04 165 kn 0.055 s Kb1
39 2.94 186 kn 0.062 s Kb1
40 2.94 198 kn 0.066 s Kb1
...
Robert P.
A couple of notes.
1. Your 40 ply search is _very_ small. 198K nodes total. Crafty searches about 10x that much. And there are no extensions to speak of, for obvious reasons...
2. The node counts, when compared, make sense. It has a definite cost to not use the scores on PV nodes. And your output shows that the tree size is significantly smaller when hashing everywhere, which makes perfect sense.
Those that don't hash on PV nodes do so, not because it makes them stronger, but because it prevents them from having a short PV. Since you are not showing any PV at all, I would go with that which searches the smaller tree. And I would also investigate why the tree size seems so small. Might be perfectly legit, or not...
lucasart wrote:* At non PV nodes, return the TT score if you know it creates a cutoff [...]
As I already wrote in a different thread today, I do not see the point of applying this restriction: "if you know it creates a cutoff". If the TT contains sufficient information (i.e., sufficient draft, matching type of score) to avoid the search then avoid it, and return the TT value, no matter how it relates to "beta". TT cutoff is not the same as beta cutoff, it is just saving time after finding a "transposition".
Sven
The check he is talking about is one that is necessary. If you get a "LOWER" entry with a bound from the table, you have to verify that the bound will cause a cutoff, legitimately, somewhere. That is, table bound has to be >= current beta value. Some check it in HashProbe() (as I do). Some just return the value and type and check it in search. 6 of one, half-dozen of the other. But if UPPER and bound < beta, or if LOWER and bound > alpha, you can't avoid doing anything and you have to continue searching. So you two might be talking about the same thing done in different places...
The puzzle is that in my engine the nonstandard option #2 is much stronger (around 100 Elo) than #1.
It seems implausible that option #2 is "really" better, because in that case everyone would be using it.
I tracked this down to some evil effect of TT mate-scores from previous searches. With the standard adjustments #1 for ply, simply clearing the TT between moves removes the anomaly, giving 100+ Elo boost. Of course I don't want to do that; for one thing clearing a huge TT is so slow that matches are impossible at very short time control.
Instead I now test if a mate-score derives from an earlier search (easy because my TT struct has a moveClock field) and if so, ignore it.
Why? mate score from earlier search for from somewhere else in this search is the same thing, namely it should be stored as "mate in N plies from the current position in the tree (not from the root). Then it works everywhere. And it is a significant gain in endgames where you start to have lots of egtb hits, since those are mate scores, and sticking them in the hash table is far more efficient than doing another egtb probe, even if the entry is in the egtb cache somewhere...