Actual source code: random.c
1: /*$Id: random.c,v 1.58 2001/04/06 19:24:30 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" /*I "petscsys.h" I*/
17: #include <stdlib.h>
19: /* Private data */
20: struct _p_PetscRandom {
21: PETSCHEADER(int)
22: unsigned long seed;
23: Scalar low,width; /* lower bound and width of the interval over
24: which the random numbers are distributed */
25: PetscTruth iset; /* if true, indicates that the user has set the interval */
26: /* array for shuffling ??? */
27: };
29: /*@C
30: PetscRandomDestroy - Destroys a context that has been formed by
31: PetscRandomCreate().
33: Collective on PetscRandom
35: Intput Parameter:
36: . r - the random number generator context
38: Level: intermediate
40: .seealso: PetscRandomGetValue(), PetscRandomCreate(), VecSetRandom()
41: @*/
42: int PetscRandomDestroy(PetscRandom r)
43: {
46: if (--r->refct > 0) return(0);
48: PetscLogObjectDestroy((PetscObject)r);
49: PetscHeaderDestroy((PetscObject)r);
50: return(0);
51: }
53: /*@C
54: PetscRandomSetInterval - Sets the interval over which the random numbers
55: will be randomly distributed. By default, this interval is [0,1).
57: Collective on PetscRandom
59: Input Parameters:
60: . r - the random number generator context
62: Example of Usage:
63: .vb
64: PetscRandomCreate(PETSC_COMM_WORLD,RANDOM_DEFAULT,&r);
65: PetscRandomSetInterval(RANDOM_DEFAULT,&r);
66: PetscRandomGetValue(r,&value1);
67: PetscRandomGetValue(r,&value2);
68: PetscRandomDestroy(r);
69: .ve
71: Level: intermediate
73: Concepts: random numbers^range
75: .seealso: PetscRandomCreate()
76: @*/
77: int PetscRandomSetInterval(PetscRandom r,Scalar low,Scalar high)
78: {
81: #if defined(PETSC_USE_COMPLEX)
82: if (PetscRealPart(low) >= PetscRealPart(high)) SETERRQ(PETSC_ERR_ARG_OUTOFRANGE,"only low < high");
83: if (PetscImaginaryPart(low) >= PetscImaginaryPart(high)) SETERRQ(PETSC_ERR_ARG_OUTOFRANGE,"only low < high");
84: #else
85: if (low >= high) SETERRQ2(PETSC_ERR_ARG_OUTOFRANGE,"only low < high: Instead %g %g",low,high);
86: #endif
87: r->low = low;
88: r->width = high-low;
89: r->iset = PETSC_TRUE;
90: return(0);
91: }
93: /*
94: For now we have set up using the DRAND48() generater. We need to deal
95: with other variants of random number generators. We should also add
96: a routine to enable restarts [seed48()]
97: */
98: #if defined(PETSC_HAVE_DRAND48)
99: EXTERN_C_BEGIN
100: extern double drand48();
101: extern void srand48(long);
102: EXTERN_C_END
104: /*@C
105: PetscRandomCreate - Creates a context for generating random numbers,
106: and initializes the random-number generator.
108: Collective on MPI_Comm
110: Input Parameters:
111: + comm - MPI communicator
112: - type - the type of random numbers to be generated, usually RANDOM_DEFAULT
114: Output Parameter:
115: . r - the random number generator context
117: Level: intermediate
119: Notes:
120: By default, we generate random numbers via srand48()/drand48() that
121: are uniformly distributed over [0,1). The user can shift and stretch
122: this interval by calling PetscRandomSetInterval().
123:
124: Currently three types of random numbers are supported. These types
125: are equivalent when working with real numbers.
126: . RANDOM_DEFAULT - both real and imaginary components are random
127: . RANDOM_DEFAULT_REAL - real component is random; imaginary component is 0
128: . RANDOM_DEFAULT_IMAGINARY - imaginary component is random; real component is 0
130: Use VecSetRandom() to set the elements of a vector to random numbers.
132: Example of Usage:
133: .vb
134: PetscRandomCreate(PETSC_COMM_SELF,RANDOM_DEFAULT,&r);
135: PetscRandomGetValue(r,&value1);
136: PetscRandomGetValue(r,&value2);
137: PetscRandomGetValue(r,&value3);
138: PetscRandomDestroy(r);
139: .ve
141: Concepts: random numbers^creating
143: .seealso: PetscRandomGetValue(), PetscRandomSetInterval(), PetscRandomDestroy(), VecSetRandom()
144: @*/
145: int PetscRandomCreate(MPI_Comm comm,PetscRandomType type,PetscRandom *r)
146: {
147: PetscRandom rr;
148: int ierr,rank;
151: *r = 0;
152: if (type != RANDOM_DEFAULT && type != RANDOM_DEFAULT_REAL && type != RANDOM_DEFAULT_IMAGINARY){
153: SETERRQ(PETSC_ERR_SUP,"Not for this random number type");
154: }
155: PetscHeaderCreate(rr,_p_PetscRandom,int,PETSCRANDOM_COOKIE,type,"random",comm,PetscRandomDestroy,0);
156: PetscLogObjectCreate(rr);
157: rr->low = 0.0;
158: rr->width = 1.0;
159: rr->iset = PETSC_FALSE;
160: rr->seed = 0;
161: MPI_Comm_rank(comm,&rank);
162: srand48(0x12345678+rank);
163: *r = rr;
164: return(0);
165: }
167: /*@C
168: PetscRandomGetValue - Generates a random number. Call this after first calling
169: PetscRandomCreate().
171: Not Collective
173: Intput Parameter:
174: . r - the random number generator context
176: Output Parameter:
177: . val - the value
179: Level: intermediate
181: Notes:
182: Use VecSetRandom() to set the elements of a vector to random numbers.
184: Example of Usage:
185: .vb
186: PetscRandomCreate(PETSC_COMM_WORLD,RANDOM_DEFAULT,&r);
187: PetscRandomGetValue(r,&value1);
188: PetscRandomGetValue(r,&value2);
189: PetscRandomGetValue(r,&value3);
190: PetscRandomDestroy(r);
191: .ve
193: Concepts: random numbers^getting
195: .seealso: PetscRandomCreate(), PetscRandomDestroy(), VecSetRandom()
196: @*/
197: int PetscRandomGetValue(PetscRandom r,Scalar *val)
198: {
201: #if defined(PETSC_USE_COMPLEX)
202: if (r->type == RANDOM_DEFAULT) {
203: if (r->iset == PETSC_TRUE) {
204: *val = PetscRealPart(r->width)*drand48() + PetscRealPart(r->low) +
205: (PetscImaginaryPart(r->width)*drand48() + PetscImaginaryPart(r->low)) * PETSC_i;
206: }
207: else *val = drand48() + drand48()*PETSC_i;
208: } else if (r->type == RANDOM_DEFAULT_REAL) {
209: if (r->iset == PETSC_TRUE) *val = PetscRealPart(r->width)*drand48() + PetscRealPart(r->low);
210: else *val = drand48();
211: } else if (r->type == RANDOM_DEFAULT_IMAGINARY) {
212: if (r->iset == PETSC_TRUE) *val = (PetscImaginaryPart(r->width)*drand48()+PetscImaginaryPart(r->low))*PETSC_i;
213: else *val = drand48()*PETSC_i;
214: } else {
215: SETERRQ(PETSC_ERR_ARG_OUTOFRANGE,"Invalid random number type");
216: }
217: #else
218: if (r->iset == PETSC_TRUE) *val = r->width * drand48() + r->low;
219: else *val = drand48();
220: #endif
221: return(0);
222: }
224: #elif defined(PETSC_HAVE_RAND)
226: int PetscRandomCreate(MPI_Comm comm,PetscRandomType type,PetscRandom *r)
227: {
228: PetscRandom rr;
229: int rank,ierr;
232: PetscLogInfo(0,"PetscRandomCreate: using rand(). not as efficinet as dran48n");
233: *r = 0;
234: if (type != RANDOM_DEFAULT && type != RANDOM_DEFAULT_REAL && type != RANDOM_DEFAULT_IMAGINARY) {
235: SETERRQ(PETSC_ERR_SUP,"Not for this random number type");
236: }
237: PetscHeaderCreate(rr,_p_PetscRandom,int,PETSCRANDOM_COOKIE,type,"random",comm,PetscRandomDestroy,0);
238: PetscLogObjectCreate(rr);
239: rr->low = 0.0;
240: rr->width = 1.0;
241: rr->iset = PETSC_FALSE;
242: rr->seed = 0;
243: MPI_Comm_rank(comm,&rank);
244: srand(0x12345678+rank);
245: *r = rr;
246: return(0);
247: }
249: #define RAND_WRAP() (rand()/(double)(RAND_MAX+1))
250: int PetscRandomGetValue(PetscRandom r,Scalar *val)
251: {
254: #if defined(PETSC_USE_COMPLEX)
255: if (r->type == RANDOM_DEFAULT) {
256: if (r->iset == PETSC_TRUE)
257: *val = PetscRealPart(r->width)*RAND_WRAP() + PetscRealPart(r->low) +
258: (PetscImaginaryPart(r->width)*RAND_WRAP() + PetscImaginaryPart(r->low)) * PETSC_i;
259: else *val = RAND_WRAP() + RAND_WRAP()*PETSC_i;
260: } else if (r->type == RANDOM_DEFAULT_REAL) {
261: if (r->iset == PETSC_TRUE) *val = PetscRealPart(r->width)*RAND_WRAP() + PetscRealPart(r->low);
262: else *val = RAND_WRAP();
263: } else if (r->type == RANDOM_DEFAULT_IMAGINARY) {
264: if (r->iset == PETSC_TRUE) *val = (PetscImaginaryPart(r->width)*RAND_WRAP()+PetscImaginaryPart(r->low))*PETSC_i;
265: else *val = RAND_WRAP()*PETSC_i;
266: } else SETERRQ(PETSC_ERR_ARG_OUTOFRANGE,"Invalid random number type");
267: #else
268: if (r->iset == PETSC_TRUE) *val = r->width * RAND_WRAP() + r->low;
269: else *val = RAND_WRAP();
270: #endif
271: return(0);
272: }
274: #else
275: /* Should put a simple, portable random number generator here? */
277: extern double drand48();
279: int PetscRandomCreate(MPI_Comm comm,PetscRandomType type,PetscRandom *r)
280: {
281: PetscRandom rr;
282: char arch[10];
283: int ierr;
286: *r = 0;
287: if (type != RANDOM_DEFAULT) SETERRQ(PETSC_ERR_SUP,"Not for this random number type");
288: PetscHeaderCreate(rr,_p_PetscRandom,int,PETSCRANDOM_COOKIE,type,"random",comm,PetscRandomDestroy,0);
289: PetscLogObjectCreate(rr);
290: *r = rr;
291: PetscGetArchType(arch,10);
292: PetscPrintf(comm,"PetscRandomCreate: Warning: Random number generator not set for machine %s; using fake random numbers.n",arch);
293: return(0);
294: }
296: int PetscRandomGetValue(PetscRandom r,Scalar *val)
297: {
300: #if defined(PETSC_USE_COMPLEX)
301: *val = (0.5,0.5);
302: #else
303: *val = 0.5;
304: #endif
305: return(0);
306: }
307: #endif