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
 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