Actual source code: random123.c

  1: #include <petsc/private/randomimpl.h>
  2: #include <Random123/threefry.h>

  4: /* The structure of the Random123 methods are similar enough that templates could be used to make the other CBRNGs in
  5:  * the package (aes, ars, philox) available, as well as different block sizes.  But threefry4x64 is a good default,
  6:  * and I'd rather get a simple implementation up and working and come back if there's interest. */
  7: typedef struct _n_PetscRandom123
  8: {
  9:   threefry4x64_ctr_t  counter;
 10:   threefry4x64_key_t  key;
 11:   threefry4x64_ctr_t  result;
 12:   PetscInt            count;
 13: }
 14: PetscRandom123;

 16: R123_ULONG_LONG PETSCR123_SEED_0 = R123_64BIT(0x615D333D2655FE14);
 17: R123_ULONG_LONG PETSCR123_SEED_1 = R123_64BIT(0xAFF6369B3EE9FE96);
 18: R123_ULONG_LONG PETSCR123_SEED_2 = R123_64BIT(0x5956EBC717B60E07);
 19: R123_ULONG_LONG PETSCR123_SEED_3 = R123_64BIT(0xEE8612A0CBEABFF1);

 21: PetscErrorCode PetscRandomSeed_Random123(PetscRandom r)
 22: {
 23:   threefry4x64_ukey_t  ukey;
 24:   PetscRandom123      *r123 = (PetscRandom123 *) r->data;

 26:   ukey.v[0] = (R123_ULONG_LONG) r->seed;
 27:   ukey.v[1] = PETSCR123_SEED_1;
 28:   ukey.v[2] = PETSCR123_SEED_2;
 29:   ukey.v[3] = PETSCR123_SEED_3;
 30:   /* The point of seeding should be that every time the sequence is seeded you get the same output.  In this CBRNG,
 31:    * that means we have to initialize the key and reset the counts */
 32:   r123->key = threefry4x64keyinit(ukey);
 33:   r123->counter.v[0] = 0;
 34:   r123->counter.v[1] = 1;
 35:   r123->counter.v[2] = 2;
 36:   r123->counter.v[3] = 3;
 37:   r123->result = threefry4x64(r123->counter,r123->key);
 38:   r123->count = 0;
 39:   return 0;
 40: }

 42: static PetscReal PetscRandom123Step(PetscRandom123 *r123)
 43: {
 44:   PetscReal scale = ((PetscReal) 1.) / (UINT64_MAX + ((PetscReal) 1.));
 45:   PetscReal shift = .5 * scale;
 46:   PetscInt  mod   = (r123->count++) % 4;
 47:   PetscReal ret;

 49:   ret = r123->result.v[mod] * scale + shift;

 51:   if (mod == 3) {
 52:     r123->counter.v[0] += 4;
 53:     r123->counter.v[1] += 4;
 54:     r123->counter.v[2] += 4;
 55:     r123->counter.v[3] += 4;
 56:     r123->result = threefry4x64(r123->counter,r123->key);
 57:   }

 59:   return ret;
 60: }

 62: PetscErrorCode PetscRandomGetValue_Random123(PetscRandom r,PetscScalar *val)
 63: {
 64:   PetscRandom123 *r123 = (PetscRandom123 *) r->data;
 65:   PetscScalar     rscal;

 67: #if defined(PETSC_USE_COMPLEX)
 68:   {
 69:     PetscReal re = PetscRandom123Step(r123);
 70:     PetscReal im = PetscRandom123Step(r123);

 72:     if (r->iset) {
 73:       re = re * PetscRealPart(r->width) + PetscRealPart(r->low);
 74:       im = im * PetscImaginaryPart(r->width) + PetscImaginaryPart(r->low);
 75:     }

 77:     rscal = PetscCMPLX(re,im);
 78:   }
 79: #else
 80:   rscal = PetscRandom123Step(r123);
 81:   if (r->iset) rscal = rscal * r->width + r->low;
 82: #endif
 83:   *val = rscal;
 84:   return 0;
 85: }

 87: PetscErrorCode  PetscRandomGetValueReal_Random123(PetscRandom r,PetscReal *val)
 88: {
 89:   PetscRandom123 *r123 = (PetscRandom123 *) r->data;
 90:   PetscReal       rreal;

 92:   rreal = PetscRandom123Step(r123);
 93:   if (r->iset) rreal = rreal * PetscRealPart(r->width) + PetscRealPart(r->low);
 94:   *val = rreal;
 95:   return 0;
 96: }

 98: PetscErrorCode PetscRandomDestroy_Random123(PetscRandom r)
 99: {
100:   PetscFree(r->data);
101:   return 0;
102: }

104: static struct _PetscRandomOps PetscRandomOps_Values = {
105:   PetscDesignatedInitializer(seed,PetscRandomSeed_Random123),
106:   PetscDesignatedInitializer(getvalue,PetscRandomGetValue_Random123),
107:   PetscDesignatedInitializer(getvaluereal,PetscRandomGetValueReal_Random123),
108:   PetscDesignatedInitializer(getvalues,NULL),
109:   PetscDesignatedInitializer(getvaluesreal,NULL),
110:   PetscDesignatedInitializer(destroy,PetscRandomDestroy_Random123),
111: };

113: /*MC
114:    PETSCRANDOM123 - access to Random123 counter based pseudorandom number generators (currently threefry4x64)

116:    Options Database Keys:
117: . -random_type <rand,rand48,sprng,random123>

119:   Level: beginner

121:    PETSc must have been ./configure with the option --download-random123 to use
122:    this random number generator.

124: .seealso: RandomCreate(), RandomSetType(), PETSCRAND, PETSCRAND48, PETSCSPRNG
125: M*/

127: PETSC_EXTERN PetscErrorCode PetscRandomCreate_Random123(PetscRandom r)
128: {
129:   PetscRandom123 *r123;

131:   PetscNewLog(r,&r123);
132:   r->data = r123;
133:   PetscMemcpy(r->ops,&PetscRandomOps_Values,sizeof(PetscRandomOps_Values));
134:   PetscObjectChangeTypeName((PetscObject)r,PETSCRANDOM123);
135:   PetscRandomSeed(r);
136:   return 0;
137: }