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: /*@C
 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:    PetscRandomSetInterval - Sets the interval over which the random numbers
 72:    will be randomly distributed.  By default, this interval is [0,1).

 74:    Collective on PetscRandom

 76:    Input Parameters:
 77: .  r  - the random number generator context

 79:    Example of Usage:
 80: .vb
 81:       PetscRandomCreate(PETSC_COMM_WORLD,RANDOM_DEFAULT,&r);
 82:       PetscRandomSetInterval(RANDOM_DEFAULT,&r);
 83:       PetscRandomGetValue(r,&value1);
 84:       PetscRandomGetValue(r,&value2);
 85:       PetscRandomDestroy(r);
 86: .ve

 88:    Level: intermediate

 90:    Concepts: random numbers^range

 92: .seealso: PetscRandomCreate()
 93: @*/
 94: PetscErrorCode PETSC_DLLEXPORT PetscRandomSetInterval(PetscRandom r,PetscScalar low,PetscScalar high)
 95: {
 98: #if defined(PETSC_USE_COMPLEX)
 99:   if (PetscRealPart(low) >= PetscRealPart(high))           SETERRQ(PETSC_ERR_ARG_OUTOFRANGE,"only low < high");
100:   if (PetscImaginaryPart(low) >= PetscImaginaryPart(high)) SETERRQ(PETSC_ERR_ARG_OUTOFRANGE,"only low < high");
101: #else
102:   if (low >= high) SETERRQ2(PETSC_ERR_ARG_OUTOFRANGE,"only low < high: Instead %g %g",low,high);
103: #endif
104:   r->low   = low;
105:   r->width = high-low;
106:   r->iset  = PETSC_TRUE;
107:   return(0);
108: }

110: /*
111:    For now we have set up using the DRAND48() generater. We need to deal 
112:    with other variants of random number generators. We should also add
113:    a routine to enable restarts [seed48()] 
114: */
115: #if defined(PETSC_HAVE_DRAND48)

119: /*@C
120:    PetscRandomCreate - Creates a context for generating random numbers,
121:    and initializes the random-number generator.

123:    Collective on MPI_Comm

125:    Input Parameters:
126: +  comm - MPI communicator
127: -  type - the type of random numbers to be generated, usually RANDOM_DEFAULT

129:    Output Parameter:
130: .  r  - the random number generator context

132:    Level: intermediate

134:    Notes:
135:    By default, we generate random numbers via srand48()/drand48() that
136:    are uniformly distributed over [0,1).  The user can shift and stretch
137:    this interval by calling PetscRandomSetInterval().
138:   
139:    Currently three types of random numbers are supported. These types
140:    are equivalent when working with real numbers.
141: .     RANDOM_DEFAULT - both real and imaginary components are random
142: .     RANDOM_DEFAULT_REAL - real component is random; imaginary component is 0
143: .     RANDOM_DEFAULT_IMAGINARY - imaginary component is random; real component is 0

145:    Use VecSetRandom() to set the elements of a vector to random numbers.

147:    Example of Usage:
148: .vb
149:       PetscRandomCreate(PETSC_COMM_SELF,RANDOM_DEFAULT,&r);
150:       PetscRandomGetValue(r,&value1);
151:       PetscRandomGetValue(r,&value2);
152:       PetscRandomGetValue(r,&value3);
153:       PetscRandomDestroy(r);
154: .ve

156:    Concepts: random numbers^creating

158: .seealso: PetscRandomGetValue(), PetscRandomSetInterval(), PetscRandomDestroy(), VecSetRandom()
159: @*/
160: PetscErrorCode PETSC_DLLEXPORT PetscRandomCreate(MPI_Comm comm,PetscRandomType type,PetscRandom *r)
161: {
162:   PetscRandom    rr;
164:   PetscMPIInt    rank;

167:   *r = 0;
168:   if (type != RANDOM_DEFAULT && type != RANDOM_DEFAULT_REAL && type != RANDOM_DEFAULT_IMAGINARY){
169:     SETERRQ(PETSC_ERR_SUP,"Not for this random number type");
170:   }
171:   PetscHeaderCreate(rr,_p_PetscRandom,int,PETSC_RANDOM_COOKIE,type,"random",comm,PetscRandomDestroy,0);
172:   rr->low   = 0.0;
173:   rr->width = 1.0;
174:   rr->iset  = PETSC_FALSE;
175:   rr->seed  = 0;
176:   MPI_Comm_rank(comm,&rank);
177:   srand48(0x12345678+rank);
178:   *r = rr;
179:   return(0);
180: }

184: /*@C
185:    PetscRandomGetValue - Generates a random number.  Call this after first calling
186:    PetscRandomCreate().

188:    Not Collective

190:    Intput Parameter:
191: .  r  - the random number generator context

193:    Output Parameter:
194: .  val - the value

196:    Level: intermediate

198:    Notes:
199:    Use VecSetRandom() to set the elements of a vector to random numbers.

201:    Example of Usage:
202: .vb
203:       PetscRandomCreate(PETSC_COMM_WORLD,RANDOM_DEFAULT,&r);
204:       PetscRandomGetValue(r,&value1);
205:       PetscRandomGetValue(r,&value2);
206:       PetscRandomGetValue(r,&value3);
207:       PetscRandomDestroy(r);
208: .ve

210:    Concepts: random numbers^getting

212: .seealso: PetscRandomCreate(), PetscRandomDestroy(), VecSetRandom()
213: @*/
214: PetscErrorCode PETSC_DLLEXPORT PetscRandomGetValue(PetscRandom r,PetscScalar *val)
215: {
219: #if defined(PETSC_USE_COMPLEX)
220:   if (r->type == RANDOM_DEFAULT) {
221:     if (r->iset) {
222:          *val = PetscRealPart(r->width)*drand48() + PetscRealPart(r->low) +
223:                 (PetscImaginaryPart(r->width)*drand48() + PetscImaginaryPart(r->low)) * PETSC_i;
224:     }
225:     else *val = drand48() + drand48()*PETSC_i;
226:   } else if (r->type == RANDOM_DEFAULT_REAL) {
227:     if (r->iset) *val = PetscRealPart(r->width)*drand48() + PetscRealPart(r->low);
228:     else                       *val = drand48();
229:   } else if (r->type == RANDOM_DEFAULT_IMAGINARY) {
230:     if (r->iset) *val = (PetscImaginaryPart(r->width)*drand48()+PetscImaginaryPart(r->low))*PETSC_i;
231:     else         *val = drand48()*PETSC_i;
232:   } else {
233:     SETERRQ(PETSC_ERR_ARG_OUTOFRANGE,"Invalid random number type");
234:   }
235: #else
236:   if (r->iset) *val = r->width * drand48() + r->low;
237:   else         *val = drand48();
238: #endif
239:   return(0);
240: }

242: #elif defined(PETSC_HAVE_RAND)

246: PetscErrorCode PETSC_DLLEXPORT PetscRandomCreate(MPI_Comm comm,PetscRandomType type,PetscRandom *r)
247: {
248:   PetscRandom    rr;
250:   PetscMPIInt    rank;

253:   PetscLogInfo((0,"PetscRandomCreate: using rand(). not as efficinet as dran48\n"));
254:   *r = 0;
255:   if (type != RANDOM_DEFAULT && type != RANDOM_DEFAULT_REAL && type != RANDOM_DEFAULT_IMAGINARY) {
256:     SETERRQ(PETSC_ERR_SUP,"Not for this random number type");
257:   }
258:   PetscHeaderCreate(rr,_p_PetscRandom,int,PETSC_RANDOM_COOKIE,type,"random",comm,PetscRandomDestroy,0);
259:   rr->low   = 0.0;
260:   rr->width = 1.0;
261:   rr->iset  = PETSC_FALSE;
262:   rr->seed  = 0;
263:   MPI_Comm_rank(comm,&rank);
264:   srand(0x12345678+rank);
265:   *r = rr;
266:   return(0);
267: }

269: #define RAND_WRAP() (rand()/(double)((unsigned int)RAND_MAX+1))
272: PetscErrorCode PETSC_DLLEXPORT PetscRandomGetValue(PetscRandom r,PetscScalar *val)
273: {
277: #if defined(PETSC_USE_COMPLEX)
278:   if (r->type == RANDOM_DEFAULT) {
279:     if (r->iset)
280:          *val = PetscRealPart(r->width)*RAND_WRAP() + PetscRealPart(r->low) +
281:                 (PetscImaginaryPart(r->width)*RAND_WRAP() + PetscImaginaryPart(r->low)) * PETSC_i;
282:     else *val = RAND_WRAP() + RAND_WRAP()*PETSC_i;
283:   } else if (r->type == RANDOM_DEFAULT_REAL) {
284:     if (r->iset) *val = PetscRealPart(r->width)*RAND_WRAP() + PetscRealPart(r->low);
285:     else         *val = RAND_WRAP();
286:   } else if (r->type == RANDOM_DEFAULT_IMAGINARY) {
287:     if (r->iset) *val = (PetscImaginaryPart(r->width)*RAND_WRAP()+PetscImaginaryPart(r->low))*PETSC_i;
288:     else         *val = RAND_WRAP()*PETSC_i;
289:   } else SETERRQ(PETSC_ERR_ARG_OUTOFRANGE,"Invalid random number type");
290: #else
291:   if (r->iset) *val = r->width * RAND_WRAP() + r->low;
292:   else         *val = RAND_WRAP();
293: #endif
294:   return(0);
295: }

297: #else
298: /* Should put a simple, portable random number generator here? */

302: PetscErrorCode PETSC_DLLEXPORT PetscRandomCreate(MPI_Comm comm,PetscRandomType type,PetscRandom *r)
303: {
304:   PetscRandom    rr;
305:   char           arch[10];

309:   *r = 0;
310:   if (type != RANDOM_DEFAULT) SETERRQ(PETSC_ERR_SUP,"Not for this random number type");
311:   PetscHeaderCreate(rr,_p_PetscRandom,int,PETSC_RANDOM_COOKIE,type,"random",comm,PetscRandomDestroy,0);
312:   *r = rr;
313:   PetscGetArchType(arch,10);
314:   PetscPrintf(comm,"PetscRandomCreate: Warning: Random number generator not set for machine %s; using fake random numbers.\n",arch);
315:   return(0);
316: }

320: PetscErrorCode PETSC_DLLEXPORT PetscRandomGetValue(PetscRandom r,PetscScalar *val)
321: {
325: #if defined(PETSC_USE_COMPLEX)
326:   *val = (0.5,0.5);
327: #else
328:   *val = 0.5;
329: #endif
330:   return(0);
331: }
332: #endif