Actual source code: random.c
1: #define PETSC_DLL
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: #if defined (PETSC_HAVE_STDLIB_H)
18: #include <stdlib.h>
19: #else
20: /* maybe the protypes are missing */
21: #if defined(PETSC_HAVE_DRAND48)
26: #else
28: #endif
29: #endif
31: PetscCookie PETSC_DLLEXPORT PETSC_RANDOM_COOKIE = 0;
33: /* Private data */
34: struct _p_PetscRandom {
35: PETSCHEADER(int);
36: unsigned long seed;
37: PetscScalar low,width; /* lower bound and width of the interval over
38: which the random numbers are distributed */
39: PetscTruth iset; /* if true, indicates that the user has set the interval */
40: /* array for shuffling ??? */
41: };
45: /*@
46: PetscRandomDestroy - Destroys a context that has been formed by
47: PetscRandomCreate().
49: Collective on PetscRandom
51: Intput Parameter:
52: . r - the random number generator context
54: Level: intermediate
56: .seealso: PetscRandomGetValue(), PetscRandomCreate(), VecSetRandom()
57: @*/
58: PetscErrorCode PETSC_DLLEXPORT PetscRandomDestroy(PetscRandom r)
59: {
63: if (--r->refct > 0) return(0);
64: PetscHeaderDestroy(r);
65: return(0);
66: }
70: /*@C
71: PetscRandomGetInterval - Gets the interval over which the random numbers
72: will be randomly distributed. By default, this interval is [0,1).
74: Not collective
76: Input Parameters:
77: . r - the random number generator context
79: Output Parameters:
80: + low - The lower bound of the interval
81: - high - The upper bound of the interval
83: Level: intermediate
85: Concepts: random numbers^range
87: .seealso: PetscRandomCreate(), PetscRandomSetInterval()
88: @*/
89: PetscErrorCode PETSC_DLLEXPORT PetscRandomGetInterval(PetscRandom r,PetscScalar *low,PetscScalar *high)
90: {
93: if (low) {
95: *low = r->low;
96: }
97: if (high) {
99: *high = r->low+r->width;
100: }
101: return(0);
102: }
106: /*@C
107: PetscRandomSetInterval - Sets the interval over which the random numbers
108: will be randomly distributed. By default, this interval is [0,1).
110: Not collective
112: Input Parameters:
113: + r - the random number generator context
114: . low - The lower bound of the interval
115: - high - The upper bound of the interval
117: Level: intermediate
119: Concepts: random numbers^range
121: .seealso: PetscRandomCreate(), PetscRandomGetInterval()
122: @*/
123: PetscErrorCode PETSC_DLLEXPORT PetscRandomSetInterval(PetscRandom r,PetscScalar low,PetscScalar high)
124: {
127: #if defined(PETSC_USE_COMPLEX)
128: if (PetscRealPart(low) >= PetscRealPart(high)) SETERRQ(PETSC_ERR_ARG_OUTOFRANGE,"only low < high");
129: if (PetscImaginaryPart(low) >= PetscImaginaryPart(high)) SETERRQ(PETSC_ERR_ARG_OUTOFRANGE,"only low < high");
130: #else
131: if (low >= high) SETERRQ2(PETSC_ERR_ARG_OUTOFRANGE,"only low < high: Instead %G %G",low,high);
132: #endif
133: r->low = low;
134: r->width = high-low;
135: r->iset = PETSC_TRUE;
136: return(0);
137: }
141: /*@C
142: PetscRandomGetSeed - Gets the random seed.
144: Not collective
146: Input Parameters:
147: . r - The random number generator context
149: Output Parameter:
150: . seed - The random seed
152: Level: intermediate
154: Concepts: random numbers^seed
156: .seealso: PetscRandomCreate(), PetscRandomSetSeed(), PetscRandomSeed()
157: @*/
158: PetscErrorCode PETSC_DLLEXPORT PetscRandomGetSeed(PetscRandom r,unsigned long *seed)
159: {
162: if (seed) {
164: *seed = r->seed;
165: }
166: return(0);
167: }
171: /*@C
172: PetscRandomSetSeed - Sets the random seed.
174: Not collective
176: Input Parameters:
177: + r - The random number generator context
178: - seed - The random seed
180: Level: intermediate
182: Concepts: random numbers^seed
184: .seealso: PetscRandomCreate(), PetscRandomGetSeed(), PetscRandomSeed()
185: @*/
186: PetscErrorCode PETSC_DLLEXPORT PetscRandomSetSeed(PetscRandom r,unsigned long seed)
187: {
190: r->seed = seed;
191: return(0);
192: }
194: /*
195: For now we have set up using the DRAND48() generater. We need to deal
196: with other variants of random number generators. We should also add
197: a routine to enable restarts [seed48()]
198: */
199: #if defined(PETSC_HAVE_DRAND48)
203: /*@
204: PetscRandomCreate - Creates a context for generating random numbers,
205: and initializes the random-number generator.
207: Collective on MPI_Comm
209: Input Parameters:
210: + comm - MPI communicator
211: - type - the type of random numbers to be generated, usually RANDOM_DEFAULT
213: Output Parameter:
214: . r - the random number generator context
216: Level: intermediate
218: Notes:
219: By default, we generate random numbers via srand48()/drand48() that
220: are uniformly distributed over [0,1). The user can shift and stretch
221: this interval by calling PetscRandomSetInterval().
222:
223: Currently three types of random numbers are supported. These types
224: are equivalent when working with real numbers.
225: . RANDOM_DEFAULT - both real and imaginary components are random
226: . RANDOM_DEFAULT_REAL - real component is random; imaginary component is 0
227: . RANDOM_DEFAULT_IMAGINARY - imaginary component is random; real component is 0
229: Use VecSetRandom() to set the elements of a vector to random numbers.
231: Example of Usage:
232: .vb
233: PetscRandomCreate(PETSC_COMM_SELF,RANDOM_DEFAULT,&r);
234: PetscRandomGetValue(r,&value1);
235: PetscRandomGetValue(r,&value2);
236: PetscRandomGetValue(r,&value3);
237: PetscRandomDestroy(r);
238: .ve
240: Concepts: random numbers^creating
242: .seealso: PetscRandomGetValue(), PetscRandomSetInterval(), PetscRandomDestroy(), VecSetRandom()
243: @*/
244: PetscErrorCode PETSC_DLLEXPORT PetscRandomCreate(MPI_Comm comm,PetscRandomType type,PetscRandom *r)
245: {
246: PetscRandom rr;
248: PetscMPIInt rank;
251: *r = 0;
252: if (type != RANDOM_DEFAULT && type != RANDOM_DEFAULT_REAL && type != RANDOM_DEFAULT_IMAGINARY){
253: SETERRQ(PETSC_ERR_SUP,"Not for this random number type");
254: }
255: PetscHeaderCreate(rr,_p_PetscRandom,int,PETSC_RANDOM_COOKIE,type,"PetscRandom",comm,PetscRandomDestroy,0);
256: MPI_Comm_rank(comm,&rank);
257: rr->low = 0.0;
258: rr->width = 1.0;
259: rr->iset = PETSC_FALSE;
260: rr->seed = 0x12345678+rank;
261: srand48(rr->seed);
262: *r = rr;
263: return(0);
264: }
268: /*@C
269: PetscRandomSeed - Seed the generator.
271: Not collective
273: Input Parameters:
274: . r - The random number generator context
276: Level: intermediate
278: Concepts: random numbers^seed
280: .seealso: PetscRandomCreate(), PetscRandomGetSeed(), PetscRandomSetSeed()
281: @*/
282: PetscErrorCode PETSC_DLLEXPORT PetscRandomSeed(PetscRandom r)
283: {
286: srand48(r->seed);
287: return(0);
288: }
292: /*@
293: PetscRandomGetValue - Generates a random number. Call this after first calling
294: PetscRandomCreate().
296: Not Collective
298: Intput Parameter:
299: . r - the random number generator context
301: Output Parameter:
302: . val - the value
304: Level: intermediate
306: Notes:
307: Use VecSetRandom() to set the elements of a vector to random numbers.
309: Example of Usage:
310: .vb
311: PetscRandomCreate(PETSC_COMM_WORLD,RANDOM_DEFAULT,&r);
312: PetscRandomGetValue(r,&value1);
313: PetscRandomGetValue(r,&value2);
314: PetscRandomGetValue(r,&value3);
315: PetscRandomDestroy(r);
316: .ve
318: Concepts: random numbers^getting
320: .seealso: PetscRandomCreate(), PetscRandomDestroy(), VecSetRandom()
321: @*/
322: PetscErrorCode PETSC_DLLEXPORT PetscRandomGetValue(PetscRandom r,PetscScalar *val)
323: {
327: #if defined(PETSC_USE_COMPLEX)
328: if (r->type == RANDOM_DEFAULT) {
329: if (r->iset) {
330: *val = PetscRealPart(r->width)*drand48() + PetscRealPart(r->low) +
331: (PetscImaginaryPart(r->width)*drand48() + PetscImaginaryPart(r->low)) * PETSC_i;
332: }
333: else *val = drand48() + drand48()*PETSC_i;
334: } else if (r->type == RANDOM_DEFAULT_REAL) {
335: if (r->iset) *val = PetscRealPart(r->width)*drand48() + PetscRealPart(r->low);
336: else *val = drand48();
337: } else if (r->type == RANDOM_DEFAULT_IMAGINARY) {
338: if (r->iset) *val = (PetscImaginaryPart(r->width)*drand48()+PetscImaginaryPart(r->low))*PETSC_i;
339: else *val = drand48()*PETSC_i;
340: } else {
341: SETERRQ(PETSC_ERR_ARG_OUTOFRANGE,"Invalid random number type");
342: }
343: #else
344: if (r->iset) *val = r->width * drand48() + r->low;
345: else *val = drand48();
346: #endif
347: return(0);
348: }
350: #elif defined(PETSC_HAVE_RAND)
354: PetscErrorCode PETSC_DLLEXPORT PetscRandomCreate(MPI_Comm comm,PetscRandomType type,PetscRandom *r)
355: {
356: PetscRandom rr;
358: PetscMPIInt rank;
361: PetscInfo(0,"using rand(). not as efficinet as dran48\n");
362: *r = 0;
363: if (type != RANDOM_DEFAULT && type != RANDOM_DEFAULT_REAL && type != RANDOM_DEFAULT_IMAGINARY) {
364: SETERRQ(PETSC_ERR_SUP,"Not for this random number type");
365: }
366: PetscHeaderCreate(rr,_p_PetscRandom,int,PETSC_RANDOM_COOKIE,type,"PetscRandom",comm,PetscRandomDestroy,0);
367: MPI_Comm_rank(comm,&rank);
368: rr->low = 0.0;
369: rr->width = 1.0;
370: rr->iset = PETSC_FALSE;
371: rr->seed = 0x12345678+rank;
372: srand(rr->seed);
373: *r = rr;
374: return(0);
375: }
379: /*@C
380: PetscRandomSeed - Seed the generator.
382: Not collective
384: Input Parameters:
385: . r - The random number generator context
387: Level: intermediate
389: Concepts: random numbers^seed
391: .seealso: PetscRandomCreate(), PetscRandomGetSeed(), PetscRandomSetSeed()
392: @*/
393: PetscErrorCode PETSC_DLLEXPORT PetscRandomSeed(PetscRandom r)
394: {
397: srand(r->seed);
398: return(0);
399: }
401: #define RAND_WRAP() (rand()/(double)((unsigned int)RAND_MAX+1))
404: PetscErrorCode PETSC_DLLEXPORT PetscRandomGetValue(PetscRandom r,PetscScalar *val)
405: {
409: #if defined(PETSC_USE_COMPLEX)
410: if (r->type == RANDOM_DEFAULT) {
411: if (r->iset)
412: *val = PetscRealPart(r->width)*RAND_WRAP() + PetscRealPart(r->low) +
413: (PetscImaginaryPart(r->width)*RAND_WRAP() + PetscImaginaryPart(r->low)) * PETSC_i;
414: else *val = RAND_WRAP() + RAND_WRAP()*PETSC_i;
415: } else if (r->type == RANDOM_DEFAULT_REAL) {
416: if (r->iset) *val = PetscRealPart(r->width)*RAND_WRAP() + PetscRealPart(r->low);
417: else *val = RAND_WRAP();
418: } else if (r->type == RANDOM_DEFAULT_IMAGINARY) {
419: if (r->iset) *val = (PetscImaginaryPart(r->width)*RAND_WRAP()+PetscImaginaryPart(r->low))*PETSC_i;
420: else *val = RAND_WRAP()*PETSC_i;
421: } else SETERRQ(PETSC_ERR_ARG_OUTOFRANGE,"Invalid random number type");
422: #else
423: if (r->iset) *val = r->width * RAND_WRAP() + r->low;
424: else *val = RAND_WRAP();
425: #endif
426: return(0);
427: }
429: #else
430: /* Should put a simple, portable random number generator here? */
434: PetscErrorCode PETSC_DLLEXPORT PetscRandomCreate(MPI_Comm comm,PetscRandomType type,PetscRandom *r)
435: {
436: PetscRandom rr;
437: char arch[10];
441: *r = 0;
442: if (type != RANDOM_DEFAULT) SETERRQ(PETSC_ERR_SUP,"Not for this random number type");
443: PetscHeaderCreate(rr,_p_PetscRandom,int,PETSC_RANDOM_COOKIE,type,"PetscRandom",comm,PetscRandomDestroy,0);
444: *r = rr;
445: PetscGetArchType(arch,10);
446: PetscPrintf(comm,"PetscRandomCreate: Warning: Random number generator not set for machine %s; using fake random numbers.\n",arch);
447: return(0);
448: }
452: /*@C
453: PetscRandomSeed - Seed the generator.
455: Not collective
457: Input Parameters:
458: . r - The random number generator context
460: Level: intermediate
462: Concepts: random numbers^seed
464: .seealso: PetscRandomCreate(), PetscRandomGetSeed(), PetscRandomSetSeed()
465: @*/
466: PetscErrorCode PETSC_DLLEXPORT PetscRandomSeed(PetscRandom r)
467: {
470: return(0);
471: }
475: PetscErrorCode PETSC_DLLEXPORT PetscRandomGetValue(PetscRandom r,PetscScalar *val)
476: {
480: #if defined(PETSC_USE_COMPLEX)
481: *val = (0.5,0.5);
482: #else
483: *val = 0.5;
484: #endif
485: return(0);
486: }
487: #endif