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
@@ -2,38 +2,35 @@ require 'distribution/hypergeometric/ruby'
2
2
  require 'distribution/hypergeometric/gsl'
3
3
  require 'distribution/hypergeometric/java'
4
4
 
5
-
6
5
  module Distribution
7
6
  # From Wikipedia:
8
7
  # In probability theory and statistics, the hypergeometric distribution is a discrete probability distribution that
9
8
  # describes the number of successes in a sequence of n draws from a finite population without replacement, just as
10
9
  # the binomial distribution describes the number of successes for draws with replacement.
11
10
  module Hypergeometric
12
- SHORTHAND='hypg'
11
+ SHORTHAND = 'hypg'
13
12
  extend Distributable
14
13
 
15
14
  create_distribution_methods
16
15
 
17
16
  ##
18
17
  # :singleton-method: pdf(k,m,n,total)
19
- # This function computes the probability p(k) of obtaining k
20
- # from a hypergeometric distribution with parameters
18
+ # This function computes the probability p(k) of obtaining k
19
+ # from a hypergeometric distribution with parameters
21
20
  # m, n t.
22
21
  # * m: number of elements with desired attribute on population
23
- # * n: sample size
22
+ # * n: sample size
24
23
  # * t: population size
25
24
 
26
25
  ##
27
26
  # :singleton-method: cdf(k,m,n,total)
28
27
  # These functions compute the cumulative distribution function P(k)
29
- # for the hypergeometric distribution with parameters m, n and t.
28
+ # for the hypergeometric distribution with parameters m, n and t.
30
29
  # * m: number of elements with desired attribute on population
31
30
  # * n: sample size
32
31
  # * t: population size
33
-
34
32
 
35
33
  ##
36
34
  # :singleton-method: p_value(k,m,n,total)
37
-
38
35
  end
39
36
  end
@@ -3,15 +3,14 @@ module Distribution
3
3
  module GSL_
4
4
  class << self
5
5
  def pdf(k, m, n, total) # :nodoc:
6
- GSL::Ran::hypergeometric_pdf(k, m, total-m, n)
6
+ GSL::Ran.hypergeometric_pdf(k, m, total - m, n)
7
7
  end
8
- # The GSL::Cdf function for hypergeometric
9
- #
8
+ # The GSL::Cdf function for hypergeometric
9
+ #
10
10
  def cdf(k, m, n, total) # :nodoc:
11
- GSL::Cdf::hypergeometric_P(k, m, total-m, n)
11
+ GSL::Cdf.hypergeometric_P(k, m, total - m, n)
12
12
  end
13
-
14
13
  end
15
14
  end
16
15
  end
17
- end
16
+ end
@@ -6,4 +6,4 @@ module Distribution
6
6
  end
7
7
  end
8
8
  end
9
- end
9
+ end
@@ -1,13 +1,14 @@
1
- # Added by John O. Woods, SciRuby project.
1
+ # Added by John O. Woods, SciRuby project.
2
2
  # Optimized by Claudio Bustos
3
3
 
4
4
  module Distribution
5
5
  module Hypergeometric
6
6
  module Ruby_
7
7
  class << self
8
- def bc(n,k)
9
- Math.binomial_coefficient(n,k)
8
+ def bc(n, k)
9
+ Math.binomial_coefficient(n, k)
10
10
  end
11
+
11
12
  # Hypergeometric probability density function
12
13
  #
13
14
  # Probability p(+k+, +m+, +n+, +total+) of drawing sets of size +m+ and +n+ with an intersection of size +k+
@@ -17,50 +18,48 @@ module Distribution
17
18
  # * http://www.gnu.org/software/gsl/manual/html_node/The-Hypergeometric-Distribution.html
18
19
  # * http://en.wikipedia.org/wiki/Hypergeometric_distribution
19
20
  def pdf(k, m, n, total)
20
- min_m_n=m<n ? m : n
21
- max_t=[0,m+n-total].max
22
- return 0 if k>min_m_n or k<max_t
23
- (bc(m,k) * bc(total-m,n-k)).quo(bc(total,n))
24
- end
25
-
26
-
27
-
28
- def pdf_with_den(k,m,n,total,den)
29
- (bc(m,k) * bc(total-m,n-k)).quo(den)
21
+ min_m_n = m < n ? m : n
22
+ max_t = [0, m + n - total].max
23
+ return 0 if k > min_m_n || k < max_t
24
+ (bc(m, k) * bc(total - m, n - k)).quo(bc(total, n))
30
25
  end
31
26
 
32
- # p-value:
33
-
34
- def p_value(pr, m, n, total)
35
- ac=0
36
- den=bc(total,n)
37
-
38
- (0..total).each do |i|
39
- ac+=pdf_with_den(i,m,n,total,den)
40
- return i if ac>=pr
41
- end
27
+ alias_method :exact_pdf, :pdf
28
+
29
+ def pdf_with_den(k, m, n, total, den)
30
+ (bc(m, k) * bc(total - m, n - k)).quo(den)
42
31
  end
32
+
43
33
  # Cumulative distribution function.
44
34
  # The probability of obtain, from a sample of
45
35
  # size +n+, +k+ or less elements
46
36
  # in a population size +total+ with +m+ interesting elements.
47
- #
37
+ #
48
38
  # Slow, but secure
49
39
  def cdf(k, m, n, total)
50
- raise "k>m" if k>m
51
- raise "k>n" if k>n
40
+ fail(ArgumentError, 'k>m') if k > m
41
+ fail(ArgumentError, 'k>n') if k > n
52
42
  # Store the den
53
- den=bc(total,n)
54
- (0..k).collect { |ki| pdf_with_den(ki,m,n,total,den) }.inject { |sum,v| sum+v}
43
+ den = bc(total, n)
44
+ (0..k).collect { |ki| pdf_with_den(ki, m, n, total, den) }.inject { |sum, v| sum + v }
45
+ end
46
+
47
+ alias_method :exact_cdf, :cdf
48
+
49
+ # p-value:
50
+ def quantile(pr, m, n, total)
51
+ ac = 0
52
+ den = bc(total, n)
53
+
54
+ (0..total).each do |i|
55
+ ac += pdf_with_den(i, m, n, total, den)
56
+ return i if ac >= pr
57
+ end
55
58
  end
56
-
57
-
58
- alias :exact_pdf :pdf
59
- alias :exact_p_value :p_value
60
- alias :exact_cdf :cdf
61
59
 
62
-
60
+ alias_method :p_value, :quantile
61
+ alias_method :exact_p_value, :p_value
63
62
  end
64
63
  end
65
64
  end
66
- end
65
+ end
@@ -1,13 +1,12 @@
1
1
  require 'distribution/logistic/ruby'
2
- #require 'distribution/logistic/gsl'
3
- #require 'distribution/logistic/java'
4
-
2
+ # require 'distribution/logistic/gsl'
3
+ # require 'distribution/logistic/java'
5
4
 
6
5
  module Distribution
7
6
  # From Wikipedia:
8
7
  # In probability theory and statistics, the logistic distribution is a continuous probability distribution. Its cumulative distribution function is the logistic function, which appears in logistic regression and feedforward neural networks. It resembles the normal distribution in shape but has heavier tails (higher kurtosis).
9
8
  module Logistic
10
- SHORTHAND='logis'
9
+ SHORTHAND = 'logis'
11
10
  extend Distributable
12
11
  create_distribution_methods
13
12
  ##
@@ -21,20 +20,18 @@ module Distribution
21
20
  # Returns the pdf for logistic distribution (f(x,u,s))
22
21
  # * u: mean
23
22
  # * s: variance related parameter
24
-
23
+
25
24
  ##
26
- # :singleton-method: cdf(x , u,s)
25
+ # :singleton-method: cdf(x,u,s)
27
26
  # Returns the cdf for logistic distribution (F(x,u,s))
28
27
  # * u: mean
29
28
  # * s: variance related parameter
30
29
 
31
30
  ##
32
31
  # :singleton-method: p_value(pr , u,s)
33
- # Returns the inverse cdf for logistic distribution
32
+ # Returns the inverse cdf for logistic distribution
34
33
  # (F^-1(pr,u,s))
35
34
  # * u: mean
36
35
  # * s: variance related parameter
37
-
38
-
39
36
  end
40
37
  end
@@ -2,18 +2,23 @@ module Distribution
2
2
  module Logistic
3
3
  module Ruby_
4
4
  class << self
5
- def rng(u,s)
6
- lambda {p_value(rand(),u,s)}
7
- end
8
- def pdf(x,u,s )
9
- (Math.exp(-(x-u)/s))/(s*(1+Math.exp(-(x-u)/s)**2))
5
+ def rng(u, s)
6
+ -> { p_value(rand, u, s) }
10
7
  end
11
- def cdf(x,u,s )
12
- 1/(1+Math.exp(-(x-u)/s))
8
+
9
+ def pdf(x, u, s)
10
+ (Math.exp(-(x - u) / s)) / (s * (1 + Math.exp(-(x - u) / s)**2))
13
11
  end
14
- def p_value(pr,u,s )
15
- u+s*Math.log(pr/(1-pr))
12
+
13
+ def cdf(x, u, s)
14
+ 1 / (1 + Math.exp(-(x - u) / s))
16
15
  end
16
+
17
+ def quantile(pr, u, s)
18
+ u + s * Math.log(pr / (1 - pr))
19
+ end
20
+
21
+ alias_method :p_value, :quantile
17
22
  end
18
23
  end
19
24
  end
@@ -0,0 +1,37 @@
1
+ require 'distribution/lognormal/gsl'
2
+ require 'distribution/lognormal/ruby'
3
+
4
+ module Distribution
5
+ # From Wikipedia:
6
+ # In probability theory, a log-normal distribution is a probability
7
+ # distribution of a random variable whose logarithm is normally
8
+ # distributed. If X is a random variable with a normal distribution, then
9
+ # Y = exp(X) has a log-normal distribution; likewise, if Y is
10
+ # log-normally distributed, then X = log(Y) is normally distributed. (This
11
+ # is true regardless of the base of the logarithmic function: if loga(Y) is
12
+ # normally distributed, then so is logb(Y), for any two positive numbers
13
+ # a, b ≠ 1.)
14
+ #
15
+ # This module calculates the pdf, cdf and inverse cdf for the Lognormal distribution.
16
+ #
17
+ module LogNormal
18
+ extend Distributable
19
+ SHORTHAND = 'lognormal'
20
+ create_distribution_methods
21
+
22
+ ##
23
+ # :singleton-method: pdf(x,u,s)
24
+ # Returns the PDF of the Lognormal distribution of x with parameters u (position) and
25
+ # s (deviation)
26
+
27
+ ##
28
+ # :singleton-method: cdf(x,u,s)
29
+ # Returns the CDF of the Lognormal distribution of x with parameters u (position) and
30
+ # s(deviation)
31
+
32
+ ##
33
+ # :singleton-method: p_value(pr,u,s)
34
+ # Return the quantile of the corresponding integral +pr+
35
+ # on a lognormal distribution's cdf with parameters z and s
36
+ end
37
+ end
@@ -0,0 +1,21 @@
1
+ module Distribution
2
+ module LogNormal
3
+ module GSL_
4
+ class << self
5
+ def pdf(x, u, s)
6
+ GSL::Ran.lognormal_pdf(x.to_f, u.to_f, s.to_f)
7
+ end
8
+
9
+ def cdf(x, u, s)
10
+ GSL::Cdf.lognormal_P(x.to_f, u.to_f, s.to_f)
11
+ end
12
+
13
+ def quantile(pr, u, s)
14
+ GSL::Cdf.lognormal_Pinv(pr.to_f, u.to_f, s.to_f)
15
+ end
16
+
17
+ alias_method :p_value, :quantile
18
+ end
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,16 @@
1
+ module Distribution
2
+ module LogNormal
3
+ module Ruby_
4
+ class << self
5
+ def pdf(x, u, s)
6
+ fail 'x should be > 0 ' if x < 0
7
+ (1.0 / (x * s * Math.sqrt(2 * Math::PI))) * Math.exp(-((Math.log(x) - u)**2 / (2 * s**2)))
8
+ end
9
+
10
+ def cdf(x, u, s)
11
+ Distribution::Normal.cdf((Math.log(x) - u) / s)
12
+ end
13
+ end
14
+ end
15
+ end
16
+ end
@@ -1,78 +1,19 @@
1
- # The next few requires eventually probably need to go in their own gem. They're all functions and constants used by
2
- # GSL-adapted pure Ruby math functions.
3
- require "distribution/math_extension/chebyshev_series"
4
- require "distribution/math_extension/erfc"
5
- require "distribution/math_extension/exponential_integral"
6
- require "distribution/math_extension/gammastar"
7
- require "distribution/math_extension/gsl_utilities"
8
- require "distribution/math_extension/incomplete_gamma"
9
- require "distribution/math_extension/incomplete_beta"
10
- require "distribution/math_extension/log_utilities"
11
-
12
-
13
- if RUBY_VERSION<"1.9"
14
- require 'mathn'
15
- def Prime.each(upper,&block)
16
- @primes=Prime.new
17
- @primes.each do |prime|
18
- break if prime > upper.to_i
19
- block.call(prime)
20
- end
21
- end
22
- else
23
- require 'prime'
24
- end
25
-
26
1
  require 'bigdecimal'
27
2
  require 'bigdecimal/math'
3
+ require 'prime'
28
4
 
29
- module Distribution
30
- # Extension for Ruby18
31
- # Includes gamma and lgamma
32
- module MathExtension18
33
- LOG_2PI = Math.log(2 * Math::PI)# log(2PI)
34
- N = 8
35
- B0 = 1.0
36
- B1 = -1.0 / 2.0
37
- B2 = 1.0 / 6.0
38
- B4 = -1.0 / 30.0
39
- B6 = 1.0 / 42.0
40
- B8 = -1.0 / 30.0
41
- B10 = 5.0 / 66.0
42
- B12 = -691.0 / 2730.0
43
- B14 = 7.0 / 6.0
44
- B16 = -3617.0 / 510.0
45
-
46
-
47
- # From statistics2
48
- def loggamma(x)
49
- v = 1.0
50
- while (x < N)
51
- v *= x
52
- x += 1.0
53
- end
54
- w = 1.0 / (x * x)
55
- ret = B16 / (16 * 15)
56
- ret = ret * w + B14 / (14 * 13)
57
- ret = ret * w + B12 / (12 * 11)
58
- ret = ret * w + B10 / (10 * 9)
59
- ret = ret * w + B8 / ( 8 * 7)
60
- ret = ret * w + B6 / ( 6 * 5)
61
- ret = ret * w + B4 / ( 4 * 3)
62
- ret = ret * w + B2 / ( 2 * 1)
63
- ret = ret / x + 0.5 * LOG_2PI - Math.log(v) - x + (x - 0.5) * Math.log(x)
64
- ret
65
- end
5
+ # The next few requires eventually probably need to go in their own gem. They're all functions and constants used by
6
+ # GSL-adapted pure Ruby math functions.
7
+ require 'distribution/math_extension/chebyshev_series'
8
+ require 'distribution/math_extension/erfc'
9
+ require 'distribution/math_extension/exponential_integral'
10
+ require 'distribution/math_extension/gammastar'
11
+ require 'distribution/math_extension/gsl_utilities'
12
+ require 'distribution/math_extension/incomplete_gamma'
13
+ require 'distribution/math_extension/incomplete_beta'
14
+ require 'distribution/math_extension/log_utilities'
66
15
 
67
- # Gamma function.
68
- # From statistics2
69
- def gamma(x)
70
- if (x < 0.0)
71
- return Math::PI / (Math.sin(Math.PI * x) * Math.exp(loggamma(1 - x))) #/
72
- end
73
- Math.exp(loggamma(x))
74
- end
75
- end
16
+ module Distribution
76
17
  # Useful additions to Math
77
18
  module MathExtension
78
19
  # Factorization based on Prime Swing algorithm, by Luschny (the king of factorial numbers analysis :P )
@@ -80,200 +21,221 @@ module Distribution
80
21
  # * The Homepage of Factorial Algorithms. (C) Peter Luschny, 2000-2010
81
22
  # == URL: http://www.luschny.de/math/factorial/csharp/FactorialPrimeSwing.cs.html
82
23
  class SwingFactorial
24
+ SmallOddSwing = [1, 1, 1, 3, 3, 15, 5, 35, 35, 315, 63, 693, 231, 3003,
25
+ 429, 6435, 6435, 109_395, 12_155, 230_945, 46_189,
26
+ 969_969, 88_179, 2_028_117, 676_039, 16_900_975,
27
+ 1_300_075, 35_102_025, 5_014_575, 145_422_675,
28
+ 9_694_845, 300_540_195, 300_540_195]
29
+
30
+ SmallFactorial = [1, 1, 2, 6, 24, 120, 720, 5040, 40_320, 362_880,
31
+ 3_628_800, 39_916_800, 479_001_600, 6_227_020_800,
32
+ 87_178_291_200, 1_307_674_368_000, 20_922_789_888_000,
33
+ 355_687_428_096_000, 6_402_373_705_728_000,
34
+ 121_645_100_408_832_000, 2_432_902_008_176_640_000]
35
+
83
36
  attr_reader :result
84
- SmallOddSwing=[ 1, 1, 1, 3, 3, 15, 5, 35, 35, 315, 63, 693, 231, 3003, 429, 6435, 6435, 109395, 12155, 230945, 46189, 969969, 88179, 2028117, 676039, 16900975, 1300075, 35102025, 5014575,145422675, 9694845, 300540195, 300540195]
85
- SmallFactorial=[1, 1, 2, 6, 24, 120, 720, 5040, 40320, 362880, 3628800, 39916800, 479001600, 6227020800, 87178291200, 1307674368000, 20922789888000, 355687428096000, 6402373705728000, 121645100408832000, 2432902008176640000]
37
+
86
38
  def bitcount(n)
87
- bc = n - ((n >> 1) & 0x55555555);
88
- bc = (bc & 0x33333333) + ((bc >> 2) & 0x33333333);
89
- bc = (bc + (bc >> 4)) & 0x0f0f0f0f;
90
- bc += bc >> 8;
91
- bc += bc >> 16;
92
- bc = bc & 0x3f;
39
+ bc = n - ((n >> 1) & 0x55555555)
40
+ bc = (bc & 0x33333333) + ((bc >> 2) & 0x33333333)
41
+ bc = (bc + (bc >> 4)) & 0x0f0f0f0f
42
+ bc += bc >> 8
43
+ bc += bc >> 16
44
+ bc &= 0x3f
93
45
  bc
94
46
  end
47
+
95
48
  def initialize(n)
96
- if (n<20)
97
- @result=SmallFactorial[n]
98
- #naive_factorial(n)
49
+ if n < 20
50
+ @result = SmallFactorial[n]
51
+ # naive_factorial(n)
99
52
  else
100
- @prime_list=[]
101
- exp2 = n - bitcount(n);
102
- @result= recfactorial(n)<< exp2
53
+ @prime_list = []
54
+ exp2 = n - bitcount(n)
55
+ @result = recfactorial(n) << exp2
103
56
  end
104
57
  end
58
+
105
59
  def recfactorial(n)
106
- return 1 if n<2
107
- (recfactorial(n/2)**2) * swing(n)
60
+ return 1 if n < 2
61
+ (recfactorial(n / 2)**2) * swing(n)
108
62
  end
63
+
109
64
  def swing(n)
110
- return SmallOddSwing[n] if (n<33)
65
+ return SmallOddSwing[n] if n < 33
111
66
  sqrtN = Math.sqrt(n).floor
112
- count=0
113
-
114
- Prime.each(n/3) do |prime|
115
- next if prime<3
116
- if (prime<=sqrtN)
117
- q=n
118
- _p=1
119
-
120
- while((q=(q/prime).truncate)>0) do
121
- if((q%2)==1)
122
- _p*=prime
123
- end
67
+ count = 0
68
+
69
+ Prime.each(n / 3) do |prime|
70
+ next if prime < 3
71
+ if (prime <= sqrtN)
72
+ q = n
73
+ _p = 1
74
+
75
+ while (q = (q / prime).truncate) > 0
76
+ _p *= prime if q.odd?
124
77
  end
125
- if _p>1
126
- @prime_list[count]=_p
127
- count+=1
78
+ if _p > 1
79
+ @prime_list[count] = _p
80
+ count += 1
128
81
  end
129
-
82
+
130
83
  else
131
- if ((n/prime).truncate%2==1)
132
- @prime_list[count]=prime
133
- count+=1
84
+ if (n / prime).truncate.odd?
85
+ @prime_list[count] = prime
86
+ count += 1
134
87
  end
135
88
  end
136
89
  end
137
- prod=get_primorial((n/2).truncate+1,n)
138
- prod * @prime_list[0,count].inject(1) {|ac,v| ac*v}
90
+ prod = get_primorial((n / 2).truncate + 1, n)
91
+ prod * @prime_list[0, count].inject(1) { |ac, v| ac * v }
139
92
  end
140
- def get_primorial(low,up)
141
- prod=1;
93
+
94
+ def get_primorial(low, up)
95
+ prod = 1
142
96
  Prime.each(up) do |prime|
143
- next if prime<low
144
- prod*=prime
97
+ next if prime < low
98
+ prod *= prime
145
99
  end
146
100
  prod
147
101
  end
102
+
148
103
  def naive_factorial(n)
149
- @result=(self.class).naive_factorial(n)
104
+ @result = (self.class).naive_factorial(n)
150
105
  end
106
+
151
107
  def self.naive_factorial(n)
152
- (2..n).inject(1) { |f,nn| f * nn }
108
+ (2..n).inject(1) { |f, nn| f * nn }
153
109
  end
154
110
  end
111
+
155
112
  # Module to calculate approximated factorial
156
113
  # Based (again) on Luschny formula, with 16 digits of precision
157
114
  # == Reference
158
115
  # * http://www.luschny.de/math/factorial/approx/SimpleCases.html
159
116
  module ApproxFactorial
160
- def self.stieltjes_ln_factorial(z)
161
-
162
- a0 = 1.quo(12); a1 = 1.quo(30); a2 = 53.quo(210); a3 = 195.quo(371);
163
- a4 = 22999.quo(22737); a5 = 29944523.quo(19733142);
164
- a6 = 109535241009.quo(48264275462);
165
- zz = z+1;
166
-
167
- (1.quo(2))*Math.log(2*Math::PI)+(zz-1.quo(2))*Math.log(zz) - zz +
168
- a0.quo(zz+a1.quo(zz+a2.quo(zz+a3.quo(zz+a4.quo(zz+a5.quo(zz+a6.quo(zz)))))))
169
- end
170
-
171
- def self.stieltjes_ln_factorial_big(z)
172
-
173
- a0 = 1/12.0; a1 = 1/30.0; a2 = 53/210.0; a3 = 195/371.0;
174
- a4 = 22999/22737.0; a5 = 29944523/19733142.0;
175
- a6 = 109535241009/48264275462.0;
176
- zz = z+1;
177
-
178
- BigDecimal("0.5") * BigMath.log(BigDecimal("2")*BigMath::PI(20),20) + BigDecimal((zz - 0.5).to_s) * BigMath.log(BigDecimal(zz.to_s),20) - BigDecimal(zz.to_s) + BigDecimal( (
179
- a0 / (zz+a1/(zz+a2/(zz+a3/(zz+a4/(zz+a5/(zz+a6/zz))))))
180
- ).to_s)
181
-
182
- end
183
- # Valid upto 11 digits
184
- def self.stieltjes_factorial(x)
185
- y = x; _p = 1;
186
- while y < 8 do
187
- _p = _p*y; y = y+1
117
+ class << self
118
+ def stieltjes_ln_factorial(z)
119
+ a0 = 1.quo(12); a1 = 1.quo(30); a2 = 53.quo(210); a3 = 195.quo(371)
120
+ a4 = 22_999.quo(22_737); a5 = 29_944_523.quo(19_733_142)
121
+ a6 = 109_535_241_009.quo(48_264_275_462)
122
+ zz = z + 1
123
+
124
+ (1.quo(2)) * Math.log(2 * Math::PI) + (zz - 1.quo(2)) * Math.log(zz) - zz +
125
+ a0.quo(zz + a1.quo(zz + a2.quo(zz + a3.quo(zz + a4.quo(zz + a5.quo(zz + a6.quo(zz)))))))
126
+ end
127
+
128
+ def stieltjes_ln_factorial_big(z)
129
+ a0 = 1 / 12.0; a1 = 1 / 30.0; a2 = 53 / 210.0; a3 = 195 / 371.0
130
+ a4 = 22_999 / 22_737.0; a5 = 29_944_523 / 19_733_142.0
131
+ a6 = 109_535_241_009 / 48_264_275_462.0
132
+ zz = z + 1
133
+
134
+ BigDecimal('0.5') * BigMath.log(BigDecimal('2') * BigMath::PI(20), 20) + BigDecimal((zz - 0.5).to_s) * BigMath.log(BigDecimal(zz.to_s), 20) - BigDecimal(zz.to_s) + BigDecimal((
135
+ a0 / (zz + a1 / (zz + a2 / (zz + a3 / (zz + a4 / (zz + a5 / (zz + a6 / zz))))))
136
+ ).to_s)
137
+ end
138
+
139
+ # Valid upto 11 digits
140
+ def stieltjes_factorial(x)
141
+ y = x
142
+ _p = 1
143
+
144
+ _p *= y; y += 1 while y < 8
145
+
146
+ lr = stieltjes_ln_factorial(y)
147
+ r = Math.exp(lr)
148
+
149
+ if r.infinite?
150
+ r = BigMath.exp(BigDecimal(lr.to_s), 20)
151
+ r = (r * x) / (_p * y) if x < 8
152
+ r = r.to_i
153
+ else
154
+ r = (r * x) / (_p * y) if x < 8
188
155
  end
189
- lr= stieltjes_ln_factorial(y)
190
- r = Math.exp(lr)
191
- #puts "valid: #{5/2.0+(13/2.0)*Math::log(x)}"
192
- if r.infinite?
193
- r=BigMath.exp(BigDecimal(lr.to_s),20)
194
- r = (r*x) / (_p*y) if x < 8
195
- r=r.to_i
196
- else
197
- r = (r*x) / (_p*y) if x < 8
156
+ r
198
157
  end
199
- r
200
- end
201
- end
202
- # Exact factorial.
203
- # Use lookup on a Hash table on n<20
204
- # and Prime Swing algorithm for higher values.
158
+ end
159
+ end
160
+
161
+ # Exact factorial.
162
+ # Use lookup on a Hash table on n<20
163
+ # and Prime Swing algorithm for higher values.
205
164
  def factorial(n)
206
165
  SwingFactorial.new(n).result
207
166
  end
167
+
208
168
  # Approximate factorial, up to 16 digits
209
169
  # Based of Luschy algorithm
210
170
  def fast_factorial(n)
211
171
  ApproxFactorial.stieltjes_factorial(n)
212
172
  end
213
-
173
+
214
174
  # Beta function.
215
175
  # Source:
216
176
  # * http://mathworld.wolfram.com/BetaFunction.html
217
- def beta(x,y)
218
- (gamma(x)*gamma(y)).quo(gamma(x+y))
177
+ def beta(x, y)
178
+ (gamma(x) * gamma(y)).quo(gamma(x + y))
219
179
  end
220
180
 
221
181
  # Get pure-Ruby logbeta
222
- def logbeta(x,y)
223
- Beta.log_beta(x,y).first
182
+ def logbeta(x, y)
183
+ Beta.log_beta(x, y).first
224
184
  end
225
185
 
226
186
  # Log beta function conforming to style of lgamma (returns sign in second array index)
227
- def lbeta(x,y)
228
- Beta.log_beta(x,y)
187
+ def lbeta(x, y)
188
+ Beta.log_beta(x, y)
229
189
  end
230
190
 
231
191
  # I_x(a,b): Regularized incomplete beta function
232
192
  # Fast version. For a exact calculation, based on factorial
233
193
  # use exact_regularized_beta_function
234
- def regularized_beta(x,a,b)
235
- return 1 if x==1
236
- IncompleteBeta.evaluate(a,b,x)
194
+ def regularized_beta(x, a, b)
195
+ return 1 if x == 1
196
+ IncompleteBeta.evaluate(a, b, x)
237
197
  end
198
+
238
199
  # I_x(a,b): Regularized incomplete beta function
239
200
  # TODO: Find a faster version.
240
201
  # Source:
241
202
  # * http://dlmf.nist.gov/8.17
242
- def exact_regularized_beta(x,a,b)
243
- return 1 if x==1
244
- m=a.to_i
245
- n=(b+a-1).to_i
246
- (m..n).inject(0) {|sum,j|
247
- sum+(binomial_coefficient(n,j)* x**j * (1-x)**(n-j))
248
- }
249
-
250
- end
251
- #
203
+ def exact_regularized_beta(x, a, b)
204
+ return 1 if x == 1
205
+
206
+ m = a.to_i
207
+ n = (b + a - 1).to_i
208
+
209
+ (m..n).inject(0) do|sum, j|
210
+ sum + (binomial_coefficient(n, j) * x**j * (1 - x)**(n - j))
211
+ end
212
+ end
213
+
252
214
  # Incomplete beta function: B(x;a,b)
253
- # +a+ and +b+ are parameters and +x+ is
215
+ # +a+ and +b+ are parameters and +x+ is
254
216
  # integration upper limit.
255
- def incomplete_beta(x,a,b)
256
- IncompleteBeta.evaluate(a,b,x)*beta(a,b)
257
- #Math::IncompleteBeta.axpy(1.0, 0.0, a,b,x)
217
+ def incomplete_beta(x, a, b)
218
+ IncompleteBeta.evaluate(a, b, x) * beta(a, b)
219
+ # Math::IncompleteBeta.axpy(1.0, 0.0, a,b,x)
258
220
  end
259
-
221
+
260
222
  # Rising factorial
261
- def rising_factorial(x,n)
262
- factorial(x+n-1).quo(factorial(x-1))
223
+ def rising_factorial(x, n)
224
+ factorial(x + n - 1).quo(factorial(x - 1))
263
225
  end
264
-
226
+
265
227
  # Ln of gamma
266
228
  def loggamma(x)
267
229
  Math.lgamma(x).first
268
230
  end
269
231
 
270
232
  def incomplete_gamma(a, x = 0, with_error = false)
271
- IncompleteGamma.p(a,x, with_error)
233
+ IncompleteGamma.p(a, x, with_error)
272
234
  end
273
- alias :gammp :incomplete_gamma
235
+ alias_method :gammp, :incomplete_gamma
274
236
 
275
237
  def gammq(a, x, with_error = false)
276
- IncompleteGamma.q(a,x,with_error)
238
+ IncompleteGamma.q(a, x, with_error)
277
239
  end
278
240
 
279
241
  def unnormalized_incomplete_gamma(a, x, with_error = false)
@@ -281,36 +243,36 @@ module Distribution
281
243
  end
282
244
 
283
245
  # Not the same as erfc. This is the GSL version, which may have slightly different results.
284
- def erfc_e x, with_error = false
246
+ def erfc_e(x, with_error = false)
285
247
  Erfc.evaluate(x, with_error)
286
248
  end
287
-
249
+
288
250
  # Sequences without repetition. n^k'
289
251
  # Also called 'failing factorial'
290
- def permutations(n,k)
291
- return 1 if k==0
292
- return n if k==1
293
- return factorial(n) if k==n
294
- (((n-k+1)..n).inject(1) {|ac,v| ac * v})
295
- #factorial(x).quo(factorial(x-n))
252
+ def permutations(n, k)
253
+ return 1 if k == 0
254
+ return n if k == 1
255
+ return factorial(n) if k == n
256
+ (((n - k + 1)..n).inject(1) { |ac, v| ac * v })
257
+ # factorial(x).quo(factorial(x-n))
296
258
  end
297
-
259
+
298
260
  # Binomial coeffients, or:
299
261
  # ( n )
300
262
  # ( k )
301
263
  #
302
264
  # Gives the number of *different* k size subsets of a set size n
303
- #
265
+ #
304
266
  # Uses:
305
267
  #
306
268
  # (n) n^k' (n)..(n-k+1)
307
269
  # ( ) = ---- = ------------
308
270
  # (k) k! k!
309
271
  #
310
- def binomial_coefficient(n,k)
311
- return 1 if (k==0 or k==n)
312
- k=[k, n-k].min
313
- permutations(n,k).quo(factorial(k))
272
+ def binomial_coefficient(n, k)
273
+ return 1 if k == 0 || k == n
274
+ k = [k, n - k].min
275
+ permutations(n, k).quo(factorial(k))
314
276
  # The factorial way is
315
277
  # factorial(n).quo(factorial(k)*(factorial(n-k)))
316
278
  # The multiplicative way is
@@ -319,54 +281,48 @@ module Distribution
319
281
  # Binomial coefficient using multiplicative algorithm
320
282
  # On benchmarks, is faster that raising factorial method
321
283
  # when k is little. Use only when you're sure of that.
322
- def binomial_coefficient_multiplicative(n,k)
323
- return 1 if (k==0 or k==n)
324
- k=[k, n-k].min
325
- (1..k).inject(1) {|ac, i| (ac*(n-k+i).quo(i))}
284
+ def binomial_coefficient_multiplicative(n, k)
285
+ return 1 if k == 0 || k == n
286
+ k = [k, n - k].min
287
+ (1..k).inject(1) { |ac, i| (ac * (n - k + i).quo(i)) }
326
288
  end
327
-
289
+
328
290
  # Approximate binomial coefficient, using gamma function.
329
291
  # The fastest method, until we fall on BigDecimal!
330
- def binomial_coefficient_gamma(n,k)
331
- return 1 if (k==0 or k==n)
332
- k=[k, n-k].min
292
+ def binomial_coefficient_gamma(n, k)
293
+ return 1 if k == 0 || k == n
294
+ k = [k, n - k].min
333
295
  # First, we try direct gamma calculation for max precission
334
296
 
335
- val=gamma(n + 1).quo(gamma(k+1)*gamma(n-k+1))
297
+ val = gamma(n + 1).quo(gamma(k + 1) * gamma(n - k + 1))
336
298
  # Ups. Outside float point range. We try with logs
337
- if (val.nan?)
338
- #puts "nan"
339
- lg=loggamma( n + 1 ) - (loggamma(k+1)+ loggamma(n-k+1))
340
- val=Math.exp(lg)
299
+ if val.nan?
300
+ # puts "nan"
301
+ lg = loggamma(n + 1) - (loggamma(k + 1) + loggamma(n - k + 1))
302
+ val = Math.exp(lg)
341
303
  # Crash again! We require BigDecimals
342
304
  if val.infinite?
343
- #puts "infinite"
344
- val=BigMath.exp(BigDecimal(lg.to_s),16)
305
+ # puts "infinite"
306
+ val = BigMath.exp(BigDecimal(lg.to_s), 16)
345
307
  end
346
308
  end
347
309
  val
348
310
  end
349
- alias :combinations :binomial_coefficient
311
+ alias_method :combinations, :binomial_coefficient
350
312
  end
351
313
  end
352
314
 
353
315
  module Math
354
316
  include Distribution::MathExtension
355
- module_function :factorial, :beta, :loggamma, :erfc_e, :unnormalized_incomplete_gamma, :incomplete_gamma, :gammp, :gammq, :binomial_coefficient, :binomial_coefficient_gamma, :exact_regularized_beta, :incomplete_beta, :regularized_beta, :permutations, :rising_factorial , :fast_factorial, :combinations, :logbeta, :lbeta
317
+ module_function :factorial, :beta, :loggamma, :erfc_e, :unnormalized_incomplete_gamma, :incomplete_gamma, :gammp, :gammq, :binomial_coefficient, :binomial_coefficient_gamma, :exact_regularized_beta, :incomplete_beta, :regularized_beta, :permutations, :rising_factorial, :fast_factorial, :combinations, :logbeta, :lbeta
356
318
  end
357
319
 
358
320
  # Necessary on Ruby 1.9
359
321
  module CMath # :nodoc:
360
322
  include Distribution::MathExtension
361
- module_function :factorial, :beta, :loggamma, :unnormalized_incomplete_gamma, :incomplete_gamma, :gammp, :gammq, :erfc_e, :binomial_coefficient, :binomial_coefficient_gamma, :incomplete_beta, :exact_regularized_beta, :regularized_beta, :permutations, :rising_factorial, :fast_factorial, :combinations, :logbeta, :lbeta
362
- end
363
-
364
- if RUBY_VERSION<"1.9"
365
- module Math
366
- remove_method :loggamma
367
- include Distribution::MathExtension18
368
- module_function :gamma, :loggamma
369
- end
323
+ module_function :factorial, :beta, :loggamma, :unnormalized_incomplete_gamma,
324
+ :incomplete_gamma, :gammp, :gammq, :erfc_e, :binomial_coefficient,
325
+ :binomial_coefficient_gamma, :incomplete_beta, :exact_regularized_beta,
326
+ :regularized_beta, :permutations, :rising_factorial, :fast_factorial,
327
+ :combinations, :logbeta, :lbeta
370
328
  end
371
-
372
-