The silence is deafening
Anyway now I am more or less convinced that adding the keys works as good as ,if not better ,than any other method. To summarize:
Code: Select all
key(piece,square) = key1[piece] + key2[square]
And then xor to get final keys.
Code: Select all
final_key = key(p1,sq1) ^ key(p2,sq2) ^ key(p3,sq3) ^ ... etc
Advantages:
a) addition is much
faster than multiplication
b) requires very small talbles at least for this game. 209 + 36 x 36 = 1505 keys are required which a reduction of about
465X times!
c) keeps the
uniform distribution while others like multiplication skew it somehow.
So even if addition turns out to be poor for some reason, the advantages are too much tempting not to use it.
I found a good page that discusses about different string hashing techniques, among which additive hashing is mentioned..yeah!
Eternally confused.
Additive hashing:
--------------------
The authors mentioned it is a very poor hashing because permutations are hashed to the same key. But this is not relevant for us, because that is what we want unlike in strings where order matters. Other than that it should work fine. I was afraid of overflow effect but I think that is not much of an issue.
XOR hashing:
----------------
They said this is poor for string hashing because it doesn't have the "avalanche" property. Well zobrist uses xor so I guess this is a non issue. The only problem here is that XOR to get both the piece_on_square key and make the final key introduces clear collisions that are easily demonstrated.
Rotate hashing
-----------------
I am not sure how to use this to hash piece and square, but it is very similar to XORing so it faces the same problems. A rotate by 4 bits would be ((p << 4) ^ (p >> 28) ^ sq) so if zobrist hashing is still used (xoring) then it would face the same problems.
Bernestein hash
------------------
No theory behind this method and I am not sure it will work for us, since a magic multiplier other than 33 will probably be required. Anyway multiply and add (MAD) is another option. Still expensive though. But it should work with zobrist xoring.
Shift and xoring
-------------------
Similar to rotate hashing but this one works with zobrist as it has an add.
The rest seem to be either too expensive or something else... Anyway you can review them yourself.
Finally there is a suggestion on how to design hash functions that I quote here verbatim
Designing a hash function is more trial and error with a touch of theory than any well defined procedure. For example, beyond making the connection between random numbers and the desirable random distribution of hash values, the better part of the design for my JSW hash involved playing around with constants to see what would work best.
I would also be lying if I said that the choice of operations was not almost completely random trial and error by pulling from a pool of combinations of XOR, OR, AND, addition, subtraction, and multiplication. The biggest design element of JSW hash is using the table of random numbers keyed on each byte of the input to act as a mixing step. Then it was simply a matter of choosing a less complicated hash algorithm to paste that addition onto, and finally the fiddling and testing to get the algorithm performing well.
I will not claim that hash function design is always like that, but the evidence certainly suggests it. If you design hash functions in a deterministic way, I would love to hear from you.
So the distribution of hash keys is important as I tried to maintain a uniform distribution. That is important to reduce clustering. Also I think they mentioned that multiplication changes the distribution as I observed.
They have also a test code for hash collision test so I will try them out if I have time and the interest to pursue it, but to me adding the keys is the best so far
Daniel