rubystats 0.2.6 → 0.4.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.
- checksums.yaml +4 -4
- data/.github/workflows/test.yml +21 -0
- data/History.txt +31 -0
- data/README.rdoc +17 -6
- data/examples/uniform.rb +14 -0
- data/lib/rubystats/beta_distribution.rb +4 -0
- data/lib/rubystats/binomial_distribution.rb +42 -131
- data/lib/rubystats/cauchy_distribution.rb +50 -0
- data/lib/rubystats/exponential_distribution.rb +2 -2
- data/lib/rubystats/gamma_distribution.rb +70 -0
- data/lib/rubystats/lognormal_distribution.rb +59 -0
- data/lib/rubystats/modules.rb +6 -0
- data/lib/rubystats/multivariate_normal_distribution.rb +73 -0
- data/lib/rubystats/normal_distribution.rb +2 -2
- data/lib/rubystats/poisson_distribution.rb +78 -0
- data/lib/rubystats/probability_distribution.rb +3 -3
- data/lib/rubystats/student_t_distribution.rb +62 -0
- data/lib/rubystats/uniform_distribution.rb +70 -0
- data/lib/rubystats/version.rb +1 -1
- data/lib/rubystats/weibull_distribution.rb +56 -0
- data/lib/rubystats.rb +29 -0
- data/rubystats.gemspec +6 -0
- data/test/tc_beta.rb +21 -0
- data/test/tc_binomial.rb +14 -0
- data/test/tc_cauchy.rb +39 -0
- data/test/tc_exponential.rb +10 -0
- data/test/tc_gamma.rb +39 -0
- data/test/tc_lnorm.rb +45 -0
- data/test/tc_multivariate_normal.rb +53 -0
- data/test/tc_norm.rb +11 -1
- data/test/tc_poisson.rb +35 -0
- data/test/tc_studentt.rb +43 -0
- data/test/tc_unif.rb +48 -0
- data/test/tc_weibull.rb +51 -0
- metadata +28 -3
- data/.travis.yml +0 -12
@@ -0,0 +1,78 @@
|
|
1
|
+
require 'rubystats/probability_distribution'
|
2
|
+
|
3
|
+
module Rubystats
|
4
|
+
class PoissonDistribution < Rubystats::ProbabilityDistribution
|
5
|
+
include Rubystats::MakeDiscrete
|
6
|
+
|
7
|
+
# Constructs a Poisson distribution
|
8
|
+
def initialize (rate)
|
9
|
+
if rate <= 0.0
|
10
|
+
raise ArgumentError.new("The rate for the Poisson distribution should be greater than zero.")
|
11
|
+
end
|
12
|
+
@rate = rate.to_f
|
13
|
+
end
|
14
|
+
|
15
|
+
#returns the mean
|
16
|
+
def get_mean
|
17
|
+
@rate
|
18
|
+
end
|
19
|
+
|
20
|
+
#returns the variance
|
21
|
+
def get_variance
|
22
|
+
@rate
|
23
|
+
end
|
24
|
+
|
25
|
+
# Private methods below
|
26
|
+
|
27
|
+
private
|
28
|
+
|
29
|
+
# Probability mass function of a Poisson distribution .
|
30
|
+
# k should be an integer
|
31
|
+
# returns the probability that a stochastic variable x has the value k,
|
32
|
+
# i.e. P(x = k)
|
33
|
+
def get_pdf(k)
|
34
|
+
raise ArgumentError.new("Poisson pdf: k needs to be >= 0") if k < 0
|
35
|
+
(@rate**k) * Math.exp(-@rate) / get_factorial(k).to_f
|
36
|
+
end
|
37
|
+
|
38
|
+
# Private shared function for getting cumulant for particular x
|
39
|
+
# param k should be integer-valued
|
40
|
+
# returns the probability that a stochastic variable x is less than _x
|
41
|
+
# i.e P(x < k)
|
42
|
+
def get_cdf(k)
|
43
|
+
raise ArgumentError.new("Poisson pdf: k needs to be >= 0") if k < 0
|
44
|
+
sum = 0.0
|
45
|
+
for i in (0 .. k)
|
46
|
+
sum = sum + get_pdf(i)
|
47
|
+
end
|
48
|
+
return sum
|
49
|
+
end
|
50
|
+
|
51
|
+
# Inverse of the cumulative Poisson distribution function
|
52
|
+
def get_icdf(prob)
|
53
|
+
check_range(prob)
|
54
|
+
sum = 0.0
|
55
|
+
k = 0
|
56
|
+
until prob <= sum
|
57
|
+
sum += get_pdf(k)
|
58
|
+
k += 1
|
59
|
+
end
|
60
|
+
return k - 1
|
61
|
+
end
|
62
|
+
|
63
|
+
# Private Poisson RNG function
|
64
|
+
# Poisson generator based upon the inversion by sequential search
|
65
|
+
def get_rng
|
66
|
+
x = 0
|
67
|
+
p = Math.exp(-@rate)
|
68
|
+
s = p
|
69
|
+
u = Kernel.rand
|
70
|
+
while u > s
|
71
|
+
x += 1
|
72
|
+
p *= @rate / x.to_f
|
73
|
+
s += p
|
74
|
+
end
|
75
|
+
x
|
76
|
+
end
|
77
|
+
end
|
78
|
+
end
|
@@ -122,15 +122,15 @@ module Rubystats
|
|
122
122
|
def check_range(x, lo=0.0, hi=1.0)
|
123
123
|
raise ArgumentError.new("x cannot be nil") if x.nil?
|
124
124
|
if x < lo or x > hi
|
125
|
-
raise ArgumentError.new("x must be
|
125
|
+
raise ArgumentError.new("x must be greater than lo (#{lo}) and less than hi (#{hi})")
|
126
126
|
end
|
127
127
|
end
|
128
128
|
|
129
129
|
def get_factorial(n)
|
130
130
|
if n <= 1
|
131
131
|
return 1
|
132
|
-
else
|
133
|
-
return n
|
132
|
+
else
|
133
|
+
return n.downto(1).reduce(:*)
|
134
134
|
end
|
135
135
|
end
|
136
136
|
|
@@ -0,0 +1,62 @@
|
|
1
|
+
require 'rubystats/probability_distribution'
|
2
|
+
require 'rubystats/normal_distribution'
|
3
|
+
# This class provides an object for encapsulating student t distributions
|
4
|
+
module Rubystats
|
5
|
+
class StudentTDistribution < Rubystats::ProbabilityDistribution
|
6
|
+
include Rubystats::SpecialMath
|
7
|
+
|
8
|
+
# Constructs a student t distribution.
|
9
|
+
def initialize(degree_of_freedom=1.0)
|
10
|
+
raise "Argument Error: degrees of freedom for student t distribution must be greater than zero." if degree_of_freedom <= 0.0
|
11
|
+
@dof = degree_of_freedom.to_f
|
12
|
+
@pdf_factor = Math.gamma((@dof + 1.0) / 2.0) / ( Math.sqrt(@dof * Math::PI) * Math.gamma(@dof / 2.0))
|
13
|
+
@stdnorm = Rubystats::NormalDistribution.new(0.0,1.0)
|
14
|
+
end
|
15
|
+
|
16
|
+
# Returns the mean of the distribution
|
17
|
+
def get_mean
|
18
|
+
(@dof > 1) ? 0.0 : Float::NAN
|
19
|
+
end
|
20
|
+
|
21
|
+
# Returns the standard deviation of the distribution
|
22
|
+
def get_standard_deviation
|
23
|
+
return Math.sqrt(get_variance)
|
24
|
+
end
|
25
|
+
|
26
|
+
# Returns the variance of the distribution
|
27
|
+
def get_variance
|
28
|
+
(@dof > 2.0) ? (@dof / (@dof - 2)) : Float::NAN
|
29
|
+
end
|
30
|
+
|
31
|
+
private
|
32
|
+
|
33
|
+
# Obtain single PDF value
|
34
|
+
# Returns the probability that a stochastic variable x has the value X,
|
35
|
+
# i.e. P(x=X)
|
36
|
+
def get_pdf(x)
|
37
|
+
return @pdf_factor * (1.0 + (x**2.0) / @dof)**(-(@dof+1.0)/2.0)
|
38
|
+
end
|
39
|
+
|
40
|
+
# Obtain single CDF value
|
41
|
+
# Returns the probability that a stochastic variable x is less than X,
|
42
|
+
# i.e. P(x<X)
|
43
|
+
def get_cdf(x)
|
44
|
+
raise "method 'cdf' not implemented for student t"
|
45
|
+
end
|
46
|
+
|
47
|
+
# Obtain single inverse CDF value.
|
48
|
+
# returns the value X for which P(x<X).
|
49
|
+
def get_icdf(p)
|
50
|
+
raise "method 'icdf' not implemented for student t"
|
51
|
+
end
|
52
|
+
|
53
|
+
# returns single random number from the student t distribution
|
54
|
+
def get_rng
|
55
|
+
k = @dof.to_i
|
56
|
+
samples = []
|
57
|
+
k.times {|i| samples << @stdnorm.rng }
|
58
|
+
factor = 1.0 / Math.sqrt(samples.inject(0.0) {|sum,x| sum + x**2} / k)
|
59
|
+
return (factor * @stdnorm.rng)
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
@@ -0,0 +1,70 @@
|
|
1
|
+
require 'rubystats/probability_distribution'
|
2
|
+
# This class provides an object for encapsulating uniform distributions
|
3
|
+
module Rubystats
|
4
|
+
class UniformDistribution < Rubystats::ProbabilityDistribution
|
5
|
+
include Rubystats::SpecialMath
|
6
|
+
|
7
|
+
# Constructs a uniform distribution (defaults to zero lower and
|
8
|
+
# unity upper bound).
|
9
|
+
def initialize(lower=0.0, upper=1.0)
|
10
|
+
lower,upper = upper,lower if lower > upper
|
11
|
+
@lower = lower.to_f
|
12
|
+
@upper = upper.to_f
|
13
|
+
@pdf_denominator = 1.0 / (@upper - @lower)
|
14
|
+
@use_last = nil
|
15
|
+
end
|
16
|
+
|
17
|
+
# Returns the mean of the distribution
|
18
|
+
def get_mean
|
19
|
+
return 0.5*(@lower + @upper)
|
20
|
+
end
|
21
|
+
|
22
|
+
# Returns the standard deviation of the distribution
|
23
|
+
def get_standard_deviation
|
24
|
+
return Math.sqrt(get_variance)
|
25
|
+
end
|
26
|
+
|
27
|
+
# Returns the variance of the distribution
|
28
|
+
def get_variance
|
29
|
+
return 1.0/12.0 * (@upper-@lower)**2
|
30
|
+
end
|
31
|
+
|
32
|
+
private
|
33
|
+
|
34
|
+
# Obtain single PDF value
|
35
|
+
# Returns the probability that a stochastic variable x has the value X,
|
36
|
+
# i.e. P(x=X)
|
37
|
+
def get_pdf(x)
|
38
|
+
if x >= @lower && x <= @upper
|
39
|
+
@pdf_denominator
|
40
|
+
else
|
41
|
+
0.0
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
# Obtain single CDF value
|
46
|
+
# Returns the probability that a stochastic variable x is less than X,
|
47
|
+
# i.e. P(x<X)
|
48
|
+
def get_cdf(x)
|
49
|
+
if x >= @lower && x < @upper
|
50
|
+
(x - @lower).fdiv(@upper - @lower)
|
51
|
+
elsif x >= @upper
|
52
|
+
1.0
|
53
|
+
else
|
54
|
+
0.0
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
# Obtain single inverse CDF value.
|
59
|
+
# returns the value X for which P(x<X).
|
60
|
+
def get_icdf(p)
|
61
|
+
check_range(p)
|
62
|
+
return @lower + p.to_f * (@upper - @lower)
|
63
|
+
end
|
64
|
+
|
65
|
+
# returns single random number
|
66
|
+
def get_rng
|
67
|
+
return @lower + (@upper - @lower) * Kernel.rand
|
68
|
+
end
|
69
|
+
end
|
70
|
+
end
|
data/lib/rubystats/version.rb
CHANGED
@@ -0,0 +1,56 @@
|
|
1
|
+
require 'rubystats/probability_distribution'
|
2
|
+
module Rubystats
|
3
|
+
class WeibullDistribution < Rubystats::ProbabilityDistribution
|
4
|
+
include Rubystats::NumericalConstants
|
5
|
+
|
6
|
+
def initialize(scale=1.0, shape=1.0)
|
7
|
+
if scale <= 0.0
|
8
|
+
raise ArgumentError.new("Scale parameter should be greater than zero.")
|
9
|
+
end
|
10
|
+
if shape <= 0.0
|
11
|
+
raise ArgumentError.new("Shape parameter should be greater than zero.")
|
12
|
+
end
|
13
|
+
@scale = scale.to_f
|
14
|
+
@shape = shape.to_f
|
15
|
+
end
|
16
|
+
|
17
|
+
private
|
18
|
+
|
19
|
+
def get_mean
|
20
|
+
@scale * Math.gamma(1.0 + 1.0 / @shape)
|
21
|
+
end
|
22
|
+
|
23
|
+
def get_variance
|
24
|
+
@scale**2 * (Math.gamma(1.0 + 2.0 / @shape) - (Math.gamma(1.0 + 1.0 / @shape))**2)
|
25
|
+
end
|
26
|
+
|
27
|
+
# Private method to obtain single PDF value.
|
28
|
+
# x should be greater than or equal to 0.0
|
29
|
+
# returns the probability that a stochastic variable x has the value X, i.e. P(x=X).
|
30
|
+
def get_pdf(x)
|
31
|
+
check_range(x, 0.0, MAX_VALUE)
|
32
|
+
(@shape / @scale) * (x / @scale)**(@shape-1.0) * Math.exp(-1.0 * ((x/@scale)**@shape))
|
33
|
+
end
|
34
|
+
|
35
|
+
# Private method to obtain single CDF value.
|
36
|
+
# param x should be greater than 0
|
37
|
+
# return the probability that a stochastic variable x is less then X, i.e. P(x<X).
|
38
|
+
def get_cdf(x)
|
39
|
+
check_range(x,0.0,MAX_VALUE)
|
40
|
+
1.0 - Math.exp(-1.0 * ((x.to_f/@scale)**@shape))
|
41
|
+
end
|
42
|
+
|
43
|
+
# Private method to obtain single inverse CDF value.
|
44
|
+
# return the value X for which P(x<X).
|
45
|
+
def get_icdf(p)
|
46
|
+
check_range(p)
|
47
|
+
@scale * (-1.0 * Math.log(1.0 - p.to_f))**(1.0 / @shape)
|
48
|
+
end
|
49
|
+
|
50
|
+
# Private method to obtain single RNG value.
|
51
|
+
def get_rng
|
52
|
+
self.icdf(Kernel.rand)
|
53
|
+
end
|
54
|
+
|
55
|
+
end
|
56
|
+
end
|
data/lib/rubystats.rb
CHANGED
@@ -1,8 +1,16 @@
|
|
1
1
|
require 'rubystats/normal_distribution'
|
2
2
|
require 'rubystats/binomial_distribution'
|
3
|
+
require 'rubystats/poisson_distribution'
|
3
4
|
require 'rubystats/beta_distribution'
|
4
5
|
require 'rubystats/fishers_exact_test'
|
5
6
|
require 'rubystats/exponential_distribution'
|
7
|
+
require 'rubystats/uniform_distribution'
|
8
|
+
require 'rubystats/lognormal_distribution'
|
9
|
+
require 'rubystats/student_t_distribution'
|
10
|
+
require 'rubystats/weibull_distribution'
|
11
|
+
require 'rubystats/cauchy_distribution'
|
12
|
+
require 'rubystats/gamma_distribution'
|
13
|
+
require 'rubystats/multivariate_normal_distribution'
|
6
14
|
require 'rubystats/version'
|
7
15
|
|
8
16
|
module Rubystats
|
@@ -10,6 +18,27 @@ end
|
|
10
18
|
|
11
19
|
NormalDistribution = Rubystats::NormalDistribution
|
12
20
|
BinomialDistribution = Rubystats::BinomialDistribution
|
21
|
+
PoissonDistribution = Rubystats::PoissonDistribution
|
13
22
|
BetaDistribution = Rubystats::BetaDistribution
|
14
23
|
FishersExactTest = Rubystats::FishersExactTest
|
15
24
|
ExponentialDistribution = Rubystats::ExponentialDistribution
|
25
|
+
UniformDistribution = Rubystats::UniformDistribution
|
26
|
+
LognormalDistribution = Rubystats::LognormalDistribution
|
27
|
+
StudentTDistribution = Rubystats::StudentTDistribution
|
28
|
+
WeibullDistribution = Rubystats::WeibullDistribution
|
29
|
+
CauchyDistribution = Rubystats::CauchyDistribution
|
30
|
+
GammaDistribution = Rubystats::GammaDistribution
|
31
|
+
MultivariateNormalDistribution = Rubystats::MultivariateNormalDistribution
|
32
|
+
|
33
|
+
#short-hand notation
|
34
|
+
Normal = Rubystats::NormalDistribution
|
35
|
+
Binomial = Rubystats::BinomialDistribution
|
36
|
+
Poisson = Rubystats::PoissonDistribution
|
37
|
+
Beta = Rubystats::BetaDistribution
|
38
|
+
Exponential = Rubystats::ExponentialDistribution
|
39
|
+
Uniform = Rubystats::UniformDistribution
|
40
|
+
Lognormal = Rubystats::LognormalDistribution
|
41
|
+
Weibull = Rubystats::WeibullDistribution
|
42
|
+
Cauchy = Rubystats::CauchyDistribution
|
43
|
+
Gamma = Rubystats::GammaDistribution
|
44
|
+
MultivariateNormal = Rubystats::MultivariateNormalDistribution
|
data/rubystats.gemspec
CHANGED
@@ -20,5 +20,11 @@ Gem::Specification.new do |s|
|
|
20
20
|
|
21
21
|
s.add_development_dependency("minitest", ">= 4.2", "< 5.0")
|
22
22
|
s.add_development_dependency("hoe", ">= 1.7.0")
|
23
|
+
if RUBY_VERSION >= "3.1"
|
24
|
+
# matrix was removed from default gems in Ruby 3.1, see
|
25
|
+
# https://github.com/ruby/ruby/pull/4530 and https://stdgems.org/
|
26
|
+
s.add_runtime_dependency("matrix")
|
27
|
+
end
|
28
|
+
|
23
29
|
end
|
24
30
|
|
data/test/tc_beta.rb
CHANGED
@@ -96,5 +96,26 @@ class TestBeta < MiniTest::Unit::TestCase
|
|
96
96
|
ucl=bin.icdf(1-alpha)
|
97
97
|
return ucl
|
98
98
|
end
|
99
|
+
|
100
|
+
def test_rng_distribution
|
101
|
+
p = 4.0
|
102
|
+
q = 12.0
|
103
|
+
beta = Rubystats::BetaDistribution.new(p,q)
|
104
|
+
|
105
|
+
total = 10000
|
106
|
+
values = Array.new(total).map{ beta.rng }
|
107
|
+
|
108
|
+
mean = values.inject(0.0) {|sum,v| sum + v} / values.size
|
109
|
+
assert_in_epsilon 0.25, mean.round(2), 0.01
|
110
|
+
end
|
99
111
|
|
112
|
+
def test_integer_input
|
113
|
+
pi, qi = 2, 4
|
114
|
+
pf, qf = 2.0, 4.0
|
115
|
+
x = 0.25
|
116
|
+
dbetai = Rubystats::BetaDistribution.new(pi,qi).pdf(x)
|
117
|
+
dbetaf = Rubystats::BetaDistribution.new(pf,qf).pdf(x)
|
118
|
+
assert_in_delta dbetai, dbetaf, 0.00000001
|
119
|
+
end
|
120
|
+
|
100
121
|
end
|
data/test/tc_binomial.rb
CHANGED
@@ -10,13 +10,27 @@ class TestBinomial < MiniTest::Unit::TestCase
|
|
10
10
|
|
11
11
|
bin = Rubystats::BinomialDistribution.new(t,p)
|
12
12
|
cdf = bin.cdf(f)
|
13
|
+
pmf = bin.pmf(f)
|
13
14
|
pdf = bin.pdf(f)
|
14
15
|
mean = bin.mean
|
15
16
|
inv_cdf = bin.icdf(cdf)
|
16
17
|
|
18
|
+
assert_equal pmf, pdf
|
17
19
|
assert_in_delta(0.10602553736479, pdf, 0.00000000000001 )
|
18
20
|
assert_in_delta(0.87203952137960, cdf, 0.00000000000001)
|
19
21
|
assert_equal("5.0",mean.to_s)
|
20
22
|
assert_equal(f,inv_cdf)
|
21
23
|
end
|
24
|
+
|
25
|
+
def test_rng
|
26
|
+
t, p = 100, 0.75
|
27
|
+
bin = Rubystats::BinomialDistribution.new(t,p)
|
28
|
+
|
29
|
+
rngs = []
|
30
|
+
n = 1000
|
31
|
+
n.times { rngs << bin.rng.to_f }
|
32
|
+
avg = rngs.reduce(:+) / rngs.size
|
33
|
+
|
34
|
+
assert_in_delta(avg, bin.mean, 0.5)
|
35
|
+
end
|
22
36
|
end
|
data/test/tc_cauchy.rb
ADDED
@@ -0,0 +1,39 @@
|
|
1
|
+
$:.unshift File.join(File.dirname(__FILE__), "..", "lib")
|
2
|
+
require 'minitest/autorun'
|
3
|
+
require 'rubystats/cauchy_distribution'
|
4
|
+
|
5
|
+
class TestCauchy < MiniTest::Unit::TestCase
|
6
|
+
def test_simple
|
7
|
+
location = 0.0
|
8
|
+
scale = 0.5
|
9
|
+
cd = Rubystats::CauchyDistribution.new(location,scale)
|
10
|
+
assert_in_delta(0.6366198, cd.pdf(0.0), 0.000001)
|
11
|
+
assert_in_delta(0.5, cd.cdf(0.0), 0.00000001)
|
12
|
+
assert_in_delta(3.169765, cd.icdf(0.9502), 0.000001)
|
13
|
+
|
14
|
+
# make sure the mean of RNG values is close to the expected mean
|
15
|
+
rngs = []
|
16
|
+
n = 10000
|
17
|
+
n.times {|i| rngs << cd.rng }
|
18
|
+
quantile = rngs.sort[(0.75*rngs.size).ceil]
|
19
|
+
assert_in_delta(quantile, 0.5, 0.1)
|
20
|
+
|
21
|
+
x_vals = [-2.0, -1.0, -0.5, 0.0, 0.5, 1.0, 2.0]
|
22
|
+
|
23
|
+
x_vals.each do |x|
|
24
|
+
cdf = cd.cdf(x)
|
25
|
+
inv_cdf = cd.icdf(cdf)
|
26
|
+
assert_in_delta(x, inv_cdf, 0.00000001)
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
def test_integer_input
|
31
|
+
locationi, scalei = 3, 1
|
32
|
+
locationf, scalef = 3.0, 1.0
|
33
|
+
xi = 4
|
34
|
+
xf = 4.0
|
35
|
+
dcdi = Rubystats::CauchyDistribution.new(locationi,scalei).pdf(xi)
|
36
|
+
dcdf = Rubystats::CauchyDistribution.new(locationf,scalef).pdf(xf)
|
37
|
+
assert_in_delta dcdi, dcdf, 0.00000001
|
38
|
+
end
|
39
|
+
end
|
data/test/tc_exponential.rb
CHANGED
@@ -57,4 +57,14 @@ class TestExponential < MiniTest::Unit::TestCase
|
|
57
57
|
assert_in_delta(x, inv_cdf, 0.00000001)
|
58
58
|
end
|
59
59
|
end
|
60
|
+
|
61
|
+
def test_integer_input
|
62
|
+
lambdai = 2
|
63
|
+
lambdaf = 2.0
|
64
|
+
xi = 3
|
65
|
+
xf = 3.0
|
66
|
+
dexpi = Rubystats::ExponentialDistribution.new(lambdai).pdf(xi)
|
67
|
+
dexpf = Rubystats::ExponentialDistribution.new(lambdaf).pdf(xf)
|
68
|
+
assert_in_delta dexpi, dexpf, 0.00000001
|
69
|
+
end
|
60
70
|
end
|
data/test/tc_gamma.rb
ADDED
@@ -0,0 +1,39 @@
|
|
1
|
+
$:.unshift File.join(File.dirname(__FILE__), "..", "lib")
|
2
|
+
require 'minitest/autorun'
|
3
|
+
require 'rubystats/gamma_distribution'
|
4
|
+
|
5
|
+
class TestGamma < MiniTest::Unit::TestCase
|
6
|
+
def test_simple
|
7
|
+
shape = 3.0
|
8
|
+
scale = 2.0
|
9
|
+
gamma = Rubystats::GammaDistribution.new(shape,scale)
|
10
|
+
|
11
|
+
#check properties
|
12
|
+
assert_in_delta(6.0, gamma.mean, 0.000001)
|
13
|
+
assert_in_delta(12.0, gamma.variance, 0.000001)
|
14
|
+
|
15
|
+
#check distributions
|
16
|
+
assert_in_delta(0.0, gamma.pdf(0.0), 0.000001)
|
17
|
+
assert_in_delta(0.1353353, gamma.pdf(4.0), 0.000001)
|
18
|
+
assert_in_delta(0.001134998, gamma.pdf(20.0), 0.000001)
|
19
|
+
assert_in_delta(0.5768099, gamma.cdf(6.0), 0.01)
|
20
|
+
assert_in_delta(0.986246, gamma.cdf(16.0), 0.01)
|
21
|
+
|
22
|
+
# make sure the mean of RNG values is close to the expected mean
|
23
|
+
rngs = []
|
24
|
+
n = 10000
|
25
|
+
n.times {|i| rngs << gamma.rng }
|
26
|
+
quantile = rngs.sort[(0.75*rngs.size).ceil]
|
27
|
+
assert_in_delta(quantile, 7.84080, 0.2)
|
28
|
+
end
|
29
|
+
|
30
|
+
def test_integer_input
|
31
|
+
shapei, scalei = 3, 1
|
32
|
+
shapef, scalef = 3.0, 1.0
|
33
|
+
xi = 4
|
34
|
+
xf = 4.0
|
35
|
+
pdfi = Rubystats::GammaDistribution.new(shapei,scalei).pdf(xi)
|
36
|
+
pdff = Rubystats::GammaDistribution.new(shapef,scalef).pdf(xf)
|
37
|
+
assert_in_delta pdfi, pdff, 0.00000001
|
38
|
+
end
|
39
|
+
end
|
data/test/tc_lnorm.rb
ADDED
@@ -0,0 +1,45 @@
|
|
1
|
+
$:.unshift File.join(File.dirname(__FILE__), '..', 'lib')
|
2
|
+
require 'minitest/autorun'
|
3
|
+
require 'rubystats/lognormal_distribution'
|
4
|
+
|
5
|
+
class TestLognormal < MiniTest::Unit::TestCase
|
6
|
+
def test_cdf_pdf
|
7
|
+
lnorm = Rubystats::LognormalDistribution.new(2.0,0.2)
|
8
|
+
|
9
|
+
cdf = lnorm.cdf(8.0)
|
10
|
+
assert_in_epsilon cdf, 0.654392, 0.0001, "cdf"
|
11
|
+
|
12
|
+
pdf = lnorm.pdf(8.0)
|
13
|
+
assert_in_epsilon pdf, 0.2304252, 0.000001, "pdf"
|
14
|
+
|
15
|
+
end
|
16
|
+
|
17
|
+
def test_properties
|
18
|
+
lnorm = Rubystats::LognormalDistribution.new(2.0,0.2)
|
19
|
+
assert_in_epsilon lnorm.mean, 7.538325, 0.000001, "mean"
|
20
|
+
assert_in_epsilon lnorm.variance, 2.319127, 0.000001, "variance"
|
21
|
+
end
|
22
|
+
|
23
|
+
def test_rng
|
24
|
+
lnorm = Rubystats::LognormalDistribution.new(2.0,0.2)
|
25
|
+
|
26
|
+
total = 100000
|
27
|
+
values = Array.new(total).map{lnorm.rng}
|
28
|
+
|
29
|
+
mean = values.inject(0.0) {|sum, v| sum + v} / values.size
|
30
|
+
|
31
|
+
assert_in_delta mean, 7.538325, 0.1, "rng mean"
|
32
|
+
assert_equal values.min >= 0.0, true, "rng min value"
|
33
|
+
end
|
34
|
+
|
35
|
+
def test_integer_input
|
36
|
+
meani, sdi = 2, 1
|
37
|
+
meanf, sdf = 2.0, 1.0
|
38
|
+
xi = 9
|
39
|
+
xf = 9.0
|
40
|
+
dlnormi = Rubystats::LognormalDistribution.new(meani,sdi).pdf(xi)
|
41
|
+
dlnormf = Rubystats::LognormalDistribution.new(meanf,sdf).pdf(xf)
|
42
|
+
assert_in_delta dlnormi, dlnormf, 0.000001
|
43
|
+
end
|
44
|
+
|
45
|
+
end
|
@@ -0,0 +1,53 @@
|
|
1
|
+
$:.unshift File.join(File.dirname(__FILE__), "..", "lib")
|
2
|
+
require 'minitest/autorun'
|
3
|
+
require 'rubystats/multivariate_normal_distribution'
|
4
|
+
|
5
|
+
class TestMultivariateNormal < MiniTest::Unit::TestCase
|
6
|
+
def test_simple
|
7
|
+
mu = [1.3,-2.5]
|
8
|
+
sigma = [[1.0,0.3],[0.3,1.0]]
|
9
|
+
|
10
|
+
mvnorm = Rubystats::MultivariateNormalDistribution.new(mu,sigma)
|
11
|
+
|
12
|
+
assert_in_delta(0.0001340771, mvnorm.pdf([1.0,1.0]), 0.000001)
|
13
|
+
assert_in_delta(0.131732, mvnorm.pdf([1.0,-2.0]), 0.000001)
|
14
|
+
|
15
|
+
|
16
|
+
# make sure the mean of RNG values is close to the expected mean
|
17
|
+
rngs = []
|
18
|
+
n = 5000
|
19
|
+
n.times {|i| rngs << mvnorm.rng }
|
20
|
+
|
21
|
+
a,b = rngs.transpose
|
22
|
+
|
23
|
+
#check means
|
24
|
+
mean_a = a.inject(0.0) {|sum,x| sum + x} / a.size
|
25
|
+
assert_in_delta(1.3, mean_a, 0.1)
|
26
|
+
|
27
|
+
mean_b = b.inject(0.0) {|sum,x| sum + x} / b.size
|
28
|
+
assert_in_delta(1.3, mean_a, 0.1)
|
29
|
+
|
30
|
+
#check variances
|
31
|
+
var_a = a.inject(0.0) {|sum,x| sum + (x - mean_a)**2 } / a.size
|
32
|
+
assert_in_delta(1.0, var_a, 0.1)
|
33
|
+
|
34
|
+
var_b = b.inject(0.0) {|sum,x| sum + (x - mean_b)**2 } / b.size
|
35
|
+
assert_in_delta(1.0, var_b, 0.1)
|
36
|
+
|
37
|
+
#check correlation
|
38
|
+
covariance = a.zip(b).map{|xa,xb| (xa-mean_a)*(xb-mean_b)}.inject(0.0){|sum,x| sum + x} / a.size
|
39
|
+
correlation = covariance / Math.sqrt(var_a * var_b)
|
40
|
+
assert_in_delta(0.3, correlation, 0.1)
|
41
|
+
|
42
|
+
end
|
43
|
+
|
44
|
+
def test_integer_input
|
45
|
+
mui, sigmai = [1,2], [[1,0.3],[0.3,1]]
|
46
|
+
muf, sigmaf = [1.0,2.0], [[1.0,0.3],[0.3,1.0]]
|
47
|
+
xi = [1,1]
|
48
|
+
xf = [1.0,1.0]
|
49
|
+
dmvnormi = Rubystats::MultivariateNormalDistribution.new(mui,sigmai).pdf(xi)
|
50
|
+
dmvnormf = Rubystats::MultivariateNormalDistribution.new(muf,sigmaf).pdf(xf)
|
51
|
+
assert_in_delta dmvnormi, dmvnormf, 0.00000001
|
52
|
+
end
|
53
|
+
end
|
data/test/tc_norm.rb
CHANGED
@@ -28,6 +28,16 @@ class TestNormal < MiniTest::Unit::TestCase
|
|
28
28
|
|
29
29
|
three_sigma = two_sigma + histogram[7] + histogram[12]
|
30
30
|
assert_in_epsilon 0.997300203937 , three_sigma.to_f / total, 0.005, 'the 3-sigma-environment should contain 99.7%'
|
31
|
-
|
32
31
|
end
|
32
|
+
|
33
|
+
def test_integer_input
|
34
|
+
meani, sdi = 10, 2
|
35
|
+
meanf, sdf = 10.0, 2.0
|
36
|
+
xi = 11
|
37
|
+
xf = 11.0
|
38
|
+
dnormi = Rubystats::NormalDistribution.new(meani,sdi).pdf(xi)
|
39
|
+
dnormf = Rubystats::NormalDistribution.new(meanf,sdf).pdf(xf)
|
40
|
+
assert_in_delta dnormi, dnormf, 0.00000001
|
41
|
+
end
|
42
|
+
|
33
43
|
end
|
data/test/tc_poisson.rb
ADDED
@@ -0,0 +1,35 @@
|
|
1
|
+
$:.unshift File.join(File.dirname(__FILE__), "..", "lib")
|
2
|
+
require 'minitest/autorun'
|
3
|
+
require 'rubystats/poisson_distribution'
|
4
|
+
|
5
|
+
class TestPoisson < MiniTest::Unit::TestCase
|
6
|
+
def test_simple
|
7
|
+
rate = 3.5
|
8
|
+
k = 6
|
9
|
+
|
10
|
+
pois = Rubystats::PoissonDistribution.new(rate)
|
11
|
+
cdf = pois.cdf(k)
|
12
|
+
pmf = pois.pmf(k)
|
13
|
+
pdf = pois.pdf(k)
|
14
|
+
mean = pois.mean
|
15
|
+
inv_cdf = pois.icdf(cdf)
|
16
|
+
|
17
|
+
assert_equal pmf, pdf
|
18
|
+
assert_in_delta(0.0770984, pdf, 0.0000001 )
|
19
|
+
assert_in_delta(0.9347119, cdf, 0.0000001)
|
20
|
+
assert_equal(k,inv_cdf)
|
21
|
+
assert_equal(3.5,mean)
|
22
|
+
end
|
23
|
+
|
24
|
+
def test_rng
|
25
|
+
rate = 3.5
|
26
|
+
pois = Rubystats::PoissonDistribution.new(rate)
|
27
|
+
|
28
|
+
rngs = []
|
29
|
+
n = 1000
|
30
|
+
n.times { rngs << pois.rng.to_f }
|
31
|
+
avg = rngs.reduce(:+) / rngs.size
|
32
|
+
|
33
|
+
assert_in_delta(avg, pois.mean, 0.5)
|
34
|
+
end
|
35
|
+
end
|