A fast PRNG for generating hash codes

Discussion of chess software programming and technical issues.

Moderators: hgm, Rebel, chrisw

User avatar
smrf
Posts: 484
Joined: Mon Mar 13, 2006 11:08 am
Location: Klein-Gerau, Germany

Re: A fast PRNG for generating hash codes

Post by smrf »

Well, may I show my simple generator here?

I use only special balanced generated random values (BalancedKey).

Code: Select all

// (C) 2011 R.Scharnagl, 80992 München, Deutschland

#include <ctime>
#include <climits>

#pragma hdrstop

#include "Tool.h"

// - - - - - - - - - - - - - - - - - - - - - - - - - - -

// --- SPEICHER ---

// - - - - - - - - - - - - - - - - - - - - - - - - - - -

// zuletzt erzeugten Zufallszahl, lokal
U32 Tool&#58;&#58;seed = 0;
// - - - - - - - - - - - - - - - - - - - - - - - - - - -

// --- METHODEN &#40;RANDOM&#41; ---

// - - - - - - - - - - - - - - - - - - - - - - - - - - -

// setzt positive Startzahl für Generator
U32 Tool&#58;&#58;SetSeed&#40;U32 newSeed&#41;
&#123;
  // den Seed neu festlegen
  seed = newSeed;

  // technisch geswapped ausgeben
  return &#40;newSeed << 16&#41; ^ &#40;newSeed >> 16&#41;;
&#125;
// - - - - - - - - - - - - - - - - - - - - - - - - - - -

// setzt &#40;Zeit-) zufällige Generator-Startzahl
U32 Tool&#58;&#58;Randomize&#40;void&#41;
&#123;
  using namespace std;

  // Zeitpuffer
  time_t thisMoment;

  // ermittle eine Startzahl aus der Systemzeit
  time&#40;&thisMoment&#41;;

  return SetSeed&#40;MAGIC * &#40;U32&#41;thisMoment&#41;;
&#125;
// - - - - - - - - - - - - - - - - - - - - - - - - - - -

// holt <unsigned> Zufallszahl
U32 Tool&#58;&#58;Random&#40;void&#41;
&#123;
  // neue interne Zufallszahl merken
  return SetSeed&#40;seed * 87641 + 98731&#41;;
&#125;
// - - - - - - - - - - - - - - - - - - - - - - - - - - -

// holt <unsigned> Zufallszahl aus &#91;0, Limit&#41;
U32 Tool&#58;&#58;RangedRandom&#40;U32 limit&#41;
&#123;
  // Ergebnis und anzupassende Obergrenze
  U32 answer, limValid;

  // bestimme ersten ungültigen Treffer,
  // um Ungleichverteilung zu unterbinden
  limValid = UINT_MAX - UINT_MAX % limit;

  // iterative gleichverteilte Erzeugung
  for (;;) &#123;
    // solange neue Kandidaten testen
    answer = Random&#40;);
    // bis Gleichverteilung sichergestellt
    if &#40;answer < limValid&#41;
      return answer % limit;
  &#125;
&#125;
// - - - - - - - - - - - - - - - - - - - - - - - - - - -

// liefert positive Zufallszahl, die als Binärzahl
// genau 50% Einsen hat &#40;für XOR Overlay&#41;
U32 Tool&#58;&#58;BalancedKey&#40;void&#41;
&#123;
  int bitDifference;
  U32 answer;

  // selektiere ideale Hash-Kandidaten
  do &#123;
    // Prüfinstrumente
    U32 oneBit = &#40;U32&#41;INT_MIN;
    bitDifference = 0;

    // bilde Zufallszahlen
    answer = Random&#40;);

    // bis Gleichverteilung vorliegt
    do &#123;
      if &#40;answer & oneBit&#41; &#123;
        ++bitDifference;
      &#125; else &#123;
        --bitDifference;
      &#125;
    &#125; while (&#40;oneBit >>= 1&#41; != 0L&#41;;

  &#125; while &#40;bitDifference != 0&#41;;

  return answer;
&#125;
// - - - - - - - - - - - - - - - - - - - - - - - - - - -
User avatar
hgm
Posts: 27790
Joined: Fri Mar 10, 2006 10:06 am
Location: Amsterdam
Full name: H G Muller

Re: A fast PRNG for generating hash codes

Post by hgm »

sje wrote:Consider the case where some randomness is desired in positional evaluation scores, perhaps changing the bottom two bits of a score. This means that the PRNG would be called many, many times in a search, so it needs to be fast.
To create a pseudo-random term in the evaluation, I derive it from the hash key itself. That can be done much cheaper than runing the presented PRNG, e.g. (hashKey ^ GAME_ID) * MAGIC >> 24 for an 8-bit random. Another advantage is that such a random term is actually consistent: if, in the same game, you reach the same position through two different paths, it will have the same evaluation.
User avatar
sje
Posts: 4675
Joined: Mon Mar 13, 2006 7:43 pm

Re: A fast PRNG for generating hash codes

Post by sje »

smrf wrote:Well, may I show my simple generator here?
It looks like your function retains 32 bits of state information, therefore its period has to be less than or equal to 2^32.

Have you checked to see what the actual period is? Could the period be different for different seed values?
User avatar
sje
Posts: 4675
Joined: Mon Mar 13, 2006 7:43 pm

Re: A fast PRNG for generating hash codes

Post by sje »

hgm wrote:To create a pseudo-random term in the evaluation, I derive it from the hash key itself. That can be done much cheaper than runing the presented PRNG, e.g. (hashKey ^ GAME_ID) * MAGIC >> 24 for an 8-bit random. Another advantage is that such a random term is actually consistent: if, in the same game, you reach the same position through two different paths, it will have the same evaluation.
Yes, but what if you don't want it to be consistent? It seems to me that this latter choice could be more useful for some applications.
User avatar
smrf
Posts: 484
Joined: Mon Mar 13, 2006 11:08 am
Location: Klein-Gerau, Germany

Re: A fast PRNG for generating hash codes

Post by smrf »

sje wrote:It looks like your function retains 32 bits of state information, therefore its period has to be less than or equal to 2^32.

Have you checked to see what the actual period is? Could the period be different for different seed values?
The generator fully covers 32 Bit. Thus the seed value does not matter for the period. So it could be set to any value.

Following test routine has been used repeatedly:

Code: Select all

  // einen Startwert auslosen
  U32 val1 = Randomize&#40;);
  out << "Random Start Value&#58;"
      << Hex&#40;val1, 8&#41; << endl << endl;

  // Wiederholungszahl bestimmen
  long long cnt = 0;
  do &#123;
    ++cnt;
  &#125; while &#40;Random&#40;) != val1&#41;;
  out << "Full Cycle Count&#58; "
      << (&#40;U32&#41;cnt == 0&#41; << endl << endl;
User avatar
hgm
Posts: 27790
Joined: Fri Mar 10, 2006 10:06 am
Location: Amsterdam
Full name: H G Muller

Re: A fast PRNG for generating hash codes

Post by hgm »

sje wrote:Yes, but what if you don't want it to be consistent? It seems to me that this latter choice could be more useful for some applications.
I could not imagine any. The only reason I would want to have a random evaluation term is to act as a poor-man's mobility eval. And there it would be a severe mistake to count yourself rich because there happen to be many paths to the only node that offers an escape from total disaster, because that node gets an independent random eval every time, making it seem as though there were many escapes.

But if I would need an independent random, I would use something like Reinhard. The periodicity of 2^32 would not worry me very much, as by the time it would start to repeat the generated values would be used to take completely different decisions (in other nodes of the tree, for trees that search other positons). In practice, only the state of the entire system (chess game state + random seed + opponent) matters.
User avatar
sje
Posts: 4675
Joined: Mon Mar 13, 2006 7:43 pm

Re: A fast PRNG for generating hash codes

Post by sje »

hgm wrote:
sje wrote:Yes, but what if you don't want it to be consistent? It seems to me that this latter choice could be more useful for some applications.
I could not imagine any.
I can. Adjusting the bottom bit of a positional score independent of the position's hash could add variety to play. In fact, I'm fairly sure that this was done in some commercial dedicated units long ago; at least one unit with a Zilog z80 used the CPU's refresh register as the random source.
User avatar
hgm
Posts: 27790
Joined: Fri Mar 10, 2006 10:06 am
Location: Amsterdam
Full name: H G Muller

Re: A fast PRNG for generating hash codes

Post by hgm »

It will also add variety of play when it is done consistently. In fact this is how Joker gets its non-determinism.

Dedicated units long ago had no hash tables, so the consistecy was not that much of an issue. But with hash table I would not recommend it when there is no need for it. It just decreases search efficiency. The hash moves wik direct you to a node that had a high score the previous time, only to discover that this time that samenode is no good, because its random get recalculated.
User avatar
marcelk
Posts: 348
Joined: Sat Feb 27, 2010 12:21 am

Re: A fast PRNG for generating hash codes

Post by marcelk »

sje wrote:Adjusting the bottom bit of a positional score independent of the position's hash could add variety to play. In fact, I'm fairly sure that this was done in some commercial dedicated units long ago; at least one unit with a Zilog z80 used the CPU's refresh register as the random source.
That still doesn't require a fast RNG. You can XOR the hash with a RN created at the beginning of the game. That is how MSCP randomizes its play.
User avatar
hgm
Posts: 27790
Joined: Fri Mar 10, 2006 10:06 am
Location: Amsterdam
Full name: H G Muller

Re: A fast PRNG for generating hash codes

Post by hgm »

That is exactly what GAME_ID in my expression stands for a random number created at the start of the game (from the millisec clock). The multiplication with MAGIC is to make sure that all bits of GAME_ID affect the random, and not just (say) the lowest 8 (so that it could only play 256 different games against a deterministic opponent).