A fast PRNG for generating hash codes

Discussion of chess software programming and technical issues.

Moderators: hgm, Dann Corbit, Harvey Williamson

Forum rules
This textbox is used to restore diagrams posted with the [d] tag before the upgrade.
Post Reply
CThinker
Posts: 388
Joined: Wed Mar 08, 2006 9:08 pm
Contact:

Re: A fast PRNG for generating hash codes

Post by CThinker » Tue Mar 29, 2011 7:50 am

hgm wrote:I have yet to encounter a random generator that is so poor that the Zobrist keys generated with it performs below average. If it produces all zeros, or too few bits, then it is no good, but that is about all.

I must admit I never tried to measure the performance of super-simple PRNG like (seed *= 0x10003)>>16 for a 16-bit random.
I totally agree.

I myself use a simple linear congruential generator. I have tried all sorts of more sophisticated RNGs, but so far, none has yet to make any significant improvement over the LGC as far as zobrist keys are concerned. Mind you, we just need less than 1,000 64-bit numbers. Some engines simply hard-code the zobrist keys.

Plus, the RNGs don't need to be fast. The RNG is only used once (at program start-up) and only has to generate a few numbers.

User avatar
sje
Posts: 4675
Joined: Mon Mar 13, 2006 6:43 pm

Re: A fast PRNG for generating hash codes

Post by sje » Tue Mar 29, 2011 9:30 am

Do PRNGs have to be fast?

It depends on the definition of "fast". When loading an interpreted toolkit, a start-up time of 200 milliseconds is fast, but a delay of 20 seconds is not. And that can be the time difference between the above PRNG and one that uses a lot of tricky calculation.

Also, a PRNG has more uses than just making Zobrist hash codes. 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.

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

Re: A fast PRNG for generating hash codes

Post by smrf » Tue Mar 29, 2011 9:37 am

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: 25842
Joined: Fri Mar 10, 2006 9:06 am
Location: Amsterdam
Full name: H G Muller
Contact:

Re: A fast PRNG for generating hash codes

Post by hgm » Tue Mar 29, 2011 10:32 am

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 6:43 pm

Re: A fast PRNG for generating hash codes

Post by sje » Tue Mar 29, 2011 11:05 am

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 6:43 pm

Re: A fast PRNG for generating hash codes

Post by sje » Tue Mar 29, 2011 11:07 am

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 10:08 am
Location: Klein-Gerau, Germany
Contact:

Re: A fast PRNG for generating hash codes

Post by smrf » Tue Mar 29, 2011 11:25 am

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: 25842
Joined: Fri Mar 10, 2006 9:06 am
Location: Amsterdam
Full name: H G Muller
Contact:

Re: A fast PRNG for generating hash codes

Post by hgm » Tue Mar 29, 2011 11:45 am

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 6:43 pm

Re: A fast PRNG for generating hash codes

Post by sje » Tue Mar 29, 2011 12:14 pm

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: 25842
Joined: Fri Mar 10, 2006 9:06 am
Location: Amsterdam
Full name: H G Muller
Contact:

Re: A fast PRNG for generating hash codes

Post by hgm » Tue Mar 29, 2011 3:01 pm

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.

Post Reply