xref: /petsc/src/sys/classes/random/impls/random123/random123.c (revision 267267bdcbfbae225216e8078da17f7ca9d5f149)
1d6cc7855SJacob Faibussowitsch #include <petsc/private/randomimpl.h>
225ccb61fSToby Isaac #include <Random123/threefry.h>
325ccb61fSToby Isaac 
425ccb61fSToby Isaac /* The structure of the Random123 methods are similar enough that templates could be used to make the other CBRNGs in
525ccb61fSToby Isaac  * the package (aes, ars, philox) available, as well as different block sizes.  But threefry4x64 is a good default,
625ccb61fSToby Isaac  * and I'd rather get a simple implementation up and working and come back if there's interest. */
725ccb61fSToby Isaac typedef struct _n_PetscRandom123
825ccb61fSToby Isaac {
925ccb61fSToby Isaac   threefry4x64_ctr_t  counter;
1025ccb61fSToby Isaac   threefry4x64_key_t  key;
1125ccb61fSToby Isaac   threefry4x64_ctr_t  result;
1225ccb61fSToby Isaac   PetscInt            count;
1325ccb61fSToby Isaac }
1425ccb61fSToby Isaac PetscRandom123;
1525ccb61fSToby Isaac 
1625ccb61fSToby Isaac R123_ULONG_LONG PETSCR123_SEED_0 = R123_64BIT(0x615D333D2655FE14);
1725ccb61fSToby Isaac R123_ULONG_LONG PETSCR123_SEED_1 = R123_64BIT(0xAFF6369B3EE9FE96);
1825ccb61fSToby Isaac R123_ULONG_LONG PETSCR123_SEED_2 = R123_64BIT(0x5956EBC717B60E07);
1925ccb61fSToby Isaac R123_ULONG_LONG PETSCR123_SEED_3 = R123_64BIT(0xEE8612A0CBEABFF1);
2025ccb61fSToby Isaac 
2125ccb61fSToby Isaac PetscErrorCode PetscRandomSeed_Random123(PetscRandom r)
2225ccb61fSToby Isaac {
2325ccb61fSToby Isaac   threefry4x64_ukey_t  ukey;
2425ccb61fSToby Isaac   PetscRandom123      *r123 = (PetscRandom123 *) r->data;
2525ccb61fSToby Isaac 
2625ccb61fSToby Isaac   PetscFunctionBegin;
2725ccb61fSToby Isaac   ukey.v[0] = (R123_ULONG_LONG) r->seed;
2825ccb61fSToby Isaac   ukey.v[1] = PETSCR123_SEED_1;
2925ccb61fSToby Isaac   ukey.v[2] = PETSCR123_SEED_2;
3025ccb61fSToby Isaac   ukey.v[3] = PETSCR123_SEED_3;
3125ccb61fSToby Isaac   /* The point of seeding should be that every time the sequence is seeded you get the same output.  In this CBRNG,
3225ccb61fSToby Isaac    * that means we have to initialize the key and reset the counts */
3325ccb61fSToby Isaac   r123->key = threefry4x64keyinit(ukey);
3425ccb61fSToby Isaac   r123->counter.v[0] = 0;
3525ccb61fSToby Isaac   r123->counter.v[1] = 1;
3625ccb61fSToby Isaac   r123->counter.v[2] = 2;
3725ccb61fSToby Isaac   r123->counter.v[3] = 3;
3825ccb61fSToby Isaac   r123->result = threefry4x64(r123->counter,r123->key);
3925ccb61fSToby Isaac   r123->count = 0;
4025ccb61fSToby Isaac   PetscFunctionReturn(0);
4125ccb61fSToby Isaac }
4225ccb61fSToby Isaac 
4325ccb61fSToby Isaac static PetscReal PetscRandom123Step(PetscRandom123 *r123)
4425ccb61fSToby Isaac {
4525ccb61fSToby Isaac   PetscReal scale = ((PetscReal) 1.) / (UINT64_MAX + ((PetscReal) 1.));
4625ccb61fSToby Isaac   PetscReal shift = .5 * scale;
4725ccb61fSToby Isaac   PetscInt  mod   = (r123->count++) % 4;
4825ccb61fSToby Isaac   PetscReal ret;
4925ccb61fSToby Isaac 
5025ccb61fSToby Isaac   ret = r123->result.v[mod] * scale + shift;
5125ccb61fSToby Isaac 
5225ccb61fSToby Isaac   if (mod == 3) {
5325ccb61fSToby Isaac     r123->counter.v[0] += 4;
5425ccb61fSToby Isaac     r123->counter.v[1] += 4;
5525ccb61fSToby Isaac     r123->counter.v[2] += 4;
5625ccb61fSToby Isaac     r123->counter.v[3] += 4;
5725ccb61fSToby Isaac     r123->result = threefry4x64(r123->counter,r123->key);
5825ccb61fSToby Isaac   }
5925ccb61fSToby Isaac 
6025ccb61fSToby Isaac   return ret;
6125ccb61fSToby Isaac }
6225ccb61fSToby Isaac 
6325ccb61fSToby Isaac PetscErrorCode PetscRandomGetValue_Random123(PetscRandom r,PetscScalar *val)
6425ccb61fSToby Isaac {
6525ccb61fSToby Isaac   PetscRandom123 *r123 = (PetscRandom123 *) r->data;
6625ccb61fSToby Isaac   PetscScalar     rscal;
6725ccb61fSToby Isaac 
6825ccb61fSToby Isaac   PetscFunctionBegin;
6925ccb61fSToby Isaac #if defined(PETSC_USE_COMPLEX)
7025ccb61fSToby Isaac   {
7125ccb61fSToby Isaac     PetscReal re = PetscRandom123Step(r123);
7225ccb61fSToby Isaac     PetscReal im = PetscRandom123Step(r123);
7325ccb61fSToby Isaac 
7425ccb61fSToby Isaac     if (r->iset) {
7525ccb61fSToby Isaac       re = re * PetscRealPart(r->width) + PetscRealPart(r->low);
7625ccb61fSToby Isaac       im = im * PetscImaginaryPart(r->width) + PetscImaginaryPart(r->low);
7725ccb61fSToby Isaac     }
7825ccb61fSToby Isaac 
7925ccb61fSToby Isaac     rscal = PetscCMPLX(re,im);
8025ccb61fSToby Isaac   }
8125ccb61fSToby Isaac #else
8225ccb61fSToby Isaac   rscal = PetscRandom123Step(r123);
8325ccb61fSToby Isaac   if (r->iset) rscal = rscal * r->width + r->low;
8425ccb61fSToby Isaac #endif
8525ccb61fSToby Isaac   *val = rscal;
8625ccb61fSToby Isaac   PetscFunctionReturn(0);
8725ccb61fSToby Isaac }
8825ccb61fSToby Isaac 
894d1a973fSToby Isaac PetscErrorCode  PetscRandomGetValueReal_Random123(PetscRandom r,PetscReal *val)
9025ccb61fSToby Isaac {
9125ccb61fSToby Isaac   PetscRandom123 *r123 = (PetscRandom123 *) r->data;
924d1a973fSToby Isaac   PetscReal       rreal;
9325ccb61fSToby Isaac 
9425ccb61fSToby Isaac   PetscFunctionBegin;
9525ccb61fSToby Isaac   rreal = PetscRandom123Step(r123);
9625ccb61fSToby Isaac   if (r->iset) rreal = rreal * PetscRealPart(r->width) + PetscRealPart(r->low);
9725ccb61fSToby Isaac   *val = rreal;
9825ccb61fSToby Isaac   PetscFunctionReturn(0);
9925ccb61fSToby Isaac }
10025ccb61fSToby Isaac 
10125ccb61fSToby Isaac PetscErrorCode PetscRandomDestroy_Random123(PetscRandom r)
10225ccb61fSToby Isaac {
10325ccb61fSToby Isaac   PetscErrorCode ierr;
10425ccb61fSToby Isaac 
10525ccb61fSToby Isaac   PetscFunctionBegin;
10625ccb61fSToby Isaac   ierr = PetscFree(r->data);CHKERRQ(ierr);
10725ccb61fSToby Isaac   PetscFunctionReturn(0);
10825ccb61fSToby Isaac }
10925ccb61fSToby Isaac 
11025ccb61fSToby Isaac static struct _PetscRandomOps PetscRandomOps_Values = {
111*267267bdSJacob Faibussowitsch   PetscDesignatedInitializer(seed,PetscRandomSeed_Random123),
112*267267bdSJacob Faibussowitsch   PetscDesignatedInitializer(getvalue,PetscRandomGetValue_Random123),
113*267267bdSJacob Faibussowitsch   PetscDesignatedInitializer(getvaluereal,PetscRandomGetValueReal_Random123),
114*267267bdSJacob Faibussowitsch   PetscDesignatedInitializer(getvalues,NULL),
115*267267bdSJacob Faibussowitsch   PetscDesignatedInitializer(getvaluesreal,NULL),
116*267267bdSJacob Faibussowitsch   PetscDesignatedInitializer(destroy,PetscRandomDestroy_Random123),
11725ccb61fSToby Isaac };
11825ccb61fSToby Isaac 
11925ccb61fSToby Isaac /*MC
12025ccb61fSToby Isaac    PETSCRANDOM123- access to Random123 counter based pseudorandom number generators (currently threefry4x64)
12125ccb61fSToby Isaac 
12225ccb61fSToby Isaac    Options Database Keys:
12325ccb61fSToby Isaac . -random_type <rand,rand48,sprng,random123>
12425ccb61fSToby Isaac 
12525ccb61fSToby Isaac   Level: beginner
12625ccb61fSToby Isaac 
12725ccb61fSToby Isaac    PETSc must have been ./configure with the option --download-random123 to use
12825ccb61fSToby Isaac    this random number generator.
12925ccb61fSToby Isaac 
13025ccb61fSToby Isaac .seealso: RandomCreate(), RandomSetType(), PETSCRAND, PETSCRAND48, PETSCSPRNG
13125ccb61fSToby Isaac M*/
13225ccb61fSToby Isaac 
13325ccb61fSToby Isaac PETSC_EXTERN PetscErrorCode PetscRandomCreate_Random123(PetscRandom r)
13425ccb61fSToby Isaac {
13525ccb61fSToby Isaac   PetscRandom123 *r123;
13625ccb61fSToby Isaac   PetscErrorCode ierr;
13725ccb61fSToby Isaac 
13825ccb61fSToby Isaac   PetscFunctionBegin;
13925ccb61fSToby Isaac   ierr = PetscNewLog(r,&r123);CHKERRQ(ierr);
14025ccb61fSToby Isaac   r->data = r123;
14125ccb61fSToby Isaac   ierr = PetscMemcpy(r->ops,&PetscRandomOps_Values,sizeof(PetscRandomOps_Values));CHKERRQ(ierr);
14225ccb61fSToby Isaac   ierr = PetscObjectChangeTypeName((PetscObject)r,PETSCRANDOM123);CHKERRQ(ierr);
14325ccb61fSToby Isaac   ierr = PetscRandomSeed(r);CHKERRQ(ierr);
14425ccb61fSToby Isaac   PetscFunctionReturn(0);
14525ccb61fSToby Isaac }
146