1*25ccb61fSToby Isaac #include <../src/sys/classes/random/randomimpl.h> 2*25ccb61fSToby Isaac #include <Random123/threefry.h> 3*25ccb61fSToby Isaac 4*25ccb61fSToby Isaac /* The structure of the Random123 methods are similar enough that templates could be used to make the other CBRNGs in 5*25ccb61fSToby Isaac * the package (aes, ars, philox) available, as well as different block sizes. But threefry4x64 is a good default, 6*25ccb61fSToby Isaac * and I'd rather get a simple implementation up and working and come back if there's interest. */ 7*25ccb61fSToby Isaac typedef struct _n_PetscRandom123 8*25ccb61fSToby Isaac { 9*25ccb61fSToby Isaac threefry4x64_ctr_t counter; 10*25ccb61fSToby Isaac threefry4x64_key_t key; 11*25ccb61fSToby Isaac threefry4x64_ctr_t result; 12*25ccb61fSToby Isaac PetscInt count; 13*25ccb61fSToby Isaac } 14*25ccb61fSToby Isaac PetscRandom123; 15*25ccb61fSToby Isaac 16*25ccb61fSToby Isaac R123_ULONG_LONG PETSCR123_SEED_0 = R123_64BIT(0x615D333D2655FE14); 17*25ccb61fSToby Isaac R123_ULONG_LONG PETSCR123_SEED_1 = R123_64BIT(0xAFF6369B3EE9FE96); 18*25ccb61fSToby Isaac R123_ULONG_LONG PETSCR123_SEED_2 = R123_64BIT(0x5956EBC717B60E07); 19*25ccb61fSToby Isaac R123_ULONG_LONG PETSCR123_SEED_3 = R123_64BIT(0xEE8612A0CBEABFF1); 20*25ccb61fSToby Isaac 21*25ccb61fSToby Isaac PetscErrorCode PetscRandomSeed_Random123(PetscRandom r) 22*25ccb61fSToby Isaac { 23*25ccb61fSToby Isaac threefry4x64_ukey_t ukey; 24*25ccb61fSToby Isaac PetscRandom123 *r123 = (PetscRandom123 *) r->data; 25*25ccb61fSToby Isaac 26*25ccb61fSToby Isaac PetscFunctionBegin; 27*25ccb61fSToby Isaac ukey.v[0] = (R123_ULONG_LONG) r->seed; 28*25ccb61fSToby Isaac ukey.v[1] = PETSCR123_SEED_1; 29*25ccb61fSToby Isaac ukey.v[2] = PETSCR123_SEED_2; 30*25ccb61fSToby Isaac ukey.v[3] = PETSCR123_SEED_3; 31*25ccb61fSToby Isaac /* The point of seeding should be that every time the sequence is seeded you get the same output. In this CBRNG, 32*25ccb61fSToby Isaac * that means we have to initialize the key and reset the counts */ 33*25ccb61fSToby Isaac r123->key = threefry4x64keyinit(ukey); 34*25ccb61fSToby Isaac r123->counter.v[0] = 0; 35*25ccb61fSToby Isaac r123->counter.v[1] = 1; 36*25ccb61fSToby Isaac r123->counter.v[2] = 2; 37*25ccb61fSToby Isaac r123->counter.v[3] = 3; 38*25ccb61fSToby Isaac r123->result = threefry4x64(r123->counter,r123->key); 39*25ccb61fSToby Isaac r123->count = 0; 40*25ccb61fSToby Isaac PetscFunctionReturn(0); 41*25ccb61fSToby Isaac } 42*25ccb61fSToby Isaac 43*25ccb61fSToby Isaac static PetscReal PetscRandom123Step(PetscRandom123 *r123) 44*25ccb61fSToby Isaac { 45*25ccb61fSToby Isaac PetscReal scale = ((PetscReal) 1.) / (UINT64_MAX + ((PetscReal) 1.)); 46*25ccb61fSToby Isaac PetscReal shift = .5 * scale; 47*25ccb61fSToby Isaac PetscInt mod = (r123->count++) % 4; 48*25ccb61fSToby Isaac PetscReal ret; 49*25ccb61fSToby Isaac 50*25ccb61fSToby Isaac ret = r123->result.v[mod] * scale + shift; 51*25ccb61fSToby Isaac 52*25ccb61fSToby Isaac if (mod == 3) { 53*25ccb61fSToby Isaac r123->counter.v[0] += 4; 54*25ccb61fSToby Isaac r123->counter.v[1] += 4; 55*25ccb61fSToby Isaac r123->counter.v[2] += 4; 56*25ccb61fSToby Isaac r123->counter.v[3] += 4; 57*25ccb61fSToby Isaac r123->result = threefry4x64(r123->counter,r123->key); 58*25ccb61fSToby Isaac } 59*25ccb61fSToby Isaac 60*25ccb61fSToby Isaac return ret; 61*25ccb61fSToby Isaac } 62*25ccb61fSToby Isaac 63*25ccb61fSToby Isaac PetscErrorCode PetscRandomGetValue_Random123(PetscRandom r,PetscScalar *val) 64*25ccb61fSToby Isaac { 65*25ccb61fSToby Isaac PetscRandom123 *r123 = (PetscRandom123 *) r->data; 66*25ccb61fSToby Isaac PetscScalar rscal; 67*25ccb61fSToby Isaac 68*25ccb61fSToby Isaac PetscFunctionBegin; 69*25ccb61fSToby Isaac #if defined(PETSC_USE_COMPLEX) 70*25ccb61fSToby Isaac { 71*25ccb61fSToby Isaac PetscReal re = PetscRandom123Step(r123); 72*25ccb61fSToby Isaac PetscReal im = PetscRandom123Step(r123); 73*25ccb61fSToby Isaac 74*25ccb61fSToby Isaac if (r->iset) { 75*25ccb61fSToby Isaac re = re * PetscRealPart(r->width) + PetscRealPart(r->low); 76*25ccb61fSToby Isaac im = im * PetscImaginaryPart(r->width) + PetscImaginaryPart(r->low); 77*25ccb61fSToby Isaac } 78*25ccb61fSToby Isaac 79*25ccb61fSToby Isaac rscal = PetscCMPLX(re,im); 80*25ccb61fSToby Isaac } 81*25ccb61fSToby Isaac #else 82*25ccb61fSToby Isaac rscal = PetscRandom123Step(r123); 83*25ccb61fSToby Isaac if (r->iset) rscal = rscal * r->width + r->low; 84*25ccb61fSToby Isaac #endif 85*25ccb61fSToby Isaac *val = rscal; 86*25ccb61fSToby Isaac PetscFunctionReturn(0); 87*25ccb61fSToby Isaac } 88*25ccb61fSToby Isaac 89*25ccb61fSToby Isaac PetscErrorCode PetscRandomGetValueReal_Random123(PetscRandom r,PetscScalar *val) 90*25ccb61fSToby Isaac { 91*25ccb61fSToby Isaac PetscRandom123 *r123 = (PetscRandom123 *) r->data; 92*25ccb61fSToby Isaac PetscScalar rreal; 93*25ccb61fSToby Isaac 94*25ccb61fSToby Isaac PetscFunctionBegin; 95*25ccb61fSToby Isaac rreal = PetscRandom123Step(r123); 96*25ccb61fSToby Isaac if (r->iset) rreal = rreal * PetscRealPart(r->width) + PetscRealPart(r->low); 97*25ccb61fSToby Isaac *val = rreal; 98*25ccb61fSToby Isaac PetscFunctionReturn(0); 99*25ccb61fSToby Isaac } 100*25ccb61fSToby Isaac 101*25ccb61fSToby Isaac PetscErrorCode PetscRandomDestroy_Random123(PetscRandom r) 102*25ccb61fSToby Isaac { 103*25ccb61fSToby Isaac PetscErrorCode ierr; 104*25ccb61fSToby Isaac 105*25ccb61fSToby Isaac PetscFunctionBegin; 106*25ccb61fSToby Isaac ierr = PetscFree(r->data);CHKERRQ(ierr); 107*25ccb61fSToby Isaac PetscFunctionReturn(0); 108*25ccb61fSToby Isaac } 109*25ccb61fSToby Isaac 110*25ccb61fSToby Isaac static struct _PetscRandomOps PetscRandomOps_Values = { 111*25ccb61fSToby Isaac /* 0 */ 112*25ccb61fSToby Isaac PetscRandomSeed_Random123, 113*25ccb61fSToby Isaac PetscRandomGetValue_Random123, 114*25ccb61fSToby Isaac PetscRandomGetValueReal_Random123, 115*25ccb61fSToby Isaac PetscRandomDestroy_Random123, 116*25ccb61fSToby Isaac /* 5 */ 117*25ccb61fSToby Isaac 0 118*25ccb61fSToby Isaac }; 119*25ccb61fSToby Isaac 120*25ccb61fSToby Isaac /*MC 121*25ccb61fSToby Isaac PETSCRANDOM123- access to Random123 counter based pseudorandom number generators (currently threefry4x64) 122*25ccb61fSToby Isaac 123*25ccb61fSToby Isaac Options Database Keys: 124*25ccb61fSToby Isaac . -random_type <rand,rand48,sprng,random123> 125*25ccb61fSToby Isaac 126*25ccb61fSToby Isaac Level: beginner 127*25ccb61fSToby Isaac 128*25ccb61fSToby Isaac PETSc must have been ./configure with the option --download-random123 to use 129*25ccb61fSToby Isaac this random number generator. 130*25ccb61fSToby Isaac 131*25ccb61fSToby Isaac .seealso: RandomCreate(), RandomSetType(), PETSCRAND, PETSCRAND48, PETSCSPRNG 132*25ccb61fSToby Isaac M*/ 133*25ccb61fSToby Isaac 134*25ccb61fSToby Isaac PETSC_EXTERN PetscErrorCode PetscRandomCreate_Random123(PetscRandom r) 135*25ccb61fSToby Isaac { 136*25ccb61fSToby Isaac PetscRandom123 *r123; 137*25ccb61fSToby Isaac PetscErrorCode ierr; 138*25ccb61fSToby Isaac 139*25ccb61fSToby Isaac PetscFunctionBegin; 140*25ccb61fSToby Isaac ierr = PetscNewLog(r,&r123);CHKERRQ(ierr); 141*25ccb61fSToby Isaac r->data = r123; 142*25ccb61fSToby Isaac ierr = PetscMemcpy(r->ops,&PetscRandomOps_Values,sizeof(PetscRandomOps_Values));CHKERRQ(ierr); 143*25ccb61fSToby Isaac ierr = PetscObjectChangeTypeName((PetscObject)r,PETSCRANDOM123);CHKERRQ(ierr); 144*25ccb61fSToby Isaac ierr = PetscRandomSeed(r);CHKERRQ(ierr); 145*25ccb61fSToby Isaac PetscFunctionReturn(0); 146*25ccb61fSToby Isaac } 147