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;
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: };
31: /*@C
32: PetscRandomDestroy - Destroys a context that has been formed by
33: PetscRandomCreate().
35: Collective on PetscRandom
37: Intput Parameter:
38: . r - the random number generator context
40: Level: intermediate
42: .seealso: PetscRandomGetValue(), PetscRandomCreate(), VecSetRandom()
43: @*/
44: int PetscRandomDestroy(PetscRandom r)
45: {
48: if (--r->refct > 0) return(0);
50: PetscLogObjectDestroy((PetscObject)r);
51: PetscHeaderDestroy((PetscObject)r);
52: return(0);
53: }
55: /*@C
56: PetscRandomSetInterval - Sets the interval over which the random numbers
57: will be randomly distributed. By default, this interval is [0,1).
59: Collective on PetscRandom
61: Input Parameters:
62: . r - the random number generator context
64: Example of Usage:
65: .vb
66: PetscRandomCreate(PETSC_COMM_WORLD,RANDOM_DEFAULT,&r);
67: PetscRandomSetInterval(RANDOM_DEFAULT,&r);
68: PetscRandomGetValue(r,&value1);
69: PetscRandomGetValue(r,&value2);
70: PetscRandomDestroy(r);
71: .ve
73: Level: intermediate
75: Concepts: random numbers^range
77: .seealso: PetscRandomCreate()
78: @*/
79: int PetscRandomSetInterval(PetscRandom r,PetscScalar low,PetscScalar high)
80: {
83: #if defined(PETSC_USE_COMPLEX)
84: if (PetscRealPart(low) >= PetscRealPart(high)) SETERRQ(PETSC_ERR_ARG_OUTOFRANGE,"only low < high");
85: if (PetscImaginaryPart(low) >= PetscImaginaryPart(high)) SETERRQ(PETSC_ERR_ARG_OUTOFRANGE,"only low < high");
86: #else
87: if (low >= high) SETERRQ2(PETSC_ERR_ARG_OUTOFRANGE,"only low < high: Instead %g %g",low,high);
88: #endif
89: r->low = low;
90: r->width = high-low;
91: r->iset = PETSC_TRUE;
92: return(0);
93: }
95: /*
96: For now we have set up using the DRAND48() generater. We need to deal
97: with other variants of random number generators. We should also add
98: a routine to enable restarts [seed48()]
99: */
100: #if defined(PETSC_HAVE_DRAND48)
101: EXTERN_C_BEGIN
102: extern double drand48();
103: extern void srand48(long);
104: EXTERN_C_END
106: /*@C
107: PetscRandomCreate - Creates a context for generating random numbers,
108: and initializes the random-number generator.
110: Collective on MPI_Comm
112: Input Parameters:
113: + comm - MPI communicator
114: - type - the type of random numbers to be generated, usually RANDOM_DEFAULT
116: Output Parameter:
117: . r - the random number generator context
119: Level: intermediate
121: Notes:
122: By default, we generate random numbers via srand48()/drand48() that
123: are uniformly distributed over [0,1). The user can shift and stretch
124: this interval by calling PetscRandomSetInterval().
125:
126: Currently three types of random numbers are supported. These types
127: are equivalent when working with real numbers.
128: . RANDOM_DEFAULT - both real and imaginary components are random
129: . RANDOM_DEFAULT_REAL - real component is random; imaginary component is 0
130: . RANDOM_DEFAULT_IMAGINARY - imaginary component is random; real component is 0
132: Use VecSetRandom() to set the elements of a vector to random numbers.
134: Example of Usage:
135: .vb
136: PetscRandomCreate(PETSC_COMM_SELF,RANDOM_DEFAULT,&r);
137: PetscRandomGetValue(r,&value1);
138: PetscRandomGetValue(r,&value2);
139: PetscRandomGetValue(r,&value3);
140: PetscRandomDestroy(r);
141: .ve
143: Concepts: random numbers^creating
145: .seealso: PetscRandomGetValue(), PetscRandomSetInterval(), PetscRandomDestroy(), VecSetRandom()
146: @*/
147: int PetscRandomCreate(MPI_Comm comm,PetscRandomType type,PetscRandom *r)
148: {
149: PetscRandom rr;
150: int ierr,rank;
153: *r = 0;
154: if (type != RANDOM_DEFAULT && type != RANDOM_DEFAULT_REAL && type != RANDOM_DEFAULT_IMAGINARY){
155: SETERRQ(PETSC_ERR_SUP,"Not for this random number type");
156: }
157: PetscHeaderCreate(rr,_p_PetscRandom,int,PETSC_RANDOM_COOKIE,type,"random",comm,PetscRandomDestroy,0);
158: PetscLogObjectCreate(rr);
159: rr->low = 0.0;
160: rr->width = 1.0;
161: rr->iset = PETSC_FALSE;
162: rr->seed = 0;
163: MPI_Comm_rank(comm,&rank);
164: srand48(0x12345678+rank);
165: *r = rr;
166: return(0);
167: }
169: /*@C
170: PetscRandomGetValue - Generates a random number. Call this after first calling
171: PetscRandomCreate().
173: Not Collective
175: Intput Parameter:
176: . r - the random number generator context
178: Output Parameter:
179: . val - the value
181: Level: intermediate
183: Notes:
184: Use VecSetRandom() to set the elements of a vector to random numbers.
186: Example of Usage:
187: .vb
188: PetscRandomCreate(PETSC_COMM_WORLD,RANDOM_DEFAULT,&r);
189: PetscRandomGetValue(r,&value1);
190: PetscRandomGetValue(r,&value2);
191: PetscRandomGetValue(r,&value3);
192: PetscRandomDestroy(r);
193: .ve
195: Concepts: random numbers^getting
197: .seealso: PetscRandomCreate(), PetscRandomDestroy(), VecSetRandom()
198: @*/
199: int PetscRandomGetValue(PetscRandom r,PetscScalar *val)
200: {
203: #if defined(PETSC_USE_COMPLEX)
204: if (r->type == RANDOM_DEFAULT) {
205: if (r->iset == PETSC_TRUE) {
206: *val = PetscRealPart(r->width)*drand48() + PetscRealPart(r->low) +
207: (PetscImaginaryPart(r->width)*drand48() + PetscImaginaryPart(r->low)) * PETSC_i;
208: }
209: else *val = drand48() + drand48()*PETSC_i;
210: } else if (r->type == RANDOM_DEFAULT_REAL) {
211: if (r->iset == PETSC_TRUE) *val = PetscRealPart(r->width)*drand48() + PetscRealPart(r->low);
212: else *val = drand48();
213: } else if (r->type == RANDOM_DEFAULT_IMAGINARY) {
214: if (r->iset == PETSC_TRUE) *val = (PetscImaginaryPart(r->width)*drand48()+PetscImaginaryPart(r->low))*PETSC_i;
215: else *val = drand48()*PETSC_i;
216: } else {
217: SETERRQ(PETSC_ERR_ARG_OUTOFRANGE,"Invalid random number type");
218: }
219: #else
220: if (r->iset == PETSC_TRUE) *val = r->width * drand48() + r->low;
221: else *val = drand48();
222: #endif
223: return(0);
224: }
226: #elif defined(PETSC_HAVE_RAND)
228: int PetscRandomCreate(MPI_Comm comm,PetscRandomType type,PetscRandom *r)
229: {
230: PetscRandom rr;
231: int rank,ierr;
234: PetscLogInfo(0,"PetscRandomCreate: using rand(). not as efficinet as dran48n");
235: *r = 0;
236: if (type != RANDOM_DEFAULT && type != RANDOM_DEFAULT_REAL && type != RANDOM_DEFAULT_IMAGINARY) {
237: SETERRQ(PETSC_ERR_SUP,"Not for this random number type");
238: }
239: PetscHeaderCreate(rr,_p_PetscRandom,int,PETSC_RANDOM_COOKIE,type,"random",comm,PetscRandomDestroy,0);
240: PetscLogObjectCreate(rr);
241: rr->low = 0.0;
242: rr->width = 1.0;
243: rr->iset = PETSC_FALSE;
244: rr->seed = 0;
245: MPI_Comm_rank(comm,&rank);
246: srand(0x12345678+rank);
247: *r = rr;
248: return(0);
249: }
251: #define RAND_WRAP() (rand()/(double)((unsigned int)RAND_MAX+1))
252: int PetscRandomGetValue(PetscRandom r,PetscScalar *val)
253: {
256: #if defined(PETSC_USE_COMPLEX)
257: if (r->type == RANDOM_DEFAULT) {
258: if (r->iset == PETSC_TRUE)
259: *val = PetscRealPart(r->width)*RAND_WRAP() + PetscRealPart(r->low) +
260: (PetscImaginaryPart(r->width)*RAND_WRAP() + PetscImaginaryPart(r->low)) * PETSC_i;
261: else *val = RAND_WRAP() + RAND_WRAP()*PETSC_i;
262: } else if (r->type == RANDOM_DEFAULT_REAL) {
263: if (r->iset == PETSC_TRUE) *val = PetscRealPart(r->width)*RAND_WRAP() + PetscRealPart(r->low);
264: else *val = RAND_WRAP();
265: } else if (r->type == RANDOM_DEFAULT_IMAGINARY) {
266: if (r->iset == PETSC_TRUE) *val = (PetscImaginaryPart(r->width)*RAND_WRAP()+PetscImaginaryPart(r->low))*PETSC_i;
267: else *val = RAND_WRAP()*PETSC_i;
268: } else SETERRQ(PETSC_ERR_ARG_OUTOFRANGE,"Invalid random number type");
269: #else
270: if (r->iset == PETSC_TRUE) *val = r->width * RAND_WRAP() + r->low;
271: else *val = RAND_WRAP();
272: #endif
273: return(0);
274: }
276: #else
277: /* Should put a simple, portable random number generator here? */
279: extern double drand48();
281: int PetscRandomCreate(MPI_Comm comm,PetscRandomType type,PetscRandom *r)
282: {
283: PetscRandom rr;
284: char arch[10];
285: int ierr;
288: *r = 0;
289: if (type != RANDOM_DEFAULT) SETERRQ(PETSC_ERR_SUP,"Not for this random number type");
290: PetscHeaderCreate(rr,_p_PetscRandom,int,PETSC_RANDOM_COOKIE,type,"random",comm,PetscRandomDestroy,0);
291: PetscLogObjectCreate(rr);
292: *r = rr;
293: PetscGetArchType(arch,10);
294: PetscPrintf(comm,"PetscRandomCreate: Warning: Random number generator not set for machine %s; using fake random numbers.n",arch);
295: return(0);
296: }
298: int PetscRandomGetValue(PetscRandom r,PetscScalar *val)
299: {
302: #if defined(PETSC_USE_COMPLEX)
303: *val = (0.5,0.5);
304: #else
305: *val = 0.5;
306: #endif
307: return(0);
308: }
309: #endif