Actual source code: random.c

  1: /*
  2:     This file contains routines for interfacing to random number generators.
  3:     This provides more than just an interface to some system random number
  4:     generator:

  6:     Numbers can be shuffled for use as random tuples

  8:     Multiple random number generators may be used

 10:     We are still not sure what interface we want here.  There should be
 11:     one to reinitialize and set the seed.
 12:  */

 14:  #include petsc.h
 15:  #include petscsys.h
 16: #include <stdlib.h>

 18: PetscCookie PETSC_RANDOM_COOKIE = 0;

 20: /* Private data */
 21: struct _p_PetscRandom {
 22:   PETSCHEADER(int)
 23:   unsigned    long seed;
 24:   PetscScalar low,width;       /* lower bound and width of the interval over
 25:                                   which the random numbers are distributed */
 26:   PetscTruth  iset;             /* if true, indicates that the user has set the interval */
 27:   /* array for shuffling ??? */
 28: };

 32: /*@C
 33:    PetscRandomDestroy - Destroys a context that has been formed by 
 34:    PetscRandomCreate().

 36:    Collective on PetscRandom

 38:    Intput Parameter:
 39: .  r  - the random number generator context

 41:    Level: intermediate

 43: .seealso: PetscRandomGetValue(), PetscRandomCreate(), VecSetRandom()
 44: @*/
 45: PetscErrorCode PetscRandomDestroy(PetscRandom r)
 46: {
 49:   if (--r->refct > 0) return(0);

 51:   PetscLogObjectDestroy((PetscObject)r);
 52:   PetscHeaderDestroy((PetscObject)r);
 53:   return(0);
 54: }

 58: /*@C
 59:    PetscRandomSetInterval - Sets the interval over which the random numbers
 60:    will be randomly distributed.  By default, this interval is [0,1).

 62:    Collective on PetscRandom

 64:    Input Parameters:
 65: .  r  - the random number generator context

 67:    Example of Usage:
 68: .vb
 69:       PetscRandomCreate(PETSC_COMM_WORLD,RANDOM_DEFAULT,&r);
 70:       PetscRandomSetInterval(RANDOM_DEFAULT,&r);
 71:       PetscRandomGetValue(r,&value1);
 72:       PetscRandomGetValue(r,&value2);
 73:       PetscRandomDestroy(r);
 74: .ve

 76:    Level: intermediate

 78:    Concepts: random numbers^range

 80: .seealso: PetscRandomCreate()
 81: @*/
 82: PetscErrorCode PetscRandomSetInterval(PetscRandom r,PetscScalar low,PetscScalar high)
 83: {
 86: #if defined(PETSC_USE_COMPLEX)
 87:   if (PetscRealPart(low) >= PetscRealPart(high))           SETERRQ(PETSC_ERR_ARG_OUTOFRANGE,"only low < high");
 88:   if (PetscImaginaryPart(low) >= PetscImaginaryPart(high)) SETERRQ(PETSC_ERR_ARG_OUTOFRANGE,"only low < high");
 89: #else
 90:   if (low >= high) SETERRQ2(PETSC_ERR_ARG_OUTOFRANGE,"only low < high: Instead %g %g",low,high);
 91: #endif
 92:   r->low   = low;
 93:   r->width = high-low;
 94:   r->iset  = PETSC_TRUE;
 95:   return(0);
 96: }

 98: /*
 99:    For now we have set up using the DRAND48() generater. We need to deal 
100:    with other variants of random number generators. We should also add
101:    a routine to enable restarts [seed48()] 
102: */
103: #if defined(PETSC_HAVE_DRAND48)

111: /*@C
112:    PetscRandomCreate - Creates a context for generating random numbers,
113:    and initializes the random-number generator.

115:    Collective on MPI_Comm

117:    Input Parameters:
118: +  comm - MPI communicator
119: -  type - the type of random numbers to be generated, usually RANDOM_DEFAULT

121:    Output Parameter:
122: .  r  - the random number generator context

124:    Level: intermediate

126:    Notes:
127:    By default, we generate random numbers via srand48()/drand48() that
128:    are uniformly distributed over [0,1).  The user can shift and stretch
129:    this interval by calling PetscRandomSetInterval().
130:   
131:    Currently three types of random numbers are supported. These types
132:    are equivalent when working with real numbers.
133: .     RANDOM_DEFAULT - both real and imaginary components are random
134: .     RANDOM_DEFAULT_REAL - real component is random; imaginary component is 0
135: .     RANDOM_DEFAULT_IMAGINARY - imaginary component is random; real component is 0

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

139:    Example of Usage:
140: .vb
141:       PetscRandomCreate(PETSC_COMM_SELF,RANDOM_DEFAULT,&r);
142:       PetscRandomGetValue(r,&value1);
143:       PetscRandomGetValue(r,&value2);
144:       PetscRandomGetValue(r,&value3);
145:       PetscRandomDestroy(r);
146: .ve

148:    Concepts: random numbers^creating

150: .seealso: PetscRandomGetValue(), PetscRandomSetInterval(), PetscRandomDestroy(), VecSetRandom()
151: @*/
152: PetscErrorCode PetscRandomCreate(MPI_Comm comm,PetscRandomType type,PetscRandom *r)
153: {
154:   PetscRandom rr;
156:   int         rank;

159:   *r = 0;
160:   if (type != RANDOM_DEFAULT && type != RANDOM_DEFAULT_REAL && type != RANDOM_DEFAULT_IMAGINARY){
161:     SETERRQ(PETSC_ERR_SUP,"Not for this random number type");
162:   }
163:   PetscHeaderCreate(rr,_p_PetscRandom,int,PETSC_RANDOM_COOKIE,type,"random",comm,PetscRandomDestroy,0);
164:   PetscLogObjectCreate(rr);
165:   rr->low   = 0.0;
166:   rr->width = 1.0;
167:   rr->iset  = PETSC_FALSE;
168:   rr->seed  = 0;
169:   MPI_Comm_rank(comm,&rank);
170:   srand48(0x12345678+rank);
171:   *r = rr;
172:   return(0);
173: }

177: /*@C
178:    PetscRandomGetValue - Generates a random number.  Call this after first calling
179:    PetscRandomCreate().

181:    Not Collective

183:    Intput Parameter:
184: .  r  - the random number generator context

186:    Output Parameter:
187: .  val - the value

189:    Level: intermediate

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

194:    Example of Usage:
195: .vb
196:       PetscRandomCreate(PETSC_COMM_WORLD,RANDOM_DEFAULT,&r);
197:       PetscRandomGetValue(r,&value1);
198:       PetscRandomGetValue(r,&value2);
199:       PetscRandomGetValue(r,&value3);
200:       PetscRandomDestroy(r);
201: .ve

203:    Concepts: random numbers^getting

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

235: #elif defined(PETSC_HAVE_RAND)

239: PetscErrorCode PetscRandomCreate(MPI_Comm comm,PetscRandomType type,PetscRandom *r)
240: {
241:   PetscRandom rr;
243:   int      rank;

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

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

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


298: PetscErrorCode PetscRandomCreate(MPI_Comm comm,PetscRandomType type,PetscRandom *r)
299: {
300:   PetscRandom rr;
301:   char        arch[10];

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

317: PetscErrorCode PetscRandomGetValue(PetscRandom r,PetscScalar *val)
318: {
322: #if defined(PETSC_USE_COMPLEX)
323:   *val = (0.5,0.5);
324: #else
325:   *val = 0.5;
326: #endif
327:   return(0);
328: }
329: #endif