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.ExpSource; 8 private import Integer = tango.text.convert.Integer; 9 import tango.math.Math:exp,log; 10 import tango.math.random.Ziggurat; 11 import tango.core.Traits:isRealType; 12 13 /// class that returns exponential distributed numbers (f=exp(-x) for x>0, 0 otherwise) 14 final class ExpSource(RandG,T){ 15 static assert(isRealType!(T),T.stringof~" not acceptable, only floating point variables supported"); 16 /// probability distribution 17 static real probDensityF(real x){ return exp(-x); } 18 /// inverse probability distribution 19 static real invProbDensityF(real x){ return -log(x); } 20 /// complement of the cumulative density distribution (integral x..infinity probDensityF) 21 static real cumProbDensityFCompl(real x){ return exp(-x); } 22 /// tail for exponential distribution 23 static T tailGenerator(RandG r, T dMin) 24 { 25 return dMin-log(r.uniform!(T)()); 26 } 27 alias Ziggurat!(RandG,T,probDensityF,tailGenerator,false) SourceT; 28 /// internal source of exp distribued numbers 29 SourceT source; 30 /// initializes the probability distribution 31 this(RandG r){ 32 source=SourceT.create!(invProbDensityF,cumProbDensityFCompl)(r,0xf.64ec94bf5dc14bcp-1L); 33 } 34 /// chainable call style initialization of variables (thorugh a call to randomize) 35 ExpSource opCall(U,S...)(ref U a,S args){ 36 randomize(a,args); 37 return this; 38 } 39 /// returns a exp distribued number 40 T getRandom(){ 41 return source.getRandom(); 42 } 43 /// returns a exp distribued number with the given beta (survival rate, average) 44 /// f=1/beta*exp(-x/beta) 45 T getRandom(T beta){ 46 return beta*source.getRandom(); 47 } 48 /// initializes the given variable with an exponentially distribued number 49 U randomize(U)(ref U x){ 50 return source.randomize(x); 51 } 52 /// initializes the given variable with an exponentially distribued number with 53 /// scale parameter beta 54 U randomize(U,V)(ref U x,V beta){ 55 return source.randomizeOp((T el){ return el*cast(T)beta; },x); 56 } 57 /// initializes the given variable with an exponentially distribued number and maps op on it 58 U randomizeOp(U,S)(scope S delegate(T)op,ref U a){ 59 return source.randomizeOp(op,a); 60 } 61 /// exp distribution with different default scale parameter beta 62 /// f=1/beta*exp(-x/beta) for x>0, 0 otherwise 63 struct ExpDistribution{ 64 T beta; 65 ExpSource source; // does not use Ziggurat directly to keep this struct small 66 /// constructor 67 static ExpDistribution create()(ExpSource source,T beta){ 68 ExpDistribution res; 69 res.beta=beta; 70 res.source=source; 71 return res; 72 } 73 /// chainable call style initialization of variables (thorugh a call to randomize) 74 ExpDistribution opCall(U,S...)(ref U a,S args){ 75 randomize(a,args); 76 return this; 77 } 78 /// returns a single number 79 T getRandom(){ 80 return beta*source.getRandom(); 81 } 82 /// initialize a 83 U randomize(U)(ref U a){ 84 return source.randomizeOp((T x){return beta*x; },a); 85 } 86 /// initialize a 87 U randomize(U,V)(ref U a,V b){ 88 return source.randomizeOp((T x){return (cast(T)b)*x; },a); 89 } 90 } 91 /// returns an exp distribution with a different beta 92 ExpDistribution expD(T beta){ 93 return ExpDistribution.create(this,beta); 94 } 95 }