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