xref: /petsc/src/sys/classes/random/interface/randomc.c (revision a8d69d7b0124b1e6ce75950a93e6ff079980e86f)
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 /*@
22    PetscRandomDestroy - Destroys a context that has been formed by
23    PetscRandomCreate().
24 
25    Collective on PetscRandom
26 
27    Intput Parameter:
28 .  r  - the random number generator context
29 
30    Level: intermediate
31 
32 .seealso: PetscRandomGetValue(), PetscRandomCreate(), VecSetRandom()
33 @*/
34 PetscErrorCode  PetscRandomDestroy(PetscRandom *r)
35 {
36   PetscErrorCode ierr;
37 
38   PetscFunctionBegin;
39   if (!*r) PetscFunctionReturn(0);
40   PetscValidHeaderSpecific(*r,PETSC_RANDOM_CLASSID,1);
41   if (--((PetscObject)(*r))->refct > 0) {*r = 0; PetscFunctionReturn(0);}
42   if ((*r)->ops->destroy) {
43     ierr = (*(*r)->ops->destroy)(*r);CHKERRQ(ierr);
44   }
45   ierr = PetscHeaderDestroy(r);CHKERRQ(ierr);
46   PetscFunctionReturn(0);
47 }
48 
49 
50 /*@C
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 /*@C
79    PetscRandomSetSeed - Sets the random seed. You MUST call PetscRandomSeed() after this call to have the new seed used.
80 
81    Not collective
82 
83    Input Parameters:
84 +  r  - The random number generator context
85 -  seed - The random seed
86 
87    Level: intermediate
88 
89    Usage:
90       PetscRandomSetSeed(r,a positive integer);
91       PetscRandomSeed(r);  PetscRandomGetValue() will now start with the new seed.
92 
93       PetscRandomSeed(r) without a call to PetscRandomSetSeed() re-initializes
94         the seed. The random numbers generated will be the same as before.
95 
96    Concepts: random numbers^seed
97 
98 .seealso: PetscRandomCreate(), PetscRandomGetSeed(), PetscRandomSeed()
99 @*/
100 PetscErrorCode  PetscRandomSetSeed(PetscRandom r,unsigned long seed)
101 {
102   PetscErrorCode ierr;
103 
104   PetscFunctionBegin;
105   PetscValidHeaderSpecific(r,PETSC_RANDOM_CLASSID,1);
106   r->seed = seed;
107   ierr    = PetscInfo1(NULL,"Setting seed to %d\n",(int)seed);CHKERRQ(ierr);
108   PetscFunctionReturn(0);
109 }
110 
111 /* ------------------------------------------------------------------- */
112 /*
113   PetscRandomSetTypeFromOptions_Private - Sets the type of random generator from user options. Defaults to type PETSCRAND48 or PETSCRAND.
114 
115   Collective on PetscRandom
116 
117   Input Parameter:
118 . rnd - The random number generator context
119 
120   Level: intermediate
121 
122 .keywords: PetscRandom, set, options, database, type
123 .seealso: PetscRandomSetFromOptions(), PetscRandomSetType()
124 */
125 static PetscErrorCode PetscRandomSetTypeFromOptions_Private(PetscOptionItems *PetscOptionsObject,PetscRandom rnd)
126 {
127   PetscBool      opt;
128   const char     *defaultType;
129   char           typeName[256];
130   PetscErrorCode ierr;
131 
132   PetscFunctionBegin;
133   if (((PetscObject)rnd)->type_name) {
134     defaultType = ((PetscObject)rnd)->type_name;
135   } else {
136     defaultType = PETSCRANDER48;
137   }
138 
139   ierr = PetscRandomRegisterAll();CHKERRQ(ierr);
140   ierr = PetscOptionsFList("-random_type","PetscRandom type","PetscRandomSetType",PetscRandomList,defaultType,typeName,256,&opt);CHKERRQ(ierr);
141   if (opt) {
142     ierr = PetscRandomSetType(rnd, typeName);CHKERRQ(ierr);
143   } else {
144     ierr = PetscRandomSetType(rnd, defaultType);CHKERRQ(ierr);
145   }
146   PetscFunctionReturn(0);
147 }
148 
149 /*@
150   PetscRandomSetFromOptions - Configures the random number generator from the options database.
151 
152   Collective on PetscRandom
153 
154   Input Parameter:
155 . rnd - The random number generator context
156 
157   Options Database:
158 + -random_seed <integer> - provide a seed to the random number generater
159 - -random_no_imaginary_part - makes the imaginary part of the random number zero, this is useful when you want the
160                               same code to produce the same result when run with real numbers or complex numbers for regression testing purposes
161 
162   Notes:
163     To see all options, run your program with the -help option.
164           Must be called after PetscRandomCreate() but before the rnd is used.
165 
166   Level: beginner
167 
168 .keywords: PetscRandom, set, options, database
169 .seealso: PetscRandomCreate(), PetscRandomSetType()
170 @*/
171 PetscErrorCode  PetscRandomSetFromOptions(PetscRandom rnd)
172 {
173   PetscErrorCode ierr;
174   PetscBool      set,noimaginary = PETSC_FALSE;
175   PetscInt       seed;
176 
177   PetscFunctionBegin;
178   PetscValidHeaderSpecific(rnd,PETSC_RANDOM_CLASSID,1);
179 
180   ierr = PetscObjectOptionsBegin((PetscObject)rnd);CHKERRQ(ierr);
181 
182   /* Handle PetscRandom type options */
183   ierr = PetscRandomSetTypeFromOptions_Private(PetscOptionsObject,rnd);CHKERRQ(ierr);
184 
185   /* Handle specific random generator's options */
186   if (rnd->ops->setfromoptions) {
187     ierr = (*rnd->ops->setfromoptions)(PetscOptionsObject,rnd);CHKERRQ(ierr);
188   }
189   ierr = PetscOptionsInt("-random_seed","Seed to use to generate random numbers","PetscRandomSetSeed",0,&seed,&set);CHKERRQ(ierr);
190   if (set) {
191     ierr = PetscRandomSetSeed(rnd,(unsigned long int)seed);CHKERRQ(ierr);
192     ierr = PetscRandomSeed(rnd);CHKERRQ(ierr);
193   }
194   ierr = PetscOptionsBool("-random_no_imaginary_part","The imaginary part of the random number will be zero","PetscRandomSetInterval",noimaginary,&noimaginary,&set);CHKERRQ(ierr);
195 #if defined(PETSC_HAVE_COMPLEX)
196   if (set) {
197     if (noimaginary) {
198       PetscScalar low,high;
199       ierr = PetscRandomGetInterval(rnd,&low,&high);CHKERRQ(ierr);
200       low  = low - PetscImaginaryPart(low);
201       high = high - PetscImaginaryPart(high);
202       ierr = PetscRandomSetInterval(rnd,low,high);CHKERRQ(ierr);
203     }
204   }
205 #endif
206   ierr = PetscOptionsEnd();CHKERRQ(ierr);
207   ierr = PetscRandomViewFromOptions(rnd,NULL, "-random_view");CHKERRQ(ierr);
208   PetscFunctionReturn(0);
209 }
210 
211 #if defined(PETSC_HAVE_SAWS)
212 #include <petscviewersaws.h>
213 #endif
214 /*@C
215    PetscRandomView - Views a random number generator object.
216 
217    Collective on PetscRandom
218 
219    Input Parameters:
220 +  rnd - The random number generator context
221 -  viewer - an optional visualization context
222 
223    Notes:
224    The available visualization contexts include
225 +     PETSC_VIEWER_STDOUT_SELF - standard output (default)
226 -     PETSC_VIEWER_STDOUT_WORLD - synchronized standard
227          output where only the first processor opens
228          the file.  All other processors send their
229          data to the first processor to print.
230 
231    You can change the format the vector is printed using the
232    option PetscViewerPushFormat().
233 
234    Level: beginner
235 
236 .seealso:  PetscRealView(), PetscScalarView(), PetscIntView()
237 @*/
238 PetscErrorCode  PetscRandomView(PetscRandom rnd,PetscViewer viewer)
239 {
240   PetscErrorCode ierr;
241   PetscBool      iascii;
242 #if defined(PETSC_HAVE_SAWS)
243   PetscBool      issaws;
244 #endif
245 
246   PetscFunctionBegin;
247   PetscValidHeaderSpecific(rnd,PETSC_RANDOM_CLASSID,1);
248   PetscValidType(rnd,1);
249   if (!viewer) {
250     ierr = PetscViewerASCIIGetStdout(PetscObjectComm((PetscObject)rnd),&viewer);CHKERRQ(ierr);
251   }
252   PetscValidHeaderSpecific(viewer,PETSC_VIEWER_CLASSID,2);
253   PetscCheckSameComm(rnd,1,viewer,2);
254   ierr = PetscObjectTypeCompare((PetscObject)viewer,PETSCVIEWERASCII,&iascii);CHKERRQ(ierr);
255 #if defined(PETSC_HAVE_SAWS)
256   ierr = PetscObjectTypeCompare((PetscObject)viewer,PETSCVIEWERSAWS,&issaws);CHKERRQ(ierr);
257 #endif
258   if (iascii) {
259     PetscMPIInt rank;
260     ierr = PetscObjectPrintClassNamePrefixType((PetscObject)rnd,viewer);CHKERRQ(ierr);
261     ierr = MPI_Comm_rank(PetscObjectComm((PetscObject)rnd),&rank);CHKERRQ(ierr);
262     ierr = PetscViewerASCIIPushSynchronized(viewer);CHKERRQ(ierr);
263     ierr = PetscViewerASCIISynchronizedPrintf(viewer,"[%d] Random type %s, seed %lu\n",rank,((PetscObject)rnd)->type_name,rnd->seed);CHKERRQ(ierr);
264     ierr = PetscViewerFlush(viewer);CHKERRQ(ierr);
265     ierr = PetscViewerASCIIPopSynchronized(viewer);CHKERRQ(ierr);
266 #if defined(PETSC_HAVE_SAWS)
267   } else if (issaws) {
268     PetscMPIInt rank;
269     const char  *name;
270 
271     ierr = PetscObjectGetName((PetscObject)rnd,&name);CHKERRQ(ierr);
272     ierr = MPI_Comm_rank(PETSC_COMM_WORLD,&rank);CHKERRQ(ierr);
273     if (!((PetscObject)rnd)->amsmem && !rank) {
274       char       dir[1024];
275 
276       ierr = PetscObjectViewSAWs((PetscObject)rnd,viewer);CHKERRQ(ierr);
277       ierr = PetscSNPrintf(dir,1024,"/PETSc/Objects/%s/Low",name);CHKERRQ(ierr);
278       PetscStackCallSAWs(SAWs_Register,(dir,&rnd->low,1,SAWs_READ,SAWs_DOUBLE));
279     }
280 #endif
281   }
282   PetscFunctionReturn(0);
283 }
284 
285 /*@
286    PetscRandomCreate - Creates a context for generating random numbers,
287    and initializes the random-number generator.
288 
289    Collective on MPI_Comm
290 
291    Input Parameters:
292 .  comm - MPI communicator
293 
294    Output Parameter:
295 .  r  - the random number generator context
296 
297    Level: intermediate
298 
299    Notes:
300    The random type has to be set by PetscRandomSetType().
301 
302    This is only a primative "parallel" random number generator, it should NOT
303    be used for sophisticated parallel Monte Carlo methods since it will very likely
304    not have the correct statistics across processors. You can provide your own
305    parallel generator using PetscRandomRegister();
306 
307    If you create a PetscRandom() using PETSC_COMM_SELF on several processors then
308    the SAME random numbers will be generated on all those processors. Use PETSC_COMM_WORLD
309    or the appropriate parallel communicator to eliminate this issue.
310 
311    Use VecSetRandom() to set the elements of a vector to random numbers.
312 
313    Example of Usage:
314 .vb
315       PetscRandomCreate(PETSC_COMM_SELF,&r);
316       PetscRandomSetType(r,PETSCRAND48);
317       PetscRandomGetValue(r,&value1);
318       PetscRandomGetValueReal(r,&value2);
319       PetscRandomDestroy(&r);
320 .ve
321 
322    Concepts: random numbers^creating
323 
324 .seealso: PetscRandomSetType(), PetscRandomGetValue(), PetscRandomGetValueReal(), PetscRandomSetInterval(),
325           PetscRandomDestroy(), VecSetRandom(), PetscRandomType
326 @*/
327 
328 PetscErrorCode  PetscRandomCreate(MPI_Comm comm,PetscRandom *r)
329 {
330   PetscRandom    rr;
331   PetscErrorCode ierr;
332   PetscMPIInt    rank;
333 
334   PetscFunctionBegin;
335   PetscValidPointer(r,3);
336   *r = NULL;
337   ierr = PetscRandomInitializePackage();CHKERRQ(ierr);
338 
339   ierr = PetscHeaderCreate(rr,PETSC_RANDOM_CLASSID,"PetscRandom","Random number generator","Sys",comm,PetscRandomDestroy,PetscRandomView);CHKERRQ(ierr);
340 
341   ierr = MPI_Comm_rank(comm,&rank);CHKERRQ(ierr);
342 
343   rr->data  = NULL;
344   rr->low   = 0.0;
345   rr->width = 1.0;
346   rr->iset  = PETSC_FALSE;
347   rr->seed  = 0x12345678 + 76543*rank;
348   ierr = PetscRandomSetType(rr,PETSCRANDER48);CHKERRQ(ierr);
349   *r = rr;
350   PetscFunctionReturn(0);
351 }
352 
353 /*@
354    PetscRandomSeed - Seed the generator.
355 
356    Not collective
357 
358    Input Parameters:
359 .  r - The random number generator context
360 
361    Level: intermediate
362 
363    Usage:
364       PetscRandomSetSeed(r,a positive integer);
365       PetscRandomSeed(r);  PetscRandomGetValue() will now start with the new seed.
366 
367       PetscRandomSeed(r) without a call to PetscRandomSetSeed() re-initializes
368         the seed. The random numbers generated will be the same as before.
369 
370    Concepts: random numbers^seed
371 
372 .seealso: PetscRandomCreate(), PetscRandomGetSeed(), PetscRandomSetSeed()
373 @*/
374 PetscErrorCode  PetscRandomSeed(PetscRandom r)
375 {
376   PetscErrorCode ierr;
377 
378   PetscFunctionBegin;
379   PetscValidHeaderSpecific(r,PETSC_RANDOM_CLASSID,1);
380   PetscValidType(r,1);
381 
382   ierr = (*r->ops->seed)(r);CHKERRQ(ierr);
383   ierr = PetscObjectStateIncrease((PetscObject)r);CHKERRQ(ierr);
384   PetscFunctionReturn(0);
385 }
386 
387