Moderator: Andres Valverde
H.G.Muller wrote:Before I can answer that one, I have to make sure how you define R. In the description of nul-move pruning I saw I was a bit confused by its exact meaning: dou you count the null-move as 1 ply or doesn't it count in the depth at all? If R=1 means that, in a node where you would normally search 6 ply, you would search the null-move branch only 5 ply deep, i.e. the initial null-move followed by 5 ply, than I would say that it hurts in positions where the 6th ply (where the opponent moves!) holds an unpleasant surprise. If it means you search 6-1=5 plies after the null move, then I would agree: there is no pain, but I also see little gain. Any other move you would have selected to try first would have been searched equally deep, and if you would not have picked a really stupid one, it would have caused the cut-off as well.
Uri Blass wrote:H.G.Muller wrote:Before I can answer that one, I have to make sure how you define R. In the description of nul-move pruning I saw I was a bit confused by its exact meaning: dou you count the null-move as 1 ply or doesn't it count in the depth at all? If R=1 means that, in a node where you would normally search 6 ply, you would search the null-move branch only 5 ply deep, i.e. the initial null-move followed by 5 ply, than I would say that it hurts in positions where the 6th ply (where the opponent moves!) holds an unpleasant surprise. If it means you search 6-1=5 plies after the null move, then I would agree: there is no pain, but I also see little gain. Any other move you would have selected to try first would have been searched equally deep, and if you would not have picked a really stupid one, it would have caused the cut-off as well.
R=1 means the first case and I believe that R=3 is more common.
if remaining depth before null moves is n plies then remaining depth after the null move is n-R-1 plies.
Uri
mridul wrote:Uri Blass wrote:H.G.Muller wrote:Before I can answer that one, I have to make sure how you define R. In the description of nul-move pruning I saw I was a bit confused by its exact meaning: dou you count the null-move as 1 ply or doesn't it count in the depth at all? If R=1 means that, in a node where you would normally search 6 ply, you would search the null-move branch only 5 ply deep, i.e. the initial null-move followed by 5 ply, than I would say that it hurts in positions where the 6th ply (where the opponent moves!) holds an unpleasant surprise. If it means you search 6-1=5 plies after the null move, then I would agree: there is no pain, but I also see little gain. Any other move you would have selected to try first would have been searched equally deep, and if you would not have picked a really stupid one, it would have caused the cut-off as well.
R=1 means the first case and I believe that R=3 is more common.
if remaining depth before null moves is n plies then remaining depth after the null move is n-R-1 plies.
Uri
R=1 would still mean that you are reducing by a ply.
R=3 is more common ? I thought it was R=2 (or some adaptive version of 2,3).
My impression was that R=3 was tried by only those who were -
1) more adventurous,
2) had checks in qsearch
3) did not have much of other pruning.
I could be wrong on all three
Just 'cos of 1 , I use R=3
More seriously , R=3 prunes a hell lot - so you should have sufficient safegaurds to ensure that it is not making you tactically blind.
Mridul
Uri Blass wrote:Note that in the endgame I use verified null move pruning with R=3 and in pawn endgame I do not use null move pruning.
Alessandro Scotti wrote:Uri Blass wrote:Note that in the endgame I use verified null move pruning with R=3 and in pawn endgame I do not use null move pruning.
Hi Uri,
do you use verified null move like in the Tabibi paper or null move followed by a verification search?
H.G.Muller wrote:Before I can answer that one, I have to make sure how you define R. In the description of nul-move pruning I saw I was a bit confused by its exact meaning: dou you count the null-move as 1 ply or doesn't it count in the depth at all? If R=1 means that, in a node where you would normally search 6 ply, you would search the null-move branch only 5 ply deep, i.e. the initial null-move followed by 4 ply*), than I would say that it hurts in positions where the 6th ply (where the opponent moves!) holds an unpleasant surprise. If it means you search 6-1=5 plies after the null move, then I would agree: there is no pain, but I also see little gain. Any other move you would have selected to try first would have been searched equally deep, and if you would not have picked a really stupid one, it would have caused the cut-off as well.
*) unfortunately I made a typo here initially, I meant to say 4 but wrote 5. This would make the two cases I distinguish the same! It seems the following posters were not confused by this, however.
L?szl? G?sp?r wrote:H.G.Muller wrote:Before I can answer that one, I have to make sure how you define R. In the description of nul-move pruning I saw I was a bit confused by its exact meaning: dou you count the null-move as 1 ply or doesn't it count in the depth at all? If R=1 means that, in a node where you would normally search 6 ply, you would search the null-move branch only 5 ply deep, i.e. the initial null-move followed by 4 ply*), than I would say that it hurts in positions where the 6th ply (where the opponent moves!) holds an unpleasant surprise. If it means you search 6-1=5 plies after the null move, then I would agree: there is no pain, but I also see little gain. Any other move you would have selected to try first would have been searched equally deep, and if you would not have picked a really stupid one, it would have caused the cut-off as well.
*) unfortunately I made a typo here initially, I meant to say 4 but wrote 5. This would make the two cases I distinguish the same! It seems the following posters were not confused by this, however.
Hi H.G.,
In my interpretation R=1 is your second variation. I think you are right if you use any move instead of nullmove when R=1. In recursive R=1 nullmove I thought I get the usual (R>=2) nullmove advantages without sacrificing the correctness, since the depth reductions accumulate. Now it seems to me that it gives just the plane alpha-beta and I can only save a few move generation. This is not where I would like to get to...
Regards,
L?szl?
Uri Blass wrote:Note that in that case searching null first is a very bad idea because doing nothing is a bad candidate to be the best move.
H.G.Muller wrote:Uri Blass wrote:Note that in that case searching null first is a very bad idea because doing nothing is a bad candidate to be the best move.
Well, if you do it only when eval>beta, this objection might not be valid. Because in that case there might be a good chance that doing nothing, although it will almost certainly not be the best, will still be good enough to cause the cutoff we are aiming for.
In the other thread about tree size we both had examples where tree size benifitted from searching a non-best move first, as long as it is good enough to fail high, and is expected to have a small tree. Picking the null move as a first try when there is no need to improve on the current eval, as opposed to a real move, gives you a guarantee that you will not make your position worse. A real move might leave other pieces undefended, go to an unsave square, allow passage of enemy pieces over the square it evacuated, etc. So even if eval>beta you should exercise some care in picking the move that you want to produce the fail high with. This might require testing of quite a lot of conditions, which you don't need by simply picking the null move.
It would be nice if you could just pick the best move from an earlier iteration as one that most likely will not lower the current eval, but remember that this is a situation where the first move you try should cause the cut-off. So any choice that you make is likely to be 'frozen-in' for the rest of the deepening process (if it was not a bad one), and you must effectively make the choice at the earliest possible time, without the benifit of earlier iterations. If in that case you will pick the null move, and it causes the fail, none of the real moves will be tried, and you would have to make this choice between null-move and a real move that might worsen your position at later iterations as well.
In addition, if the null-move does not fail high, it might give you a clue as to how to sort the rest of your moves. Because apparently you are dealing with a threat in that case, like the capture of a piece that came under attack in the previous ply, so withdrawing that piece to a safe square suddenly becomes a very attractive idea, where that move would have lacked any appeal in the absence of the threat. Of course you could also try to extract such information from unexpectedly poor performance of a real move, but this is much more difficult: if a real move turns out bad you might have provoked the punishment by the move itself (e.g. moving a pinned piece), not necessarily that there was a threat that would refute any other move except a few specific defensive ones.
H.G.Muller wrote:Sure, if you know that a piece is under threat it makes no sense to do a null-move, unless you are prepared to abandon that piece (i.e. if eval is so much larger than beta that even the loss of that piece would not prevent the fail high). I am assuming that the eval is such that it is not smart enough to anticipate such losses in a static manner.
The problem is: can you make a static analysis that recognizes such threats faster than the search. When I experimented with this, I had very poor results. My static judgement of the situation would completely fail in a large fraction of the cases, because some of the pieces it counted as defenders were in fact pinned, could be exchanged, or were burdoned with defending other pieces (so that their use in recapture for this piece would lead to the loss of another).
if(ok_to_do_nullmove(board)) {
if(static_eval(board) - biggest_threat(board, them) >= beta)
do_nullmove(board);
value = -search(board, -beta, -(beta-1), depth-(R+1));
undo_nullmove(board);
if(value >= beta) return value;
}
}
if(ok_to_do_nullmove(board)) {
static_value = static_eval(board);
if(depth <= 2 && static_value - biggest_threat(board, them) >= beta + margin)
return beta;
else if(static_value >= beta) {
do_nullmove(board);
value = -search(board, -beta, -(beta-1), depth-(R+1));
undo_nullmove(board);
if(value >= beta) return value;
}
}
So I kind of gave up on that idea, and now I am trying to decide such matters (if a piece is sufficiently defended or under threat) by search only. The search can still be guided by static clues, of course.
if(ok_to_do_nullmove(board)) {
int value = -Infinity;
bool do_nullmove_search = true;
do_nullmove(board);
if(depth >= 7) {
value = -qsearch(board, -beta, -(beta-1));
if(value < beta) do_nullmove_search = false;
}
if(do_nullmove_search)
value = -search(board, -beta, -(beta-1), depth-(R+1));
undo_nullmove(board);
if(value >= beta) return beta;
}
H.G.Muller wrote:
A question:
If you have a reliable way to identify threats statically, that is compatitive to a null-move search, why do you do such a search to make the pruning decision in null-move pruning (or the reduction decision in verified null-move pruning)? If you can identify which piece is under threat staticaly, this must also tell you if there is no threat at all. And when that is the case, you can act as if the null-move search would have returned a score above eval, i.e. prune. Especially in verified null-move pruning the risk seems small, becase if you miss a threat now and then, there is a good chance that the verification search will still recognize it.
Return to Programming and Technical Discussions
Users browsing this forum: No registered users and 19 guests