hgm wrote:bob wrote:No it wasn't what we were discussing. We were discussing changing from a simple repetition list to a hash-table implementation of the repetition list. That is absolutely not a 30 second change. It is almost certainly not even a one hour change as it is not done the same way at all.
But the above change does make it a hash table. You don't understand C-code?
Not quite. How did you get the data _into_ the hash table? How do you remove it later? How do you update/decrement the counter you find there? And what is your loop limit to handle collisions? So that one line change just _broke_ any sane program, because that is not all that is required... And again it doesn't consider the SMP issues..
I don't really understand your remarks about 'doing it twice'. If you implement your repetion list as a stack, you will have to pop the element too, on UnMake. Clearing the entry or decrementing the repeat stack pointer is the same work (involving one memory load and one memory store).
Why would I need to do that? I index the list by "ply". When I back up to the previous ply, I always do ply=ply-1. The next time I step down a ply, it is incremented. Which causes me to overwrite the entry in the list. I never have to remove it at all, as I never check any element beyond "ply"...
During the repeat test your loop tests for a key-match and you have to test for loop end. I can test for a key match or a key zero. That is also exactly the same amount of work.
Except you can't just check one entry or you will miss many repetitions, you have to run down a chain of unknown length. And you have to add the entry and remove it where I don't need to remove mine at all. So you get a double hit on adding and removing, where I just add. And I don't have to worry about the case where that entry is already occupied and chain off of it, I just store it where it goes.
BTW, here is some interesting data. Since I was curious about the very small time spent in RepetitionCheck()) I added two counters to Crafty, one is incremented every time RepetitionCheck() is called, one is incremented every time a repetition check loop is executed. I had crafty play two games against itself without a book, here are the final numbers from those two games:
Game 1 went 72 moves, played at 5 minutes for 60 moves, then 5 minutes per 60 moves, etc...
87899526 RepetitionCheck() calls, 98850190 total loops, average = 1
Game 2 went 85 moves, same time control
126436017 RepetitionCheck() calls, 160747325 total loops, average = 1
The above is integer math. On average, over two much longer than usual games, it averages to about 1.25 loop iterations per RepetitionCheck() call. I am sure it is higher in the latter part of those games, but that is irrelevant to the issue of optimization, as I care about overall performance. Since hashing can't go below 1 iteration period, it looks to me that any savings is going to be tiny, as my 1.25 iterations are _very_ simple iterations, with no need to remove an entry ever, I just have to add them to the end as I advance thru the tree.
As I said, when I tried this, I saw no speed advantage and the added complexity of having a shared repetition table, or the added cost of copying the entire thing on each split made me go back to the repetition list approach.
I am playing a longer game to see if things change, but at move 62, the average is still right at 1, I will report the results later when the two games finish, but they will take a while as each game will take an hour if they get to 30 moves, or two hours if they get to 60... For the first 35 moves, the average was zero (about .75 if not using integer divide). By move 65 it is up to 1.1. No idea where it will end up but it is going to take a _lot_ to get it to average over 2.0