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