distribution 0.7.3 → 0.8.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (100) hide show
  1. checksums.yaml +5 -5
  2. data/.travis.yml +4 -6
  3. data/.yardopts +5 -0
  4. data/History.txt +3 -0
  5. data/README.md +87 -44
  6. data/benchmark/binomial_coefficient.rb +19 -23
  7. data/benchmark/binomial_coefficient/experiment.rb +33 -36
  8. data/benchmark/factorial_hash.rb +7 -8
  9. data/benchmark/factorial_method.rb +4 -6
  10. data/benchmark/odd.rb +6 -7
  11. data/benchmark/power.rb +11 -11
  12. data/bin/distribution +26 -26
  13. data/distribution.gemspec +3 -4
  14. data/lib/distribution.rb +55 -96
  15. data/lib/distribution/beta/gsl.rb +10 -5
  16. data/lib/distribution/beta/ruby.rb +3 -1
  17. data/lib/distribution/binomial/ruby.rb +5 -2
  18. data/lib/distribution/bivariatenormal.rb +4 -5
  19. data/lib/distribution/bivariatenormal/gsl.rb +2 -2
  20. data/lib/distribution/bivariatenormal/java.rb +1 -1
  21. data/lib/distribution/bivariatenormal/ruby.rb +245 -254
  22. data/lib/distribution/chisquare.rb +8 -10
  23. data/lib/distribution/chisquare/gsl.rb +24 -19
  24. data/lib/distribution/chisquare/java.rb +1 -1
  25. data/lib/distribution/chisquare/ruby.rb +25 -25
  26. data/lib/distribution/chisquare/statistics2.rb +16 -13
  27. data/lib/distribution/distributable.rb +40 -0
  28. data/lib/distribution/exponential.rb +4 -5
  29. data/lib/distribution/exponential/gsl.rb +13 -9
  30. data/lib/distribution/exponential/ruby.rb +14 -9
  31. data/lib/distribution/f.rb +1 -1
  32. data/lib/distribution/f/gsl.rb +26 -22
  33. data/lib/distribution/f/java.rb +1 -1
  34. data/lib/distribution/f/ruby.rb +16 -19
  35. data/lib/distribution/f/statistics2.rb +22 -19
  36. data/lib/distribution/gamma.rb +5 -7
  37. data/lib/distribution/gamma/gsl.rb +13 -9
  38. data/lib/distribution/gamma/java.rb +1 -1
  39. data/lib/distribution/gamma/ruby.rb +5 -11
  40. data/lib/distribution/hypergeometric.rb +5 -8
  41. data/lib/distribution/hypergeometric/gsl.rb +4 -5
  42. data/lib/distribution/hypergeometric/java.rb +1 -1
  43. data/lib/distribution/hypergeometric/ruby.rb +34 -35
  44. data/lib/distribution/logistic.rb +5 -8
  45. data/lib/distribution/logistic/ruby.rb +13 -8
  46. data/lib/distribution/lognormal.rb +5 -7
  47. data/lib/distribution/lognormal/gsl.rb +8 -6
  48. data/lib/distribution/lognormal/ruby.rb +5 -9
  49. data/lib/distribution/math_extension.rb +6 -15
  50. data/lib/distribution/math_extension/chebyshev_series.rb +281 -272
  51. data/lib/distribution/math_extension/erfc.rb +26 -29
  52. data/lib/distribution/math_extension/exponential_integral.rb +17 -17
  53. data/lib/distribution/math_extension/gammastar.rb +19 -20
  54. data/lib/distribution/math_extension/gsl_utilities.rb +12 -12
  55. data/lib/distribution/math_extension/incomplete_beta.rb +52 -61
  56. data/lib/distribution/math_extension/incomplete_gamma.rb +166 -168
  57. data/lib/distribution/math_extension/log_utilities.rb +20 -22
  58. data/lib/distribution/normal.rb +11 -13
  59. data/lib/distribution/normal/gsl.rb +13 -10
  60. data/lib/distribution/normal/java.rb +14 -13
  61. data/lib/distribution/normal/ruby.rb +68 -58
  62. data/lib/distribution/normal/statistics2.rb +5 -2
  63. data/lib/distribution/normalmultivariate.rb +64 -64
  64. data/lib/distribution/poisson.rb +11 -13
  65. data/lib/distribution/poisson/gsl.rb +7 -7
  66. data/lib/distribution/poisson/java.rb +19 -24
  67. data/lib/distribution/poisson/ruby.rb +38 -9
  68. data/lib/distribution/shorthand.rb +17 -0
  69. data/lib/distribution/t.rb +13 -15
  70. data/lib/distribution/t/gsl.rb +27 -24
  71. data/lib/distribution/t/java.rb +1 -1
  72. data/lib/distribution/t/ruby.rb +99 -100
  73. data/lib/distribution/t/statistics2.rb +19 -19
  74. data/lib/distribution/uniform.rb +26 -0
  75. data/lib/distribution/uniform/gsl.rb +36 -0
  76. data/lib/distribution/uniform/ruby.rb +91 -0
  77. data/lib/distribution/version.rb +1 -1
  78. data/lib/distribution/weibull.rb +6 -7
  79. data/lib/distribution/weibull/gsl.rb +16 -16
  80. data/lib/distribution/weibull/ruby.rb +30 -23
  81. data/spec/beta_spec.rb +45 -47
  82. data/spec/binomial_spec.rb +77 -85
  83. data/spec/bivariatenormal_spec.rb +28 -35
  84. data/spec/chisquare_spec.rb +48 -52
  85. data/spec/distribution_spec.rb +10 -10
  86. data/spec/exponential_spec.rb +44 -49
  87. data/spec/f_spec.rb +4 -4
  88. data/spec/gamma_spec.rb +50 -53
  89. data/spec/hypergeometric_spec.rb +63 -69
  90. data/spec/logistic_spec.rb +32 -37
  91. data/spec/lognormal_spec.rb +25 -31
  92. data/spec/math_extension_spec.rb +192 -210
  93. data/spec/normal_spec.rb +80 -73
  94. data/spec/poisson_spec.rb +63 -41
  95. data/spec/shorthand_spec.rb +19 -22
  96. data/spec/spec_helper.rb +8 -9
  97. data/spec/t_spec.rb +63 -77
  98. data/spec/uniform_spec.rb +154 -0
  99. data/spec/weibull_spec.rb +13 -14
  100. metadata +17 -8
@@ -4,27 +4,25 @@ require 'distribution/chisquare/statistics2'
4
4
  require 'distribution/chisquare/java'
5
5
  module Distribution
6
6
  # Calculate cdf and inverse cdf for Chi Square Distribution.
7
- #
7
+ #
8
8
  module ChiSquare
9
9
  extend Distributable
10
- SHORTHAND='chisq'
10
+ SHORTHAND = 'chisq'
11
11
  create_distribution_methods
12
-
12
+
13
13
  ##
14
14
  # :singleton-method: pdf(x)
15
- # Returns PDF of of Chi-squared distribution
15
+ # Returns PDF of of Chi-squared distribution
16
16
  # with +k+ degrees of freedom
17
-
18
-
17
+
19
18
  ##
20
19
  # :singleton-method: cdf(x,k)
21
- # Returns the integral of Chi-squared distribution
22
- # with +k+ degrees of freedom over [0, +x+]
20
+ # Returns the integral of Chi-squared distribution
21
+ # with +k+ degrees of freedom over [0, +x+]
23
22
 
24
23
  ##
25
24
  # :singleton-method: p_value(qn, k)
26
- # Return the P-value of the corresponding integral +qn+ with
25
+ # Return the P-value of the corresponding integral +qn+ with
27
26
  # +k+ degrees of freedom
28
-
29
27
  end
30
28
  end
@@ -2,25 +2,30 @@ module Distribution
2
2
  module ChiSquare
3
3
  module GSL_
4
4
  class << self
5
- def rng(k,seed=nil)
6
-
7
- end
8
- def pdf(x,k)
9
- GSL::Ran::chisq_pdf(x.to_f,k.to_i)
10
- end
11
- # Return the P-value of the corresponding integral with
12
- # k degrees of freedom
13
- def p_value(pr,k)
14
- GSL::Cdf::chisq_Pinv(pr.to_f,k.to_i)
15
- end
16
- # Chi-square cumulative distribution function (cdf).
17
- #
18
- # Returns the integral of Chi-squared distribution
19
- # with k degrees of freedom over [0, x]
20
- #
21
- def cdf(x, k)
22
- GSL::Cdf::chisq_P(x.to_f,k.to_i)
23
- end
5
+ def rng(_k, _seed = nil)
6
+ nil
7
+ end
8
+
9
+ def pdf(x, k)
10
+ GSL::Ran.chisq_pdf(x.to_f, k.to_i)
11
+ end
12
+
13
+ # Chi-square cumulative distribution function (cdf).
14
+ #
15
+ # Returns the integral of Chi-squared distribution
16
+ # with k degrees of freedom over [0, x]
17
+ #
18
+ def cdf(x, k)
19
+ GSL::Cdf.chisq_P(x.to_f, k.to_i)
20
+ end
21
+
22
+ # Return the P-value of the corresponding integral with
23
+ # k degrees of freedom
24
+ def quantile(pr, k)
25
+ GSL::Cdf.chisq_Pinv(pr.to_f, k.to_i)
26
+ end
27
+
28
+ alias_method :p_value, :quantile
24
29
  end
25
30
  end
26
31
  end
@@ -6,4 +6,4 @@ module Distribution
6
6
  end
7
7
  end
8
8
  end
9
- end
9
+ end
@@ -2,27 +2,25 @@ module Distribution
2
2
  module ChiSquare
3
3
  module Ruby_
4
4
  class << self
5
-
6
5
  include Math
7
- def pdf(x,n)
6
+ def pdf(x, n)
8
7
  if n == 1
9
- 1.0/Math.sqrt(2 * Math::PI * x) * Math::E**(-x/2.0)
8
+ 1.0 / Math.sqrt(2 * Math::PI * x) * Math::E**(-x / 2.0)
10
9
  elsif n == 2
11
- 0.5 * Math::E**(-x/2.0)
10
+ 0.5 * Math::E**(-x / 2.0)
12
11
  else
13
12
  n = n.to_f
14
- n2 = n/2
13
+ n2 = n / 2
15
14
  x = x.to_f
16
- 1.0 / 2**n2 / gamma(n2) * x**(n2 - 1.0) * Math.exp(-x/2.0)
17
- end
15
+ 1.0 / 2**n2 / gamma(n2) * x**(n2 - 1.0) * Math.exp(-x / 2.0)
16
+ end
18
17
  end
19
-
20
-
18
+
21
19
  # CDF Inverse over [x, \infty)
22
20
  # Pr([x, \infty)) = y -> x
23
21
  def pchi2(n, y)
24
22
  if n == 1
25
- w = Distribution::Normal.p_value(1 - y/2) # = p1.0-Distribution::Normal.cdf(y/2)
23
+ w = Distribution::Normal.p_value(1 - y / 2) # = p1.0-Distribution::Normal.cdf(y/2)
26
24
  w * w
27
25
  elsif n == 2
28
26
  # v = (1.0 / y - 1.0) / 33.0
@@ -34,26 +32,22 @@ module Distribution
34
32
  s = 10.0
35
33
  loop do
36
34
  v += s
37
- if s <= eps then break end
35
+ break if s <= eps
38
36
  if (qe = q_chi2(n, v) - y) == 0.0 then break end
39
37
  if qe < 0.0
40
- v -= s
41
- s /= 10.0
38
+ v -= s
39
+ s /= 10.0
40
+ end
42
41
  end
43
- end
44
42
 
45
- v
43
+ v
46
44
  end
47
45
  end
48
46
 
49
- def p_value(pr,k)
50
- pchi2(k, 1.0-pr)
47
+ def cdf(x, k)
48
+ 1.0 - q_chi2(k, x)
51
49
  end
52
50
 
53
- def cdf(x,k)
54
- 1.0-q_chi2(k,x)
55
- end
56
-
57
51
  # chi-square distribution ([1])
58
52
  # Integral over [x, \infty)
59
53
  def q_chi2(df, chi2)
@@ -61,28 +55,34 @@ module Distribution
61
55
  if (df & 1) != 0
62
56
  chi = Math.sqrt(chi2)
63
57
 
64
- if (df == 1) then return 2 * (1.0-Distribution::Normal.cdf(chi)); end
58
+ return 2 * (1.0 - Distribution::Normal.cdf(chi)) if (df == 1)
65
59
  s = t = chi * Math.exp(-0.5 * chi2) / SQ2PI
66
60
  k = 3
67
61
 
68
62
  while k < df
69
- t *= chi2 / k; s += t;
63
+ t *= chi2 / k; s += t
70
64
  k += 2
71
65
  end
72
66
 
73
- 2 * (1.0-(Distribution::Normal.cdf(chi)) + s)
67
+ 2 * (1.0 - (Distribution::Normal.cdf(chi)) + s)
74
68
 
75
69
  else
76
70
  s = t = Math.exp(-0.5 * chi2)
77
71
  k = 2
78
72
 
79
73
  while k < df
80
- t *= chi2 / k; s += t;
74
+ t *= chi2 / k; s += t
81
75
  k += 2
82
76
  end
83
77
  s
84
78
  end
85
79
  end
80
+
81
+ def quantile(pr, k)
82
+ pchi2(k, 1.0 - pr)
83
+ end
84
+
85
+ alias_method :p_value, :quantile
86
86
  end
87
87
  end
88
88
  end
@@ -2,20 +2,23 @@ module Distribution
2
2
  module ChiSquare
3
3
  module Statistics2_
4
4
  class << self
5
- # Return the P-value of the corresponding integral with
6
- # k degrees of freedom
7
- def p_value(pr,k)
8
- Statistics2.pchi2X_(k.to_i, pr)
9
- end
10
- # Chi-square cumulative distribution function (cdf).
11
- #
12
- # Returns the integral of Chi-squared distribution
13
- # with k degrees of freedom over [0, x]
14
- #
15
- def cdf(x, k)
16
- Statistics2.chi2dist(k.to_i,x)
5
+ # Chi-square cumulative distribution function (cdf).
6
+ #
7
+ # Returns the integral of Chi-squared distribution
8
+ # with k degrees of freedom over [0, x]
9
+ #
10
+ def cdf(x, k)
11
+ Statistics2.chi2dist(k.to_i, x)
12
+ end
13
+
14
+ # Return the P-value of the corresponding integral with
15
+ # k degrees of freedom
16
+ def quantile(pr, k)
17
+ Statistics2.pchi2X_(k.to_i, pr)
18
+ end
19
+
20
+ alias_method :p_value, :quantile
17
21
  end
18
22
  end
19
23
  end
20
- end
21
24
  end
@@ -0,0 +1,40 @@
1
+ module Distribution
2
+ # Magic module
3
+ module Distributable #:nodoc:
4
+ # Create methods for each module and add methods to
5
+ # Distribution::Shorthand.
6
+ #
7
+ # Traverse Distribution.libraries_order adding
8
+ # methods availables for each engine module on
9
+ # the current library
10
+ #
11
+ # Kids: Metaprogramming trickery! Don't do at work.
12
+ # This section was created between a very long reunion
13
+ # and a 456 Km. travel
14
+ def create_distribution_methods
15
+ Distribution.libraries_order.each do |l_name|
16
+ if const_defined? l_name
17
+ l = const_get(l_name)
18
+ # Add methods from engine to base base, if not yet included
19
+ l.singleton_methods.each do |m|
20
+ unless singleton_methods.include? m
21
+ define_method(m) do |*args|
22
+ l.send(m, *args)
23
+ end
24
+ # Add method to Distribution::Shorthand
25
+ sh = const_get(:SHORTHAND)
26
+ Distribution::Shorthand.add_shortcut(sh, m) do |*args|
27
+ l.send(m, *args)
28
+ end
29
+
30
+ module_function m
31
+ end
32
+ end
33
+ end
34
+ end
35
+
36
+ # create alias for common methods
37
+ alias_method :inverse_cdf, :p_value if singleton_methods.include? :p_value
38
+ end
39
+ end
40
+ end
@@ -1,19 +1,18 @@
1
1
  require 'distribution/exponential/ruby'
2
2
  require 'distribution/exponential/gsl'
3
- #require 'distribution/exponential/java'
4
-
3
+ # require 'distribution/exponential/java'
5
4
 
6
5
  module Distribution
7
6
  # From Wikipedia:
8
- # In probability theory and statistics, the exponential distribution
7
+ # In probability theory and statistics, the exponential distribution
9
8
  # (a.k.a. negative exponential distribution) is a family of continuous
10
9
  # probability distributions. It describes the time between events in a
11
- # Poisson process, i.e. a process in which events occur continuously
10
+ # Poisson process, i.e. a process in which events occur continuously
12
11
  # and independently at a constant average rate.
13
12
  #
14
13
  # Parameter +l+ is the rate parameter, the number of occurrences/unit time.
15
14
  module Exponential
16
- SHORTHAND='expo'
15
+ SHORTHAND = 'expo'
17
16
  extend Distributable
18
17
  create_distribution_methods
19
18
  ##
@@ -2,18 +2,22 @@ module Distribution
2
2
  module Exponential
3
3
  module GSL_
4
4
  class << self
5
- def pdf(x,l)
6
- return 0 if x<0
7
- GSL::Ran.exponential_pdf(x,1/l.to_f)
5
+ def pdf(x, l)
6
+ return 0 if x < 0
7
+ GSL::Ran.exponential_pdf(x, 1 / l.to_f)
8
8
  end
9
- def cdf(x,l)
10
- return 0 if x<0
11
- GSL::Cdf.exponential_P(x,1/l.to_f)
9
+
10
+ def cdf(x, l)
11
+ return 0 if x < 0
12
+ GSL::Cdf.exponential_P(x, 1 / l.to_f)
12
13
  end
13
- def p_value(pr,l)
14
- GSL::Cdf.exponential_Pinv(pr,1/l.to_f)
14
+
15
+ def quantile(pr, l)
16
+ GSL::Cdf.exponential_Pinv(pr, 1 / l.to_f)
15
17
  end
18
+
19
+ alias_method :p_value, :quantile
16
20
  end
17
21
  end
18
22
  end
19
- end
23
+ end
@@ -4,19 +4,24 @@ module Distribution
4
4
  class << self
5
5
  def rng(l, opts = {})
6
6
  rng = opts[:random] || Random
7
- lambda {p_value(rng.rand,l)}
7
+ -> { p_value(rng.rand, l) }
8
8
  end
9
- def pdf(x,l)
10
- return 0 if x<0
11
- l*Math.exp(-l*x)
9
+
10
+ def pdf(x, l)
11
+ return 0 if x < 0
12
+ l * Math.exp(-l * x)
12
13
  end
13
- def cdf(x,l)
14
- return 0 if x<0
15
- 1-Math.exp(-l*x)
14
+
15
+ def cdf(x, l)
16
+ return 0 if x < 0
17
+ 1 - Math.exp(-l * x)
16
18
  end
17
- def p_value(pr,l)
18
- (-Math.log(1-pr)).quo(l)
19
+
20
+ def quantile(pr, l)
21
+ (-Math.log(1 - pr)).quo(l)
19
22
  end
23
+
24
+ alias_method :p_value, :quantile
20
25
  end
21
26
  end
22
27
  end
@@ -6,7 +6,7 @@ module Distribution
6
6
  # Calculate cdf and inverse cdf for F Distribution.
7
7
  #
8
8
  module F
9
- SHORTHAND='fdist'
9
+ SHORTHAND = 'fdist'
10
10
  extend Distributable
11
11
  create_distribution_methods
12
12
 
@@ -1,27 +1,31 @@
1
1
  module Distribution
2
2
  module F
3
- module GSL_
4
- class << self
5
- def pdf(x,k1,k2)
6
- GSL::Ran.fdist_pdf(x.to_f,k1,k2)
7
- end
8
- # Return the P-value of the corresponding integral with
9
- # k degrees of freedom
10
- #
11
- # Distribution::F.p_value(0.95,1,2)
12
- def p_value(pr,k1,k2)
13
- GSL::Cdf.fdist_Pinv(pr.to_f,k1,k2)
14
- end
15
- # F cumulative distribution function (cdf).
16
- #
17
- # Returns the integral of F-distribution
18
- # with k1 and k2 degrees of freedom
19
- # over [0, x].
20
- # Distribution::F.cdf(20,3,2)
21
- #
22
- def cdf(x, k1, k2)
23
- GSL::Cdf.fdist_P(x.to_f.to_f,k1,k2)
24
- end
3
+ module GSL_
4
+ class << self
5
+ def pdf(x, k1, k2)
6
+ GSL::Ran.fdist_pdf(x.to_f, k1, k2)
7
+ end
8
+
9
+ # F cumulative distribution function (cdf).
10
+ #
11
+ # Returns the integral of F-distribution
12
+ # with k1 and k2 degrees of freedom
13
+ # over [0, x].
14
+ # Distribution::F.cdf(20,3,2)
15
+ #
16
+ def cdf(x, k1, k2)
17
+ GSL::Cdf.fdist_P(x.to_f.to_f, k1, k2)
18
+ end
19
+
20
+ # Return the P-value of the corresponding integral with
21
+ # k degrees of freedom
22
+ #
23
+ # Distribution::F.p_value(0.95,1,2)
24
+ def quantile(pr, k1, k2)
25
+ GSL::Cdf.fdist_Pinv(pr.to_f, k1, k2)
26
+ end
27
+
28
+ alias_method :p_value, :quantile
25
29
  end
26
30
  end
27
31
  end
@@ -6,4 +6,4 @@ module Distribution
6
6
  end
7
7
  end
8
8
  end
9
- end
9
+ end
@@ -16,19 +16,19 @@ module Distribution
16
16
  module Ruby_
17
17
  extend Distribution::MathExtension
18
18
 
19
- # functions needed:
20
- # - pdf
21
- # - cdf (lower cumulative function, P(x))
22
- # - Q(x), upper cumulative function
23
- # - mean
24
- # - mode
25
- # - kurtosis
26
- # - skewness
27
- # - entropy
28
- # - "fit" (maximum likelihood?)
29
- # - expected value (given a function)
30
- # - lower-tail quantile -> P
31
- # - upper tail quantile -> Q
19
+ # functions needed:
20
+ # - pdf
21
+ # - cdf (lower cumulative function, P(x))
22
+ # - Q(x), upper cumulative function
23
+ # - mean
24
+ # - mode
25
+ # - kurtosis
26
+ # - skewness
27
+ # - entropy
28
+ # - "fit" (maximum likelihood?)
29
+ # - expected value (given a function)
30
+ # - lower-tail quantile -> P
31
+ # - upper tail quantile -> Q
32
32
 
33
33
  class << self
34
34
  # F Distribution (Ruby) -- Probability Density Function
@@ -61,7 +61,7 @@ module Distribution
61
61
  #
62
62
  # Taken from:
63
63
  # https://github.com/JuliaLang/Rmath-julia/blob/master/src/qf.c
64
- def p_value(probability, n, m)
64
+ def quantile(probability, n, m)
65
65
  return Float::NAN if n <= 0.0 || m <= 0.0
66
66
 
67
67
  if n == Float::INFINITY || n == -Float::INFINITY || m == Float::INFINITY || m == -Float::INFINITY
@@ -80,6 +80,8 @@ module Distribution
80
80
  end
81
81
  end
82
82
 
83
+ alias_method :p_value, :quantile
84
+
83
85
  # Complementary quantile function.
84
86
  #
85
87
  # def cquantile(prob, n, m)
@@ -95,23 +97,18 @@ module Distribution
95
97
  # @return [Float] Value of the F distribution that gives a p-value of `y`.
96
98
 
97
99
  def mean
98
-
99
100
  end
100
101
 
101
102
  def mode
102
-
103
103
  end
104
104
 
105
105
  def skewness
106
-
107
106
  end
108
107
 
109
108
  def kurtosis
110
-
111
109
  end
112
110
 
113
111
  def entropy
114
-
115
112
  end
116
113
  end
117
114
  end