mcostalba wrote:bob wrote:
If you capture a piece, you do not change mobility, since the same square is occupied before/after the capture. All that changes is the source square. It is not likely this square changes the mobility for all pieces, or even most pieces.
Due to "stand pat" the cached mobility bitboard is two moves away from the current move, not one.
For instance you are in position P and do move m1 then call evaluate and here cache mobility. Then evaluate value allow you to cut-off, so that return immediately with a fail high score that is a fail low from the parent node P.
From P the search will try another move m2 and here you call evaluate again but then the cached mobility values refer to position P+m1 and now you are at P+m2.
So if m1 and m2 refer to move of different pieces you end up with two changed mobilities out of 6 pieces i.e. 30% and this could explain why my hit rate is about 65%.
BTW I have great doubts that you are able to reach 99% hit rate. Could you please measure it directly ?
First, your "two moves away" is simply wrong. When I enter q-search, I do a stand pat score, then try a capture, do a stand-pat, try a capture, etc. Always one intervening move except when I back up a couple of plies and start going forward again.
I don't remember the 99% hit rate quote since I have never measured it, what I do remember is that once we added this, in place of our old mobility that just summed squares and used the sum to index into a small table to compute mobility scores (like most including stockfish/glaurung do), the cost was absolutely immeasurable. Our NPS did not change one bit. Before we did the cache trick, it was more expensive as we turned one popcnt() into 4.
That's been my claim all along. It is better than just a "sum of reachable squares" approach, and can be extended to have as many different "square classes" as you want, all the way up to the Cray Blitz approach of 64 different values for the squares.
when I have time, I will add the code to count mobility cache hits vs misses, aggregated over all pieces, to get a number. If I were really analyzing, I would expect 75%. Why? Because this had no cost. And we now do 4x the work to compute mobility, yet the cost did not increase at all. If 75% of the attempts hit cache, that would be the result.
Note that when I am talking 75% hits, I mean that 3 of every 4 times I call (say) EvaluateRooks(), the mobility is unchanged from the last time it was computed because the rank/file occupancy for that rook is unchanged. That actually sounds low, but I will try to measure to see.