Sven Schüle wrote:bob wrote:Sven Schüle wrote:Cheney wrote:OK, thanks.
My bool isPVNode is misleading when compared to bSearchPv. However, both are serving the same purpose in my search and they start a null/zero window search when alpha is raised within a node.
I never understood that a PV-Node is defined by beta-alpha>1, a root node, and all leftmost nodes. However, later in the tree, on some central branch, if alpha is raised, am I correct at saying: (1) I have a new Principal Variation, (2) I am now playing a new set of PV-Nodes? I am interpreting a position/node where alpha is raised then that node becomes a PV-Node and this can happen anywhere in the tree.
I have tried various adjustments to the search following your recommendations, but no luck, the lines are still chopped short at certain depths. Further testing continues to show it is the null move pruning causing this. If I change the R value, the shorter lines are more frequent for both the PVTT and the Triangular Array. If I completely turn it off, no truncated PV Line walked from my PV TT.
I guess part of the problem, too, is I do not understand why one should not perform null move pruning within a PV-Node.
I'll continue to dig, and code, and code some more

, and post back any findings. My hunch is that a nullmove performing a cut is breaking that chain when walking through the PVTT because later in the tree, where alpha was raised, it then becomes a cut node.
Thanks again.
Hi Cheney,
I think you should either rename your flag into "foundPV", or invert its boolean value (i.e., initialize it to true and set it to false after one child raises alpha) and then rename it into something like "useFullWindowSearch".
I also see one difference of your PVS implementation to the "standard": you are using fail-hard but your re-search condition is "score > alpha && score < beta" which is common for a fail-soft implementation only. I can't tell whether it leads to severe problems in case of fail-hard but at least you might give it a try to omit the "&& score < beta" part.
Your observation that null-move pruning has some negative impact on your PVs might indicate a bug either in your null-move code or your PV-collecting code. Normally those parts of the search tree that are part of a subtree of a null-move should never have any impact on the root PV. If your case is different then something might go wrong. A null move will either refute the previous move of the opponent - then both that previous move as well as the null move that refuted him do not become part of the root PV -, or it won't refute that previous move, then the null move still does not make it into the root PV. Any information that you store in order to display a root PV later on should not be related to any null move.
Is it possible that you store information from a null move subtree in your "PVTT" by accident? That should not happen ...
Sven
that >alpha < beta sounds like pure PVS.
Only way that can happen is if the original alpha/beta passed in is not a null-window. After establishing the score for the first move, you search the remainder with alpha, alpha+1 (but alpha+1 is less than the original beta) If you get a score back > alpha and less than beta, in fail hard it would be "alpha+1" and you need to re-search. If you enter search with a null-window, this can never happen.
[I deleted my first attempt of this reply and restarted after finding that it was wrong.]
I think you are right. We can deduct that the "score < beta" is actually not redundant in fail hard (despite my first thoughts about it) but that it is in fact necessary to avoid some useless re-searches:
In fail hard, after establishing the score for the first move and searching with a zero window, "score > alpha" implies "score == alpha+1", just as you say. So there is one case in fail hard where the two conditions
A) if (score > alpha)
and
B) if (score > alpha && score < beta)
are not logically identical, and this is "alpha+1 >= beta", since in that case A is true but B is false so B would not perform the re-search. In fail hard "alpha+1 > beta" would be impossible IMO so "alpha+1 >= beta" would in fact mean "alpha+1 == beta", so the difference between A and B occurs exactly if the node has already been entered with a zero window, or if alpha has been raised to beta-1 in the meantime. In both cases a re-search would also not be required at all since in fail hard it would not return a different result (the "full window" is already the same as the zero window), so "missing the re-research" actually misses nothing.
This means that B correctly avoids some redundant re-searches in fail hard while A does not. When entering a node with a non-zero window, A and B are identical since "alpha+1 < beta" is always true. The code can be written slightly more efficiently by using a separate zwSearch() function for the zero-window search where no re-search is even attempted.
Do you agree?
I never stumbled upon this fine detail in my engines since I always used fail soft for ages.
Sven
I am not sure I understand your question, so let me provide a better explanation of what I was writing.
In classic PVS, you initially do a v = Search(alpha,beta,etc.) at the root, where alpha and beta are not a null interval (beta > alpha+1).
Inside the search, most of the time, Search() is recursively called with a null window, alpha, alpha+1.
When you recurse with those values, you can never do the "if (value > alpha && value < beta) because beta = alpha+1 99+% of the time, and therefore if value > alpha, then it is at least == beta and for fail-soft it could be even higher.
But along the PV, where beta != alpha+1, you search the first move at such a node with the normal alpha/beta window, then you search the remainder of the moves at that ply with alpha, alpha+1. On occasion, here, you CAN get the value > alpha & value < beta, because the window you just failed high on was alpha, alpha+1, and you want to re-search with alpha,beta to see if it still fails high or if you get a real score back.
It definitely looks odd to see code like:
Code: Select all
value = -Search(tree, -alpha-1, -alpha, ...)
if (value > alpha && value < beta)
value = -Search(-beta, -alpha, ...
That if is hardly ever true because as I mentioned, almost all recursive search calls specify a null-window, so if value > alpha, it is also at least == beta and the if will never be true.
I remember when Murray Campbell first showed me this in 1978 and I inserted the idea into my chess program because he had not tested it out as of then. It looked really odd. But after sitting down for a bit with it, suddenly the light came on. This idea was not particularly new, as Belle used this same sort of algorithm in 1978 as well, although only at the root of the tree.
Hope that explains what I was trying to describe. Now, if you have a question, fire away and maybe I can follow given the context above. I don't see where it matters about fail-soft or fail-hard. I have done both at various points in time inside Crafty and I didn't have to change that part of the basic PVS search at all as I remember...