1d6cc7855SJacob Faibussowitsch #include <petsc/private/randomimpl.h>
2003ee160SMatthew G. Knepley
3e4e5cec9SBarry Smith typedef struct {
4e4e5cec9SBarry Smith unsigned short seed[3];
5e4e5cec9SBarry Smith unsigned short mult[3];
6e4e5cec9SBarry Smith unsigned short add;
7e4e5cec9SBarry Smith } PetscRandom_Rander48;
8e4e5cec9SBarry Smith
9003ee160SMatthew G. Knepley #define RANDER48_SEED_0 (0x330e)
10003ee160SMatthew G. Knepley #define RANDER48_SEED_1 (0xabcd)
11003ee160SMatthew G. Knepley #define RANDER48_SEED_2 (0x1234)
12003ee160SMatthew G. Knepley #define RANDER48_MULT_0 (0xe66d)
13003ee160SMatthew G. Knepley #define RANDER48_MULT_1 (0xdeec)
14003ee160SMatthew G. Knepley #define RANDER48_MULT_2 (0x0005)
15003ee160SMatthew G. Knepley #define RANDER48_ADD (0x000b)
16003ee160SMatthew G. Knepley
_dorander48(PetscRandom_Rander48 * r48)17d71ae5a4SJacob Faibussowitsch static double _dorander48(PetscRandom_Rander48 *r48)
18d71ae5a4SJacob Faibussowitsch {
19003ee160SMatthew G. Knepley unsigned long accu;
20003ee160SMatthew G. Knepley unsigned short temp[2];
21003ee160SMatthew G. Knepley
22e4e5cec9SBarry Smith accu = (unsigned long)r48->mult[0] * (unsigned long)r48->seed[0] + (unsigned long)r48->add;
23003ee160SMatthew G. Knepley temp[0] = (unsigned short)accu; /* lower 16 bits */
24003ee160SMatthew G. Knepley accu >>= sizeof(unsigned short) * 8;
25e4e5cec9SBarry Smith accu += (unsigned long)r48->mult[0] * (unsigned long)r48->seed[1] + (unsigned long)r48->mult[1] * (unsigned long)r48->seed[0];
26003ee160SMatthew G. Knepley temp[1] = (unsigned short)accu; /* middle 16 bits */
27003ee160SMatthew G. Knepley accu >>= sizeof(unsigned short) * 8;
286f2c871aSStefano Zampini accu += (unsigned long)r48->mult[0] * r48->seed[2] + (unsigned long)r48->mult[1] * r48->seed[1] + (unsigned long)r48->mult[2] * r48->seed[0];
29e4e5cec9SBarry Smith r48->seed[0] = temp[0];
30e4e5cec9SBarry Smith r48->seed[1] = temp[1];
31e4e5cec9SBarry Smith r48->seed[2] = (unsigned short)accu;
32e4e5cec9SBarry Smith return ldexp((double)r48->seed[0], -48) + ldexp((double)r48->seed[1], -32) + ldexp((double)r48->seed[2], -16);
33003ee160SMatthew G. Knepley }
34003ee160SMatthew G. Knepley
PetscRandomSeed_Rander48(PetscRandom r)35d71ae5a4SJacob Faibussowitsch static PetscErrorCode PetscRandomSeed_Rander48(PetscRandom r)
36d71ae5a4SJacob Faibussowitsch {
37e4e5cec9SBarry Smith PetscRandom_Rander48 *r48 = (PetscRandom_Rander48 *)r->data;
38e4e5cec9SBarry Smith
39003ee160SMatthew G. Knepley PetscFunctionBegin;
40e4e5cec9SBarry Smith r48->seed[0] = RANDER48_SEED_0;
41e4e5cec9SBarry Smith r48->seed[1] = (unsigned short)r->seed;
42e4e5cec9SBarry Smith r48->seed[2] = (unsigned short)(r->seed >> 16);
43e4e5cec9SBarry Smith r48->mult[0] = RANDER48_MULT_0;
44e4e5cec9SBarry Smith r48->mult[1] = RANDER48_MULT_1;
45e4e5cec9SBarry Smith r48->mult[2] = RANDER48_MULT_2;
46e4e5cec9SBarry Smith r48->add = RANDER48_ADD;
473ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS);
48003ee160SMatthew G. Knepley }
49003ee160SMatthew G. Knepley
PetscRandomGetValue_Rander48(PetscRandom r,PetscScalar * val)50d71ae5a4SJacob Faibussowitsch static PetscErrorCode PetscRandomGetValue_Rander48(PetscRandom r, PetscScalar *val)
51d71ae5a4SJacob Faibussowitsch {
52e4e5cec9SBarry Smith PetscRandom_Rander48 *r48 = (PetscRandom_Rander48 *)r->data;
53e4e5cec9SBarry Smith
54003ee160SMatthew G. Knepley PetscFunctionBegin;
55003ee160SMatthew G. Knepley #if defined(PETSC_USE_COMPLEX)
56003ee160SMatthew G. Knepley if (r->iset) {
579f0394f4SBarry Smith *val = PetscRealPart(r->low) + PetscImaginaryPart(r->low) * PETSC_i;
58ad540459SPierre Jolivet if (PetscRealPart(r->width)) *val += PetscRealPart(r->width) * _dorander48(r48);
59ad540459SPierre Jolivet if (PetscImaginaryPart(r->width)) *val += PetscImaginaryPart(r->width) * _dorander48(r48) * PETSC_i;
60003ee160SMatthew G. Knepley } else {
61e4e5cec9SBarry Smith *val = _dorander48(r48) + _dorander48(r48) * PETSC_i;
62003ee160SMatthew G. Knepley }
63003ee160SMatthew G. Knepley #else
64e4e5cec9SBarry Smith if (r->iset) *val = r->width * _dorander48(r48) + r->low;
65e4e5cec9SBarry Smith else *val = _dorander48(r48);
66003ee160SMatthew G. Knepley #endif
673ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS);
68003ee160SMatthew G. Knepley }
69003ee160SMatthew G. Knepley
PetscRandomGetValueReal_Rander48(PetscRandom r,PetscReal * val)70d71ae5a4SJacob Faibussowitsch static PetscErrorCode PetscRandomGetValueReal_Rander48(PetscRandom r, PetscReal *val)
71d71ae5a4SJacob Faibussowitsch {
72e4e5cec9SBarry Smith PetscRandom_Rander48 *r48 = (PetscRandom_Rander48 *)r->data;
73e4e5cec9SBarry Smith
74003ee160SMatthew G. Knepley PetscFunctionBegin;
75003ee160SMatthew G. Knepley #if defined(PETSC_USE_COMPLEX)
76e4e5cec9SBarry Smith if (r->iset) *val = PetscRealPart(r->width) * _dorander48(r48) + PetscRealPart(r->low);
77e4e5cec9SBarry Smith else *val = _dorander48(r48);
78003ee160SMatthew G. Knepley #else
79e4e5cec9SBarry Smith if (r->iset) *val = r->width * _dorander48(r48) + r->low;
80e4e5cec9SBarry Smith else *val = _dorander48(r48);
81003ee160SMatthew G. Knepley #endif
823ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS);
83003ee160SMatthew G. Knepley }
84003ee160SMatthew G. Knepley
PetscRandomDestroy_Rander48(PetscRandom r)85d71ae5a4SJacob Faibussowitsch static PetscErrorCode PetscRandomDestroy_Rander48(PetscRandom r)
86d71ae5a4SJacob Faibussowitsch {
87e4e5cec9SBarry Smith PetscFunctionBegin;
889566063dSJacob Faibussowitsch PetscCall(PetscFree(r->data));
893ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS);
90e4e5cec9SBarry Smith }
91e4e5cec9SBarry Smith
92003ee160SMatthew G. Knepley static struct _PetscRandomOps PetscRandomOps_Values = {
93267267bdSJacob Faibussowitsch PetscDesignatedInitializer(seed, PetscRandomSeed_Rander48),
94267267bdSJacob Faibussowitsch PetscDesignatedInitializer(getvalue, PetscRandomGetValue_Rander48),
95267267bdSJacob Faibussowitsch PetscDesignatedInitializer(getvaluereal, PetscRandomGetValueReal_Rander48),
96267267bdSJacob Faibussowitsch PetscDesignatedInitializer(getvalues, NULL),
97267267bdSJacob Faibussowitsch PetscDesignatedInitializer(getvaluesreal, NULL),
98267267bdSJacob Faibussowitsch PetscDesignatedInitializer(destroy, PetscRandomDestroy_Rander48),
99*8a403008SStefano Zampini PetscDesignatedInitializer(setfromoptions, NULL),
100003ee160SMatthew G. Knepley };
101003ee160SMatthew G. Knepley
102003ee160SMatthew G. Knepley /*MC
103c31d2375SBarry Smith PETSCRANDER48 - simple portable reimplementation of basic Unix `drand48()` random number generator that should generate the
104b3bd51deSBarry Smith exact same random numbers on any system.
105003ee160SMatthew G. Knepley
106c31d2375SBarry Smith Options Database Key:
1071179163eSBarry Smith . -random_type <rand,rand48,rander48,sprng> - select the random number generator at runtime
108003ee160SMatthew G. Knepley
109c31d2375SBarry Smith Level: beginner
110c31d2375SBarry Smith
11195452b02SPatrick Sanan Notes:
112811af0c4SBarry Smith This is the default random number generate provided by `PetscRandomCreate()` if you do not set a particular implementation.
113e4e5cec9SBarry Smith
114811af0c4SBarry Smith Each `PetscRandom` object created with this type has its own seed and its own history, so multiple `PetscRandom` objects of this type
115d5b43468SJose E. Roman will not interfere with random numbers generated by other objects. Each PETSc object of this type will produce the exact same set of
116811af0c4SBarry Smith random numbers so if you wish different `PetscRandom` objects of this type set different seeds for each one after you create them with
117811af0c4SBarry Smith `PetscRandomSetSeed()` followed by `PetscRandomSeed()`.
118e4e5cec9SBarry Smith
1191179163eSBarry Smith .seealso: `PetscRandomCreate()`, `PetscRandomSetType()`, `PETSCRAND`, `PETSCRAND48`, `PETSCRANDER48`, `PETSCSPRNG`, `PetscRandomSetSeed()`,
1201179163eSBarry Smith `PetscRandomSeed()`, `PetscRandomSetFromOptions()`
121003ee160SMatthew G. Knepley M*/
122003ee160SMatthew G. Knepley
PetscRandomCreate_Rander48(PetscRandom r)123d71ae5a4SJacob Faibussowitsch PETSC_EXTERN PetscErrorCode PetscRandomCreate_Rander48(PetscRandom r)
124d71ae5a4SJacob Faibussowitsch {
125e4e5cec9SBarry Smith PetscRandom_Rander48 *r48;
126003ee160SMatthew G. Knepley
127003ee160SMatthew G. Knepley PetscFunctionBegin;
1284dfa11a4SJacob Faibussowitsch PetscCall(PetscNew(&r48));
129e4e5cec9SBarry Smith /* r48 does not need to be initialized because PetscRandomSeed() is always called before use and sets the needed values */
130e4e5cec9SBarry Smith r->data = r48;
131aea10558SJacob Faibussowitsch r->ops[0] = PetscRandomOps_Values;
1329566063dSJacob Faibussowitsch PetscCall(PetscObjectChangeTypeName((PetscObject)r, PETSCRANDER48));
1333ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS);
134003ee160SMatthew G. Knepley }
135