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: /*@C
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, unsigned long *seed)
62: {
63: PetscFunctionBegin;
65: if (seed) {
66: PetscAssertPointer(seed, 2);
67: *seed = r->seed;
68: }
69: PetscFunctionReturn(PETSC_SUCCESS);
70: }
72: /*@C
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, unsigned long seed)
96: {
97: PetscFunctionBegin;
99: r->seed = seed;
100: PetscCall(PetscInfo(NULL, "Setting seed to %d\n", (int)seed));
101: PetscFunctionReturn(PETSC_SUCCESS);
102: }
104: /* ------------------------------------------------------------------- */
105: /*
106: PetscRandomSetTypeFromOptions_Private - Sets the type of random generator from user options. Defaults to type PETSCRAND48 or PETSCRAND.
108: Collective
110: Input Parameter:
111: . rnd - The random number generator context
113: Level: intermediate
115: .seealso: `PetscRandomSetFromOptions()`, `PetscRandomSetType()`
116: */
117: static PetscErrorCode PetscRandomSetTypeFromOptions_Private(PetscRandom rnd, PetscOptionItems *PetscOptionsObject)
118: {
119: PetscBool opt;
120: const char *defaultType;
121: char typeName[256];
123: PetscFunctionBegin;
124: if (((PetscObject)rnd)->type_name) {
125: defaultType = ((PetscObject)rnd)->type_name;
126: } else {
127: defaultType = PETSCRANDER48;
128: }
130: PetscCall(PetscRandomRegisterAll());
131: PetscCall(PetscOptionsFList("-random_type", "PetscRandom type", "PetscRandomSetType", PetscRandomList, defaultType, typeName, 256, &opt));
132: if (opt) {
133: PetscCall(PetscRandomSetType(rnd, typeName));
134: } else {
135: PetscCall(PetscRandomSetType(rnd, defaultType));
136: }
137: PetscFunctionReturn(PETSC_SUCCESS);
138: }
140: /*@
141: PetscRandomSetFromOptions - Configures the random number generator from the options database.
143: Collective
145: Input Parameter:
146: . rnd - The random number generator context
148: Options Database Keys:
149: + -random_seed <integer> - provide a seed to the random number generator
150: - -random_no_imaginary_part - makes the imaginary part of the random number zero, this is useful when you want the
151: same code to produce the same result when run with real numbers or complex numbers for regression testing purposes
153: Level: beginner
155: Note:
156: Must be called after `PetscRandomCreate()` but before the rnd is used.
158: .seealso: `PetscRandom`, `PetscRandomCreate()`, `PetscRandomSetType()`
159: @*/
160: PetscErrorCode PetscRandomSetFromOptions(PetscRandom rnd)
161: {
162: PetscBool set, noimaginary = PETSC_FALSE;
163: PetscInt seed;
165: PetscFunctionBegin;
168: PetscObjectOptionsBegin((PetscObject)rnd);
170: /* Handle PetscRandom type options */
171: PetscCall(PetscRandomSetTypeFromOptions_Private(rnd, PetscOptionsObject));
173: /* Handle specific random generator's options */
174: PetscTryTypeMethod(rnd, setfromoptions, PetscOptionsObject);
175: PetscCall(PetscOptionsInt("-random_seed", "Seed to use to generate random numbers", "PetscRandomSetSeed", 0, &seed, &set));
176: if (set) {
177: PetscCall(PetscRandomSetSeed(rnd, (unsigned long int)seed));
178: PetscCall(PetscRandomSeed(rnd));
179: }
180: PetscCall(PetscOptionsBool("-random_no_imaginary_part", "The imaginary part of the random number will be zero", "PetscRandomSetInterval", noimaginary, &noimaginary, &set));
181: #if defined(PETSC_HAVE_COMPLEX)
182: if (set) {
183: if (noimaginary) {
184: PetscScalar low, high;
185: PetscCall(PetscRandomGetInterval(rnd, &low, &high));
186: low = low - PetscImaginaryPart(low);
187: high = high - PetscImaginaryPart(high);
188: PetscCall(PetscRandomSetInterval(rnd, low, high));
189: }
190: }
191: #endif
192: PetscOptionsEnd();
193: PetscCall(PetscRandomViewFromOptions(rnd, NULL, "-random_view"));
194: PetscFunctionReturn(PETSC_SUCCESS);
195: }
197: /*@
198: PetscRandomSetOptionsPrefix - Sets the prefix used for searching for all
199: `PetscRandom` options in the database.
201: Logically Collective
203: Input Parameters:
204: + r - the random number generator context
205: - prefix - the prefix to prepend to all option names
207: Level: advanced
209: Note:
210: A hyphen (-) must NOT be given at the beginning of the prefix name.
211: The first character of all runtime options is AUTOMATICALLY the hyphen.
213: .seealso: `PetscRandom`, `PetscRandomSetFromOptions()`
214: @*/
215: PetscErrorCode PetscRandomSetOptionsPrefix(PetscRandom r, const char prefix[])
216: {
217: PetscFunctionBegin;
219: PetscCall(PetscObjectSetOptionsPrefix((PetscObject)r, prefix));
220: PetscFunctionReturn(PETSC_SUCCESS);
221: }
223: #if defined(PETSC_HAVE_SAWS)
224: #include <petscviewersaws.h>
225: #endif
227: /*@
228: PetscRandomViewFromOptions - View a `PetscRandom` object based on the options database
230: Collective
232: Input Parameters:
233: + A - the random number generator context
234: . obj - Optional object
235: - name - command line option
237: Level: intermediate
239: .seealso: `PetscRandom`, `PetscRandomView`, `PetscObjectViewFromOptions()`, `PetscRandomCreate()`
240: @*/
241: PetscErrorCode PetscRandomViewFromOptions(PetscRandom A, PetscObject obj, const char name[])
242: {
243: PetscFunctionBegin;
245: PetscCall(PetscObjectViewFromOptions((PetscObject)A, obj, name));
246: PetscFunctionReturn(PETSC_SUCCESS);
247: }
249: /*@
250: PetscRandomView - Views a random number generator object.
252: Collective
254: Input Parameters:
255: + rnd - The random number generator context
256: - viewer - an optional visualization context
258: Level: beginner
260: Note:
261: The available visualization contexts include
262: + `PETSC_VIEWER_STDOUT_SELF` - standard output (default)
263: - `PETSC_VIEWER_STDOUT_WORLD` - synchronized standard
264: output where only the first processor opens
265: the file. All other processors send their
266: data to the first processor to print.
268: .seealso: `PetscRandom`, `PetscRealView()`, `PetscScalarView()`, `PetscIntView()`
269: @*/
270: PetscErrorCode PetscRandomView(PetscRandom rnd, PetscViewer viewer)
271: {
272: PetscBool iascii;
273: #if defined(PETSC_HAVE_SAWS)
274: PetscBool issaws;
275: #endif
277: PetscFunctionBegin;
280: if (!viewer) PetscCall(PetscViewerASCIIGetStdout(PetscObjectComm((PetscObject)rnd), &viewer));
282: PetscCheckSameComm(rnd, 1, viewer, 2);
283: PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERASCII, &iascii));
284: #if defined(PETSC_HAVE_SAWS)
285: PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERSAWS, &issaws));
286: #endif
287: if (iascii) {
288: PetscMPIInt rank;
289: PetscCall(PetscObjectPrintClassNamePrefixType((PetscObject)rnd, viewer));
290: PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)rnd), &rank));
291: PetscCall(PetscViewerASCIIPushSynchronized(viewer));
292: PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "[%d] Random type %s, seed %lu\n", rank, ((PetscObject)rnd)->type_name, rnd->seed));
293: PetscCall(PetscViewerFlush(viewer));
294: PetscCall(PetscViewerASCIIPopSynchronized(viewer));
295: #if defined(PETSC_HAVE_SAWS)
296: } else if (issaws) {
297: PetscMPIInt rank;
298: const char *name;
300: PetscCall(PetscObjectGetName((PetscObject)rnd, &name));
301: PetscCallMPI(MPI_Comm_rank(PETSC_COMM_WORLD, &rank));
302: if (!((PetscObject)rnd)->amsmem && rank == 0) {
303: char dir[1024];
305: PetscCall(PetscObjectViewSAWs((PetscObject)rnd, viewer));
306: PetscCall(PetscSNPrintf(dir, 1024, "/PETSc/Objects/%s/Low", name));
307: PetscCallSAWs(SAWs_Register, (dir, &rnd->low, 1, SAWs_READ, SAWs_DOUBLE));
308: }
309: #endif
310: }
311: PetscFunctionReturn(PETSC_SUCCESS);
312: }
314: /*@
315: PetscRandomCreate - Creates an object for generating random numbers,
316: and initializes the random-number generator.
318: Collective
320: Input Parameter:
321: . comm - MPI communicator
323: Output Parameter:
324: . r - the random number generator object
326: Level: intermediate
328: Notes:
329: The random type has to be set by `PetscRandomSetType()`.
331: This is only a primitive "parallel" random number generator, it should NOT
332: be used for sophisticated parallel Monte Carlo methods since it will very likely
333: not have the correct statistics across processors. You can provide your own
334: parallel generator using `PetscRandomRegister()`;
336: If you create a `PetscRandom()` using `PETSC_COMM_SELF` on several processors then
337: the SAME random numbers will be generated on all those processors. Use `PETSC_COMM_WORLD`
338: or the appropriate parallel communicator to eliminate this issue.
340: Use `VecSetRandom()` to set the elements of a vector to random numbers.
342: Example of Usage:
343: .vb
344: PetscRandomCreate(PETSC_COMM_SELF,&r);
345: PetscRandomSetType(r,PETSCRAND48);
346: PetscRandomGetValue(r,&value1);
347: PetscRandomGetValueReal(r,&value2);
348: PetscRandomDestroy(&r);
349: .ve
351: .seealso: `PetscRandomSetType()`, `PetscRandomGetValue()`, `PetscRandomGetValueReal()`, `PetscRandomSetInterval()`,
352: `PetscRandomDestroy()`, `VecSetRandom()`, `PetscRandomType`, `PetscRandom`
353: @*/
354: PetscErrorCode PetscRandomCreate(MPI_Comm comm, PetscRandom *r)
355: {
356: PetscRandom rr;
357: PetscMPIInt rank;
359: PetscFunctionBegin;
360: PetscAssertPointer(r, 2);
361: PetscCall(PetscRandomInitializePackage());
363: PetscCall(PetscHeaderCreate(rr, PETSC_RANDOM_CLASSID, "PetscRandom", "Random number generator", "Sys", comm, PetscRandomDestroy, PetscRandomView));
364: PetscCallMPI(MPI_Comm_rank(comm, &rank));
365: rr->data = NULL;
366: rr->low = 0.0;
367: rr->width = 1.0;
368: rr->iset = PETSC_FALSE;
369: rr->seed = 0x12345678 + 76543 * rank;
370: PetscCall(PetscRandomSetType(rr, PETSCRANDER48));
371: *r = rr;
372: PetscFunctionReturn(PETSC_SUCCESS);
373: }
375: /*@
376: PetscRandomSeed - Seed the random number generator.
378: Not collective
380: Input Parameter:
381: . r - The random number generator context
383: Level: intermediate
385: Example Usage:
386: .vb
387: PetscRandomSetSeed(r,a positive integer);
388: PetscRandomSeed(r);
389: PetscRandomGetValue() will now start with the new seed.
391: PetscRandomSeed(r) without a call to PetscRandomSetSeed() re-initializes
392: the seed. The random numbers generated will be the same as before.
393: .ve
395: .seealso: `PetscRandomCreate()`, `PetscRandomGetSeed()`, `PetscRandomSetSeed()`
396: @*/
397: PetscErrorCode PetscRandomSeed(PetscRandom r)
398: {
399: PetscFunctionBegin;
403: PetscUseTypeMethod(r, seed);
404: PetscCall(PetscObjectStateIncrease((PetscObject)r));
405: PetscFunctionReturn(PETSC_SUCCESS);
406: }