Actual source code: random.c
1: /*
2: This file contains routines for interfacing to random number generators.
3: This provides more than just an interface to some system random number
4: generator:
6: Numbers can be shuffled for use as random tuples
8: Multiple random number generators may be used
10: We are still not sure what interface we want here. There should be
11: one to reinitialize and set the seed.
12: */
14: #include petsc.h
15: #include petscsys.h
16: #include <stdlib.h>
18: PetscCookie PETSC_RANDOM_COOKIE = 0;
20: /* Private data */
21: struct _p_PetscRandom {
22: PETSCHEADER(int)
23: unsigned long seed;
24: PetscScalar low,width; /* lower bound and width of the interval over
25: which the random numbers are distributed */
26: PetscTruth iset; /* if true, indicates that the user has set the interval */
27: /* array for shuffling ??? */
28: };
32: /*@C
33: PetscRandomDestroy - Destroys a context that has been formed by
34: PetscRandomCreate().
36: Collective on PetscRandom
38: Intput Parameter:
39: . r - the random number generator context
41: Level: intermediate
43: .seealso: PetscRandomGetValue(), PetscRandomCreate(), VecSetRandom()
44: @*/
45: PetscErrorCode PetscRandomDestroy(PetscRandom r)
46: {
49: if (--r->refct > 0) return(0);
51: PetscLogObjectDestroy((PetscObject)r);
52: PetscHeaderDestroy((PetscObject)r);
53: return(0);
54: }
58: /*@C
59: PetscRandomSetInterval - Sets the interval over which the random numbers
60: will be randomly distributed. By default, this interval is [0,1).
62: Collective on PetscRandom
64: Input Parameters:
65: . r - the random number generator context
67: Example of Usage:
68: .vb
69: PetscRandomCreate(PETSC_COMM_WORLD,RANDOM_DEFAULT,&r);
70: PetscRandomSetInterval(RANDOM_DEFAULT,&r);
71: PetscRandomGetValue(r,&value1);
72: PetscRandomGetValue(r,&value2);
73: PetscRandomDestroy(r);
74: .ve
76: Level: intermediate
78: Concepts: random numbers^range
80: .seealso: PetscRandomCreate()
81: @*/
82: PetscErrorCode PetscRandomSetInterval(PetscRandom r,PetscScalar low,PetscScalar high)
83: {
86: #if defined(PETSC_USE_COMPLEX)
87: if (PetscRealPart(low) >= PetscRealPart(high)) SETERRQ(PETSC_ERR_ARG_OUTOFRANGE,"only low < high");
88: if (PetscImaginaryPart(low) >= PetscImaginaryPart(high)) SETERRQ(PETSC_ERR_ARG_OUTOFRANGE,"only low < high");
89: #else
90: if (low >= high) SETERRQ2(PETSC_ERR_ARG_OUTOFRANGE,"only low < high: Instead %g %g",low,high);
91: #endif
92: r->low = low;
93: r->width = high-low;
94: r->iset = PETSC_TRUE;
95: return(0);
96: }
98: /*
99: For now we have set up using the DRAND48() generater. We need to deal
100: with other variants of random number generators. We should also add
101: a routine to enable restarts [seed48()]
102: */
103: #if defined(PETSC_HAVE_DRAND48)
111: /*@C
112: PetscRandomCreate - Creates a context for generating random numbers,
113: and initializes the random-number generator.
115: Collective on MPI_Comm
117: Input Parameters:
118: + comm - MPI communicator
119: - type - the type of random numbers to be generated, usually RANDOM_DEFAULT
121: Output Parameter:
122: . r - the random number generator context
124: Level: intermediate
126: Notes:
127: By default, we generate random numbers via srand48()/drand48() that
128: are uniformly distributed over [0,1). The user can shift and stretch
129: this interval by calling PetscRandomSetInterval().
130:
131: Currently three types of random numbers are supported. These types
132: are equivalent when working with real numbers.
133: . RANDOM_DEFAULT - both real and imaginary components are random
134: . RANDOM_DEFAULT_REAL - real component is random; imaginary component is 0
135: . RANDOM_DEFAULT_IMAGINARY - imaginary component is random; real component is 0
137: Use VecSetRandom() to set the elements of a vector to random numbers.
139: Example of Usage:
140: .vb
141: PetscRandomCreate(PETSC_COMM_SELF,RANDOM_DEFAULT,&r);
142: PetscRandomGetValue(r,&value1);
143: PetscRandomGetValue(r,&value2);
144: PetscRandomGetValue(r,&value3);
145: PetscRandomDestroy(r);
146: .ve
148: Concepts: random numbers^creating
150: .seealso: PetscRandomGetValue(), PetscRandomSetInterval(), PetscRandomDestroy(), VecSetRandom()
151: @*/
152: PetscErrorCode PetscRandomCreate(MPI_Comm comm,PetscRandomType type,PetscRandom *r)
153: {
154: PetscRandom rr;
156: int rank;
159: *r = 0;
160: if (type != RANDOM_DEFAULT && type != RANDOM_DEFAULT_REAL && type != RANDOM_DEFAULT_IMAGINARY){
161: SETERRQ(PETSC_ERR_SUP,"Not for this random number type");
162: }
163: PetscHeaderCreate(rr,_p_PetscRandom,int,PETSC_RANDOM_COOKIE,type,"random",comm,PetscRandomDestroy,0);
164: PetscLogObjectCreate(rr);
165: rr->low = 0.0;
166: rr->width = 1.0;
167: rr->iset = PETSC_FALSE;
168: rr->seed = 0;
169: MPI_Comm_rank(comm,&rank);
170: srand48(0x12345678+rank);
171: *r = rr;
172: return(0);
173: }
177: /*@C
178: PetscRandomGetValue - Generates a random number. Call this after first calling
179: PetscRandomCreate().
181: Not Collective
183: Intput Parameter:
184: . r - the random number generator context
186: Output Parameter:
187: . val - the value
189: Level: intermediate
191: Notes:
192: Use VecSetRandom() to set the elements of a vector to random numbers.
194: Example of Usage:
195: .vb
196: PetscRandomCreate(PETSC_COMM_WORLD,RANDOM_DEFAULT,&r);
197: PetscRandomGetValue(r,&value1);
198: PetscRandomGetValue(r,&value2);
199: PetscRandomGetValue(r,&value3);
200: PetscRandomDestroy(r);
201: .ve
203: Concepts: random numbers^getting
205: .seealso: PetscRandomCreate(), PetscRandomDestroy(), VecSetRandom()
206: @*/
207: PetscErrorCode PetscRandomGetValue(PetscRandom r,PetscScalar *val)
208: {
212: #if defined(PETSC_USE_COMPLEX)
213: if (r->type == RANDOM_DEFAULT) {
214: if (r->iset == PETSC_TRUE) {
215: *val = PetscRealPart(r->width)*drand48() + PetscRealPart(r->low) +
216: (PetscImaginaryPart(r->width)*drand48() + PetscImaginaryPart(r->low)) * PETSC_i;
217: }
218: else *val = drand48() + drand48()*PETSC_i;
219: } else if (r->type == RANDOM_DEFAULT_REAL) {
220: if (r->iset == PETSC_TRUE) *val = PetscRealPart(r->width)*drand48() + PetscRealPart(r->low);
221: else *val = drand48();
222: } else if (r->type == RANDOM_DEFAULT_IMAGINARY) {
223: if (r->iset == PETSC_TRUE) *val = (PetscImaginaryPart(r->width)*drand48()+PetscImaginaryPart(r->low))*PETSC_i;
224: else *val = drand48()*PETSC_i;
225: } else {
226: SETERRQ(PETSC_ERR_ARG_OUTOFRANGE,"Invalid random number type");
227: }
228: #else
229: if (r->iset == PETSC_TRUE) *val = r->width * drand48() + r->low;
230: else *val = drand48();
231: #endif
232: return(0);
233: }
235: #elif defined(PETSC_HAVE_RAND)
239: PetscErrorCode PetscRandomCreate(MPI_Comm comm,PetscRandomType type,PetscRandom *r)
240: {
241: PetscRandom rr;
243: int rank;
246: PetscLogInfo(0,"PetscRandomCreate: using rand(). not as efficinet as dran48\n");
247: *r = 0;
248: if (type != RANDOM_DEFAULT && type != RANDOM_DEFAULT_REAL && type != RANDOM_DEFAULT_IMAGINARY) {
249: SETERRQ(PETSC_ERR_SUP,"Not for this random number type");
250: }
251: PetscHeaderCreate(rr,_p_PetscRandom,int,PETSC_RANDOM_COOKIE,type,"random",comm,PetscRandomDestroy,0);
252: PetscLogObjectCreate(rr);
253: rr->low = 0.0;
254: rr->width = 1.0;
255: rr->iset = PETSC_FALSE;
256: rr->seed = 0;
257: MPI_Comm_rank(comm,&rank);
258: srand(0x12345678+rank);
259: *r = rr;
260: return(0);
261: }
263: #define RAND_WRAP() (rand()/(double)((unsigned int)RAND_MAX+1))
266: PetscErrorCode PetscRandomGetValue(PetscRandom r,PetscScalar *val)
267: {
271: #if defined(PETSC_USE_COMPLEX)
272: if (r->type == RANDOM_DEFAULT) {
273: if (r->iset == PETSC_TRUE)
274: *val = PetscRealPart(r->width)*RAND_WRAP() + PetscRealPart(r->low) +
275: (PetscImaginaryPart(r->width)*RAND_WRAP() + PetscImaginaryPart(r->low)) * PETSC_i;
276: else *val = RAND_WRAP() + RAND_WRAP()*PETSC_i;
277: } else if (r->type == RANDOM_DEFAULT_REAL) {
278: if (r->iset == PETSC_TRUE) *val = PetscRealPart(r->width)*RAND_WRAP() + PetscRealPart(r->low);
279: else *val = RAND_WRAP();
280: } else if (r->type == RANDOM_DEFAULT_IMAGINARY) {
281: if (r->iset == PETSC_TRUE) *val = (PetscImaginaryPart(r->width)*RAND_WRAP()+PetscImaginaryPart(r->low))*PETSC_i;
282: else *val = RAND_WRAP()*PETSC_i;
283: } else SETERRQ(PETSC_ERR_ARG_OUTOFRANGE,"Invalid random number type");
284: #else
285: if (r->iset == PETSC_TRUE) *val = r->width * RAND_WRAP() + r->low;
286: else *val = RAND_WRAP();
287: #endif
288: return(0);
289: }
291: #else
292: /* Should put a simple, portable random number generator here? */
298: PetscErrorCode PetscRandomCreate(MPI_Comm comm,PetscRandomType type,PetscRandom *r)
299: {
300: PetscRandom rr;
301: char arch[10];
305: *r = 0;
306: if (type != RANDOM_DEFAULT) SETERRQ(PETSC_ERR_SUP,"Not for this random number type");
307: PetscHeaderCreate(rr,_p_PetscRandom,int,PETSC_RANDOM_COOKIE,type,"random",comm,PetscRandomDestroy,0);
308: PetscLogObjectCreate(rr);
309: *r = rr;
310: PetscGetArchType(arch,10);
311: PetscPrintf(comm,"PetscRandomCreate: Warning: Random number generator not set for machine %s; using fake random numbers.\n",arch);
312: return(0);
313: }
317: PetscErrorCode PetscRandomGetValue(PetscRandom r,PetscScalar *val)
318: {
322: #if defined(PETSC_USE_COMPLEX)
323: *val = (0.5,0.5);
324: #else
325: *val = 0.5;
326: #endif
327: return(0);
328: }
329: #endif