bob wrote:Most important difference is that YBW splits HERE or not at all, while DTS can split ANYWHERE. That gives you a better opportunity to find a safer place to split the tree, not just being forced to split HERE or else deferring the split until later.
I believe splitting HERE or not at all is an implementation aspect that is not mandated by YBW. But I agree it is advantageous to be able to split anywhere. The question remains though how that advantage leads to a more efficient search: decreased idle time? decreased search overhead?
Again, the messages and such are generally "small potatos" in terms of performance benefits. The real advantage is that you get to choose a split point anywhere in any current search that is active. And the split overhead is very low to boot, there, since all the data is accessed as a large global array rather than via pointers. Think about this: At which of these two choices would you rather split: (a) current ply, 6 plies from the tip, you just completed the first move; or (b) a position 4 plies from the root position where you have already searched 4 moves without a fail high? I'm more confident splitting in (b), but it is difficult with a recursive search.
I agree that splitting in (b) is preferable, and that is what my engine does using a recursive search.
But I wouldn't call communication and splitting overhead "small potatoes". If the overhead is high, it is either just costing a lot, or you have to increase the minimum split depth which will increase idle time.
The problem lies in the recursive stack. Things are set up with no split being done, so there is no easy way to back up and split at an earlier ply, unless you are willing to do the complicated code to really unwind back to the ply where you want to split, do the split, then to un-unwind back to where you were and continue. Doable, but horribly messy. If I am going to do a split, I need to link in a split block for each child, plus a split block for the parent, but it is not easy to get to that information to change it, since all I currently have is local data on the stack in the call tree.
There is no need to back up. All you need is the moves leading from the root to the node where you want to split (so those should be global and not (only) on the stack). The idle thread locates a good split point in the tree of one of the active threads, copies the moves from the root to that node, and performs those moves on its own copy of the position. The master thread does not need to be involved in the split operation (it does have to initialise the candidate split point after having searched captures and killers, but that only requires copying alpha, beta, depth).
Of course the master will remain responsible for returning the node's score to the parent node, so the master node is limited to helpful master once it runs out of work.