| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596 | /******************************************************************************* copyright: Copyright (c) 2008. Fawzi Mohamed license: BSD style: $(LICENSE) version: Initial release: July 2008 author: Fawzi Mohamed *******************************************************************************/ module tango.math.random.ExpSource; private import Integer = tango.text.convert.Integer; import tango.math.Math:exp,log; import tango.math.random.Ziggurat; import tango.core.Traits:isRealType; /// class that returns exponential distributed numbers (f=exp(-x) for x>0, 0 otherwise) final class ExpSource(RandG,T){ static assert(isRealType!(T),T.stringof~" not acceptable, only floating point variables supported"); /// probability distribution static real probDensityF(real x){ return exp(-x); } /// inverse probability distribution static real invProbDensityF(real x){ return -log(x); } /// complement of the cumulative density distribution (integral x..infinity probDensityF) static real cumProbDensityFCompl(real x){ return exp(-x); } /// tail for exponential distribution static T tailGenerator(RandG r, T dMin) { return dMin-log(r.uniform!(T)()); } alias Ziggurat!(RandG,T,probDensityF,tailGenerator,false) SourceT; /// internal source of exp distribued numbers SourceT source; /// initializes the probability distribution this(RandG r){ source=SourceT.create!(invProbDensityF,cumProbDensityFCompl)(r,0xf.64ec94bf5dc14bcp-1L); } /// chainable call style initialization of variables (thorugh a call to randomize) ExpSource opCall(U,S...)(ref U a,S args){ randomize(a,args); return this; } /// returns a exp distribued number T getRandom(){ return source.getRandom(); } /// returns a exp distribued number with the given beta (survival rate, average) /// f=1/beta*exp(-x/beta) T getRandom(T beta){ return beta*source.getRandom(); } /// initializes the given variable with an exponentially distribued number U randomize(U)(ref U x){ return source.randomize(x); } /// initializes the given variable with an exponentially distribued number with /// scale parameter beta U randomize(U,V)(ref U x,V beta){ return source.randomizeOp((T el){ return el*cast(T)beta; },x); } /// initializes the given variable with an exponentially distribued number and maps op on it U randomizeOp(U,S)(scope S delegate(T)op,ref U a){ return source.randomizeOp(op,a); } /// exp distribution with different default scale parameter beta /// f=1/beta*exp(-x/beta) for x>0, 0 otherwise struct ExpDistribution{ T beta; ExpSource source; // does not use Ziggurat directly to keep this struct small /// constructor static ExpDistribution create()(ExpSource source,T beta){ ExpDistribution res; res.beta=beta; res.source=source; return res; } /// chainable call style initialization of variables (thorugh a call to randomize) ExpDistribution opCall(U,S...)(ref U a,S args){ randomize(a,args); return this; } /// returns a single number T getRandom(){ return beta*source.getRandom(); } /// initialize a U randomize(U)(ref U a){ return source.randomizeOp((T x){return beta*x; },a); } /// initialize a U randomize(U,V)(ref U a,V b){ return source.randomizeOp((T x){return (cast(T)b)*x; },a); } } /// returns an exp distribution with a different beta ExpDistribution expD(T beta){ return ExpDistribution.create(this,beta); } } |