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
@@ -3,36 +3,35 @@
3
3
 
4
4
  module Distribution
5
5
  module MathExtension
6
-
7
6
  # Error function from GSL-1.9, with epsilon information. Access it using Math.erfc_e
8
7
  module Erfc
9
- P = [ 2.97886562639399288862,
10
- 7.409740605964741794425,
11
- 6.1602098531096305440906,
12
- 5.019049726784267463450058,
13
- 1.275366644729965952479585264,
14
- 0.5641895835477550741253201704 ]
15
- Q = [ 3.3690752069827527677,
16
- 9.608965327192787870698,
17
- 17.08144074746600431571095,
18
- 12.0489519278551290360340491,
19
- 9.396034016235054150430579648,
20
- 2.260528520767326969591866945,
21
- 1.0 ]
8
+ P = [2.97886562639399288862,
9
+ 7.409740605964741794425,
10
+ 6.1602098531096305440906,
11
+ 5.019049726784267463450058,
12
+ 1.275366644729965952479585264,
13
+ 0.5641895835477550741253201704]
14
+ Q = [3.3690752069827527677,
15
+ 9.608965327192787870698,
16
+ 17.08144074746600431571095,
17
+ 12.0489519278551290360340491,
18
+ 9.396034016235054150430579648,
19
+ 2.260528520767326969591866945,
20
+ 1.0]
22
21
 
23
22
  class << self
24
23
  # Estimates erfc(x) valid for 8 < x < 100
25
24
  # erfc8_sum from GSL-1.9
26
25
  def erfc8_sum(x)
27
26
  num = P[5]
28
- 4.downto(0) { |i| num = x*num + P[i] }
27
+ 4.downto(0) { |i| num = x * num + P[i] }
29
28
  den = Q[6]
30
- 5.downto(0) { |i| den = x*den + Q[i] }
29
+ 5.downto(0) { |i| den = x * den + Q[i] }
31
30
  num / den
32
31
  end
33
32
 
34
33
  def erfc8(x)
35
- erfc8_sum(x) * Math.exp(-x*x)
34
+ erfc8_sum(x) * Math.exp(-x * x)
36
35
  end
37
36
 
38
37
  # gsl_sf_erfc_e
@@ -41,39 +40,37 @@ module Distribution
41
40
  e = nil
42
41
 
43
42
  if ax <= 1.0
44
- t = 2*ax-1
43
+ t = 2 * ax - 1
45
44
  e = ChebyshevSeries.evaluate(:erfc_xlt1, t, with_error)
46
45
  elsif ax <= 5.0
47
- ex2 = Math.exp(-x*x)
48
- t = (ax-3).quo(2)
46
+ ex2 = Math.exp(-x * x)
47
+ t = (ax - 3).quo(2)
49
48
  e = ChebyshevSeries.evaluate(:erfc_x15, t, with_error)
50
49
  if with_error
51
50
  e[0] *= ex2
52
- e[1] = ex2 * (e[1] + 2*x.abs*Float::EPSILON)
51
+ e[1] = ex2 * (e[1] + 2 * x.abs * Float::EPSILON)
53
52
  else
54
53
  e *= ex2
55
54
  end
56
55
  elsif ax < 10.0
57
- exterm = Math.exp(-x*x) / ax
58
- t = (2*ax-15).quo(5)
56
+ exterm = Math.exp(-x * x) / ax
57
+ t = (2 * ax - 15).quo(5)
59
58
  e = ChebyshevSeries.evaluate(:erfc_x510, t, with_error)
60
59
  if with_error
61
60
  e[0] *= exterm
62
- e[1] = exterm * (e[1] + 2*x.abs*Float::EPSILON + Float::EPSILON)
61
+ e[1] = exterm * (e[1] + 2 * x.abs * Float::EPSILON + Float::EPSILON)
63
62
  else
64
63
  e *= exterm
65
64
  end
66
65
  else
67
66
  e8 = erfc8(ax)
68
- e = with_error ? [e8, (x*x + 1) * Float::EPSILON * e8.abs] : e8
67
+ e = with_error ? [e8, (x * x + 1) * Float::EPSILON * e8.abs] : e8
69
68
  end
70
69
 
71
70
  result = x < 0 ? 2 - (with_error ? e.first : e) : (with_error ? e.first : e)
72
- with_error ? [result, e.last + 2*Float::EPSILON*result.abs] : result
71
+ with_error ? [result, e.last + 2 * Float::EPSILON * result.abs] : result
73
72
  end
74
73
  end
75
-
76
74
  end
77
-
78
75
  end
79
- end
76
+ end
@@ -3,57 +3,57 @@ module Distribution
3
3
  # From GSL-1.9.
4
4
  module ExponentialIntegral
5
5
  class << self
6
- def first_order x, scale = 0, with_error = false
6
+ def first_order(x, scale = 0, with_error = false)
7
7
  xmaxt = -Math::LOG_FLOAT_MIN
8
8
  xmax = xmaxt - Math.log(xmaxt)
9
9
  result = nil
10
10
  error = with_error ? nil : 0.0
11
11
 
12
12
  if x < -xmax && !scale
13
- raise("Overflow Error")
13
+ fail('Overflow Error')
14
14
  elsif x <= -10.0
15
- s = 1.0 / x * ( scale ? 1.0 : Math.exp(-x))
16
- result_c = ChebyshevSeries.eval(20.0/x+1.0, :ae11, with_error)
15
+ s = 1.0 / x * (scale ? 1.0 : Math.exp(-x))
16
+ result_c = ChebyshevSeries.eval(20.0 / x + 1.0, :ae11, with_error)
17
17
  result_c, result_c_err = result_c if with_error
18
18
  result = s * (1.0 + result_c)
19
- error ||= (s * result_c_err) + 2.0*Float::EPSILON * (x.abs + 1.0) * result.abs
19
+ error ||= (s * result_c_err) + 2.0 * Float::EPSILON * (x.abs + 1.0) * result.abs
20
20
  elsif x <= -4.0
21
21
  s = 1.0 / x * (scale ? 1.0 : Math.exp(-x))
22
- result_c = ChebyshevSeries.eval((40.0/x+7.0)/3.0, :ae12, with_error)
22
+ result_c = ChebyshevSeries.eval((40.0 / x + 7.0) / 3.0, :ae12, with_error)
23
23
  result_c, result_c_err = result_c if with_error
24
24
  result = s * (1.0 + result_c)
25
- error ||= (s * result_c_err) + 2.0*Float::EPSILON * result.abs
25
+ error ||= (s * result_c_err) + 2.0 * Float::EPSILON * result.abs
26
26
  elsif x <= -1.0
27
27
  ln_term = - Math.log(x.abs)
28
28
  scale_factor = scale ? Math.exp(x) : 1.0
29
- result_c = ChebyshevSeries.eval((2.0*x+5.0)/3.0, :e11, with_error)
29
+ result_c = ChebyshevSeries.eval((2.0 * x + 5.0) / 3.0, :e11, with_error)
30
30
  result_c, result_c_err = result_c if with_error
31
31
  result = scale_factor * (ln_term + result_c)
32
- error ||= scale_factor * (result_c_err + Float::EPSILON * ln_term.abs) + 2.0*Float::EPSILON*result.abs
32
+ error ||= scale_factor * (result_c_err + Float::EPSILON * ln_term.abs) + 2.0 * Float::EPSILON * result.abs
33
33
  elsif x == 0.0
34
- raise(ArgumentError, "Domain Error")
34
+ fail(ArgumentError, 'Domain Error')
35
35
  elsif x <= 1.0
36
36
  ln_term = - Math.log(x.abs)
37
37
  scale_factor = scale ? Math.exp(x) : 1.0
38
38
  result_c = ChebyshevSeries.eval(x, :e12, with_error)
39
39
  result_c, result_c_err = result_c if with_error
40
40
  result = scale_factor * (ln_term - 0.6875 + x + result_c)
41
- error ||= scale_factor * (result_c_err + Float::EPSILON * ln_term.abs) + 2.0*Float::EPSILON*result.abs
41
+ error ||= scale_factor * (result_c_err + Float::EPSILON * ln_term.abs) + 2.0 * Float::EPSILON * result.abs
42
42
  elsif x <= 4.0
43
43
  s = 1.0 / x * (scale ? 1.0 : Math.exp(-x))
44
- result_c = ChebyshevSeries.eval((8.0/x-5.0)/3.0, :ae13, with_error)
44
+ result_c = ChebyshevSeries.eval((8.0 / x - 5.0) / 3.0, :ae13, with_error)
45
45
  result_c, result_c_err = result_c if with_error
46
46
  result = s * (1.0 + result_c)
47
- error ||= (s * result_c_err) + 2.0*Float::EPSILON * result.abs
47
+ error ||= (s * result_c_err) + 2.0 * Float::EPSILON * result.abs
48
48
  elsif x <= xmax || scale
49
49
  s = 1.0 / x * (scale ? 1.0 : Math.exp(-x))
50
- result_c = ChebyshevSeries.eval(8.0/x-1.0, :ae14, with_error)
50
+ result_c = ChebyshevSeries.eval(8.0 / x - 1.0, :ae14, with_error)
51
51
  result_c, result_c_err = result_c if with_error
52
52
  result = s * (1.0 + result_c)
53
- error ||= s * (Float::EPSILON + result_c_err) + 2.0*(x+1.0)*Float::EPSILON * result.abs
54
- raise("Underflow Error") if result == 0.0
53
+ error ||= s * (Float::EPSILON + result_c_err) + 2.0 * (x + 1.0) * Float::EPSILON * result.abs
54
+ fail('Underflow Error') if result == 0.0
55
55
  else
56
- raise("Underflow Error")
56
+ fail('Underflow Error')
57
57
  end
58
58
  with_error ? [result, error] : result
59
59
  end
@@ -10,52 +10,51 @@ module Distribution
10
10
  C2 = 1.quo(1260)
11
11
  C3 = -1.quo(1680)
12
12
  C4 = 1.quo(1188)
13
- C5 = -691.quo(360360)
13
+ C5 = -691.quo(360_360)
14
14
  C6 = 1.quo(156)
15
- C7 = -3617.quo(122400)
15
+ C7 = -3617.quo(122_400)
16
16
 
17
17
  class << self
18
-
19
- def series x, with_error = false
18
+ def series(x, with_error = false)
20
19
  # Use the Stirling series for the correction to Log(Gamma(x)),
21
20
  # which is better behaved and easier to compute than the
22
21
  # regular Stirling series for Gamma(x).
23
- y = 1.quo(x*x)
24
- ser = C0 + y*(C1 + y*(C2 + y*(C3 + y*(C4 + y*(C5 + y*(C6 + y*C7))))))
25
- result = Math.exp(ser/x)
26
- with_error ? [result, 2.0 * Float::EPSILON * result * [1, ser/x].max] : result
22
+ y = 1.quo(x * x)
23
+ ser = C0 + y * (C1 + y * (C2 + y * (C3 + y * (C4 + y * (C5 + y * (C6 + y * C7))))))
24
+ result = Math.exp(ser / x)
25
+ with_error ? [result, 2.0 * Float::EPSILON * result * [1, ser / x].max] : result
27
26
  end
28
27
 
29
- def evaluate x, with_error = false
30
- raise(ArgumentError, "x must be positive") if x <= 0
28
+ def evaluate(x, with_error = false)
29
+ fail(ArgumentError, 'x must be positive') if x <= 0
31
30
  if x < 0.5
32
31
  STDERR.puts("Warning: Don't know error on lg_x, error for this function will be incorrect") if with_error
33
32
  lg = Math.lgamma(x).first
34
33
  lg_err = Float::EPSILON # Guess
35
34
  lx = Math.log(x)
36
35
  c = 0.5 * (LN2 + LNPI)
37
- lnr_val = lg - (x-0.5)*lx + x - c
38
- lnr_err = lg_err + 2.0*Float::EPSILON * ((x+0.5)*lx.abs + c)
36
+ lnr_val = lg - (x - 0.5) * lx + x - c
37
+ lnr_err = lg_err + 2.0 * Float::EPSILON * ((x + 0.5) * lx.abs + c)
39
38
  with_error ? exp_err(lnr_val, lnr_err) : Math.exp(lnr_val)
40
39
  elsif x < 2.0
41
- t = 4.0/3.0*(x-0.5) - 1.0
40
+ t = 4.0 / 3.0 * (x - 0.5) - 1.0
42
41
  ChebyshevSeries.evaluate(:gstar_a, t, with_error)
43
42
  elsif x < 10.0
44
- t = 0.25*(x-2.0) - 1.0
43
+ t = 0.25 * (x - 2.0) - 1.0
45
44
  c = ChebyshevSeries.evaluate(:gstar_b, t, with_error)
46
45
  c, c_err = c if with_error
47
46
 
48
- result = c / (x*x) + 1.0 + 1.0/(12.0*x)
49
- with_error ? [result, c_err / (x*x) + 2.0*Float::EPSILON*result.abs] : result
50
- elsif x < 1.0/Math::ROOT4_FLOAT_EPSILON
47
+ result = c / (x * x) + 1.0 + 1.0 / (12.0 * x)
48
+ with_error ? [result, c_err / (x * x) + 2.0 * Float::EPSILON * result.abs] : result
49
+ elsif x < 1.0 / Math::ROOT4_FLOAT_EPSILON
51
50
  series x, with_error
52
51
  elsif x < 1.0 / Float::EPSILON # Stirling
53
52
  xi = 1.0 / x
54
- result = 1.0 + xi/12.0*(1.0 + xi/24.0*(1.0 - xi*(139.0/180.0 + 571.0/8640.0*xi)))
53
+ result = 1.0 + xi / 12.0 * (1.0 + xi / 24.0 * (1.0 - xi * (139.0 / 180.0 + 571.0 / 8640.0 * xi)))
55
54
  result_err = 2.0 * Float::EPSILON * result.abs
56
- with_error ? [result,result_err] : result
55
+ with_error ? [result, result_err] : result
57
56
  else
58
- with_error ? [1.0,1.0/x] : 1.0
57
+ with_error ? [1.0, 1.0 / x] : 1.0
59
58
  end
60
59
  end
61
60
  end
@@ -8,14 +8,14 @@ module Distribution
8
8
  SQRT2 = 1.41421356237309504880168872421
9
9
  SQRTPI = 1.77245385090551602729816748334
10
10
 
11
- ROOT3_FLOAT_MIN = Float::MIN ** (1/3.0)
12
- ROOT3_FLOAT_EPSILON = Float::EPSILON ** (1/3.0)
13
- ROOT4_FLOAT_MIN = Float::MIN ** (1/4.0)
14
- ROOT4_FLOAT_EPSILON = Float::EPSILON ** (1/4.0)
15
- ROOT5_FLOAT_MIN = Float::MIN ** (1/5.0)
16
- ROOT5_FLOAT_EPSILON = Float::EPSILON ** (1/5.0)
17
- ROOT6_FLOAT_MIN = Float::MIN ** (1/6.0)
18
- ROOT6_FLOAT_EPSILON = Float::EPSILON ** (1/6.0)
11
+ ROOT3_FLOAT_MIN = Float::MIN**(1 / 3.0)
12
+ ROOT3_FLOAT_EPSILON = Float::EPSILON**(1 / 3.0)
13
+ ROOT4_FLOAT_MIN = Float::MIN**(1 / 4.0)
14
+ ROOT4_FLOAT_EPSILON = Float::EPSILON**(1 / 4.0)
15
+ ROOT5_FLOAT_MIN = Float::MIN**(1 / 5.0)
16
+ ROOT5_FLOAT_EPSILON = Float::EPSILON**(1 / 5.0)
17
+ ROOT6_FLOAT_MIN = Float::MIN**(1 / 6.0)
18
+ ROOT6_FLOAT_EPSILON = Float::EPSILON**(1 / 6.0)
19
19
  LOG_FLOAT_MIN = Math.log(Float::MIN)
20
20
  EULER = 0.57721566490153286060651209008
21
21
 
@@ -23,9 +23,9 @@ module Distribution
23
23
  # gsl_sf_exp_err_e
24
24
  def exp_err(x, dx)
25
25
  adx = dx.abs
26
- raise("Overflow Error in exp_err: x + adx > LOG_FLOAT_MAX") if x + adx > LOG_FLOAT_MAX
27
- raise("Underflow Error in exp_err: x - adx < LOG_FLOAT_MIN") if x - adx < LOG_FLOAT_MIN
28
- [Math.exp(x), Math.exp(x) * [Float::EPSILON, Math.exp(adx) - 1.0/Math.exp(adx)] + 2.0 * Float::EPSILON * Math.exp(x).abs]
26
+ fail('Overflow Error in exp_err: x + adx > LOG_FLOAT_MAX') if x + adx > LOG_FLOAT_MAX
27
+ fail('Underflow Error in exp_err: x - adx < LOG_FLOAT_MIN') if x - adx < LOG_FLOAT_MIN
28
+ [Math.exp(x), Math.exp(x) * [Float::EPSILON, Math.exp(adx) - 1.0 / Math.exp(adx)] + 2.0 * Float::EPSILON * Math.exp(x).abs]
29
29
  end
30
30
  end
31
- end
31
+ end
@@ -7,37 +7,37 @@ module Distribution
7
7
  class << self
8
8
  # Based on gsl_sf_lnbeta_e and gsl_sf_lnbeta_sgn_e
9
9
  # Returns result and sign in an array. If with_error is specified, also returns the error.
10
- def log_beta(x,y, with_error=false)
10
+ def log_beta(x, y, with_error = false)
11
11
  sign = nil
12
12
 
13
- raise(ArgumentError, "x and y must be nonzero") if x == 0.0 || y == 0.0
14
- raise(ArgumentError, "not defined for negative integers") if [x,y].any? { |v| (v.is_a?(Fixnum) && v < 0) }
13
+ fail(ArgumentError, 'x and y must be nonzero') if x == 0.0 || y == 0.0
14
+ fail(ArgumentError, 'not defined for negative integers') if [x, y].any? { |v| v < 0 }
15
15
 
16
16
  # See if we can handle the positive case with min/max < 0.2
17
17
  if x > 0 && y > 0
18
- min, max = [x,y].minmax
18
+ min, max = [x, y].minmax
19
19
  ratio = min.quo(max)
20
20
 
21
21
  if ratio < 0.2
22
22
  gsx = Gammastar.evaluate(x, with_error)
23
23
  gsy = Gammastar.evaluate(y, with_error)
24
- gsxy = Gammastar.evaluate(x+y, with_error)
25
- lnopr = Log::log_1plusx(ratio, with_error)
24
+ gsxy = Gammastar.evaluate(x + y, with_error)
25
+ lnopr = Log.log_1plusx(ratio, with_error)
26
26
 
27
- gsx, gsx_err, gsy, gsy_err, gsxy, gsxy_err, lnopr, lnopr_err = [gsx,gsy,gsxy,lnopr].flatten if with_error
27
+ gsx, gsx_err, gsy, gsy_err, gsxy, gsxy_err, lnopr, lnopr_err = [gsx, gsy, gsxy, lnopr].flatten if with_error
28
28
 
29
- lnpre = Math.log((gsx*gsy).quo(gsxy) * Math::SQRT2 * Math::SQRTPI)
29
+ lnpre = Math.log((gsx * gsy).quo(gsxy) * Math::SQRT2 * Math::SQRTPI)
30
30
  lnpre_err = gsx_err.quo(gsx) + gsy_err(gsy) + gsxy_err.quo(gsxy) if with_error
31
31
 
32
32
  t1 = min * Math.log(ratio)
33
33
  t2 = 0.5 * Math.log(min)
34
- t3 = (x+y-0.5)*lnopr
34
+ t3 = (x + y - 0.5) * lnopr
35
35
 
36
36
  lnpow = t1 - t2 - t3
37
- lnpow_err = Float::EPSILON * (t1.abs + t2.abs + t3.abs) + (x+y-0.5).abs * lnopr_err if with_error
37
+ lnpow_err = Float::EPSILON * (t1.abs + t2.abs + t3.abs) + (x + y - 0.5).abs * lnopr_err if with_error
38
38
 
39
39
  result = lnpre + lnpow
40
- error = lnpre_err + lnpow_err + 2.0*Float::EPSILON*result.abs if with_error
40
+ error = lnpre_err + lnpow_err + 2.0 * Float::EPSILON * result.abs if with_error
41
41
 
42
42
  return with_error ? [result, 1.0, error] : [result, 1.0]
43
43
  end
@@ -46,84 +46,80 @@ module Distribution
46
46
  # General case: fallback
47
47
  lgx, sgx = Math.lgamma(x)
48
48
  lgy, sgy = Math.lgamma(y)
49
- lgxy, sgxy = Math.lgamma(x+y)
49
+ lgxy, sgxy = Math.lgamma(x + y)
50
50
  sgn = sgx * sgy * sgxy
51
51
 
52
- raise("Domain error: sign is -") if sgn == -1
52
+ fail('Domain error: sign is -') if sgn == -1
53
53
 
54
54
  result = lgx + lgy - lgxy
55
55
  if with_error
56
56
  lgx_err, lgy_err, lgxy_err = begin
57
- STDERR.puts("Warning: Error is unknown for Math::lgamma, guessing.")
57
+ STDERR.puts('Warning: Error is unknown for Math::lgamma, guessing.')
58
58
  [Math::EPSILON, Math::EPSILON, Math::EPSILON]
59
59
  end
60
60
 
61
- error = lgx_err + lgy_err + lgxy_err + Float::EPSILON*(lgx.abs+lgy.abs+lgxy.abs) + 2.0*(Float::EPSILON)*result.abs
61
+ error = lgx_err + lgy_err + lgxy_err + Float::EPSILON * (lgx.abs + lgy.abs + lgxy.abs) + 2.0 * (Float::EPSILON) * result.abs
62
62
  return [result, sgn, error]
63
63
  else
64
64
  return [result, sgn]
65
65
  end
66
-
67
66
  end
68
67
  end
69
68
  end
70
69
  # Calculate regularized incomplete beta function
71
70
  module IncompleteBeta
72
-
73
71
  MAX_ITER = 512
74
72
  CUTOFF = 2.0 * Float::MIN
75
73
 
76
74
  class << self
77
-
78
75
  # Evaluate aa * beta_inc(a,b,x) + yy
79
76
  #
80
77
  # No error mode available.
81
78
  #
82
79
  # From GSL-1.9: cdf/beta_inc.c, beta_inc_AXPY
83
- def axpy(aa,yy,a,b,x)
84
- return aa*0 + yy if x == 0.0
85
- return aa*1 + yy if x == 1.0
80
+ def axpy(aa, yy, a, b, x)
81
+ return aa * 0 + yy if x == 0.0
82
+ return aa * 1 + yy if x == 1.0
86
83
 
87
84
  ln_beta = Math.logbeta(a, b)
88
- ln_pre = -ln_beta + a * Math.log(x) + b * Math::Log.log1p(-x)
85
+ ln_pre = -ln_beta + a * Math.log(x) + b * Math::Log.log1p(-x)
89
86
  prefactor = Math.exp(ln_pre)
90
87
 
91
- if x < (a+1).quo(a+b+2)
88
+ if x < (a + 1).quo(a + b + 2)
92
89
  # Apply continued fraction directly
93
90
  epsabs = yy.quo((aa * prefactor).quo(a)).abs * Float::EPSILON
94
91
  cf = continued_fraction(a, b, x, epsabs)
95
92
  return aa * (prefactor * cf).quo(a) + yy
96
93
  else
97
94
  # Apply continued fraction after hypergeometric transformation
98
- epsabs = (aa + yy).quo( (aa*prefactor).quo(b) ) * Float::EPSILON
99
- cf = continued_fraction(b, a, 1-x, epsabs)
95
+ epsabs = (aa + yy).quo((aa * prefactor).quo(b)) * Float::EPSILON
96
+ cf = continued_fraction(b, a, 1 - x, epsabs)
100
97
  term = (prefactor * cf).quo(b)
101
- return aa == -yy ? -aa*term : aa*(1-term)+yy
98
+ return aa == -yy ? -aa * term : aa * (1 - term) + yy
102
99
  end
103
100
  end
104
101
 
105
-
106
102
  # Evaluate the incomplete beta function
107
103
  # gsl_sf_beta_inc_e
108
- def evaluate(a,b,x,with_error=false)
109
- raise(ArgumentError, "Domain error: a(#{a}), b(#{b}) must be positive; x(#{x}) must be between 0 and 1, inclusive") if a <= 0 || b <= 0 || x < 0 || x > 1
104
+ def evaluate(a, b, x, with_error = false)
105
+ fail(ArgumentError, "Domain error: a(#{a}), b(#{b}) must be positive; x(#{x}) must be between 0 and 1, inclusive") if a <= 0 || b <= 0 || x < 0 || x > 1
110
106
  if x == 0
111
- return with_error ? [0.0,0.0] : 0.0
107
+ return with_error ? [0.0, 0.0] : 0.0
112
108
  elsif x == 1
113
- return with_error ? [1.0,0.0] : 1.0
109
+ return with_error ? [1.0, 0.0] : 1.0
114
110
  else
115
111
 
116
- ln_beta = Beta.log_beta(a,b, with_error)
112
+ ln_beta = Beta.log_beta(a, b, with_error)
117
113
  ln_1mx = Log.log_1plusx(-x, with_error)
118
114
  ln_x = Math.log(x)
119
115
 
120
116
  ln_beta, ln_beta_err, ln_1mx, ln_1mx_err, ln_x_err = begin
121
- #STDERR.puts("Warning: Error is unknown for Math::log, guessing.")
122
- [ln_beta,ln_1mx,Float::EPSILON].flatten
117
+ # STDERR.puts("Warning: Error is unknown for Math::log, guessing.")
118
+ [ln_beta, ln_1mx, Float::EPSILON].flatten
123
119
  end
124
120
 
125
- ln_pre = -ln_beta + a*ln_x + b*ln_1mx
126
- ln_pre_err = ln_beta_err + (a*ln_x_err).abs + (b*ln_1mx_err).abs if with_error
121
+ ln_pre = -ln_beta + a * ln_x + b * ln_1mx
122
+ ln_pre_err = ln_beta_err + (a * ln_x_err).abs + (b * ln_1mx_err).abs if with_error
127
123
 
128
124
  prefactor, prefactor_err = begin
129
125
  if with_error
@@ -133,31 +129,30 @@ module Distribution
133
129
  end
134
130
  end
135
131
 
136
- if x < (a+1).quo(a+b+2)
132
+ if x < (a + 1).quo(a + b + 2)
137
133
  # Apply continued fraction directly
138
-
139
- cf = continued_fraction(a,b,x, nil, with_error)
140
- cf,cf_err = cf if with_error
134
+
135
+ cf = continued_fraction(a, b, x, nil, with_error)
136
+ cf, cf_err = cf if with_error
141
137
  result = (prefactor * cf).quo(a)
142
- return with_error ? [result, ((prefactor_err*cf).abs + (prefactor*cf_err).abs).quo(a)] : result
138
+ return with_error ? [result, ((prefactor_err * cf).abs + (prefactor * cf_err).abs).quo(a)] : result
143
139
  else
144
140
  # Apply continued fraction after hypergeometric transformation
145
141
 
146
- cf = continued_fraction(b, a, 1-x, nil)
147
- cf,cf_err = cf if with_error
142
+ cf = continued_fraction(b, a, 1 - x, nil)
143
+ cf, cf_err = cf if with_error
148
144
  term = (prefactor * cf).quo(b)
149
145
  result = 1 - term
150
146
 
151
- return with_error ? [result, (prefactor_err*cf).quo(b) + (prefactor*cf_err).quo(b) + 2.0*Float::EPSILON*(1+term.abs)] : result
147
+ return with_error ? [result, (prefactor_err * cf).quo(b) + (prefactor * cf_err).quo(b) + 2.0 * Float::EPSILON * (1 + term.abs)] : result
152
148
  end
153
149
 
154
150
  end
155
151
  end
156
152
 
157
-
158
153
  def continued_fraction_cutoff(epsabs)
159
154
  return CUTOFF if epsabs.nil?
160
- 0.0/0 # NaN
155
+ 0.0 / 0 # NaN
161
156
  end
162
157
 
163
158
  # Continued fraction calculation of incomplete beta
@@ -165,9 +160,9 @@ module Distribution
165
160
  #
166
161
  # If epsabs is set, will execute the version of the GSL function in the cdf folder. Otherwise, does the
167
162
  # basic one in specfunc.
168
- def continued_fraction(a,b,x,epsabs=nil,with_error=false)
163
+ def continued_fraction(a, b, x, epsabs = nil, with_error = false)
169
164
  num_term = 1
170
- den_term = 1 - (a+b)*x.quo(a+1)
165
+ den_term = 1 - (a + b) * x.quo(a + 1)
171
166
  k = 0
172
167
 
173
168
  den_term = continued_fraction_cutoff(epsabs) if den_term.abs < CUTOFF
@@ -175,11 +170,10 @@ module Distribution
175
170
  cf = den_term
176
171
 
177
172
  1.upto(MAX_ITER) do |k|
178
- coeff = k *(b-k)*x.quo(((a-1)+2*k)*(a+2*k)) # coefficient for step 1
173
+ coeff = k * (b - k) * x.quo(((a - 1) + 2 * k) * (a + 2 * k)) # coefficient for step 1
179
174
  delta_frac = nil
180
175
  2.times do
181
-
182
- den_term = 1 + coeff*den_term
176
+ den_term = 1 + coeff * den_term
183
177
  num_term = 1 + coeff.quo(num_term)
184
178
 
185
179
  den_term = continued_fraction_cutoff(epsabs) if den_term.abs < CUTOFF
@@ -188,26 +182,23 @@ module Distribution
188
182
  den_term = 1.quo(den_term)
189
183
 
190
184
  delta_frac = den_term * num_term
191
- cf *= delta_frac
185
+ cf *= delta_frac
192
186
 
193
- coeff = -(a+k)*(a+b+k)*x.quo((a+2*k)*(a+2*k+1)) # coefficient for step 2
187
+ coeff = -(a + k) * (a + b + k) * x.quo((a + 2 * k) * (a + 2 * k + 1)) # coefficient for step 2
194
188
  end
195
189
 
196
- break if (delta_frac-1).abs < 2.0*Float::EPSILON
197
- break if !epsabs.nil? && (cf * (delta_frac-1).abs < epsabs)
190
+ break if (delta_frac - 1).abs < 2.0 * Float::EPSILON
191
+ break if !epsabs.nil? && (cf * (delta_frac - 1).abs < epsabs)
198
192
  end
199
193
 
200
194
  if k > MAX_ITER
201
- raise("Exceeded maximum number of iterations") if epsabs.nil?
202
- return with_error ? [0.0/0, 0] : 0.0/0 # NaN if epsabs is set
195
+ fail('Exceeded maximum number of iterations') if epsabs.nil?
196
+ return with_error ? [0.0 / 0, 0] : 0.0 / 0 # NaN if epsabs is set
203
197
  end
204
198
 
205
199
  with_error ? [cf, k * 4 * Float::EPSILON * cf.abs] : cf
206
200
  end
207
-
208
-
209
201
  end
210
-
211
202
  end
212
203
  end
213
- end
204
+ end