1 /******************************************************************************* 2 copyright: Copyright (c) 2008. Fawzi Mohamed 3 license: BSD style: $(LICENSE) 4 version: Initial release: July 2008 5 author: Fawzi Mohamed 6 *******************************************************************************/ 7 module tango.math.random.NormalSource; 8 private import Integer = tango.text.convert.Integer; 9 import tango.math.Math:exp,sqrt,log,PI; 10 import tango.math.ErrorFunction:erfc; 11 import tango.math.random.Ziggurat; 12 import tango.core.Traits: isRealType; 13 14 /// class that returns gaussian (normal) distributed numbers (f=exp(-0.5*x*x)/sqrt(2*pi)) 15 class NormalSource(RandG,T){ 16 static assert(isRealType!(T),T.stringof~" not acceptable, only floating point variables supported"); 17 /// probability distribution (non normalized, should be divided by sqrt(2*PI)) 18 static real probDensityF(real x){ return exp(-0.5L*x*x); } 19 /// inverse probability distribution 20 static real invProbDensityF(real x){ return sqrt(-2.0L*log(x)); } 21 /// complement of the cumulative density distribution (integral x..infinity probDensityF) 22 static real cumProbDensityFCompl(real x){ return sqrt(0.5L*PI)*erfc(x/sqrt(2.0L));/*normalDistributionCompl(x);*/ } 23 /// tail for normal distribution 24 static T tailGenerator(RandG r, T dMin, int iNegative) 25 { 26 T x, y; 27 do 28 { 29 x = -log(r.uniform!(T)()) / dMin; 30 y = -log(r.uniform!(T)()); 31 } while (y+y < x * x); 32 return (iNegative ?(-x - dMin):(dMin + x)); 33 } 34 alias Ziggurat!(RandG,T,probDensityF,tailGenerator,true) SourceT; 35 /// internal source of normal numbers 36 SourceT source; 37 /// initializes the probability distribution 38 this(RandG r){ 39 source=SourceT.create!(invProbDensityF,cumProbDensityFCompl)(r,0xe.9dda4104d699791p-2L); 40 } 41 /// chainable call style initialization of variables (thorugh a call to randomize) 42 NormalSource opCall(U,S...)(ref U a,S args){ 43 randomize(a,args); 44 return this; 45 } 46 /// returns a normal distribued number 47 final T getRandom(){ 48 return source.getRandom(); 49 } 50 /// returns a normal distribued number with the given sigma (standard deviation) 51 final T getRandom(T sigma){ 52 return sigma*source.getRandom(); 53 } 54 /// returns a normal distribued number with the given sigma (standard deviation) and mu (average) 55 final T getRandom(T sigma, T mu){ 56 return mu+sigma*source.getRandom(); 57 } 58 /// initializes a variable with normal distribued number and returns it 59 U randomize(U)(ref U a){ 60 return source.randomize(a); 61 } 62 /// initializes a variable with normal distribued number with the given sigma and returns it 63 U randomize(U,V)(ref U a,V sigma){ 64 return source.randomizeOp((T x){ return x*cast(T)sigma; },a); 65 } 66 /// initializes a variable with normal distribued numbers with the given sigma and mu and returns it 67 U randomize(U,V,S)(ref U el,V sigma, S mu){ 68 return source.randomizeOp((T x){ return x*cast(T)sigma+cast(T)mu; },a); 69 } 70 /// initializes the variable with the result of mapping op on the random numbers (of type T) 71 U randomizeOp(U,S)(scope S delegate(T) op,ref U a){ 72 return source.randomizeOp(op,a); 73 } 74 /// normal distribution with different default sigma and mu 75 /// f=exp(-x*x/(2*sigma^2))/(sqrt(2 pi)*sigma) 76 struct NormalDistribution{ 77 T sigma,mu; 78 NormalSource source; 79 /// constructor 80 static NormalDistribution create(NormalSource source,T sigma,T mu){ 81 NormalDistribution res; 82 res.source=source; 83 res.sigma=sigma; 84 res.mu=mu; 85 return res; 86 } 87 /// chainable call style initialization of variables (thorugh a call to randomize) 88 NormalDistribution opCall(U,S...)(ref U a,S args){ 89 randomize(a,args); 90 return this; 91 } 92 /// returns a single number 93 T getRandom(){ 94 return mu+sigma*source.getRandom(); 95 } 96 /// initialize a 97 U randomize(U)(ref U a){ 98 T op(T x){return mu+sigma*x; } 99 return source.randomizeOp(&op,a); 100 } 101 /// initialize a (let s and m have different types??) 102 U randomize(U,V)(ref U a,V s){ 103 T op(T x){return mu+(cast(T)s)*x; } 104 return source.randomizeOp(&op,a); 105 } 106 /// initialize a (let s and m have different types??) 107 U randomize(U,V,S)(ref U a,V s, S m){ 108 T op(T x){return (cast(T)m)+(cast(T)s)*x; } 109 return source.randomizeOp(&op,a); 110 } 111 } 112 /// returns a normal distribution with a non-default sigma/mu 113 NormalDistribution normalD(T sigma=cast(T)1,T mu=cast(T)0){ 114 return NormalDistribution.create(this,sigma,mu); 115 } 116 }