Gamma  0.9.5
Generic Synthesis Library
 All Classes Namespaces Functions Variables Typedefs Enumerations Enumerator
/Users/ljp/code/gamma/trunk/Gamma/rnd.h
00001 #ifndef GAMMA_RND_H_INC
00002 #define GAMMA_RND_H_INC
00003 
00004 /*  Gamma - Generic processing library
00005     See COPYRIGHT file for authors and license information
00006 
00007     File Description:
00008     Random variable classes
00009 */
00010 
00011 #include <math.h>
00012 #include <stdio.h>
00013 #include <time.h>   /* for time() */
00014 
00015 #include "Gamma/gen.h"
00016 #include "Gamma/mem.h"
00017 #include "Gamma/scl.h"
00018 #include "Gamma/Conversion.h"
00019 #include "Gamma/Types.h"
00020 
00021 #define TEM template <class T>
00022 
00023 namespace gam{
00024 
00025 
00026 namespace rnd{
00027     namespace{
00028         static bool initSeed = false;
00029         static uint32_t mSeedPush[4];
00030         static gen::RMulAdd<uint32_t> seedGen(1664525, 1013904223);
00031     }
00032     
00034     static uint32_t getSeed(){
00035         if(!initSeed){ seedGen.val = time(NULL); initSeed = true; } 
00036         return seedGen();
00037     }
00038 
00039 } // rnd::
00040 
00041 
00043 
00049 struct RNGLinCon : public gen::RMulAdd<uint32_t>{
00050 
00051     RNGLinCon(){ val=rnd::getSeed(); type(0); }
00052 
00054     RNGLinCon(uint32_t seed): gen::RMulAdd<uint32_t>(1,0,seed){ type(0); }
00055 
00057     
00060     void type(int v){
00061         switch(v){
00062         case 1: mul = 2147001325; add =  715136305; break; // BCPL
00063         default:mul =    1664525; add = 1013904223;        // Knuth, Numerical Recipes in C
00064         }
00065     }
00066 };
00067 
00068 
00069 
00071 
00074 struct RNGMulLinCon : public gen::RMul<uint32_t>{
00075 
00076     RNGMulLinCon(){ val=rnd::getSeed(); type(0); }
00077     
00079     RNGMulLinCon(uint32_t seed): gen::RMul<uint32_t>(1,seed){ type(0); }
00080     
00082 
00085     void type(int v){
00086         switch(v){
00087         default: mul = 69069;   // Super-duper
00088         }
00089     }
00090 };
00091 
00092 
00093 
00095 
00102 class RNGTaus{
00103 public:
00104     RNGTaus(){ (*this) = rnd::getSeed(); }
00105 
00107     RNGTaus(uint32_t seed);
00108     
00109     uint32_t s1, s2, s3, s4;
00110     
00111     uint32_t operator()();              
00112     void operator = (uint32_t seed);    
00113     void seed(uint32_t s1, uint32_t s2, uint32_t s3, uint32_t s4); 
00114 
00115 private:
00116     void iterate();
00117 };
00118 
00119 
00120 
00122 
00155 
00156 namespace rnd{
00157 
00159     
00162     TEM T& cond(T& v, const T& va, const T& vb, float pab, float pba);
00163 
00165     TEM T geom(int n, T mul, T start=1, float p=0.5);
00166 
00168     TEM T neg(T val, float prob=0.5f);
00169 
00171     TEM const T& pick(const T& val1, const T& val2, float prob=0.5f);
00172 
00174     TEM bool prob(T& rng, float p=0.5f);
00175     
00177     bool prob(float p=0.5f);
00178     bool prob(double p);
00179     
00181     
00184     bool prob(char c);
00185 
00186     #ifndef DOXYGEN_SHOULD_SKIP_THIS
00187     #define FUNCS(name)\
00188     TEM T name(T bound2, T bound1 = 0);\
00189     TEM void name(T * dst, uint32_t len);\
00190     TEM void name(T * dst, uint32_t len, T bound2, T bound1 = 0);\
00191     TEM void name(T * dst, uint32_t len, T * src, uint32_t srcLen);\
00192     TEM float name##_float(T & rng);
00193     //template <class Tv, class Tr> Tv name(Tr & rng);
00194 
00195     FUNCS(add2) FUNCS(add2I) FUNCS(add3) FUNCS(binS) FUNCS(lin) FUNCS(mul2)
00196     FUNCS(pow2) FUNCS(pow3) FUNCS(uni) FUNCS(uniS)
00197 
00198     #undef FUNCS
00199     #endif
00200 
00202     
00205     void push(uint32_t seed=0);
00206     void pop();                 
00207 
00209     TEM void permute(T * arr, uint32_t len);
00210 
00212     float quan(uint32_t q);
00213     
00215     TEM T quanOct(uint32_t q, T o);
00216 
00218     void seed(uint32_t value=0);
00219 
00221     TEM void set(T * arr, uint32_t len, uint32_t num, T val=1);
00222 
00224     TEM void thin(T * arr, uint32_t len, float prob=0.5f);
00225     
00227     TEM T uniExc(const T& exc, const T& max, const T& min=T(0));
00228     
00230     
00233     TEM uint32_t weighted(T * weights, uint32_t num, T weightsSum=(T)1);
00234     
00235     static RNGTaus gen(rnd::getSeed()); 
00236 }
00237 
00238 
00239 // Implementation_______________________________________________________________
00240 
00241 
00242 //---- RNGTaus
00243 
00244 inline RNGTaus::RNGTaus(uint32_t sd){ (*this) = sd; }
00245 
00246 inline uint32_t RNGTaus::operator()(){
00247     iterate();
00248     return s1 ^ s2 ^ s3 ^ s4;
00249 }
00250 
00251 inline void RNGTaus::operator=(uint32_t s){
00252     gen::RMulAdd<uint32_t> g(1664525, 1013904223, s);
00253     g.val = s; g();
00254     seed(g(), g(), g(), g());
00255 }
00256 
00257 inline void RNGTaus::seed(uint32_t v1, uint32_t v2, uint32_t v3, uint32_t v4){
00258     //printf("%d %d %d %d\n", v1, v2, v3, v4);
00259     v1 & 0xffffffe ? s1 = v1 : s1 = ~v1;
00260     v2 & 0xffffff8 ? s2 = v2 : s2 = ~v2;
00261     v3 & 0xffffff0 ? s3 = v3 : s3 = ~v3;
00262     v4 & 0xfffff80 ? s4 = v4 : s4 = ~v4;
00263 }
00264     
00265 inline void RNGTaus::iterate(){
00266     s1 = ((s1 & 0xfffffffe) << 18) ^ (((s1 <<  6) ^ s1) >> 13);
00267     s2 = ((s2 & 0xfffffff8) <<  2) ^ (((s2 <<  2) ^ s2) >> 27);
00268     s3 = ((s3 & 0xfffffff0) <<  7) ^ (((s3 << 13) ^ s3) >> 21);
00269     s4 = ((s4 & 0xffffff80) << 13) ^ (((s4 <<  3) ^ s4) >> 12);
00270 }
00271 
00272 
00273 //---- rnd
00274 namespace rnd{
00275 
00276 #define R uni_float(rng)
00277 TEM inline float add2_float(T& rng){ return (R + R) * 0.5f; }
00278 TEM inline float add3_float(T& rng){ return (R + R + R) * 0.33333333333f; }
00279 TEM inline float  lin_float(T& rng){ float r = R; float s = R; return r < s ? r : s; }
00280 TEM inline float mul2_float(T& rng){ return R * R; }
00281 TEM inline float pow2_float(T& rng){ float r = R; return r * r; }
00282 TEM inline float pow3_float(T& rng){ float r = R; return r * r * r; }
00283 
00284 TEM inline float add2I_float(T & rng){
00285     float r = add2_float(rng) + 0.5f; // [0.5, 1.5)
00286     return (r < 1.f) ? r : r - 1.f;
00287 }
00288 #undef R
00289 
00290 TEM inline float uni_float(T& rng){ return uintToUnit<float>(rng()); }
00291 TEM inline float uniS_float(T& rng){ return uintToUnitS<float>(rng()); }
00292 
00293 TEM inline float binS_float(T & rng){
00294     uint32_t r = rng() & MaskSign<float>() | Expo1<float>();
00295     return punUF(r);
00296 }
00297 
00298 TEM inline T & cond(T& v, const T& va, const T& vb, float pab, float pba){
00299          if(v == va) v = pick(vb, va, pba);
00300     else if(v == vb) v = pick(va, vb, pab);
00301     return v;
00302 }
00303 
00304 template <class RNG>
00305 float gaussian(RNG& rng = rnd::gen){
00306     float x1, x2, w, y1, y2;
00307 
00308     do{
00309         x1 = uniS_float(rng);
00310         x2 = uniS_float(rng);
00311         w = x1 * x1 + x2 * x2;
00312     } while( w >= 1.f );
00313 
00314     w = sqrt((-2.f * ::log(w)) / w);
00315     y1 = x1 * w;
00316     y2 = x2 * w;
00317     return y1;
00318 }
00319 
00320 TEM inline T geom(int n, T mul, T start, float p){
00321     for(; n>0; --n){
00322         if(prob(p)) break;
00323         start *= mul;
00324     }
00325     return start;
00326 }
00327 
00328 TEM inline T neg(T v, float p){ return prob(p) ? -v : v; }
00329 TEM inline const T & pick(const T & v1, const T & v2, float p){ return prob(p) ? v1 : v2; }
00330 TEM inline bool prob(T& rng, float p){ return uni_float(rng) < p; }
00331 inline bool prob(float p){ return prob(gen, p); }
00332 
00333 inline bool prob(double p){ return prob((float)p); }
00334 
00335 inline bool prob(char c){
00336     if(c>'7'||c=='/') return true; 
00337     if(c<'1')         return false;
00338     return prob((c-48) * 0.125f);
00339 }
00340 
00341 #define LOOP(n) for(uint32_t i=0;i<n;++i)
00342 
00343 TEM inline void set(T * arr, uint32_t len, uint32_t num, T val){
00344     LOOP(num){ arr[rnd::uni(len)] = val; }
00345 }
00346 
00347 TEM inline void permute(T * arr, uint32_t len){
00348     LOOP(len-1){ mem::swap(arr[i], arr[rnd::uni(len, i)]); }
00349 }
00350 
00351 inline float quan(uint32_t q){ return uni(q) / (float)q; }
00352 
00353 TEM inline T quanOct(uint32_t q, T o){ return quan(q) * o + o; }
00354 
00355 TEM inline void thin(T * arr, uint32_t len, float p){
00356     LOOP(len){ if(prob(p)) arr[i]=T(0); }
00357 }
00358 
00359 TEM inline T uniExc(const T& exc, const T& max, const T& min){
00360     T r=exc; while(exc==r){ r=uni(max,min); } return r;
00361 }
00362 
00363 #define DEF(rnd_t, fnc)\
00364     TEM inline T fnc(T b2, T b1){\
00365         return (T)( (rnd_t)b1 + fnc##_##rnd_t(gen) * (rnd_t)(b2-b1) );\
00366     }\
00367     TEM inline void fnc(T * dst, uint32_t len){\
00368         LOOP(len){ dst[i] = (T) fnc##_##rnd_t (gen); }\
00369     }\
00370     TEM inline void fnc(T * dst, uint32_t len, T bound2, T bound1){\
00371         rnd_t b1 = (rnd_t)bound1;\
00372         rnd_t df = (rnd_t)bound2 - b1;\
00373         LOOP(len){ dst[i] = (T)(b1 + fnc##_##rnd_t(gen) * df); }\
00374     }\
00375     TEM inline void fnc(T * dst, uint32_t len, T * src, uint32_t srcLen){\
00376         LOOP(len){ dst[i] = src[rnd::fnc(srcLen)]; }\
00377     }
00378     DEF(float, add2) DEF(float, add2I) DEF(float, add3) DEF(float, lin)
00379     DEF(float, mul2) DEF(float, pow2 ) DEF(float, pow3) DEF(float, uni)
00380     DEF(float, uniS)
00381 #undef DEF
00382 
00383 #undef LOOP
00384 
00385 inline void push(uint32_t seedA){
00386     mSeedPush[0] = gen.s1;
00387     mSeedPush[1] = gen.s2;
00388     mSeedPush[2] = gen.s3;
00389     mSeedPush[3] = gen.s4;
00390     if(seedA) seed(seedA);
00391 }
00392 inline void pop(){
00393     gen.s1 = mSeedPush[0];
00394     gen.s2 = mSeedPush[1];
00395     gen.s3 = mSeedPush[2];
00396     gen.s4 = mSeedPush[3];
00397 }
00398 
00399 inline void seed(uint32_t value){
00400     gen = value ? value : getSeed();
00401 }
00402 
00403 TEM uint32_t weighted(T * weights, uint32_t num, T weightsSum){
00404     if(0 == num--) return 0;
00405     T probSum = weights[0];
00406     T rnd = (T)(uni_float(gen) * (float)weightsSum);
00407     
00408     if(rnd < probSum) return 0;
00409     
00410     for(uint32_t i=1; i<num; ++i){
00411         probSum += weights[i];
00412         if(rnd < probSum) return i;
00413     }
00414     return num;
00415 }
00416 
00417 
00418 /*
00419 
00420 // some distributions from old code
00421 
00422 inline float RandomLC::exp(){
00423     uint32_t rand = nextU() & 0x3fffffff;  // 00111111111111111111111111111111
00424     return AS_FLOAT(rand) * 0.5f;
00425 }
00426 
00427 inline float RandomLC::expS(){
00428     uint32_t rand = nextU() & 0xbfffffff;   // 10111111111111111111111111111111
00429     return AS_FLOAT(rand) * 0.5f;
00430 }
00431 
00432 inline float RandomLC::gaussian(){
00433     return sqrt(-2.f * log(next1())) * sin(next1() * 6.28318530718f);
00434 }
00435 
00436 */
00437 
00438 } // rnd::
00439 } // gam::
00440 
00441 #undef TEM
00442 
00443 #endif