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