distribution 0.7.3 → 0.8.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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