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