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