distribution 0.7.3 → 0.8.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +5 -5
- data/.travis.yml +4 -6
- data/.yardopts +5 -0
- data/History.txt +3 -0
- data/README.md +87 -44
- data/benchmark/binomial_coefficient.rb +19 -23
- data/benchmark/binomial_coefficient/experiment.rb +33 -36
- data/benchmark/factorial_hash.rb +7 -8
- data/benchmark/factorial_method.rb +4 -6
- data/benchmark/odd.rb +6 -7
- data/benchmark/power.rb +11 -11
- data/bin/distribution +26 -26
- data/distribution.gemspec +3 -4
- data/lib/distribution.rb +55 -96
- data/lib/distribution/beta/gsl.rb +10 -5
- data/lib/distribution/beta/ruby.rb +3 -1
- data/lib/distribution/binomial/ruby.rb +5 -2
- data/lib/distribution/bivariatenormal.rb +4 -5
- data/lib/distribution/bivariatenormal/gsl.rb +2 -2
- data/lib/distribution/bivariatenormal/java.rb +1 -1
- data/lib/distribution/bivariatenormal/ruby.rb +245 -254
- data/lib/distribution/chisquare.rb +8 -10
- data/lib/distribution/chisquare/gsl.rb +24 -19
- data/lib/distribution/chisquare/java.rb +1 -1
- data/lib/distribution/chisquare/ruby.rb +25 -25
- data/lib/distribution/chisquare/statistics2.rb +16 -13
- data/lib/distribution/distributable.rb +40 -0
- data/lib/distribution/exponential.rb +4 -5
- data/lib/distribution/exponential/gsl.rb +13 -9
- data/lib/distribution/exponential/ruby.rb +14 -9
- data/lib/distribution/f.rb +1 -1
- data/lib/distribution/f/gsl.rb +26 -22
- data/lib/distribution/f/java.rb +1 -1
- data/lib/distribution/f/ruby.rb +16 -19
- data/lib/distribution/f/statistics2.rb +22 -19
- data/lib/distribution/gamma.rb +5 -7
- data/lib/distribution/gamma/gsl.rb +13 -9
- data/lib/distribution/gamma/java.rb +1 -1
- data/lib/distribution/gamma/ruby.rb +5 -11
- data/lib/distribution/hypergeometric.rb +5 -8
- data/lib/distribution/hypergeometric/gsl.rb +4 -5
- data/lib/distribution/hypergeometric/java.rb +1 -1
- data/lib/distribution/hypergeometric/ruby.rb +34 -35
- data/lib/distribution/logistic.rb +5 -8
- data/lib/distribution/logistic/ruby.rb +13 -8
- data/lib/distribution/lognormal.rb +5 -7
- data/lib/distribution/lognormal/gsl.rb +8 -6
- data/lib/distribution/lognormal/ruby.rb +5 -9
- data/lib/distribution/math_extension.rb +6 -15
- data/lib/distribution/math_extension/chebyshev_series.rb +281 -272
- data/lib/distribution/math_extension/erfc.rb +26 -29
- data/lib/distribution/math_extension/exponential_integral.rb +17 -17
- data/lib/distribution/math_extension/gammastar.rb +19 -20
- data/lib/distribution/math_extension/gsl_utilities.rb +12 -12
- data/lib/distribution/math_extension/incomplete_beta.rb +52 -61
- data/lib/distribution/math_extension/incomplete_gamma.rb +166 -168
- data/lib/distribution/math_extension/log_utilities.rb +20 -22
- data/lib/distribution/normal.rb +11 -13
- data/lib/distribution/normal/gsl.rb +13 -10
- data/lib/distribution/normal/java.rb +14 -13
- data/lib/distribution/normal/ruby.rb +68 -58
- data/lib/distribution/normal/statistics2.rb +5 -2
- data/lib/distribution/normalmultivariate.rb +64 -64
- data/lib/distribution/poisson.rb +11 -13
- data/lib/distribution/poisson/gsl.rb +7 -7
- data/lib/distribution/poisson/java.rb +19 -24
- data/lib/distribution/poisson/ruby.rb +38 -9
- data/lib/distribution/shorthand.rb +17 -0
- data/lib/distribution/t.rb +13 -15
- data/lib/distribution/t/gsl.rb +27 -24
- data/lib/distribution/t/java.rb +1 -1
- data/lib/distribution/t/ruby.rb +99 -100
- data/lib/distribution/t/statistics2.rb +19 -19
- data/lib/distribution/uniform.rb +26 -0
- data/lib/distribution/uniform/gsl.rb +36 -0
- data/lib/distribution/uniform/ruby.rb +91 -0
- data/lib/distribution/version.rb +1 -1
- data/lib/distribution/weibull.rb +6 -7
- data/lib/distribution/weibull/gsl.rb +16 -16
- data/lib/distribution/weibull/ruby.rb +30 -23
- data/spec/beta_spec.rb +45 -47
- data/spec/binomial_spec.rb +77 -85
- data/spec/bivariatenormal_spec.rb +28 -35
- data/spec/chisquare_spec.rb +48 -52
- data/spec/distribution_spec.rb +10 -10
- data/spec/exponential_spec.rb +44 -49
- data/spec/f_spec.rb +4 -4
- data/spec/gamma_spec.rb +50 -53
- data/spec/hypergeometric_spec.rb +63 -69
- data/spec/logistic_spec.rb +32 -37
- data/spec/lognormal_spec.rb +25 -31
- data/spec/math_extension_spec.rb +192 -210
- data/spec/normal_spec.rb +80 -73
- data/spec/poisson_spec.rb +63 -41
- data/spec/shorthand_spec.rb +19 -22
- data/spec/spec_helper.rb +8 -9
- data/spec/t_spec.rb +63 -77
- data/spec/uniform_spec.rb +154 -0
- data/spec/weibull_spec.rb +13 -14
- 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 = [
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
Q = [
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
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
|
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
|
-
|
13
|
+
fail('Overflow Error')
|
14
14
|
elsif x <= -10.0
|
15
|
-
s = 1.0 / 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
|
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
|
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
|
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
|
-
|
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
|
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
|
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
|
54
|
-
|
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
|
-
|
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(
|
13
|
+
C5 = -691.quo(360_360)
|
14
14
|
C6 = 1.quo(156)
|
15
|
-
C7 = -3617.quo(
|
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
|
30
|
-
|
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
|
12
|
-
ROOT3_FLOAT_EPSILON = Float::EPSILON
|
13
|
-
ROOT4_FLOAT_MIN = Float::MIN
|
14
|
-
ROOT4_FLOAT_EPSILON = Float::EPSILON
|
15
|
-
ROOT5_FLOAT_MIN = Float::MIN
|
16
|
-
ROOT5_FLOAT_EPSILON = Float::EPSILON
|
17
|
-
ROOT6_FLOAT_MIN = Float::MIN
|
18
|
-
ROOT6_FLOAT_EPSILON = Float::EPSILON
|
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
|
-
|
27
|
-
|
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
|
-
|
14
|
-
|
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
|
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
|
-
|
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(
|
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
|
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(
|
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
|
-
|
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
|
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
|
-
|
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
|