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
@@ -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