Actual source code: random.c

  1: /*$Id: random.c,v 1.60 2001/08/07 03:02:06 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: int PETSC_RANDOM_COOKIE;

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

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

 35:    Collective on PetscRandom

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

 40:    Level: intermediate

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

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

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

 59:    Collective on PetscRandom

 61:    Input Parameters:
 62: .  r  - the random number generator context

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

 73:    Level: intermediate

 75:    Concepts: random numbers^range

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

 95: /*
 96:    For now we have set up using the DRAND48() generater. We need to deal 
 97:    with other variants of random number generators. We should also add
 98:    a routine to enable restarts [seed48()] 
 99: */
100: #if defined(PETSC_HAVE_DRAND48)
101: EXTERN_C_BEGIN
102: extern double drand48();
103: extern void   srand48(long);
104: EXTERN_C_END

106: /*@C
107:    PetscRandomCreate - Creates a context for generating random numbers,
108:    and initializes the random-number generator.

110:    Collective on MPI_Comm

112:    Input Parameters:
113: +  comm - MPI communicator
114: -  type - the type of random numbers to be generated, usually RANDOM_DEFAULT

116:    Output Parameter:
117: .  r  - the random number generator context

119:    Level: intermediate

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

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

134:    Example of Usage:
135: .vb
136:       PetscRandomCreate(PETSC_COMM_SELF,RANDOM_DEFAULT,&r);
137:       PetscRandomGetValue(r,&value1);
138:       PetscRandomGetValue(r,&value2);
139:       PetscRandomGetValue(r,&value3);
140:       PetscRandomDestroy(r);
141: .ve

143:    Concepts: random numbers^creating

145: .seealso: PetscRandomGetValue(), PetscRandomSetInterval(), PetscRandomDestroy(), VecSetRandom()
146: @*/
147: int PetscRandomCreate(MPI_Comm comm,PetscRandomType type,PetscRandom *r)
148: {
149:   PetscRandom rr;
150:   int         ierr,rank;

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

169: /*@C
170:    PetscRandomGetValue - Generates a random number.  Call this after first calling
171:    PetscRandomCreate().

173:    Not Collective

175:    Intput Parameter:
176: .  r  - the random number generator context

178:    Output Parameter:
179: .  val - the value

181:    Level: intermediate

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

186:    Example of Usage:
187: .vb
188:       PetscRandomCreate(PETSC_COMM_WORLD,RANDOM_DEFAULT,&r);
189:       PetscRandomGetValue(r,&value1);
190:       PetscRandomGetValue(r,&value2);
191:       PetscRandomGetValue(r,&value3);
192:       PetscRandomDestroy(r);
193: .ve

195:    Concepts: random numbers^getting

197: .seealso: PetscRandomCreate(), PetscRandomDestroy(), VecSetRandom()
198: @*/
199: int PetscRandomGetValue(PetscRandom r,PetscScalar *val)
200: {
203: #if defined(PETSC_USE_COMPLEX)
204:   if (r->type == RANDOM_DEFAULT) {
205:     if (r->iset == PETSC_TRUE) {
206:          *val = PetscRealPart(r->width)*drand48() + PetscRealPart(r->low) +
207:                 (PetscImaginaryPart(r->width)*drand48() + PetscImaginaryPart(r->low)) * PETSC_i;
208:     }
209:     else *val = drand48() + drand48()*PETSC_i;
210:   } else if (r->type == RANDOM_DEFAULT_REAL) {
211:     if (r->iset == PETSC_TRUE) *val = PetscRealPart(r->width)*drand48() + PetscRealPart(r->low);
212:     else                       *val = drand48();
213:   } else if (r->type == RANDOM_DEFAULT_IMAGINARY) {
214:     if (r->iset == PETSC_TRUE) *val = (PetscImaginaryPart(r->width)*drand48()+PetscImaginaryPart(r->low))*PETSC_i;
215:     else                       *val = drand48()*PETSC_i;
216:   } else {
217:     SETERRQ(PETSC_ERR_ARG_OUTOFRANGE,"Invalid random number type");
218:   }
219: #else
220:   if (r->iset == PETSC_TRUE) *val = r->width * drand48() + r->low;
221:   else                       *val = drand48();
222: #endif
223:   return(0);
224: }

226: #elif defined(PETSC_HAVE_RAND)

228: int PetscRandomCreate(MPI_Comm comm,PetscRandomType type,PetscRandom *r)
229: {
230:   PetscRandom rr;
231:   int      rank,ierr;

234:   PetscLogInfo(0,"PetscRandomCreate: using rand(). not as efficinet as dran48n");
235:   *r = 0;
236:   if (type != RANDOM_DEFAULT && type != RANDOM_DEFAULT_REAL && type != RANDOM_DEFAULT_IMAGINARY) {
237:     SETERRQ(PETSC_ERR_SUP,"Not for this random number type");
238:   }
239:   PetscHeaderCreate(rr,_p_PetscRandom,int,PETSC_RANDOM_COOKIE,type,"random",comm,PetscRandomDestroy,0);
240:   PetscLogObjectCreate(rr);
241:   rr->low   = 0.0;
242:   rr->width = 1.0;
243:   rr->iset  = PETSC_FALSE;
244:   rr->seed  = 0;
245:   MPI_Comm_rank(comm,&rank);
246:   srand(0x12345678+rank);
247:   *r = rr;
248:   return(0);
249: }

251: #define RAND_WRAP() (rand()/(double)((unsigned int)RAND_MAX+1))
252: int PetscRandomGetValue(PetscRandom r,PetscScalar *val)
253: {
256: #if defined(PETSC_USE_COMPLEX)
257:   if (r->type == RANDOM_DEFAULT) {
258:     if (r->iset == PETSC_TRUE)
259:          *val = PetscRealPart(r->width)*RAND_WRAP() + PetscRealPart(r->low) +
260:                 (PetscImaginaryPart(r->width)*RAND_WRAP() + PetscImaginaryPart(r->low)) * PETSC_i;
261:     else *val = RAND_WRAP() + RAND_WRAP()*PETSC_i;
262:   } else if (r->type == RANDOM_DEFAULT_REAL) {
263:     if (r->iset == PETSC_TRUE) *val = PetscRealPart(r->width)*RAND_WRAP() + PetscRealPart(r->low);
264:     else                       *val = RAND_WRAP();
265:   } else if (r->type == RANDOM_DEFAULT_IMAGINARY) {
266:     if (r->iset == PETSC_TRUE) *val = (PetscImaginaryPart(r->width)*RAND_WRAP()+PetscImaginaryPart(r->low))*PETSC_i;
267:     else                       *val = RAND_WRAP()*PETSC_i;
268:   } else SETERRQ(PETSC_ERR_ARG_OUTOFRANGE,"Invalid random number type");
269: #else
270:   if (r->iset == PETSC_TRUE) *val = r->width * RAND_WRAP() + r->low;
271:   else                       *val = RAND_WRAP();
272: #endif
273:   return(0);
274: }

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

279: extern double drand48();

281: int PetscRandomCreate(MPI_Comm comm,PetscRandomType type,PetscRandom *r)
282: {
283:   PetscRandom rr;
284:   char        arch[10];
285:   int         ierr;

288:   *r = 0;
289:   if (type != RANDOM_DEFAULT) SETERRQ(PETSC_ERR_SUP,"Not for this random number type");
290:   PetscHeaderCreate(rr,_p_PetscRandom,int,PETSC_RANDOM_COOKIE,type,"random",comm,PetscRandomDestroy,0);
291:   PetscLogObjectCreate(rr);
292:   *r = rr;
293:   PetscGetArchType(arch,10);
294:   PetscPrintf(comm,"PetscRandomCreate: Warning: Random number generator not set for machine %s; using fake random numbers.n",arch);
295:   return(0);
296: }

298: int PetscRandomGetValue(PetscRandom r,PetscScalar *val)
299: {
302: #if defined(PETSC_USE_COMPLEX)
303:   *val = (0.5,0.5);
304: #else
305:   *val = 0.5;
306: #endif
307:   return(0);
308: }
309: #endif