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