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