Actual source code: random.c
1: /*$Id: random.c,v 1.60 2001/08/07 03:02:06 balay Exp $*/
2: /*
3: This file contains routines for interfacing to random number generators.
4: This provides more than just an interface to some system random number
5: generator:
7: Numbers can be shuffled for use as random tuples
9: Multiple random number generators may be used
11: We are still not sure what interface we want here. There should be
12: one to reinitialize and set the seed.
13: */
15: #include petsc.h
16: #include petscsys.h
17: #include <stdlib.h>
19: int PETSC_RANDOM_COOKIE = 0;
21: /* Private data */
22: struct _p_PetscRandom {
23: PETSCHEADER(int)
24: unsigned long seed;
25: PetscScalar low,width; /* lower bound and width of the interval over
26: which the random numbers are distributed */
27: PetscTruth iset; /* if true, indicates that the user has set the interval */
28: /* array for shuffling ??? */
29: };
33: /*@C
34: PetscRandomDestroy - Destroys a context that has been formed by
35: PetscRandomCreate().
37: Collective on PetscRandom
39: Intput Parameter:
40: . r - the random number generator context
42: Level: intermediate
44: .seealso: PetscRandomGetValue(), PetscRandomCreate(), VecSetRandom()
45: @*/
46: int PetscRandomDestroy(PetscRandom r)
47: {
50: if (--r->refct > 0) return(0);
52: PetscLogObjectDestroy((PetscObject)r);
53: PetscHeaderDestroy((PetscObject)r);
54: return(0);
55: }
59: /*@C
60: PetscRandomSetInterval - Sets the interval over which the random numbers
61: will be randomly distributed. By default, this interval is [0,1).
63: Collective on PetscRandom
65: Input Parameters:
66: . r - the random number generator context
68: Example of Usage:
69: .vb
70: PetscRandomCreate(PETSC_COMM_WORLD,RANDOM_DEFAULT,&r);
71: PetscRandomSetInterval(RANDOM_DEFAULT,&r);
72: PetscRandomGetValue(r,&value1);
73: PetscRandomGetValue(r,&value2);
74: PetscRandomDestroy(r);
75: .ve
77: Level: intermediate
79: Concepts: random numbers^range
81: .seealso: PetscRandomCreate()
82: @*/
83: int PetscRandomSetInterval(PetscRandom r,PetscScalar low,PetscScalar high)
84: {
87: #if defined(PETSC_USE_COMPLEX)
88: if (PetscRealPart(low) >= PetscRealPart(high)) SETERRQ(PETSC_ERR_ARG_OUTOFRANGE,"only low < high");
89: if (PetscImaginaryPart(low) >= PetscImaginaryPart(high)) SETERRQ(PETSC_ERR_ARG_OUTOFRANGE,"only low < high");
90: #else
91: if (low >= high) SETERRQ2(PETSC_ERR_ARG_OUTOFRANGE,"only low < high: Instead %g %g",low,high);
92: #endif
93: r->low = low;
94: r->width = high-low;
95: r->iset = PETSC_TRUE;
96: return(0);
97: }
99: /*
100: For now we have set up using the DRAND48() generater. We need to deal
101: with other variants of random number generators. We should also add
102: a routine to enable restarts [seed48()]
103: */
104: #if defined(PETSC_HAVE_DRAND48)
105: EXTERN_C_BEGIN
106: extern double drand48();
107: extern void srand48(long);
108: EXTERN_C_END
112: /*@C
113: PetscRandomCreate - Creates a context for generating random numbers,
114: and initializes the random-number generator.
116: Collective on MPI_Comm
118: Input Parameters:
119: + comm - MPI communicator
120: - type - the type of random numbers to be generated, usually RANDOM_DEFAULT
122: Output Parameter:
123: . r - the random number generator context
125: Level: intermediate
127: Notes:
128: By default, we generate random numbers via srand48()/drand48() that
129: are uniformly distributed over [0,1). The user can shift and stretch
130: this interval by calling PetscRandomSetInterval().
131:
132: Currently three types of random numbers are supported. These types
133: are equivalent when working with real numbers.
134: . RANDOM_DEFAULT - both real and imaginary components are random
135: . RANDOM_DEFAULT_REAL - real component is random; imaginary component is 0
136: . RANDOM_DEFAULT_IMAGINARY - imaginary component is random; real component is 0
138: Use VecSetRandom() to set the elements of a vector to random numbers.
140: Example of Usage:
141: .vb
142: PetscRandomCreate(PETSC_COMM_SELF,RANDOM_DEFAULT,&r);
143: PetscRandomGetValue(r,&value1);
144: PetscRandomGetValue(r,&value2);
145: PetscRandomGetValue(r,&value3);
146: PetscRandomDestroy(r);
147: .ve
149: Concepts: random numbers^creating
151: .seealso: PetscRandomGetValue(), PetscRandomSetInterval(), PetscRandomDestroy(), VecSetRandom()
152: @*/
153: int PetscRandomCreate(MPI_Comm comm,PetscRandomType type,PetscRandom *r)
154: {
155: PetscRandom rr;
156: int ierr,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: int 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: int PetscRandomCreate(MPI_Comm comm,PetscRandomType type,PetscRandom *r)
240: {
241: PetscRandom rr;
242: int rank,ierr;
245: PetscLogInfo(0,"PetscRandomCreate: using rand(). not as efficinet as dran48\n");
246: *r = 0;
247: if (type != RANDOM_DEFAULT && type != RANDOM_DEFAULT_REAL && type != RANDOM_DEFAULT_IMAGINARY) {
248: SETERRQ(PETSC_ERR_SUP,"Not for this random number type");
249: }
250: PetscHeaderCreate(rr,_p_PetscRandom,int,PETSC_RANDOM_COOKIE,type,"random",comm,PetscRandomDestroy,0);
251: PetscLogObjectCreate(rr);
252: rr->low = 0.0;
253: rr->width = 1.0;
254: rr->iset = PETSC_FALSE;
255: rr->seed = 0;
256: MPI_Comm_rank(comm,&rank);
257: srand(0x12345678+rank);
258: *r = rr;
259: return(0);
260: }
262: #define RAND_WRAP() (rand()/(double)((unsigned int)RAND_MAX+1))
265: int PetscRandomGetValue(PetscRandom r,PetscScalar *val)
266: {
270: #if defined(PETSC_USE_COMPLEX)
271: if (r->type == RANDOM_DEFAULT) {
272: if (r->iset == PETSC_TRUE)
273: *val = PetscRealPart(r->width)*RAND_WRAP() + PetscRealPart(r->low) +
274: (PetscImaginaryPart(r->width)*RAND_WRAP() + PetscImaginaryPart(r->low)) * PETSC_i;
275: else *val = RAND_WRAP() + RAND_WRAP()*PETSC_i;
276: } else if (r->type == RANDOM_DEFAULT_REAL) {
277: if (r->iset == PETSC_TRUE) *val = PetscRealPart(r->width)*RAND_WRAP() + PetscRealPart(r->low);
278: else *val = RAND_WRAP();
279: } else if (r->type == RANDOM_DEFAULT_IMAGINARY) {
280: if (r->iset == PETSC_TRUE) *val = (PetscImaginaryPart(r->width)*RAND_WRAP()+PetscImaginaryPart(r->low))*PETSC_i;
281: else *val = RAND_WRAP()*PETSC_i;
282: } else SETERRQ(PETSC_ERR_ARG_OUTOFRANGE,"Invalid random number type");
283: #else
284: if (r->iset == PETSC_TRUE) *val = r->width * RAND_WRAP() + r->low;
285: else *val = RAND_WRAP();
286: #endif
287: return(0);
288: }
290: #else
291: /* Should put a simple, portable random number generator here? */
293: extern double drand48();
297: int PetscRandomCreate(MPI_Comm comm,PetscRandomType type,PetscRandom *r)
298: {
299: PetscRandom rr;
300: char arch[10];
301: int ierr;
304: *r = 0;
305: if (type != RANDOM_DEFAULT) SETERRQ(PETSC_ERR_SUP,"Not for this random number type");
306: PetscHeaderCreate(rr,_p_PetscRandom,int,PETSC_RANDOM_COOKIE,type,"random",comm,PetscRandomDestroy,0);
307: PetscLogObjectCreate(rr);
308: *r = rr;
309: PetscGetArchType(arch,10);
310: PetscPrintf(comm,"PetscRandomCreate: Warning: Random number generator not set for machine %s; using fake random numbers.\n",arch);
311: return(0);
312: }
316: int PetscRandomGetValue(PetscRandom r,PetscScalar *val)
317: {
321: #if defined(PETSC_USE_COMPLEX)
322: *val = (0.5,0.5);
323: #else
324: *val = 0.5;
325: #endif
326: return(0);
327: }
328: #endif