distribution 0.6.0 → 0.8.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (117) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +7 -0
  3. data/.travis.yml +13 -0
  4. data/.yardopts +5 -0
  5. data/Gemfile +5 -0
  6. data/History.txt +24 -8
  7. data/LICENCE.md +26 -0
  8. data/README.md +155 -0
  9. data/Rakefile +15 -19
  10. data/benchmark/binomial_coefficient.rb +19 -23
  11. data/benchmark/binomial_coefficient/experiment.rb +33 -36
  12. data/benchmark/factorial_hash.rb +7 -8
  13. data/benchmark/factorial_method.rb +4 -6
  14. data/benchmark/odd.rb +6 -7
  15. data/benchmark/power.rb +11 -11
  16. data/bin/distribution +26 -26
  17. data/data/template/spec.erb +7 -6
  18. data/distribution.gemspec +25 -0
  19. data/lib/distribution.rb +79 -124
  20. data/lib/distribution/beta.rb +6 -8
  21. data/lib/distribution/beta/gsl.rb +14 -9
  22. data/lib/distribution/beta/java.rb +1 -1
  23. data/lib/distribution/beta/ruby.rb +41 -7
  24. data/lib/distribution/binomial.rb +10 -11
  25. data/lib/distribution/binomial/gsl.rb +6 -5
  26. data/lib/distribution/binomial/java.rb +1 -1
  27. data/lib/distribution/binomial/ruby.rb +22 -15
  28. data/lib/distribution/bivariatenormal.rb +4 -5
  29. data/lib/distribution/bivariatenormal/gsl.rb +2 -2
  30. data/lib/distribution/bivariatenormal/java.rb +1 -1
  31. data/lib/distribution/bivariatenormal/ruby.rb +245 -254
  32. data/lib/distribution/chisquare.rb +8 -10
  33. data/lib/distribution/chisquare/gsl.rb +24 -19
  34. data/lib/distribution/chisquare/java.rb +1 -1
  35. data/lib/distribution/chisquare/ruby.rb +60 -55
  36. data/lib/distribution/chisquare/statistics2.rb +16 -13
  37. data/lib/distribution/distributable.rb +40 -0
  38. data/lib/distribution/exponential.rb +4 -5
  39. data/lib/distribution/exponential/gsl.rb +13 -9
  40. data/lib/distribution/exponential/ruby.rb +17 -11
  41. data/lib/distribution/f.rb +10 -11
  42. data/lib/distribution/f/gsl.rb +26 -22
  43. data/lib/distribution/f/java.rb +1 -1
  44. data/lib/distribution/f/ruby.rb +104 -105
  45. data/lib/distribution/f/statistics2.rb +22 -19
  46. data/lib/distribution/gamma.rb +5 -7
  47. data/lib/distribution/gamma/gsl.rb +13 -9
  48. data/lib/distribution/gamma/java.rb +1 -1
  49. data/lib/distribution/gamma/ruby.rb +5 -11
  50. data/lib/distribution/hypergeometric.rb +5 -8
  51. data/lib/distribution/hypergeometric/gsl.rb +5 -6
  52. data/lib/distribution/hypergeometric/java.rb +1 -1
  53. data/lib/distribution/hypergeometric/ruby.rb +34 -35
  54. data/lib/distribution/logistic.rb +6 -9
  55. data/lib/distribution/logistic/ruby.rb +14 -9
  56. data/lib/distribution/lognormal.rb +37 -0
  57. data/lib/distribution/lognormal/gsl.rb +21 -0
  58. data/lib/distribution/lognormal/ruby.rb +16 -0
  59. data/lib/distribution/math_extension.rb +187 -231
  60. data/lib/distribution/math_extension/chebyshev_series.rb +281 -272
  61. data/lib/distribution/math_extension/erfc.rb +28 -31
  62. data/lib/distribution/math_extension/exponential_integral.rb +17 -17
  63. data/lib/distribution/math_extension/gammastar.rb +19 -20
  64. data/lib/distribution/math_extension/gsl_utilities.rb +12 -12
  65. data/lib/distribution/math_extension/incomplete_beta.rb +52 -61
  66. data/lib/distribution/math_extension/incomplete_gamma.rb +166 -168
  67. data/lib/distribution/math_extension/log_utilities.rb +20 -22
  68. data/lib/distribution/normal.rb +11 -13
  69. data/lib/distribution/normal/gsl.rb +13 -10
  70. data/lib/distribution/normal/java.rb +30 -1
  71. data/lib/distribution/normal/ruby.rb +69 -59
  72. data/lib/distribution/normal/statistics2.rb +5 -2
  73. data/lib/distribution/normalmultivariate.rb +64 -64
  74. data/lib/distribution/poisson.rb +12 -14
  75. data/lib/distribution/poisson/gsl.rb +7 -7
  76. data/lib/distribution/poisson/java.rb +26 -0
  77. data/lib/distribution/poisson/ruby.rb +38 -9
  78. data/lib/distribution/shorthand.rb +17 -0
  79. data/lib/distribution/t.rb +16 -16
  80. data/lib/distribution/t/gsl.rb +27 -24
  81. data/lib/distribution/t/java.rb +1 -1
  82. data/lib/distribution/t/ruby.rb +99 -100
  83. data/lib/distribution/t/statistics2.rb +19 -19
  84. data/lib/distribution/uniform.rb +26 -0
  85. data/lib/distribution/uniform/gsl.rb +36 -0
  86. data/lib/distribution/uniform/ruby.rb +91 -0
  87. data/lib/distribution/version.rb +3 -0
  88. data/lib/distribution/weibull.rb +10 -0
  89. data/lib/distribution/weibull/gsl.rb +21 -0
  90. data/lib/distribution/weibull/ruby.rb +34 -0
  91. data/spec/beta_spec.rb +48 -50
  92. data/spec/binomial_spec.rb +80 -84
  93. data/spec/bivariatenormal_spec.rb +28 -35
  94. data/spec/chisquare_spec.rb +49 -52
  95. data/spec/distribution_spec.rb +11 -11
  96. data/spec/exponential_spec.rb +48 -39
  97. data/spec/f_spec.rb +73 -71
  98. data/spec/gamma_spec.rb +50 -53
  99. data/spec/hypergeometric_spec.rb +63 -69
  100. data/spec/logistic_spec.rb +31 -37
  101. data/spec/lognormal_spec.rb +54 -0
  102. data/spec/math_extension_spec.rb +192 -209
  103. data/spec/normal_spec.rb +80 -73
  104. data/spec/poisson_spec.rb +78 -36
  105. data/spec/shorthand_spec.rb +19 -22
  106. data/spec/spec_helper.rb +31 -6
  107. data/spec/t_spec.rb +63 -77
  108. data/spec/uniform_spec.rb +154 -0
  109. data/spec/weibull_spec.rb +17 -0
  110. data/vendor/java/commons-math-2.2.jar +0 -0
  111. metadata +91 -111
  112. data.tar.gz.sig +0 -0
  113. data/.autotest +0 -23
  114. data/.gemtest +0 -0
  115. data/Manifest.txt +0 -95
  116. data/README.txt +0 -100
  117. metadata.gz.sig +0 -0
@@ -5,22 +5,21 @@ require 'distribution/beta/java'
5
5
 
6
6
  module Distribution
7
7
  # From Wikipedia:
8
- # In probability theory and statistics, the beta distribution
9
- # is a family of continuous probability distributions defined
10
- # on the interval (0, 1) parameterized by two positive shape
11
- # parameters, typically denoted by alpha and beta.
8
+ # In probability theory and statistics, the beta distribution
9
+ # is a family of continuous probability distributions defined
10
+ # on the interval (0, 1) parameterized by two positive shape
11
+ # parameters, typically denoted by alpha and beta.
12
12
  # This module calculate cdf and inverse cdf for Beta Distribution.
13
13
  #
14
14
  module Beta
15
15
  extend Distributable
16
- SHORTHAND='beta'
16
+ SHORTHAND = 'beta'
17
17
  create_distribution_methods
18
18
 
19
19
  ##
20
20
  # :singleton-method: pdf(x,a,b)
21
21
  # Returns PDF of of Beta distribution with parameters a and b
22
22
 
23
-
24
23
  ##
25
24
  # :singleton-method: cdf(x,a,b)
26
25
  # Returns the integral of Beta distribution with parameters a and b
@@ -28,7 +27,6 @@ module Distribution
28
27
  ##
29
28
  # :singleton-method: p_value(qn,a,b)
30
29
  # Return the quantile of the corresponding integral +qn+
31
- # on a beta distribution's cdf with parameters a and b
32
-
30
+ # on a beta distribution's cdf with parameters a and b
33
31
  end
34
32
  end
@@ -2,22 +2,27 @@ module Distribution
2
2
  module Beta
3
3
  module GSL_
4
4
  class << self
5
- def pdf(x,a,b)
6
- GSL::Ran::beta_pdf(x.to_f, a.to_f, b.to_f)
7
- end
8
- # Return the P-value of the corresponding integral with
9
- # k degrees of freedom
10
- def p_value(pr,a,b)
11
- GSL::Cdf::beta_Pinv(pr.to_f, a.to_f, b.to_f)
5
+ # PDF.
6
+ def pdf(x, a, b)
7
+ GSL::Ran.beta_pdf(x.to_f, a.to_f, b.to_f)
12
8
  end
9
+
13
10
  # Beta cumulative distribution function (cdf).
14
11
  #
15
12
  # Returns the integral of Beta distribution
16
13
  # with parameters +a+ and +b+ over [0, x]
17
14
  #
18
- def cdf(x,a,b)
19
- GSL::Cdf::beta_P(x.to_f, a.to_f, b.to_f)
15
+ def cdf(x, a, b)
16
+ GSL::Cdf.beta_P(x.to_f, a.to_f, b.to_f)
17
+ end
18
+
19
+ # Return the P-value of the corresponding integral with
20
+ # k degrees of freedom
21
+ def quantile(pr, a, b)
22
+ GSL::Cdf.beta_Pinv(pr.to_f, a.to_f, b.to_f)
20
23
  end
24
+
25
+ alias_method :p_value, :quantile
21
26
  end
22
27
  end
23
28
  end
@@ -6,4 +6,4 @@ module Distribution
6
6
  end
7
7
  end
8
8
  end
9
- end
9
+ end
@@ -3,7 +3,6 @@ module Distribution
3
3
  module Beta
4
4
  module Ruby_
5
5
  class << self
6
-
7
6
  include Math
8
7
  # Beta distribution probability density function
9
8
  #
@@ -13,29 +12,64 @@ module Distribution
13
12
  #
14
13
  # == References
15
14
  # * http://www.gnu.org/s/gsl/manual/html_node/The-Gamma-Distribution.html
16
- def pdf(x,a,b)
15
+ def pdf(x, a, b)
17
16
  return 0 if x < 0 || x > 1
18
17
 
19
- gab = Math.lgamma(a+b).first
18
+ gab = Math.lgamma(a + b).first
20
19
  ga = Math.lgamma(a).first
21
20
  gb = Math.lgamma(b).first
22
21
 
23
22
  if x == 0.0 || x == 1.0
24
- Math.exp(gab - ga - gb) * x**(a-1) * (1-x)**(b-1)
23
+ Math.exp(gab - ga - gb) * x**(a - 1) * (1 - x)**(b - 1)
25
24
  else
26
- Math.exp(gab - ga - gb + Math.log(x)*(a-1) + Math::Log.log1p(-x)*(b-1))
25
+ Math.exp(gab - ga - gb + Math.log(x) * (a - 1) + Math::Log.log1p(-x) * (b - 1))
27
26
  end
28
27
  end
29
28
 
30
29
  # Gamma cumulative distribution function
31
30
  # Translated from GSL-1.9: cdf/beta.c gsl_cdf_beta_P
32
- def cdf(x,a,b)
31
+ def cdf(x, a, b)
33
32
  return 0.0 if x <= 0.0
34
33
  return 1.0 if x >= 1.0
35
- Math::IncompleteBeta.axpy(1.0, 0.0, a,b,x)
34
+ Math::IncompleteBeta.axpy(1.0, 0.0, a, b, x)
36
35
  end
37
36
 
37
+ # Inverse of the beta distribution function
38
+ def quantile(p, a, b, rmin = 0, rmax = 1)
39
+ fail 'a <= 0' if a <= 0
40
+ fail 'b <= 0' if b <= 0
41
+ fail 'rmin == rmax' if rmin == rmax
42
+ fail 'p <= 0' if p <= 0
43
+ fail 'p > 1' if p > 1
44
+
45
+ precision = 8.88e-016
46
+ max_iterations = 256
47
+
48
+ ga = 0
49
+ gb = 2
50
+
51
+ i = 1
52
+ while ((gb - ga) > precision) && (i < max_iterations)
53
+ guess = (ga + gb) / 2.0
54
+ result = cdf(guess, a, b)
55
+
56
+ if (result == p) || (result == 0)
57
+ gb = ga
58
+ elsif result > p
59
+ gb = guess
60
+ else
61
+ ga = guess
62
+ end
63
+
64
+ fail 'No value' if i == max_iterations
65
+
66
+ i += 1
67
+ end
68
+
69
+ rmin + guess * (rmax - rmin)
70
+ end
38
71
 
72
+ alias_method :p_value, :quantile
39
73
  end
40
74
  end
41
75
  end
@@ -2,27 +2,26 @@ require 'distribution/binomial/ruby'
2
2
  require 'distribution/binomial/gsl'
3
3
  require 'distribution/binomial/java'
4
4
  module Distribution
5
-
6
5
  # Calculate statisticals for Binomial Distribution.
7
6
  module Binomial
8
- SHORTHAND = 'bino'
9
-
7
+ SHORTHAND = 'bino'
8
+
10
9
  extend Distributable
11
10
  create_distribution_methods
12
-
11
+
13
12
  ##
14
13
  # :singleton-method: pdf(x,k)
15
- # Returns the integral of T distribution
16
- # with +k+ degrees of freedom over [0, +x+]
14
+ # Returns the integral of T distribution
15
+ # with +k+ degrees of freedom over [0, +x+]
17
16
 
18
17
  ##
19
18
  # :singleton-method: p_value(qn, k)
20
- # Return the P-value of the corresponding integral +qn+ with
21
- # +k+ degrees of freedom
22
-
19
+ # Return the P-value of the corresponding integral +qn+ with
20
+ # +k+ degrees of freedom
21
+
23
22
  ##
24
23
  # :singleton-method: cdf(x,k)
25
- # Returns the integral of T distribution
26
- # with +k+ degrees of freedom over [0, +x+]
24
+ # Returns the integral of T distribution
25
+ # with +k+ degrees of freedom over [0, +x+]
27
26
  end
28
27
  end
@@ -2,13 +2,14 @@ module Distribution
2
2
  module Binomial
3
3
  module GSL_
4
4
  class << self
5
- def pdf(k,n,prob)
6
- GSL::Ran.binomial_pdf(k,prob,n)
5
+ def pdf(k, n, prob)
6
+ GSL::Ran.binomial_pdf(k, prob, n)
7
7
  end
8
- def cdf(k,n,prob)
9
- GSL::Cdf.binomial_P(k,prob,n)
8
+
9
+ def cdf(k, n, prob)
10
+ GSL::Cdf.binomial_P(k, prob, n)
10
11
  end
11
12
  end
12
13
  end
13
14
  end
14
- end
15
+ end
@@ -6,4 +6,4 @@ module Distribution
6
6
  end
7
7
  end
8
8
  end
9
- end
9
+ end
@@ -2,28 +2,35 @@ module Distribution
2
2
  module Binomial
3
3
  module Ruby_
4
4
  class << self
5
- def pdf(k,n,pr)
6
- raise "k>n" if k>n
7
- Math.binomial_coefficient(n,k)*(pr**k)*(1-pr)**(n-k)
5
+ def pdf(k, n, pr)
6
+ fail 'k>n' if k > n
7
+ Math.binomial_coefficient(n, k) * (pr**k) * (1 - pr)**(n - k)
8
8
  end
9
- # TODO: Use exact_regularized_beta for
9
+
10
+ alias_method :exact_pdf, :pdf
11
+
12
+ # TODO: Use exact_regularized_beta for
10
13
  # small values and regularized_beta for bigger ones.
11
- def cdf(k,n,pr)
12
- #(0..x.floor).inject(0) {|ac,i| ac+pdf(i,n,pr)}
13
- Math.regularized_beta(1-pr,n - k,k+1)
14
+ def cdf(k, n, pr)
15
+ # (0..x.floor).inject(0) {|ac,i| ac+pdf(i,n,pr)}
16
+ Math.regularized_beta(1 - pr, n - k, k + 1)
14
17
  end
15
- def exact_cdf(k,n,pr)
16
- (0..k).inject(0) {|ac,i| ac+pdf(i,n,pr)}
18
+
19
+ def exact_cdf(k, n, pr)
20
+ out = (0..k).inject(0) { |ac, i| ac + pdf(i, n, pr) }
21
+ out = 1 if out > 1.0
22
+ out
17
23
  end
18
- def p_value(prob,n,pr)
19
- ac=0
24
+
25
+ def quantile(prob, n, pr)
26
+ ac = 0
20
27
  (0..n).each do |i|
21
- ac+=pdf(i,n,pr)
22
- return i if prob<=ac
28
+ ac += pdf(i, n, pr)
29
+ return i if prob <= ac
23
30
  end
24
31
  end
25
-
26
- alias :exact_pdf :pdf
32
+
33
+ alias_method :p_value, :quantile
27
34
  end
28
35
  end
29
36
  end
@@ -7,21 +7,20 @@ module Distribution
7
7
  # Pdf if easy to calculate, but CDF is not trivial. Several papers
8
8
  # describe methods to calculate the integral.
9
9
  module BivariateNormal
10
- SHORTHAND='bnor'
10
+ SHORTHAND = 'bnor'
11
11
 
12
12
  extend Distributable
13
13
  create_distribution_methods
14
-
14
+
15
15
  ##
16
16
  # :singleton-method: pdf(k,n,prob)
17
17
  # Probability density function for exactly +k+ successes in +n+ trials
18
18
  # with success probability +prob+
19
- #
20
-
19
+ #
20
+
21
21
  ##
22
22
  # :singleton-method: cdf(k,n,prob)
23
23
  # Cumulative density function for +k+ or less successes in +n+ trials
24
24
  # with success probability +prob+
25
-
26
25
  end
27
26
  end
@@ -2,8 +2,8 @@ module Distribution
2
2
  module BivariateNormal
3
3
  module GSL_
4
4
  class <<self
5
- def pdf(x,y,rho,s1=1.0,s2=1.0)
6
- GSL::Ran::bivariate_gaussian_pdf(x, y, s1,s2,rho)
5
+ def pdf(x, y, rho, s1 = 1.0, s2 = 1.0)
6
+ GSL::Ran.bivariate_gaussian_pdf(x, y, s1, s2, rho)
7
7
  end
8
8
  end
9
9
  end
@@ -6,4 +6,4 @@ module Distribution
6
6
  end
7
7
  end
8
8
  end
9
- end
9
+ end
@@ -1,281 +1,272 @@
1
1
  module Distribution
2
- #
2
+ #
3
3
  # Ruby version implements three methods on this module:
4
4
  # * Genz:: Used by default, with improvement to calculate p on rho > 0.95
5
5
  # * Hull:: Port from a C++ code
6
6
  # * Jantaravareerat:: Iterative (slow and buggy)
7
- #
8
-
7
+ #
8
+
9
9
  module BivariateNormal
10
10
  module Ruby_
11
- class << self
12
- SIDE=0.1 # :nodoc:
13
- LIMIT=5 # :nodoc:
14
- # Return the partial derivative of cdf over x, with y and rho constant
15
- # Reference:
16
- # * Tallis, 1962, p.346, cited by Olsson, 1979
17
- def partial_derivative_cdf_x(x,y,rho)
18
- Distribution::Normal.pdf(x) * Distribution::Normal.cdf((y-rho*x).quo( Math::sqrt( 1 - rho**2 )))
19
- end
20
- alias :pd_cdf_x :partial_derivative_cdf_x
21
- # Probability density function for a given x, y and rho value.
22
- #
23
- # Source: http://en.wikipedia.org/wiki/Multivariate_normal_distribution
24
- def pdf(x,y, rho, s1=1.0, s2=1.0)
25
- 1.quo(2 * Math::PI * s1 * s2 * Math::sqrt( 1 - rho**2 )) * (Math::exp(-(1.quo(2*(1-rho**2))) *
26
- ((x**2.quo(s1)) + (y**2.quo(s2)) - (2*rho*x*y).quo(s1*s2))))
27
- end
28
-
29
- def f(x,y,aprime,bprime,rho)
30
- r=aprime*(2*x-aprime)+bprime*(2*y-bprime)+2*rho*(x-aprime)*(y-bprime)
31
- Math::exp(r)
32
- end
33
-
34
- # CDF for a given x, y and rho value.
35
- # Uses Genz algorithm (cdf_genz method).
36
- #
37
- def cdf(a,b,rho)
38
- cdf_genz(a,b,rho)
39
- end
40
-
41
- def sgn(x)
42
- if(x>=0)
43
- 1
44
- else
45
- -1
46
- end
47
- end
48
-
49
- # Normal cumulative distribution function (cdf) for a given x, y and rho.
50
- # Based on Hull (1993, cited by Arne, 2003)
51
- #
52
- # References:
53
- # * Arne, B.(2003). Financial Numerical Recipes in C ++. Available on http://finance.bi.no/~bernt/gcc_prog/recipes/recipes/node23.html
54
- def cdf_hull(a,b,rho)
55
- #puts "a:#{a} - b:#{b} - rho:#{rho}"
56
- if (a<=0 and b<=0 and rho<=0)
57
- # puts "ruta 1"
58
- aprime=a.quo(Math::sqrt(2.0*(1.0-rho**2)))
59
- bprime=b.quo(Math::sqrt(2.0*(1.0-rho**2)))
60
- aa=[0.3253030, 0.4211071, 0.1334425, 0.006374323]
61
- bb=[0.1337764, 0.6243247, 1.3425378, 2.2626645]
62
- sum=0
63
- 4.times do |i|
64
- 4.times do |j|
65
- sum+=aa[i]*aa[j] * f(bb[i], bb[j], aprime, bprime,rho)
66
- end
67
- end
68
- sum=sum*(Math::sqrt(1.0-rho**2).quo(Math::PI))
69
- return sum
70
- elsif(a*b*rho<=0.0)
71
-
72
- #puts "ruta 2"
73
- if(a<=0 and b>=0 and rho>=0)
74
- return Distribution::Normal.cdf(a) - cdf(a,-b,-rho)
75
- elsif (a>=0.0 and b<=0.0 and rho>=0)
76
- return Distribution::Normal.cdf(b) - cdf(-a,b,-rho)
77
- elsif (a>=0.0 and b>=0.0 and rho<=0)
78
- return Distribution::Normal.cdf(a) + Distribution::Normal.cdf(b) - 1.0 + cdf(-a,-b,rho)
11
+ class << self
12
+ SIDE = 0.1 # :nodoc:
13
+ LIMIT = 5 # :nodoc:
14
+ # Return the partial derivative of cdf over x, with y and rho constant
15
+ # Reference:
16
+ # * Tallis, 1962, p.346, cited by Olsson, 1979
17
+ def partial_derivative_cdf_x(x, y, rho)
18
+ Distribution::Normal.pdf(x) * Distribution::Normal.cdf((y - rho * x).quo(Math.sqrt(1 - rho**2)))
19
+ end
20
+ alias_method :pd_cdf_x, :partial_derivative_cdf_x
21
+ # Probability density function for a given x, y and rho value.
22
+ #
23
+ # Source: http://en.wikipedia.org/wiki/Multivariate_normal_distribution
24
+ def pdf(x, y, rho, s1 = 1.0, s2 = 1.0)
25
+ 1.quo(2 * Math::PI * s1 * s2 * Math.sqrt(1 - rho**2)) * (Math.exp(-(1.quo(2 * (1 - rho**2))) *
26
+ ((x**2.quo(s1)) + (y**2.quo(s2)) - (2 * rho * x * y).quo(s1 * s2))))
27
+ end
28
+
29
+ def f(x, y, aprime, bprime, rho)
30
+ r = aprime * (2 * x - aprime) + bprime * (2 * y - bprime) + 2 * rho * (x - aprime) * (y - bprime)
31
+ Math.exp(r)
32
+ end
33
+
34
+ # CDF for a given x, y and rho value.
35
+ # Uses Genz algorithm (cdf_genz method).
36
+ #
37
+ def cdf(a, b, rho)
38
+ cdf_genz(a, b, rho)
39
+ end
40
+
41
+ def sgn(x)
42
+ if (x >= 0)
43
+ 1
44
+ else
45
+ -1
79
46
  end
80
- elsif (a*b*rho>=0.0)
81
- #puts "ruta 3"
82
- denum=Math::sqrt(a**2 - 2*rho*a*b + b**2)
83
- rho1=((rho*a-b)*sgn(a)).quo(denum)
84
- rho2=((rho*b-a)*sgn(b)).quo(denum)
85
- delta=(1.0-sgn(a)*sgn(b)).quo(4)
86
- #puts "#{rho1} - #{rho2}"
87
- return cdf(a, 0.0, rho1) + cdf(b, 0.0, rho2) - delta
88
47
  end
89
- raise "Should'nt be here! #{a} - #{b} #{rho}"
90
- end
91
-
92
- # CDF. Iterative method by Jantaravareerat (n/d)
93
- #
94
- # Reference:
95
- # * Jantaravareerat, M. & Thomopoulos, N. (n/d). Tables for standard bivariate normal distribution
96
-
97
- def cdf_jantaravareerat(x,y,rho,s1=1,s2=1)
98
- # Special cases
99
- return 1 if x>LIMIT and y>LIMIT
100
- return 0 if x<-LIMIT or y<-LIMIT
101
- return Distribution::Normal.cdf(y) if x>LIMIT
102
- return Distribution::Normal.cdf(x) if y>LIMIT
103
-
104
- #puts "x:#{x} - y:#{y}"
105
- x=-LIMIT if x<-LIMIT
106
- x=LIMIT if x>LIMIT
107
- y=-LIMIT if y<-LIMIT
108
- y=LIMIT if y>LIMIT
109
48
 
110
- x_squares=((LIMIT+x) / SIDE).to_i
111
- y_squares=((LIMIT+y) / SIDE).to_i
112
- sum=0
113
- x_squares.times do |i|
114
- y_squares.times do |j|
115
- z1=-LIMIT+(i+1)*SIDE
116
- z2=-LIMIT+(j+1)*SIDE
117
- #puts " #{z1}-#{z2}"
118
- h=(pdf(z1,z2,rho,s1,s2)+pdf(z1-SIDE,z2,rho,s1,s2)+pdf(z1,z2-SIDE,rho,s1,s2) + pdf(z1-SIDE,z2-SIDE,rho,s1,s2)).quo(4)
119
- sum+= (SIDE**2)*h # area
49
+ # Normal cumulative distribution function (cdf) for a given x, y and rho.
50
+ # Based on Hull (1993, cited by Arne, 2003)
51
+ #
52
+ # References:
53
+ # * Arne, B.(2003). Financial Numerical Recipes in C ++. Available on http://finance.bi.no/~bernt/gcc_prog/recipes/recipes/node23.html
54
+ def cdf_hull(a, b, rho)
55
+ # puts "a:#{a} - b:#{b} - rho:#{rho}"
56
+ if a <= 0 && b <= 0 && rho <= 0
57
+ # puts "ruta 1"
58
+ aprime = a.quo(Math.sqrt(2.0 * (1.0 - rho**2)))
59
+ bprime = b.quo(Math.sqrt(2.0 * (1.0 - rho**2)))
60
+ aa = [0.3253030, 0.4211071, 0.1334425, 0.006374323]
61
+ bb = [0.1337764, 0.6243247, 1.3425378, 2.2626645]
62
+ sum = 0
63
+ 4.times do |i|
64
+ 4.times do |j|
65
+ sum += aa[i] * aa[j] * f(bb[i], bb[j], aprime, bprime, rho)
66
+ end
67
+ end
68
+ sum *= (Math.sqrt(1.0 - rho**2).quo(Math::PI))
69
+ return sum
70
+ elsif (a * b * rho <= 0.0)
71
+
72
+ # puts "ruta 2"
73
+ if a <= 0 && b >= 0 && rho >= 0
74
+ return Distribution::Normal.cdf(a) - cdf(a, -b, -rho)
75
+ elsif a >= 0.0 && b <= 0.0 && rho >= 0
76
+ return Distribution::Normal.cdf(b) - cdf(-a, b, -rho)
77
+ elsif a >= 0.0 && b >= 0.0 && rho <= 0
78
+ return Distribution::Normal.cdf(a) + Distribution::Normal.cdf(b) - 1.0 + cdf(-a, -b, rho)
79
+ end
80
+ elsif (a * b * rho >= 0.0)
81
+ # puts "ruta 3"
82
+ denum = Math.sqrt(a**2 - 2 * rho * a * b + b**2)
83
+ rho1 = ((rho * a - b) * sgn(a)).quo(denum)
84
+ rho2 = ((rho * b - a) * sgn(b)).quo(denum)
85
+ delta = (1.0 - sgn(a) * sgn(b)).quo(4)
86
+ # puts "#{rho1} - #{rho2}"
87
+ return cdf(a, 0.0, rho1) + cdf(b, 0.0, rho2) - delta
120
88
  end
89
+ fail "Should'nt be here! #{a} - #{b} #{rho}"
121
90
  end
122
- sum
123
- end
124
- # Normal cumulative distribution function (cdf) for a given x, y and rho.
125
- # Ported from Fortran code by Alan Genz
126
- #
127
- # Original documentation
128
- # DOUBLE PRECISION FUNCTION BVND( DH, DK, R )
129
- # A function for computing bivariate normal probabilities.
130
- #
131
- # Alan Genz
132
- # Department of Mathematics
133
- # Washington State University
134
- # Pullman, WA 99164-3113
135
- # Email : alangenz_AT_wsu.edu
136
- #
137
- # This function is based on the method described by
138
- # Drezner, Z and G.O. Wesolowsky, (1989),
139
- # On the computation of the bivariate normal integral,
140
- # Journal of Statist. Comput. Simul. 35, pp. 101-107,
141
- # with major modifications for double precision, and for |R| close to 1.
142
- #
143
- # Original location:
144
- # * http://www.math.wsu.edu/faculty/genz/software/fort77/tvpack.f
145
- def cdf_genz(x,y,rho)
146
- dh=-x
147
- dk=-y
148
- r=rho
149
- twopi = 6.283185307179586
150
-
151
- w=11.times.collect {[nil]*4};
152
- x=11.times.collect {[nil]*4}
153
-
154
- data=[
155
- 0.1713244923791705E+00, -0.9324695142031522E+00,
156
- 0.3607615730481384E+00, -0.6612093864662647E+00,
157
- 0.4679139345726904E+00, -0.2386191860831970E+00]
158
-
159
- (1..3).each {|i|
160
- w[i][1]=data[(i-1)*2]
161
- x[i][1]=data[(i-1)*2+1]
162
-
163
- }
164
- data=[
165
- 0.4717533638651177E-01,-0.9815606342467191E+00,
166
- 0.1069393259953183E+00,-0.9041172563704750E+00,
167
- 0.1600783285433464E+00,-0.7699026741943050E+00,
168
- 0.2031674267230659E+00,-0.5873179542866171E+00,
169
- 0.2334925365383547E+00,-0.3678314989981802E+00,
170
- 0.2491470458134029E+00,-0.1252334085114692E+00]
171
- (1..6).each {|i|
172
- w[i][2]=data[(i-1)*2]
173
- x[i][2]=data[(i-1)*2+1]
174
91
 
175
-
176
- }
177
- data=[
178
- 0.1761400713915212E-01,-0.9931285991850949E+00,
179
- 0.4060142980038694E-01,-0.9639719272779138E+00,
180
- 0.6267204833410906E-01,-0.9122344282513259E+00,
181
- 0.8327674157670475E-01,-0.8391169718222188E+00,
182
- 0.1019301198172404E+00,-0.7463319064601508E+00,
183
- 0.1181945319615184E+00,-0.6360536807265150E+00,
184
- 0.1316886384491766E+00,-0.5108670019508271E+00,
185
- 0.1420961093183821E+00,-0.3737060887154196E+00,
186
- 0.1491729864726037E+00,-0.2277858511416451E+00,
187
- 0.1527533871307259E+00,-0.7652652113349733E-01]
188
-
189
- (1..10).each {|i|
190
- w[i][3]=data[(i-1)*2]
191
- x[i][3]=data[(i-1)*2+1]
92
+ # CDF. Iterative method by Jantaravareerat (n/d)
93
+ #
94
+ # Reference:
95
+ # * Jantaravareerat, M. & Thomopoulos, N. (n/d). Tables for standard bivariate normal distribution
192
96
 
193
-
194
- }
195
-
196
-
197
- if ( r.abs < 0.3 )
198
- ng = 1
199
- lg = 3
200
- elsif ( r.abs < 0.75 )
201
- ng = 2
202
- lg = 6
203
- else
204
- ng = 3
205
- lg = 10
97
+ def cdf_jantaravareerat(x, y, rho, s1 = 1, s2 = 1)
98
+ # Special cases
99
+ return 1 if x > LIMIT && y > LIMIT
100
+ return 0 if x < -LIMIT || y < -LIMIT
101
+ return Distribution::Normal.cdf(y) if x > LIMIT
102
+ return Distribution::Normal.cdf(x) if y > LIMIT
103
+
104
+ # puts "x:#{x} - y:#{y}"
105
+ x = -LIMIT if x < -LIMIT
106
+ x = LIMIT if x > LIMIT
107
+ y = -LIMIT if y < -LIMIT
108
+ y = LIMIT if y > LIMIT
109
+
110
+ x_squares = ((LIMIT + x) / SIDE).to_i
111
+ y_squares = ((LIMIT + y) / SIDE).to_i
112
+ sum = 0
113
+ x_squares.times do |i|
114
+ y_squares.times do |j|
115
+ z1 = -LIMIT + (i + 1) * SIDE
116
+ z2 = -LIMIT + (j + 1) * SIDE
117
+ # puts " #{z1}-#{z2}"
118
+ h = (pdf(z1, z2, rho, s1, s2) + pdf(z1 - SIDE, z2, rho, s1, s2) + pdf(z1, z2 - SIDE, rho, s1, s2) + pdf(z1 - SIDE, z2 - SIDE, rho, s1, s2)).quo(4)
119
+ sum += (SIDE**2) * h # area
120
+ end
121
+ end
122
+ sum
206
123
  end
207
-
208
-
209
- h = dh
210
- k = dk
211
- hk = h*k
212
- bvn = 0
213
- if ( r.abs < 0.925 )
214
- if ( r.abs > 0 )
215
- hs = ( h*h + k*k ).quo(2)
216
- asr = Math::asin(r)
217
- (1..lg).each do |i|
218
- [-1,1].each do |is|
219
- sn = Math::sin(asr*(is* x[i][ng]+1).quo(2) )
220
- bvn = bvn + w[i][ng] * Math::exp( ( sn*hk-hs ).quo( 1-sn*sn ) )
221
- end # do
222
- end # do
223
- bvn = bvn*asr.quo( 2*twopi )
224
- end # if
225
- bvn = bvn + Distribution::Normal.cdf(-h) * Distribution::Normal.cdf(-k)
226
-
227
-
228
- else # r.abs
229
- if ( r < 0 )
230
- k = -k
231
- hk = -hk
124
+ # Normal cumulative distribution function (cdf) for a given x, y and rho.
125
+ # Ported from Fortran code by Alan Genz
126
+ #
127
+ # Original documentation
128
+ # DOUBLE PRECISION FUNCTION BVND( DH, DK, R )
129
+ # A function for computing bivariate normal probabilities.
130
+ #
131
+ # Alan Genz
132
+ # Department of Mathematics
133
+ # Washington State University
134
+ # Pullman, WA 99164-3113
135
+ # Email : alangenz_AT_wsu.edu
136
+ #
137
+ # This function is based on the method described by
138
+ # Drezner, Z and G.O. Wesolowsky, (1989),
139
+ # On the computation of the bivariate normal integral,
140
+ # Journal of Statist. Comput. Simul. 35, pp. 101-107,
141
+ # with major modifications for double precision, and for |R| close to 1.
142
+ #
143
+ # Original location:
144
+ # * http://www.math.wsu.edu/faculty/genz/software/fort77/tvpack.f
145
+ def cdf_genz(x, y, rho)
146
+ dh = -x
147
+ dk = -y
148
+ r = rho
149
+ twopi = 6.283185307179586
150
+
151
+ w = 11.times.collect { [nil] * 4 }
152
+ x = 11.times.collect { [nil] * 4 }
153
+
154
+ data = [
155
+ 0.1713244923791705E+00, -0.9324695142031522E+00,
156
+ 0.3607615730481384E+00, -0.6612093864662647E+00,
157
+ 0.4679139345726904E+00, -0.2386191860831970E+00]
158
+
159
+ (1..3).each do|i|
160
+ w[i][1] = data[(i - 1) * 2]
161
+ x[i][1] = data[(i - 1) * 2 + 1]
232
162
  end
233
-
234
- if ( r.abs < 1 )
235
- as = ( 1 - r )*( 1 + r )
236
- a = Math::sqrt(as)
237
- bs = ( h - k )**2
238
- c = ( 4 - hk ).quo(8)
239
- d = ( 12 - hk ).quo(16)
240
- asr = -( bs.quo(as) + hk ).quo(2)
241
- if ( asr > -100 )
242
- bvn = a*Math::exp(asr) * ( 1 - c*( bs - as )*( 1 - d*bs.quo(5) ).quo(3) + c*d*as*as.quo(5) )
243
- end
244
- if ( -hk < 100 )
245
- b = Math::sqrt(bs)
246
- bvn = bvn - Math::exp( -hk.quo(2) ) * Math::sqrt(twopi)*Distribution::Normal.cdf(-b.quo(a))*b *
247
- ( 1 - c*bs*( 1 - d*bs.quo(5) ).quo(3) )
163
+ data = [
164
+ 0.4717533638651177E-01, -0.9815606342467191E+00,
165
+ 0.1069393259953183E+00, -0.9041172563704750E+00,
166
+ 0.1600783285433464E+00, -0.7699026741943050E+00,
167
+ 0.2031674267230659E+00, -0.5873179542866171E+00,
168
+ 0.2334925365383547E+00, -0.3678314989981802E+00,
169
+ 0.2491470458134029E+00, -0.1252334085114692E+00]
170
+ (1..6).each do|i|
171
+ w[i][2] = data[(i - 1) * 2]
172
+ x[i][2] = data[(i - 1) * 2 + 1]
173
+ end
174
+ data = [
175
+ 0.1761400713915212E-01, -0.9931285991850949E+00,
176
+ 0.4060142980038694E-01, -0.9639719272779138E+00,
177
+ 0.6267204833410906E-01, -0.9122344282513259E+00,
178
+ 0.8327674157670475E-01, -0.8391169718222188E+00,
179
+ 0.1019301198172404E+00, -0.7463319064601508E+00,
180
+ 0.1181945319615184E+00, -0.6360536807265150E+00,
181
+ 0.1316886384491766E+00, -0.5108670019508271E+00,
182
+ 0.1420961093183821E+00, -0.3737060887154196E+00,
183
+ 0.1491729864726037E+00, -0.2277858511416451E+00,
184
+ 0.1527533871307259E+00, -0.7652652113349733E-01]
185
+
186
+ (1..10).each do|i|
187
+ w[i][3] = data[(i - 1) * 2]
188
+ x[i][3] = data[(i - 1) * 2 + 1]
189
+ end
190
+
191
+ if r.abs < 0.3
192
+ ng = 1
193
+ lg = 3
194
+ elsif r.abs < 0.75
195
+ ng = 2
196
+ lg = 6
197
+ else
198
+ ng = 3
199
+ lg = 10
200
+ end
201
+
202
+ h = dh
203
+ k = dk
204
+ hk = h * k
205
+ bvn = 0
206
+ if r.abs < 0.925
207
+ if r.abs > 0
208
+ hs = (h * h + k * k).quo(2)
209
+ asr = Math.asin(r)
210
+ (1..lg).each do |i|
211
+ [-1, 1].each do |is|
212
+ sn = Math.sin(asr * (is * x[i][ng] + 1).quo(2))
213
+ bvn += w[i][ng] * Math.exp((sn * hk - hs).quo(1 - sn * sn))
214
+ end # do
215
+ end # do
216
+ bvn *= asr.quo(2 * twopi)
217
+ end # if
218
+ bvn += Distribution::Normal.cdf(-h) * Distribution::Normal.cdf(-k)
219
+
220
+ else # r.abs
221
+ if r < 0
222
+ k = -k
223
+ hk = -hk
248
224
  end
249
-
250
-
251
- a = a.quo(2)
252
- (1..lg).each do |i|
253
- [-1,1].each do |is|
254
- xs = (a*( is*x[i][ng] + 1 ) )**2
255
- rs = Math::sqrt( 1 - xs )
256
- asr = -( bs/xs + hk ).quo(2)
257
- if ( asr > -100 )
258
- bvn = bvn + a*w[i][ng] * Math::exp( asr ) *
259
- ( Math::exp( -hk*( 1 - rs ).quo(2*( 1 + rs ) ) ) .quo(rs) - ( 1 + c*xs*( 1 + d*xs ) ) )
225
+
226
+ if r.abs < 1
227
+ as = (1 - r) * (1 + r)
228
+ a = Math.sqrt(as)
229
+ bs = (h - k)**2
230
+ c = (4 - hk).quo(8)
231
+ d = (12 - hk).quo(16)
232
+ asr = -(bs.quo(as) + hk).quo(2)
233
+ if asr > -100
234
+ bvn = a * Math.exp(asr) * (1 - c * (bs - as) * (1 - d * bs.quo(5)).quo(3) + c * d * as * as.quo(5))
235
+ end
236
+ if -hk < 100
237
+ b = Math.sqrt(bs)
238
+ bvn -= Math.exp(-hk.quo(2)) * Math.sqrt(twopi) * Distribution::Normal.cdf(-b.quo(a)) * b *
239
+ (1 - c * bs * (1 - d * bs.quo(5)).quo(3))
240
+ end
241
+
242
+ a = a.quo(2)
243
+ (1..lg).each do |i|
244
+ [-1, 1].each do |is|
245
+ xs = (a * (is * x[i][ng] + 1))**2
246
+ rs = Math.sqrt(1 - xs)
247
+ asr = -(bs / xs + hk).quo(2)
248
+ if asr > -100
249
+ bvn += a * w[i][ng] * Math.exp(asr) *
250
+ (Math.exp(-hk * (1 - rs).quo(2 * (1 + rs))) .quo(rs) - (1 + c * xs * (1 + d * xs)))
251
+ end
260
252
  end
261
253
  end
254
+ bvn = -bvn / twopi
262
255
  end
263
- bvn = -bvn/twopi
264
- end
265
-
266
- if ( r > 0 )
267
- bvn = bvn + Distribution::Normal.cdf(-[h,k].max)
268
- else
269
- bvn = -bvn
270
- if ( k > h )
271
- bvn = bvn + Distribution::Normal.cdf(k) - Distribution::Normal.cdf(h)
256
+
257
+ if r > 0
258
+ bvn += Distribution::Normal.cdf(-[h, k].max)
259
+ else
260
+ bvn = -bvn
261
+ if k > h
262
+ bvn = bvn + Distribution::Normal.cdf(k) - Distribution::Normal.cdf(h)
263
+ end
272
264
  end
273
265
  end
266
+ bvn
274
267
  end
275
- bvn
268
+ private :f, :sgn
276
269
  end
277
- private :f, :sgn
278
- end
279
270
  end
280
271
  end
281
272
  end