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>
 15: #include <petscviewer.h>

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

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

 23:   Collective

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

 28:   Level: intermediate

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

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

 49:   Not collective

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

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

 57:   Level: intermediate

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

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

 75:   Not collective

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

 81:   Level: intermediate

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

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

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

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

107:   Collective

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

112:   Level: intermediate

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

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

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

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

142:   Collective

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

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

152:   Level: beginner

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

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

164:   PetscFunctionBegin;

167:   PetscObjectOptionsBegin((PetscObject)rnd);

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

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

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

200:   Logically Collective

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

206:   Level: advanced

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

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

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

226:   Logically Collective

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

232:   Level: advanced

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

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

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

252:   Not Collective

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

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

260:   Level: advanced

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

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

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

279:   Collective

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

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

289:   Level: intermediate

291:   Note:
292:   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,
293:   rather `PetscOptionsCreateViewer()` should be used to construct the viewer once which can then be utilized in the heavily used routine.

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

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

308:   Collective

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

314:   Level: beginner

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

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

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

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

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

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

374:   Collective

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

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

382:   Level: intermediate

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

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

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

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

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

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

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

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

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

434:   Not collective

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

439:   Level: intermediate

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

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

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

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