source: Sophya/trunk/SophyaLib/BaseTools/randr48.cc@ 4053

Last change on this file since 4053 was 3890, checked in by ansari, 15 years ago

suite correction bug SetSeed() ds ThSDR48RandGen (gestion PPF) + retag en V2_2, Reza 28/09/2010

File size: 10.3 KB
Line 
1#include "machdefs.h"
2#include <math.h>
3#include <stdlib.h>
4#include <string.h>
5#include "thsafeop.h"
6#include "fiondblock.h"
7
8#include "randr48.h"
9
10namespace SOPHYA {
11
12/*!
13 \class DR48RandGen
14 \ingroup BaseTools
15 \brief Implementation of the RandomGeneratorInterface class using drand48() functions
16
17 Its PPF handler can be used to save the complete state of the class and the underlying
18 random number generator used.
19
20 \sa SOPHYA::ObjFileIO<ThSDR48RandGen>
21
22*/
23
24static bool dr48_first = true;
25DR48RandGen::DR48RandGen()
26{
27 if (dr48_first) {
28 Next(); dr48_first=false;
29 }
30}
31
32DR48RandGen::DR48RandGen(long int seed)
33{
34 srand48(seed);
35 dr48_first=false;
36}
37
38DR48RandGen::~DR48RandGen()
39{
40}
41
42void DR48RandGen::ShowRandom()
43{
44 cout<<"RandomGenerator is DR48RandGen"<<endl;
45}
46
47/*!
48 \brief Initialize the state of the random generator object using the integer value argument
49
50 \warning This method changes the global random generator drand48() state
51*/
52void DR48RandGen::SetSeed(long int seed)
53{
54 srand48(seed);
55}
56
57/*!
58 \brief Initialize the state of the random generator object using the short integer array
59
60 \warning This method changes the global random generator drand48() state
61*/
62void DR48RandGen::SetSeed(uint_2 seed[3])
63{
64 seed48(seed);
65}
66
67//! Return the random generator state
68void DR48RandGen::GetSeed(uint_2 seed[3])
69{
70 uint_2 *p, seed_dummy[3] = {0,0,0};
71 p = seed48(seed_dummy);
72 memcpy(seed,p,3*sizeof(uint_2));
73 // on re-initialise a ce qui etait avant
74 seed48(seed);
75}
76
77r_8 DR48RandGen::Next()
78{
79 return drand48();
80}
81
82/*!
83 \brief Random Initialization of the state of the random generator object using the system clock
84
85 \warning This method changes the global random generator drand48() state
86*/
87void DR48RandGen::AutoInit(int lp)
88{
89 vector<uint_2> seed;
90 GenerateSeedVector(0,seed,lp);
91 uint_2 s[3] = {seed[0],seed[1],seed[2]};
92 SetSeed(s);
93}
94
95//------------------------------------------------------------
96//------------------------------------------------------------
97//------------------------------------------------------------
98/*!
99 \class ThSDR48RandGen
100 \ingroup BaseTools
101 \brief Thread-safe version of DR48RandGen random number generator using drand48() functions.
102
103
104 Several instances of this class can be used in different threads without the risk of
105 corrupting the internal state of the drand48() generator. However, in multi-thread applications,
106 there is no guarantee to obtain the same sequence of numbers in each thread.
107 Its PPF handler can be used to save the complete state of the class and the underlying
108 random number generator (drand48() which is used.
109
110 \sa SOPHYA::ObjFileIO<ThSDR48RandGen>
111
112 \code
113 // A.1- Create a thread safe generator based on drand48()
114 ThSDR48RandGen rg;
115 // A.2- Auto initilize its state (using the system time)
116 rg.AutoInit();
117 // A.3- compute and print a smal sequence of random numbers
118 int N = 10;
119 for(int i=0; i<N; i++)
120 cout << " I=" << i << " rand_flat01= " << rg.Flat01() << " rand.gaussian= " << rg.Gaussian() << endl;
121 // A.4- Save the generator state for subsequent use
122 POutPersist po("rg.ppf");
123 po << rg;
124 // A.5- compute and print a second sequence of random numbers
125 for(int i=0; i<N; i++)
126 cout << "++ I=" << i+N << " rand_flat01= " << rg.Flat01() << " rand.gaussian= " << rg.Gaussian() << endl;
127
128 ... In another program :
129
130 // B.1- Create and initialize the generator from the previously saved state
131 ThSDR48RandGen rgr;
132 PInPersist pin("rg.ppf");
133 pin >> rgr;
134 int N = 10;
135 // B.2- Compute and print a sequence of random number, should be compared to the sequance A.5
136 for(int i=0; i<N; i++)
137 cout << "-- I=" << i << " rand_flat01= " << rgr.Flat01() << " rand.gaussian= " << rgr.Gaussian() << endl;
138
139
140 \endcode
141*/
142
143// Objet statique global pour gestion de lock entre threads
144static ThSafeOp* ths_rand = NULL;
145
146/*!
147 \brief Constructor with optional specification of the internal buffer size and thread-safety flag
148
149 The behaviour of the base class DR48RandGen can be reproduced by specifying tsafe=false
150 \param n : an internal buffer of size n is created and filled through block calls to drand48()
151 \param tsafe : if false, creates a non thread-safe generator
152*/
153
154ThSDR48RandGen::ThSDR48RandGen(size_t n, bool tsafe)
155{
156 if (ths_rand == NULL) ths_rand = new ThSafeOp;
157 if (tsafe) { // thread-safe
158 fg_nothrsafe = false;
159 if (n < 1) n = 1024;
160 rseq_.ReSize(n, false);
161 idx_ = n;
162 }
163 else { // NOT thread-safe
164 fg_nothrsafe = true;
165 idx_ = 1;
166 }
167}
168
169ThSDR48RandGen::ThSDR48RandGen(ThSDR48RandGen const & rg)
170{
171 if (ths_rand == NULL) ths_rand = new ThSafeOp;
172 if (!rg.fg_nothrsafe) { // thread-safe
173 fg_nothrsafe = false;
174 rseq_.ReSize(rg.rseq_.Size(), false);
175 idx_ = rseq_.Size();
176 }
177 else { // NOT thread-safe
178 fg_nothrsafe = true;
179 idx_ = 1;
180 }
181}
182
183
184ThSDR48RandGen::~ThSDR48RandGen(void)
185{
186 // rien a faire
187}
188
189void ThSDR48RandGen::SetBuffSize(size_t n)
190// redimensionnement du buffer
191{
192 if(fg_nothrsafe) return;
193 if (n < 1) n = 1024;
194 rseq_.ReSize(n, false);
195 idx_ = n;
196}
197
198
199void ThSDR48RandGen::ShowRandom()
200{
201 cout<<"RandomGenerator is ThSDR48RandGen("<<rseq_.Size()<<","<<!fg_nothrsafe<<")"<<endl;
202}
203
204/*!
205 \brief Initialize the state of the random generator object using the integer value argument
206
207 \warning This method changes the global random generator drand48() state
208*/
209void ThSDR48RandGen::SetSeed(long int seed)
210{
211 if (ths_rand == NULL) ths_rand = new ThSafeOp;
212 ths_rand->lock();
213 DR48RandGen::SetSeed(seed);
214 if(!fg_nothrsafe) idx_ = rseq_.Size();
215 ths_rand->unlock();
216 return;
217}
218
219/*!
220 \brief Initialize the state of the random generator object using the short integer array
221
222 \warning This method changes the global random generator drand48() state
223*/
224void ThSDR48RandGen::SetSeed(uint_2 seed[3])
225{
226 if (ths_rand == NULL) ths_rand = new ThSafeOp;
227 ths_rand->lock();
228 DR48RandGen::SetSeed(seed);
229 if(!fg_nothrsafe) idx_ = rseq_.Size();
230 ths_rand->unlock();
231}
232
233//! Return the random generator state
234void ThSDR48RandGen::GetSeed(uint_2 seed[3])
235{
236 if (ths_rand == NULL) ths_rand = new ThSafeOp;
237 ths_rand->lock();
238 DR48RandGen::GetSeed(seed);
239 ths_rand->unlock();
240 return;
241}
242
243
244/*!
245 \brief Random Initialization of the state of the random generator object using the system clock
246
247 \warning This method changes the global random generator drand48() state
248*/
249void ThSDR48RandGen::AutoInit(int lp)
250{
251 vector<uint_2> seed;
252 GenerateSeedVector(0,seed,lp);
253 uint_2 s[3] = {seed[0],seed[1],seed[2]};
254 SetSeed(s);
255}
256
257
258void ThSDR48RandGen::GenSeq(void)
259{
260 ths_rand->lock();
261 for(size_t k=0; k<rseq_.Size(); k++) rseq_(k) = drand48();
262 ths_rand->unlock();
263 idx_ = 0;
264}
265
266r_8 ThSDR48RandGen::Next()
267{
268 if (rseq_.Size() == 0) return drand48();
269 else {
270 if(idx_==rseq_.Size()) GenSeq();
271 return(rseq_(idx_++));
272 }
273}
274
275
276//----------------------------------------------------------
277// Classe pour la gestion de persistance
278// ObjFileIO<DR48RandGen>
279//----------------------------------------------------------
280
281/* --Methode-- */
282DECL_TEMP_SPEC /* equivalent a template <> , pour SGI-CC en particulier */
283void ObjFileIO<DR48RandGen>::WriteSelf(POutPersist& s) const
284{
285 if (dobj == NULL)
286 throw NullPtrError("ObjFileIO<DR48RandGen>::WriteSelf() dobj=NULL");
287 uint_2 seed[3];
288 dobj->GetSeed(seed);
289 s.Put(seed,3);
290 return;
291}
292
293/* --Methode-- */
294DECL_TEMP_SPEC /* equivalent a template <> , pour SGI-CC en particulier */
295void ObjFileIO<DR48RandGen>::ReadSelf(PInPersist& s)
296{
297 uint_2 seed[3];
298 s.Get(seed,3);
299 if(dobj == NULL) dobj = new DR48RandGen();
300 dobj->SetSeed(seed);
301 return;
302}
303
304//----------------------------------------------------------
305// Classe pour la gestion de persistance
306// ObjFileIO<ThSDR48RandGen>
307//----------------------------------------------------------
308
309/* --Methode-- */
310DECL_TEMP_SPEC /* equivalent a template <> , pour SGI-CC en particulier */
311void ObjFileIO<ThSDR48RandGen>::WriteSelf(POutPersist& s) const
312{
313 if (dobj == NULL)
314 throw NullPtrError("ObjFileIO<ThSDR48RandGen>::WriteSelf() dobj=NULL");
315 ths_rand->lock(); // thread-safety
316 uint_4 itab[6];
317 //itab : [0]: version, [1,2,3] = srand48 state/seed , [4,5] = reserved for future use
318 itab[0] = 1;
319 // On recupere et on ecrit ds le PPF l'etat du generateur aleatoire
320 uint_2 seed_16v[3];
321 dobj->GetSeed_P(seed_16v);
322 for(int i=0; i<3; i++) itab[i+1] = seed_16v[i];
323 itab[4] = 0;
324 s.Put(itab, 6);
325 uint_8 sz = dobj->rseq_.Size();
326 s.Put(sz); // Taille du tableau intermediaire
327 uint_8 ix = dobj->idx_;
328 s.Put(ix); // valeur de l'index
329
330 if (dobj->rseq_.Size() > 0) s << dobj->rseq_; // On ecrit le tableau (NDataBlock) si necessaire
331 ths_rand->unlock(); // thread-safety
332 return;
333}
334
335/* --Methode-- */
336DECL_TEMP_SPEC /* equivalent a template <> , pour SGI-CC en particulier */
337void ObjFileIO<ThSDR48RandGen>::ReadSelf(PInPersist& s)
338{
339 uint_4 itab[6];
340 //itab : [0]: version, [1,2,3] = srand48 state/seed , [4] = reserved for future use
341 s.Get(itab, 6);
342 uint_8 sz,ix;
343 s.Get(sz); // Taille du tableau intermediaire
344 s.Get(ix); // valeur de l'index ds le tableau intermediaire
345
346 if (dobj == NULL) dobj = new ThSDR48RandGen(sz, (sz>0)?true:false);
347 dobj->idx_ = ix;
348 if (sz > 0) {
349 s >> dobj->rseq_; // On lit le tableau (NDataBlock) si necessaire
350 dobj->fg_nothrsafe = false;
351 }
352 else { // Objet lu est NON thread-safe, taille_tableau rseq_ = 0
353 dobj->fg_nothrsafe = true;
354 if (dobj->rseq_.Size() > 0) dobj->rseq_.Dealloc();
355 }
356 // On initialise l'etat du generateur aleatoire avec les valeurs lues
357 uint_2 seed_16v[3];
358 //NON ? pourquoi faire GetSeed ? : dobj->GetSeed_P(seed_16v);
359 for(int i=0; i<3; i++) seed_16v[i] = itab[i+1];
360 ths_rand->lock(); // thread-safety
361 dobj->SetSeed_P(seed_16v);
362 ths_rand->unlock(); // thread-safety
363 return;
364}
365
366// ---------------------------------------------------------
367#ifdef __CXX_PRAGMA_TEMPLATES__
368#pragma define_template ObjFileIO<DR48RandGen>
369#endif
370
371#if defined(ANSI_TEMPLATES) || defined(GNU_TEMPLATES)
372template class ObjFileIO<DR48RandGen>;
373#endif
374
375// ---------------------------------------------------------
376#ifdef __CXX_PRAGMA_TEMPLATES__
377#pragma define_template ObjFileIO<ThSDR48RandGen>
378#endif
379
380#if defined(ANSI_TEMPLATES) || defined(GNU_TEMPLATES)
381template class ObjFileIO<ThSDR48RandGen>;
382#endif
383// ---------------------------------------------------------
384
385
386} /* namespace SOPHYA */
Note: See TracBrowser for help on using the repository browser.