xref: /petsc/src/sys/classes/random/interface/randomc.c (revision ec7429eab6e231810adac0f010b269bd5bae4496)
1 
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:
6 
7     Numbers can be shuffled for use as random tuples
8 
9     Multiple random number generators may be used
10 
11     We are still not sure what interface we want here.  There should be
12     one to reinitialize and set the seed.
13  */
14 
15 #include <../src/sys/classes/random/randomimpl.h>                              /*I "petscsys.h" I*/
16 #include <petscviewer.h>
17 
18 /* Logging support */
19 PetscClassId PETSC_RANDOM_CLASSID;
20 
21 #undef __FUNCT__
22 #define __FUNCT__ "PetscRandomDestroy"
23 /*@
24    PetscRandomDestroy - Destroys a context that has been formed by
25    PetscRandomCreate().
26 
27    Collective on PetscRandom
28 
29    Intput Parameter:
30 .  r  - the random number generator context
31 
32    Level: intermediate
33 
34 .seealso: PetscRandomGetValue(), PetscRandomCreate(), VecSetRandom()
35 @*/
36 PetscErrorCode  PetscRandomDestroy(PetscRandom *r)
37 {
38   PetscErrorCode ierr;
39 
40   PetscFunctionBegin;
41   if (!*r) PetscFunctionReturn(0);
42   PetscValidHeaderSpecific(*r,PETSC_RANDOM_CLASSID,1);
43   if (--((PetscObject)(*r))->refct > 0) {*r = 0; PetscFunctionReturn(0);}
44   ierr = PetscHeaderDestroy(r);CHKERRQ(ierr);
45   PetscFunctionReturn(0);
46 }
47 
48 
49 #undef __FUNCT__
50 #define __FUNCT__ "PetscRandomGetSeed"
51 /*@
52    PetscRandomGetSeed - Gets the random seed.
53 
54    Not collective
55 
56    Input Parameters:
57 .  r - The random number generator context
58 
59    Output Parameter:
60 .  seed - The random seed
61 
62    Level: intermediate
63 
64    Concepts: random numbers^seed
65 
66 .seealso: PetscRandomCreate(), PetscRandomSetSeed(), PetscRandomSeed()
67 @*/
68 PetscErrorCode  PetscRandomGetSeed(PetscRandom r,unsigned long *seed)
69 {
70   PetscFunctionBegin;
71   PetscValidHeaderSpecific(r,PETSC_RANDOM_CLASSID,1);
72   if (seed) {
73     PetscValidPointer(seed,2);
74     *seed = r->seed;
75   }
76   PetscFunctionReturn(0);
77 }
78 
79 #undef __FUNCT__
80 #define __FUNCT__ "PetscRandomSetSeed"
81 /*@
82    PetscRandomSetSeed - Sets the random seed. You MUST call PetscRandomSeed() after this call to have the new seed used.
83 
84    Not collective
85 
86    Input Parameters:
87 +  r  - The random number generator context
88 -  seed - The random seed
89 
90    Level: intermediate
91 
92    Usage:
93       PetscRandomSetSeed(r,a positive integer);
94       PetscRandomSeed(r);  PetscRandomGetValue() will now start with the new seed.
95 
96       PetscRandomSeed(r) without a call to PetscRandomSetSeed() re-initializes
97         the seed. The random numbers generated will be the same as before.
98 
99    Concepts: random numbers^seed
100 
101 .seealso: PetscRandomCreate(), PetscRandomGetSeed(), PetscRandomSeed()
102 @*/
103 PetscErrorCode  PetscRandomSetSeed(PetscRandom r,unsigned long seed)
104 {
105   PetscErrorCode ierr;
106 
107   PetscFunctionBegin;
108   PetscValidHeaderSpecific(r,PETSC_RANDOM_CLASSID,1);
109   r->seed = seed;
110   ierr    = PetscInfo1(NULL,"Setting seed to %d\n",(int)seed);CHKERRQ(ierr);
111   PetscFunctionReturn(0);
112 }
113 
114 /* ------------------------------------------------------------------- */
115 #undef __FUNCT__
116 #define __FUNCT__ "PetscRandomSetTypeFromOptions_Private"
117 /*
118   PetscRandomSetTypeFromOptions_Private - Sets the type of random generator from user options. Defaults to type PETSCRAND48 or PETSCRAND.
119 
120   Collective on PetscRandom
121 
122   Input Parameter:
123 . rnd - The random number generator context
124 
125   Level: intermediate
126 
127 .keywords: PetscRandom, set, options, database, type
128 .seealso: PetscRandomSetFromOptions(), PetscRandomSetType()
129 */
130 static PetscErrorCode PetscRandomSetTypeFromOptions_Private(PetscRandom rnd)
131 {
132   PetscBool      opt;
133   const char     *defaultType;
134   char           typeName[256];
135   PetscErrorCode ierr;
136 
137   PetscFunctionBegin;
138   if (((PetscObject)rnd)->type_name) {
139     defaultType = ((PetscObject)rnd)->type_name;
140   } else {
141 #if defined(PETSC_HAVE_DRAND48)
142     defaultType = PETSCRAND48;
143 #elif defined(PETSC_HAVE_RAND)
144     defaultType = PETSCRAND;
145 #endif
146   }
147 
148   if (!PetscRandomRegisterAllCalled) {ierr = PetscRandomRegisterAll(NULL);CHKERRQ(ierr);}
149   ierr = PetscOptionsList("-random_type","PetscRandom type","PetscRandomSetType",PetscRandomList,defaultType,typeName,256,&opt);CHKERRQ(ierr);
150   if (opt) {
151     ierr = PetscRandomSetType(rnd, typeName);CHKERRQ(ierr);
152   } else {
153     ierr = PetscRandomSetType(rnd, defaultType);CHKERRQ(ierr);
154   }
155   PetscFunctionReturn(0);
156 }
157 
158 #undef __FUNCT__
159 #define __FUNCT__ "PetscRandomSetFromOptions"
160 /*@
161   PetscRandomSetFromOptions - Configures the random number generator from the options database.
162 
163   Collective on PetscRandom
164 
165   Input Parameter:
166 . rnd - The random number generator context
167 
168   Options Database:
169 .  -random_seed <integer> - provide a seed to the random number generater
170 
171   Notes:  To see all options, run your program with the -help option.
172           Must be called after PetscRandomCreate() but before the rnd is used.
173 
174   Level: beginner
175 
176 .keywords: PetscRandom, set, options, database
177 .seealso: PetscRandomCreate(), PetscRandomSetType()
178 @*/
179 PetscErrorCode  PetscRandomSetFromOptions(PetscRandom rnd)
180 {
181   PetscErrorCode ierr;
182   PetscBool      set;
183   PetscInt       seed;
184 
185   PetscFunctionBegin;
186   PetscValidHeaderSpecific(rnd,PETSC_RANDOM_CLASSID,1);
187 
188   ierr = PetscObjectOptionsBegin((PetscObject)rnd);CHKERRQ(ierr);
189 
190   /* Handle PetscRandom type options */
191   ierr = PetscRandomSetTypeFromOptions_Private(rnd);CHKERRQ(ierr);
192 
193   /* Handle specific random generator's options */
194   if (rnd->ops->setfromoptions) {
195     ierr = (*rnd->ops->setfromoptions)(rnd);CHKERRQ(ierr);
196   }
197   ierr = PetscOptionsInt("-random_seed","Seed to use to generate random numbers","PetscRandomSetSeed",0,&seed,&set);CHKERRQ(ierr);
198   if (set) {
199     ierr = PetscRandomSetSeed(rnd,(unsigned long int)seed);CHKERRQ(ierr);
200     ierr = PetscRandomSeed(rnd);CHKERRQ(ierr);
201   }
202   ierr = PetscOptionsEnd();CHKERRQ(ierr);
203   ierr = PetscRandomViewFromOptions(rnd, "-random_view");CHKERRQ(ierr);
204   PetscFunctionReturn(0);
205 }
206 
207 #undef __FUNCT__
208 #define __FUNCT__ "PetscRandomView"
209 /*@C
210    PetscRandomView - Views a random number generator object.
211 
212    Collective on PetscRandom
213 
214    Input Parameters:
215 +  rnd - The random number generator context
216 -  viewer - an optional visualization context
217 
218    Notes:
219    The available visualization contexts include
220 +     PETSC_VIEWER_STDOUT_SELF - standard output (default)
221 -     PETSC_VIEWER_STDOUT_WORLD - synchronized standard
222          output where only the first processor opens
223          the file.  All other processors send their
224          data to the first processor to print.
225 
226    You can change the format the vector is printed using the
227    option PetscViewerSetFormat().
228 
229    Level: beginner
230 
231 .seealso:  PetscRealView(), PetscScalarView(), PetscIntView()
232 @*/
233 PetscErrorCode  PetscRandomView(PetscRandom rnd,PetscViewer viewer)
234 {
235   PetscErrorCode ierr;
236   PetscBool      iascii;
237 
238   PetscFunctionBegin;
239   PetscValidHeaderSpecific(rnd,PETSC_RANDOM_CLASSID,1);
240   PetscValidType(rnd,1);
241   if (!viewer) {
242     ierr = PetscViewerASCIIGetStdout(PetscObjectComm((PetscObject)rnd),&viewer);CHKERRQ(ierr);
243   }
244   PetscValidHeaderSpecific(viewer,PETSC_VIEWER_CLASSID,2);
245   PetscCheckSameComm(rnd,1,viewer,2);
246   ierr = PetscObjectTypeCompare((PetscObject)viewer,PETSCVIEWERASCII,&iascii);CHKERRQ(ierr);
247   if (iascii) {
248     PetscMPIInt rank;
249     ierr = MPI_Comm_rank(PetscObjectComm((PetscObject)rnd),&rank);CHKERRQ(ierr);
250     ierr = PetscViewerASCIISynchronizedAllow(viewer,PETSC_TRUE);CHKERRQ(ierr);
251     ierr = PetscViewerASCIISynchronizedPrintf(viewer,"[%D] Random type %s, seed %D\n",rank,((PetscObject)rnd)->type_name,rnd->seed);CHKERRQ(ierr);
252     ierr = PetscViewerFlush(viewer);CHKERRQ(ierr);
253     ierr = PetscViewerASCIISynchronizedAllow(viewer,PETSC_FALSE);CHKERRQ(ierr);
254   } else {
255     const char *tname;
256     ierr = PetscObjectGetName((PetscObject)viewer,&tname);CHKERRQ(ierr);
257     SETERRQ1(PETSC_COMM_SELF,PETSC_ERR_SUP,"Viewer type %s not supported for this object",tname);
258   }
259   PetscFunctionReturn(0);
260 }
261 
262 #undef  __FUNCT__
263 #define __FUNCT__ "PetscRandomViewFromOptions"
264 /*@
265   PetscRandomViewFromOptions - This function visualizes the type and the seed of the generated random numbers based upon user options.
266 
267   Collective on PetscRandom
268 
269   Input Parameters:
270 . rnd   - The random number generator context
271 . title - The title
272 
273   Level: intermediate
274 
275 .keywords: PetscRandom, view, options, database
276 .seealso: PetscRandomSetFromOptions()
277 @*/
278 PetscErrorCode  PetscRandomViewFromOptions(PetscRandom rnd, const char optionname[])
279 {
280   PetscBool         flg;
281   PetscViewer       viewer;
282   PetscErrorCode    ierr;
283   PetscViewerFormat format;
284 
285   PetscFunctionBegin;
286   ierr = PetscOptionsGetViewer(PetscObjectComm((PetscObject)rnd),((PetscObject)rnd)->prefix,optionname,&viewer,&format,&flg);CHKERRQ(ierr);
287   if (flg) {
288     ierr = PetscViewerPushFormat(viewer,format);CHKERRQ(ierr);
289     ierr = PetscRandomView(rnd,viewer);CHKERRQ(ierr);
290     ierr = PetscViewerPopFormat(viewer);CHKERRQ(ierr);
291     ierr = PetscViewerDestroy(&viewer);CHKERRQ(ierr);
292   }
293   PetscFunctionReturn(0);
294 }
295 
296 #if defined(PETSC_HAVE_AMS)
297 #include <petscviewerams.h>
298 #undef __FUNCT__
299 #define __FUNCT__ "PetscObjectAMSPublish_Random"
300 static PetscErrorCode PetscObjectAMSPublish_Random(PetscObject obj)
301 {
302   PetscRandom    rand = (PetscRandom) obj;
303   PetscErrorCode ierr;
304 
305   PetscFunctionBegin;
306   ierr = AMS_Memory_add_field(obj->amsmem,"Low",&rand->low,1,AMS_DOUBLE,AMS_READ,AMS_COMMON,AMS_REDUCT_UNDEF);CHKERRQ(ierr);
307   PetscFunctionReturn(0);
308 }
309 #endif
310 
311 #undef __FUNCT__
312 #define __FUNCT__ "PetscRandomCreate"
313 /*@
314    PetscRandomCreate - Creates a context for generating random numbers,
315    and initializes the random-number generator.
316 
317    Collective on MPI_Comm
318 
319    Input Parameters:
320 +  comm - MPI communicator
321 
322    Output Parameter:
323 .  r  - the random number generator context
324 
325    Level: intermediate
326 
327    Notes:
328    The random type has to be set by PetscRandomSetType().
329 
330    This is only a primative "parallel" random number generator, it should NOT
331    be used for sophisticated parallel Monte Carlo methods since it will very likely
332    not have the correct statistics across processors. You can provide your own
333    parallel generator using PetscRandomRegister();
334 
335    If you create a PetscRandom() using PETSC_COMM_SELF on several processors then
336    the SAME random numbers will be generated on all those processors. Use PETSC_COMM_WORLD
337    or the appropriate parallel communicator to eliminate this issue.
338 
339    Use VecSetRandom() to set the elements of a vector to random numbers.
340 
341    Example of Usage:
342 .vb
343       PetscRandomCreate(PETSC_COMM_SELF,&r);
344       PetscRandomSetType(r,PETSCRAND48);
345       PetscRandomGetValue(r,&value1);
346       PetscRandomGetValueReal(r,&value2);
347       PetscRandomDestroy(&r);
348 .ve
349 
350    Concepts: random numbers^creating
351 
352 .seealso: PetscRandomSetType(), PetscRandomGetValue(), PetscRandomGetValueReal(), PetscRandomSetInterval(),
353           PetscRandomDestroy(), VecSetRandom(), PetscRandomType
354 @*/
355 
356 PetscErrorCode  PetscRandomCreate(MPI_Comm comm,PetscRandom *r)
357 {
358   PetscRandom    rr;
359   PetscErrorCode ierr;
360   PetscMPIInt    rank;
361 
362   PetscFunctionBegin;
363   PetscValidPointer(r,3);
364   *r = NULL;
365 #if !defined(PETSC_USE_DYNAMIC_LIBRARIES)
366   ierr = PetscRandomInitializePackage(NULL);CHKERRQ(ierr);
367 #endif
368 
369   ierr = PetscHeaderCreate(rr,_p_PetscRandom,struct _PetscRandomOps,PETSC_RANDOM_CLASSID,"PetscRandom","Random number generator","Sys",comm,PetscRandomDestroy,0);CHKERRQ(ierr);
370 
371   ierr = MPI_Comm_rank(comm,&rank);CHKERRQ(ierr);
372 
373   rr->data  = NULL;
374   rr->low   = 0.0;
375   rr->width = 1.0;
376   rr->iset  = PETSC_FALSE;
377   rr->seed  = 0x12345678 + 76543*rank;
378 #if defined(PETSC_HAVE_AMS)
379   ((PetscObject)rr)->bops->publish = PetscObjectAMSPublish_Random;
380 #endif
381   *r = rr;
382   PetscFunctionReturn(0);
383 }
384 
385 #undef __FUNCT__
386 #define __FUNCT__ "PetscRandomSeed"
387 /*@
388    PetscRandomSeed - Seed the generator.
389 
390    Not collective
391 
392    Input Parameters:
393 .  r - The random number generator context
394 
395    Level: intermediate
396 
397    Usage:
398       PetscRandomSetSeed(r,a positive integer);
399       PetscRandomSeed(r);  PetscRandomGetValue() will now start with the new seed.
400 
401       PetscRandomSeed(r) without a call to PetscRandomSetSeed() re-initializes
402         the seed. The random numbers generated will be the same as before.
403 
404    Concepts: random numbers^seed
405 
406 .seealso: PetscRandomCreate(), PetscRandomGetSeed(), PetscRandomSetSeed()
407 @*/
408 PetscErrorCode  PetscRandomSeed(PetscRandom r)
409 {
410   PetscErrorCode ierr;
411 
412   PetscFunctionBegin;
413   PetscValidHeaderSpecific(r,PETSC_RANDOM_CLASSID,1);
414   PetscValidType(r,1);
415 
416   ierr = (*r->ops->seed)(r);CHKERRQ(ierr);
417   ierr = PetscObjectStateIncrease((PetscObject)r);CHKERRQ(ierr);
418   PetscFunctionReturn(0);
419 }
420 
421