Actual source code: randomc.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/private/randomimpl.h>

 16: /* Logging support */
 17: PetscClassId PETSC_RANDOM_CLASSID;

 19: /*@
 20:   PetscRandomDestroy - Destroys a `PetscRandom` object that was created by `PetscRandomCreate()`.

 22:   Collective

 24:   Input Parameter:
 25: . r - the random number generator object

 27:   Level: intermediate

 29: .seealso: `PetscRandom`, `PetscRandomGetValue()`, `PetscRandomCreate()`, `VecSetRandom()`
 30: @*/
 31: PetscErrorCode PetscRandomDestroy(PetscRandom *r)
 32: {
 33:   PetscFunctionBegin;
 34:   if (!*r) PetscFunctionReturn(PETSC_SUCCESS);
 36:   if (--((PetscObject)*r)->refct > 0) {
 37:     *r = NULL;
 38:     PetscFunctionReturn(PETSC_SUCCESS);
 39:   }
 40:   PetscTryTypeMethod(*r, destroy);
 41:   PetscCall(PetscHeaderDestroy(r));
 42:   PetscFunctionReturn(PETSC_SUCCESS);
 43: }

 45: /*@
 46:   PetscRandomGetSeed - Gets the random seed.

 48:   Not collective

 50:   Input Parameter:
 51: . r - The random number generator context

 53:   Output Parameter:
 54: . seed - The random seed

 56:   Level: intermediate

 58: .seealso: `PetscRandom`, `PetscRandomCreate()`, `PetscRandomSetSeed()`, `PetscRandomSeed()`
 59: @*/
 60: PetscErrorCode PetscRandomGetSeed(PetscRandom r, PetscInt64 *seed)
 61: {
 62:   PetscFunctionBegin;
 64:   if (seed) {
 65:     PetscAssertPointer(seed, 2);
 66:     *seed = (PetscInt64)r->seed;
 67:   }
 68:   PetscFunctionReturn(PETSC_SUCCESS);
 69: }

 71: /*@
 72:   PetscRandomSetSeed - Sets the random seed. You MUST call `PetscRandomSeed()` after this call to have the new seed used.

 74:   Not collective

 76:   Input Parameters:
 77: + r    - The random number generator context
 78: - seed - The random seed

 80:   Level: intermediate

 82:   Example Usage:
 83: .vb
 84:       PetscRandomSetSeed(r,a positive integer);
 85:       PetscRandomSeed(r);
 86:       PetscRandomGetValue() will now start with the new seed.

 88:       PetscRandomSeed(r) without a call to PetscRandomSetSeed() re-initializes
 89:       the seed. The random numbers generated will be the same as before.
 90: .ve

 92: .seealso: `PetscRandom`, `PetscRandomCreate()`, `PetscRandomGetSeed()`, `PetscRandomSeed()`
 93: @*/
 94: PetscErrorCode PetscRandomSetSeed(PetscRandom r, PetscInt64 seed)
 95: {
 96:   PetscFunctionBegin;
 98:   r->seed = (unsigned long)seed;
 99:   PetscCall(PetscInfo(NULL, "Setting seed to %d\n", (int)seed));
100:   PetscFunctionReturn(PETSC_SUCCESS);
101: }

103: /*
104:   PetscRandomSetTypeFromOptions_Private - Sets the type of random generator from user options. Defaults to type PETSCRAND48 or PETSCRAND.

106:   Collective

108:   Input Parameter:
109: . rnd - The random number generator context

111:   Level: intermediate

113: .seealso: `PetscRandomSetFromOptions()`, `PetscRandomSetType()`
114: */
115: static PetscErrorCode PetscRandomSetTypeFromOptions_Private(PetscRandom rnd, PetscOptionItems PetscOptionsObject)
116: {
117:   PetscBool   opt;
118:   const char *defaultType;
119:   char        typeName[256];

121:   PetscFunctionBegin;
122:   if (((PetscObject)rnd)->type_name) {
123:     defaultType = ((PetscObject)rnd)->type_name;
124:   } else {
125:     defaultType = PETSCRANDER48;
126:   }

128:   PetscCall(PetscRandomRegisterAll());
129:   PetscCall(PetscOptionsFList("-random_type", "PetscRandom type", "PetscRandomSetType", PetscRandomList, defaultType, typeName, sizeof(typeName), &opt));
130:   if (opt) {
131:     PetscCall(PetscRandomSetType(rnd, typeName));
132:   } else {
133:     PetscCall(PetscRandomSetType(rnd, defaultType));
134:   }
135:   PetscFunctionReturn(PETSC_SUCCESS);
136: }

138: /*@
139:   PetscRandomSetFromOptions - Configures the random number generator from the options database.

141:   Collective

143:   Input Parameter:
144: . rnd - The random number generator context

146:   Options Database Keys:
147: + -random_seed seed         - provide a seed to the random number generator
148: - -random_no_imaginary_part - makes the imaginary part of the random number zero, this is useful when you want the
149:                               same code to produce the same result when run with real numbers or complex numbers for regression testing purposes

151:   Level: beginner

153:   Note:
154:   Must be called after `PetscRandomCreate()` but before the rnd is used.

156: .seealso: `PetscRandom`, `PetscRandomCreate()`, `PetscRandomSetType()`
157: @*/
158: PetscErrorCode PetscRandomSetFromOptions(PetscRandom rnd)
159: {
160:   PetscBool set, noimaginary = PETSC_FALSE;
161:   PetscInt  seed;

163:   PetscFunctionBegin;

166:   PetscObjectOptionsBegin((PetscObject)rnd);

168:   /* Handle PetscRandom type options */
169:   PetscCall(PetscRandomSetTypeFromOptions_Private(rnd, PetscOptionsObject));

171:   /* Handle specific random generator's options */
172:   PetscTryTypeMethod(rnd, setfromoptions, PetscOptionsObject);
173:   PetscCall(PetscOptionsInt("-random_seed", "Seed to use to generate random numbers", "PetscRandomSetSeed", 0, &seed, &set));
174:   if (set) {
175:     PetscCall(PetscRandomSetSeed(rnd, (unsigned long int)seed));
176:     PetscCall(PetscRandomSeed(rnd));
177:   }
178:   PetscCall(PetscOptionsBool("-random_no_imaginary_part", "The imaginary part of the random number will be zero", "PetscRandomSetInterval", noimaginary, &noimaginary, &set));
179: #if PetscDefined(HAVE_COMPLEX)
180:   if (set) {
181:     if (noimaginary) {
182:       PetscScalar low, high;
183:       PetscCall(PetscRandomGetInterval(rnd, &low, &high));
184:       low  = low - PetscImaginaryPart(low);
185:       high = high - PetscImaginaryPart(high);
186:       PetscCall(PetscRandomSetInterval(rnd, low, high));
187:     }
188:   }
189: #endif
190:   PetscOptionsEnd();
191:   PetscCall(PetscRandomViewFromOptions(rnd, NULL, "-random_view"));
192:   PetscFunctionReturn(PETSC_SUCCESS);
193: }

195: /*@
196:   PetscRandomSetOptionsPrefix - Sets the prefix used for searching for all
197:   `PetscRandom` options in the database.

199:   Logically Collective

201:   Input Parameters:
202: + r      - the random number generator context
203: - prefix - the prefix to prepend to all option names

205:   Level: advanced

207:   Note:
208:   A hyphen (-) must NOT be given at the beginning of the prefix name.
209:   The first character of all runtime options is AUTOMATICALLY the hyphen.

211: .seealso: `PetscRandom`, `PetscRandomAppendOptionsPrefix()`, `PetscRandomSetFromOptions()`
212: @*/
213: PetscErrorCode PetscRandomSetOptionsPrefix(PetscRandom r, const char prefix[])
214: {
215:   PetscFunctionBegin;
217:   PetscCall(PetscObjectSetOptionsPrefix((PetscObject)r, prefix));
218:   PetscFunctionReturn(PETSC_SUCCESS);
219: }

221: /*@
222:   PetscRandomAppendOptionsPrefix - Appends to the prefix used for searching for all
223:   `PetscRandom` options in the database.

225:   Logically Collective

227:   Input Parameters:
228: + r      - the random number generator context
229: - prefix - the prefix string to prepend to all `PetscRandom` option requests

231:   Level: advanced

233:   Note:
234:   A hyphen (-) must NOT be given at the beginning of the prefix name.
235:   The first character of all runtime options is AUTOMATICALLY the hyphen.

237: .seealso: `PetscRandom`, `PetscRandomSetOptionsPrefix()`, `PetscRandomSetFromOptions()`
238: @*/
239: PetscErrorCode PetscRandomAppendOptionsPrefix(PetscRandom r, const char prefix[])
240: {
241:   PetscFunctionBegin;
243:   PetscCall(PetscObjectAppendOptionsPrefix((PetscObject)r, prefix));
244:   PetscFunctionReturn(PETSC_SUCCESS);
245: }

247: /*@
248:   PetscRandomGetOptionsPrefix - Gets the prefix used for searching for all
249:   `PetscRandom` options in the database.

251:   Not Collective

253:   Input Parameter:
254: . r - the random number generator context

256:   Output Parameter:
257: . prefix - pointer to the prefix string used

259:   Level: advanced

261: .seealso: `PetscRandom`, `PetscRandomSetOptionsPrefix()`, `PetscRandomAppendOptionsPrefix()`
262: @*/
263: PetscErrorCode PetscRandomGetOptionsPrefix(PetscRandom r, const char *prefix[])
264: {
265:   PetscFunctionBegin;
267:   PetscCall(PetscObjectGetOptionsPrefix((PetscObject)r, prefix));
268:   PetscFunctionReturn(PETSC_SUCCESS);
269: }

271: #if PetscDefined(HAVE_SAWS)
272: #include <petscviewersaws.h>
273: #endif

275: /*@
276:   PetscRandomViewFromOptions - View a `PetscRandom` object based on the options database

278:   Collective

280:   Input Parameters:
281: + A    - the random number generator context
282: . obj  - optional object that provides the prefix for the option names, pass `NULL` to use the options prefix of `A`
283: - name - command line option

285:   Options Database Key:
286: . -name viewer_specification - See `PetscOptionsCreateViewer()` for the values of `viewer_specification`

288:   Level: intermediate

290:   Note:
291:   This checks the options database, creates the viewer on-the-fly, uses it and then destroys it. Hence it should not be called in heavily used routines,
292:   rather `PetscOptionsCreateViewer()` should be used to construct the viewer once which can then be utilized in the heavily used routine.

294: .seealso: `PetscRandom`, `PetscRandomView()`, `PetscOptionsCreateViewer()`, `PetscObjectViewFromOptions()`, `PetscRandomCreate()`
295: @*/
296: PetscErrorCode PetscRandomViewFromOptions(PetscRandom A, PetscObject obj, const char name[])
297: {
298:   PetscFunctionBegin;
300:   PetscCall(PetscObjectViewFromOptions((PetscObject)A, obj, name));
301:   PetscFunctionReturn(PETSC_SUCCESS);
302: }

304: /*@
305:   PetscRandomView - Views a random number generator object.

307:   Collective

309:   Input Parameters:
310: + rnd    - The random number generator context
311: - viewer - an optional visualization context

313:   Level: beginner

315:   Note:
316:   The available visualization contexts include
317: +     `PETSC_VIEWER_STDOUT_SELF` - standard output (default)
318: -     `PETSC_VIEWER_STDOUT_WORLD` - synchronized standard
319:   output where only the first processor opens
320:   the file.  All other processors send their
321:   data to the first processor to print.

323: .seealso: `PetscRandom`, `PetscRealView()`, `PetscScalarView()`, `PetscIntView()`
324: @*/
325: PetscErrorCode PetscRandomView(PetscRandom rnd, PetscViewer viewer)
326: {
327:   PetscBool isascii;
328: #if PetscDefined(HAVE_SAWS)
329:   PetscBool issaws;
330: #endif

332:   PetscFunctionBegin;
335:   if (!viewer) PetscCall(PetscViewerASCIIGetStdout(PetscObjectComm((PetscObject)rnd), &viewer));
337:   PetscCheckSameComm(rnd, 1, viewer, 2);
338:   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERASCII, &isascii));
339: #if PetscDefined(HAVE_SAWS)
340:   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERSAWS, &issaws));
341: #endif
342:   if (isascii) {
343:     PetscMPIInt rank;
344:     PetscCall(PetscObjectPrintClassNamePrefixType((PetscObject)rnd, viewer));
345:     PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)rnd), &rank));
346:     PetscCall(PetscViewerASCIIPushSynchronized(viewer));
347:     PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "[%d] Random type %s, seed %lu\n", rank, ((PetscObject)rnd)->type_name, rnd->seed));
348:     PetscCall(PetscViewerFlush(viewer));
349:     PetscCall(PetscViewerASCIIPopSynchronized(viewer));
350: #if PetscDefined(HAVE_SAWS)
351:   } else if (issaws) {
352:     PetscMPIInt rank;
353:     const char *name;

355:     PetscCall(PetscObjectGetName((PetscObject)rnd, &name));
356:     PetscCallMPI(MPI_Comm_rank(PETSC_COMM_WORLD, &rank));
357:     if (!((PetscObject)rnd)->amsmem && rank == 0) {
358:       char dir[1024];

360:       PetscCall(PetscObjectViewSAWs((PetscObject)rnd, viewer));
361:       PetscCall(PetscSNPrintf(dir, 1024, "/PETSc/Objects/%s/Low", name));
362:       PetscCallSAWs(SAWs_Register, dir, &rnd->low, 1, SAWs_READ, SAWs_DOUBLE);
363:     }
364: #endif
365:   }
366:   PetscFunctionReturn(PETSC_SUCCESS);
367: }

369: /*@
370:   PetscRandomCreate - Creates an object for generating random numbers,
371:   and initializes the random-number generator.

373:   Collective

375:   Input Parameter:
376: . comm - MPI communicator

378:   Output Parameter:
379: . r - the random number generator object

381:   Level: intermediate

383:   Notes:
384:   The random type has to be set by `PetscRandomSetType()`.

386:   This is only a primitive "parallel" random number generator, it should NOT
387:   be used for sophisticated parallel Monte Carlo methods since it will very likely
388:   not have the correct statistics across processors. You can provide your own
389:   parallel generator using `PetscRandomRegister()`;

391:   If you create a `PetscRandom()` using `PETSC_COMM_SELF` on several processors then
392:   the SAME random numbers will be generated on all those processors. Use `PETSC_COMM_WORLD`
393:   or the appropriate parallel communicator to eliminate this issue.

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

397:   Example of Usage:
398: .vb
399:       PetscRandomCreate(PETSC_COMM_SELF,&r);
400:       PetscRandomSetType(r,PETSCRAND48);
401:       PetscRandomGetValue(r,&value1);
402:       PetscRandomGetValueReal(r,&value2);
403:       PetscRandomDestroy(&r);
404: .ve

406: .seealso: `PetscRandomSetType()`, `PetscRandomGetValue()`, `PetscRandomGetValueReal()`, `PetscRandomSetInterval()`,
407:           `PetscRandomDestroy()`, `VecSetRandom()`, `PetscRandomType`, `PetscRandom`
408: @*/
409: PetscErrorCode PetscRandomCreate(MPI_Comm comm, PetscRandom *r)
410: {
411:   PetscRandom rr;
412:   PetscMPIInt rank;

414:   PetscFunctionBegin;
415:   PetscAssertPointer(r, 2);
416:   PetscCall(PetscRandomInitializePackage());

418:   PetscCall(PetscHeaderCreate(rr, PETSC_RANDOM_CLASSID, "PetscRandom", "Random number generator", "Sys", comm, PetscRandomDestroy, PetscRandomView));
419:   PetscCallMPI(MPI_Comm_rank(comm, &rank));
420:   rr->data  = NULL;
421:   rr->low   = 0.0;
422:   rr->width = 1.0;
423:   rr->iset  = PETSC_FALSE;
424:   rr->seed  = 0x12345678 + 76543 * rank;
425:   PetscCall(PetscRandomSetType(rr, PETSCRANDER48));
426:   *r = rr;
427:   PetscFunctionReturn(PETSC_SUCCESS);
428: }

430: /*@
431:   PetscRandomSeed - Seed the random number generator.

433:   Not collective

435:   Input Parameter:
436: . r - The random number generator context

438:   Level: intermediate

440:   Example Usage:
441: .vb
442:       PetscRandomSetSeed(r,a positive integer);
443:       PetscRandomSeed(r);
444:       PetscRandomGetValue() will now start with the new seed.

446:       PetscRandomSeed(r) without a call to PetscRandomSetSeed() re-initializes
447:       the seed. The random numbers generated will be the same as before.
448: .ve

450: .seealso: `PetscRandomCreate()`, `PetscRandomGetSeed()`, `PetscRandomSetSeed()`
451: @*/
452: PetscErrorCode PetscRandomSeed(PetscRandom r)
453: {
454:   PetscFunctionBegin;

458:   PetscUseTypeMethod(r, seed);
459:   PetscCall(PetscObjectStateIncrease((PetscObject)r));
460:   PetscFunctionReturn(PETSC_SUCCESS);
461: }