erv 0.3.2 → 0.3.3
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/LICENSE +1 -1
- data/lib/erv/constant_distribution.rb +1 -1
- data/lib/erv/discrete_uniform_distribution.rb +1 -1
- data/lib/erv/distribution.rb +1 -1
- data/lib/erv/exponential_distribution.rb +1 -1
- data/lib/erv/gamma_distribution.rb +1 -1
- data/lib/erv/gaussian_distribution.rb +1 -1
- data/lib/erv/{general_pareto_distribution.rb → generalized_pareto_distribution.rb} +2 -2
- data/lib/erv/geometric_distribution.rb +1 -1
- data/lib/erv/mixture_distribution.rb +12 -23
- data/lib/erv/random_variable.rb +14 -8
- data/lib/erv/uniform_distribution.rb +1 -1
- data/lib/erv/version.rb +1 -1
- data/test/erv/discrete_uniform_distribution_test.rb +7 -7
- data/test/erv/exponential_distribution_test.rb +44 -0
- data/test/erv/gamma_distribution_test.rb +4 -4
- data/test/erv/gaussian_distribution_test.rb +44 -0
- data/test/erv/{general_pareto_distribution_test.rb → generalized_pareto_distribution_test.rb} +8 -8
- data/test/erv/geometric_distribution_test.rb +4 -4
- data/test/erv/mixture_distribution_test.rb +74 -39
- metadata +10 -6
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 2c01ff8ee7e228352bd7e91cf37398ac1c9a4599
|
4
|
+
data.tar.gz: 1df36e92cac62835249f6b3be46e6b15ee23609c
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 61281fab1ea61ce27f999075719b1ad7a4cd955ab2cc5d48ec8d790eee445024a880329e3fea1f2d65e0d3eb014dc1d41e289533e2caec05a815b0b554c18916
|
7
|
+
data.tar.gz: b6db99c3a1a4babc7fdbb56028b16e9b865eadb95159269a5e63e8c6618a99a5950932c75e02fae7046c22523a40a33393bad5d02e8fb378567e597c0c3c11cc
|
data/LICENSE
CHANGED
data/lib/erv/distribution.rb
CHANGED
@@ -8,7 +8,7 @@ module ERV
|
|
8
8
|
class GpdDistribution < Distribution
|
9
9
|
attr_accessor :mean, :variance
|
10
10
|
|
11
|
-
def initialize(opts)
|
11
|
+
def initialize(opts={})
|
12
12
|
super(opts)
|
13
13
|
|
14
14
|
raise ArgumentError unless opts[:scale] and opts[:shape]
|
@@ -23,7 +23,7 @@ module ERV
|
|
23
23
|
end
|
24
24
|
|
25
25
|
@variance = if @shape < 0.5
|
26
|
-
(@scale ** 2.0) / (
|
26
|
+
(@scale ** 2.0) / (1.0 - @shape) ** 2 / (1.0 - 2 * @shape)
|
27
27
|
else
|
28
28
|
Infinity
|
29
29
|
end
|
@@ -3,7 +3,7 @@ require 'erv/discrete_uniform_distribution'
|
|
3
3
|
require 'erv/exponential_distribution'
|
4
4
|
require 'erv/gamma_distribution'
|
5
5
|
require 'erv/gaussian_distribution'
|
6
|
-
require 'erv/
|
6
|
+
require 'erv/generalized_pareto_distribution'
|
7
7
|
require 'erv/geometric_distribution'
|
8
8
|
require 'erv/uniform_distribution'
|
9
9
|
|
@@ -11,7 +11,7 @@ module ERV
|
|
11
11
|
|
12
12
|
class MixtureDistribution
|
13
13
|
def initialize(confs, opts={})
|
14
|
-
raise ArgumentError, "Please, provide at least 2 distributions!"
|
14
|
+
raise ArgumentError, "Please, provide at least 2 distributions!" if confs.count < 2
|
15
15
|
|
16
16
|
@mixture = []
|
17
17
|
weight_sum = 0.0
|
@@ -22,12 +22,6 @@ module ERV
|
|
22
22
|
# ... and keep track of it
|
23
23
|
weight_sum += weight
|
24
24
|
|
25
|
-
# get amplitude
|
26
|
-
amplitude = dist_conf.fetch(:amplitude) { 1.0 }
|
27
|
-
# unless amplitude.is_a? Float
|
28
|
-
# raise ArgumentError, "Please, provide at least 2 distributions!" unless confs.length >= 2
|
29
|
-
# end
|
30
|
-
|
31
25
|
# get distribution name
|
32
26
|
dist_name = dist_conf.delete(:distribution).to_s
|
33
27
|
|
@@ -35,10 +29,10 @@ module ERV
|
|
35
29
|
klass_name = dist_name.split('_').push('distribution').map(&:capitalize).join
|
36
30
|
|
37
31
|
# create distribution object
|
38
|
-
distribution = ERV.const_get(klass_name).new(dist_conf)
|
32
|
+
distribution = ERV.const_get(klass_name).new(dist_conf[:args])
|
39
33
|
|
40
34
|
# add distribution to mixture
|
41
|
-
@mixture << {
|
35
|
+
@mixture << { weight: weight, distribution: distribution }
|
42
36
|
end
|
43
37
|
|
44
38
|
# normalize weights
|
@@ -61,7 +55,7 @@ module ERV
|
|
61
55
|
end
|
62
56
|
|
63
57
|
# return sample
|
64
|
-
@mixture[i][:
|
58
|
+
@mixture[i][:distribution].sample
|
65
59
|
end
|
66
60
|
|
67
61
|
def mean
|
@@ -76,23 +70,18 @@ module ERV
|
|
76
70
|
|
77
71
|
def calculate_mean
|
78
72
|
@mixture.inject(0.0) do |s,x|
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
# remember: E[aX] = a E[X]
|
83
|
-
x[:amplitude] * x[:distribution].mean)
|
73
|
+
# the following formula was taken from
|
74
|
+
# https://en.wikipedia.org/wiki/Mixture_Distribution#Moments
|
75
|
+
s += (x[:weight] * x[:distribution].mean)
|
84
76
|
end
|
85
77
|
end
|
86
78
|
|
87
79
|
def calculate_variance
|
88
80
|
@mixture.inject(0.0) do |s,x|
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
((x[:amplitude] * x[:distribution].mean - self.mean) ** 2 +
|
94
|
-
# remember: Var(aX) = a**2 Var(X)
|
95
|
-
x[:amplitude] ** 2 * x[:distribution].variance))
|
81
|
+
# the following formula was taken from
|
82
|
+
# https://en.wikipedia.org/wiki/Mixture_Distribution#Moments
|
83
|
+
s += (x[:weight] * ((x[:distribution].mean - self.mean) ** 2 +
|
84
|
+
x[:distribution].variance))
|
96
85
|
end
|
97
86
|
end
|
98
87
|
end
|
data/lib/erv/random_variable.rb
CHANGED
@@ -3,7 +3,7 @@ require 'erv/discrete_uniform_distribution'
|
|
3
3
|
require 'erv/exponential_distribution'
|
4
4
|
require 'erv/gamma_distribution'
|
5
5
|
require 'erv/gaussian_distribution'
|
6
|
-
require 'erv/
|
6
|
+
require 'erv/generalized_pareto_distribution'
|
7
7
|
require 'erv/geometric_distribution'
|
8
8
|
require 'erv/mixture_distribution'
|
9
9
|
require 'erv/uniform_distribution'
|
@@ -13,15 +13,20 @@ require 'erv/support/try'
|
|
13
13
|
module ERV
|
14
14
|
|
15
15
|
class RandomVariable
|
16
|
-
|
16
|
+
|
17
|
+
extend Forwardable
|
18
|
+
|
19
|
+
def_delegators :@dist, :mean, :variance
|
20
|
+
|
21
|
+
def initialize(args={})
|
17
22
|
# get distribution name
|
18
|
-
dist_name =
|
23
|
+
dist_name = args[:distribution].try(:to_s)
|
19
24
|
|
20
25
|
# get class name that corresponds to the requested distribution
|
21
26
|
klass_name = dist_name.split('_').push('distribution').map(&:capitalize).join
|
22
27
|
|
23
28
|
# create distribution object
|
24
|
-
@dist = ERV.const_get(klass_name).new(
|
29
|
+
@dist = ERV.const_get(klass_name).new(args)
|
25
30
|
end
|
26
31
|
|
27
32
|
def next
|
@@ -31,10 +36,11 @@ module ERV
|
|
31
36
|
|
32
37
|
|
33
38
|
class SequentialRandomVariable
|
34
|
-
def initialize(args)
|
35
|
-
first = args
|
36
|
-
|
37
|
-
@
|
39
|
+
def initialize(args={})
|
40
|
+
first = args.delete(:first_value)
|
41
|
+
raise ArgumentError, "First value must be provided!" if first.nil?
|
42
|
+
@most_recent = first.to_f
|
43
|
+
@var = RandomVariable.new(args)
|
38
44
|
end
|
39
45
|
|
40
46
|
def next
|
data/lib/erv/version.rb
CHANGED
@@ -4,7 +4,7 @@ require 'erv/discrete_uniform_distribution'
|
|
4
4
|
|
5
5
|
describe ERV::DiscreteUniformDistribution do
|
6
6
|
|
7
|
-
|
7
|
+
let :num_samples { 10000 }
|
8
8
|
|
9
9
|
it 'should require at least a maximum parameter' do
|
10
10
|
lambda do
|
@@ -29,16 +29,16 @@ describe ERV::DiscreteUniformDistribution do
|
|
29
29
|
|
30
30
|
context 'moments' do
|
31
31
|
let :samples do
|
32
|
-
0.upto(
|
32
|
+
0.upto(num_samples).collect { zero_to_sixty.sample }
|
33
33
|
end
|
34
34
|
|
35
35
|
it 'should have the expected mean' do
|
36
|
-
sample_mean = samples.inject(0.0) {|s,x| s += x } /
|
36
|
+
sample_mean = samples.inject(0.0) {|s,x| s += x } / num_samples.to_f
|
37
37
|
sample_mean.must_be_within_epsilon zero_to_sixty.mean, 0.05
|
38
38
|
end
|
39
39
|
|
40
40
|
it 'should have the expected variance' do
|
41
|
-
sample_variance = samples.inject(0.0) {|s,x| s += (x - zero_to_sixty.mean) ** 2 } /
|
41
|
+
sample_variance = samples.inject(0.0) {|s,x| s += (x - zero_to_sixty.mean) ** 2 } / num_samples.to_f
|
42
42
|
sample_variance.must_be_within_epsilon zero_to_sixty.variance, 0.05
|
43
43
|
end
|
44
44
|
|
@@ -62,16 +62,16 @@ describe ERV::DiscreteUniformDistribution do
|
|
62
62
|
context 'moments' do
|
63
63
|
|
64
64
|
let :samples do
|
65
|
-
0.upto(
|
65
|
+
0.upto(num_samples).collect { ten_to_ninety.sample }
|
66
66
|
end
|
67
67
|
|
68
68
|
it 'should have the expected mean' do
|
69
|
-
sample_mean = samples.inject(0.0) {|s,x| s += x } /
|
69
|
+
sample_mean = samples.inject(0.0) {|s,x| s += x } / num_samples.to_f
|
70
70
|
sample_mean.must_be_within_epsilon ten_to_ninety.mean, 0.05
|
71
71
|
end
|
72
72
|
|
73
73
|
it 'should have the expected variance' do
|
74
|
-
sample_variance = samples.inject(0.0) {|s,x| s += (x - ten_to_ninety.mean) ** 2 } /
|
74
|
+
sample_variance = samples.inject(0.0) {|s,x| s += (x - ten_to_ninety.mean) ** 2 } / num_samples.to_f
|
75
75
|
sample_variance.must_be_within_epsilon ten_to_ninety.variance, 0.05
|
76
76
|
end
|
77
77
|
|
@@ -0,0 +1,44 @@
|
|
1
|
+
require 'test_helper'
|
2
|
+
|
3
|
+
require 'erv/exponential_distribution'
|
4
|
+
|
5
|
+
describe ERV::ExponentialDistribution do
|
6
|
+
|
7
|
+
let :num_samples { 10000 }
|
8
|
+
|
9
|
+
it 'should require the rate parameter' do
|
10
|
+
lambda do
|
11
|
+
ERV::ExponentialDistribution.new()
|
12
|
+
end.must_raise ArgumentError
|
13
|
+
end
|
14
|
+
|
15
|
+
let :ed do
|
16
|
+
ERV::ExponentialDistribution.new(rate: 20.0)
|
17
|
+
end
|
18
|
+
|
19
|
+
context 'sampling' do
|
20
|
+
|
21
|
+
it 'should allow sampling' do
|
22
|
+
ed.sample
|
23
|
+
end
|
24
|
+
|
25
|
+
end
|
26
|
+
|
27
|
+
context 'moments' do
|
28
|
+
let :samples do
|
29
|
+
0.upto(num_samples).collect { ed.sample }
|
30
|
+
end
|
31
|
+
|
32
|
+
it 'should have the expected mean' do
|
33
|
+
sample_mean = samples.inject(0.0) {|s,x| s += x } / num_samples.to_f
|
34
|
+
sample_mean.must_be_within_epsilon ed.mean, 0.05
|
35
|
+
end
|
36
|
+
|
37
|
+
it 'should have the expected variance' do
|
38
|
+
sample_variance = samples.inject(0.0) {|s,x| s += (x - ed.mean) ** 2 } / num_samples.to_f
|
39
|
+
sample_variance.must_be_within_epsilon ed.variance, 0.05
|
40
|
+
end
|
41
|
+
|
42
|
+
end
|
43
|
+
|
44
|
+
end
|
@@ -4,7 +4,7 @@ require 'erv/gamma_distribution'
|
|
4
4
|
|
5
5
|
describe ERV::GammaDistribution do
|
6
6
|
|
7
|
-
|
7
|
+
let :num_samples { 10000 }
|
8
8
|
|
9
9
|
it 'should require the scale and shape parameters' do
|
10
10
|
lambda do
|
@@ -28,16 +28,16 @@ describe ERV::GammaDistribution do
|
|
28
28
|
|
29
29
|
context 'moments' do
|
30
30
|
let :samples do
|
31
|
-
0.upto(
|
31
|
+
0.upto(num_samples).collect { gsgtone.sample }
|
32
32
|
end
|
33
33
|
|
34
34
|
it 'should have the expected mean' do
|
35
|
-
sample_mean = samples.inject(0.0) {|s,x| s += x } /
|
35
|
+
sample_mean = samples.inject(0.0) {|s,x| s += x } / num_samples.to_f
|
36
36
|
sample_mean.must_be_within_epsilon gsgtone.mean, 0.05
|
37
37
|
end
|
38
38
|
|
39
39
|
it 'should have the expected variance' do
|
40
|
-
sample_variance = samples.inject(0.0) {|s,x| s += (x - gsgtone.mean) ** 2 } /
|
40
|
+
sample_variance = samples.inject(0.0) {|s,x| s += (x - gsgtone.mean) ** 2 } / num_samples.to_f
|
41
41
|
sample_variance.must_be_within_epsilon gsgtone.variance, 0.05
|
42
42
|
end
|
43
43
|
|
@@ -0,0 +1,44 @@
|
|
1
|
+
require 'test_helper'
|
2
|
+
|
3
|
+
require 'erv/gaussian_distribution'
|
4
|
+
|
5
|
+
describe ERV::GaussianDistribution do
|
6
|
+
|
7
|
+
let :num_samples { 10000 }
|
8
|
+
|
9
|
+
it 'should require the scale and shape parameters' do
|
10
|
+
lambda do
|
11
|
+
ERV::GaussianDistribution.new()
|
12
|
+
end.must_raise ArgumentError
|
13
|
+
end
|
14
|
+
|
15
|
+
let :gd do
|
16
|
+
ERV::GaussianDistribution.new(mean: 20.0, sd: 0.5)
|
17
|
+
end
|
18
|
+
|
19
|
+
context 'sampling' do
|
20
|
+
|
21
|
+
it 'should allow sampling' do
|
22
|
+
gd.sample
|
23
|
+
end
|
24
|
+
|
25
|
+
end
|
26
|
+
|
27
|
+
context 'moments' do
|
28
|
+
let :samples do
|
29
|
+
0.upto(num_samples).collect { gd.sample }
|
30
|
+
end
|
31
|
+
|
32
|
+
it 'should have the expected mean' do
|
33
|
+
sample_mean = samples.inject(0.0) {|s,x| s += x } / num_samples.to_f
|
34
|
+
sample_mean.must_be_within_epsilon gd.mean, 0.05
|
35
|
+
end
|
36
|
+
|
37
|
+
it 'should have the expected variance' do
|
38
|
+
sample_variance = samples.inject(0.0) {|s,x| s += (x - gd.mean) ** 2 } / num_samples.to_f
|
39
|
+
sample_variance.must_be_within_epsilon gd.variance, 0.05
|
40
|
+
end
|
41
|
+
|
42
|
+
end
|
43
|
+
|
44
|
+
end
|
data/test/erv/{general_pareto_distribution_test.rb → generalized_pareto_distribution_test.rb}
RENAMED
@@ -1,10 +1,10 @@
|
|
1
1
|
require 'test_helper'
|
2
2
|
|
3
|
-
require 'erv/
|
3
|
+
require 'erv/generalized_pareto_distribution'
|
4
4
|
|
5
5
|
describe ERV::GpdDistribution do
|
6
6
|
|
7
|
-
|
7
|
+
let :num_samples { 200000 }
|
8
8
|
|
9
9
|
it 'should require scale and shape parameters' do
|
10
10
|
lambda do
|
@@ -29,16 +29,16 @@ describe ERV::GpdDistribution do
|
|
29
29
|
|
30
30
|
context 'moments' do
|
31
31
|
let :samples do
|
32
|
-
0.upto(
|
32
|
+
0.upto(num_samples).collect { gpd_2params.sample }
|
33
33
|
end
|
34
34
|
|
35
35
|
it 'should have the expected mean' do
|
36
|
-
sample_mean = samples.inject(0.0) {|s,x| s += x } /
|
36
|
+
sample_mean = samples.inject(0.0) {|s,x| s += x } / num_samples.to_f
|
37
37
|
sample_mean.must_be_within_epsilon gpd_2params.mean, 0.1
|
38
38
|
end
|
39
39
|
|
40
40
|
it 'should have the expected variance' do
|
41
|
-
sample_variance = samples.inject(0.0) {|s,x| s += (x - gpd_2params.mean) ** 2 } /
|
41
|
+
sample_variance = samples.inject(0.0) {|s,x| s += (x - gpd_2params.mean) ** 2 } / num_samples.to_f
|
42
42
|
sample_variance.must_be_within_epsilon gpd_2params.variance, 0.1
|
43
43
|
end
|
44
44
|
|
@@ -64,16 +64,16 @@ describe ERV::GpdDistribution do
|
|
64
64
|
|
65
65
|
context 'moments' do
|
66
66
|
let :samples do
|
67
|
-
0.upto(
|
67
|
+
0.upto(num_samples).collect { gpd_3params.sample }
|
68
68
|
end
|
69
69
|
|
70
70
|
it 'should have the expected mean' do
|
71
|
-
sample_mean = samples.inject(0.0) {|s,x| s += x } /
|
71
|
+
sample_mean = samples.inject(0.0) {|s,x| s += x } / num_samples.to_f
|
72
72
|
sample_mean.must_be_within_epsilon gpd_3params.mean, 0.1
|
73
73
|
end
|
74
74
|
|
75
75
|
it 'should have the expected variance' do
|
76
|
-
sample_variance = samples.inject(0.0) {|s,x| s += (x - gpd_3params.mean) ** 2 } /
|
76
|
+
sample_variance = samples.inject(0.0) {|s,x| s += (x - gpd_3params.mean) ** 2 } / num_samples.to_f
|
77
77
|
sample_variance.must_be_within_epsilon gpd_3params.variance, 0.1
|
78
78
|
end
|
79
79
|
|
@@ -4,7 +4,7 @@ require 'erv/geometric_distribution'
|
|
4
4
|
|
5
5
|
describe ERV::GeometricDistribution do
|
6
6
|
|
7
|
-
|
7
|
+
let :num_samples { 10000 }
|
8
8
|
|
9
9
|
it 'should require at least a probability of success parameter' do
|
10
10
|
lambda do
|
@@ -26,16 +26,16 @@ describe ERV::GeometricDistribution do
|
|
26
26
|
|
27
27
|
context 'moments' do
|
28
28
|
let :samples do
|
29
|
-
0.upto(
|
29
|
+
0.upto(num_samples).collect { gd.sample }
|
30
30
|
end
|
31
31
|
|
32
32
|
it 'should have the expected mean' do
|
33
|
-
sample_mean = samples.inject(0.0) {|s,x| s += x } /
|
33
|
+
sample_mean = samples.inject(0.0) {|s,x| s += x } / num_samples.to_f
|
34
34
|
sample_mean.must_be_within_epsilon gd.mean, 0.05
|
35
35
|
end
|
36
36
|
|
37
37
|
it 'should have the expected variance' do
|
38
|
-
sample_variance = samples.inject(0.0) {|s,x| s += (x - gd.mean) ** 2 } /
|
38
|
+
sample_variance = samples.inject(0.0) {|s,x| s += (x - gd.mean) ** 2 } / num_samples.to_f
|
39
39
|
sample_variance.must_be_within_epsilon gd.variance, 0.05
|
40
40
|
end
|
41
41
|
|
@@ -3,20 +3,23 @@ require 'test_helper'
|
|
3
3
|
require 'erv/mixture_distribution'
|
4
4
|
|
5
5
|
describe ERV::MixtureDistribution do
|
6
|
+
|
7
|
+
let :num_samples { 10000 }
|
8
|
+
|
6
9
|
it 'should require at least two distributions' do
|
7
10
|
lambda do
|
8
|
-
ERV::MixtureDistribution.new([ { distribution: :exponential, rate: 1.0, weight: 0.5 } ])
|
11
|
+
ERV::MixtureDistribution.new([ { distribution: :exponential, args: { rate: 1.0 }, weight: 0.5 } ])
|
9
12
|
end.must_raise ArgumentError
|
10
13
|
end
|
11
14
|
|
12
|
-
let :md do
|
13
|
-
ERV::MixtureDistribution.new([ { distribution: :exponential, rate: 1.0, weight: 0.3 },
|
14
|
-
{ distribution: :exponential, rate: 2.0, weight: 0.2 },
|
15
|
-
{ distribution: :exponential, rate: 3.0, weight: 0.5 } ])
|
16
|
-
end
|
17
|
-
|
18
15
|
context 'sampling' do
|
19
16
|
|
17
|
+
let :md do
|
18
|
+
ERV::MixtureDistribution.new([ { distribution: :exponential, args: { rate: 1.0 }, weight: 0.3 },
|
19
|
+
{ distribution: :exponential, args: { rate: 2.0 }, weight: 0.2 },
|
20
|
+
{ distribution: :exponential, args: { rate: 3.0 }, weight: 0.5 } ])
|
21
|
+
end
|
22
|
+
|
20
23
|
it 'should allow sampling from the mixture' do
|
21
24
|
md.sample
|
22
25
|
end
|
@@ -25,43 +28,24 @@ describe ERV::MixtureDistribution do
|
|
25
28
|
|
26
29
|
context 'moments' do
|
27
30
|
|
28
|
-
context 'with
|
29
|
-
let :md_expected_mean do
|
30
|
-
0.3 * 1/1.0 + 0.2 * 1/2.0 + 0.5 * 1/3.0
|
31
|
-
end
|
32
|
-
|
33
|
-
let :md_expected_variance do
|
34
|
-
0.3 * ((1/1.0 - md_expected_mean) ** 2 + (1/1.0) ** 2) +
|
35
|
-
0.2 * ((1/2.0 - md_expected_mean) ** 2 + (1/2.0) ** 2) +
|
36
|
-
0.5 * ((1/3.0 - md_expected_mean) ** 2 + (1/3.0) ** 2)
|
37
|
-
end
|
31
|
+
context 'with normalized weights' do
|
38
32
|
|
39
|
-
it 'should correctly calculate the mean of the mixture' do
|
40
|
-
md.mean.must_equal md_expected_mean
|
41
|
-
end
|
42
|
-
|
43
|
-
it 'should correctly calculate the variance of the mixture' do
|
44
|
-
md.variance.must_equal md_expected_variance
|
45
|
-
end
|
46
|
-
end
|
47
|
-
|
48
|
-
context 'with different amplitudes' do
|
49
33
|
let :amd do
|
50
|
-
ERV::MixtureDistribution.new([ { distribution: :gaussian,
|
51
|
-
{ distribution: :gaussian,
|
52
|
-
{ distribution: :gaussian,
|
34
|
+
ERV::MixtureDistribution.new([ { distribution: :gaussian, args: { mean: 1.0, sd: 0.1 }, weight: 0.3 },
|
35
|
+
{ distribution: :gaussian, args: { mean: 2.0, sd: 0.2 }, weight: 0.2 },
|
36
|
+
{ distribution: :gaussian, args: { mean: 3.0, sd: 0.3 }, weight: 0.5 } ])
|
53
37
|
end
|
54
38
|
|
55
39
|
let :amd_expected_mean do
|
56
|
-
0.3 *
|
57
|
-
0.2 *
|
58
|
-
0.5 *
|
40
|
+
0.3 * 1.0 +
|
41
|
+
0.2 * 2.0 +
|
42
|
+
0.5 * 3.0
|
59
43
|
end
|
60
44
|
|
61
45
|
let :amd_expected_variance do
|
62
|
-
0.3 * ((
|
63
|
-
0.2 * ((
|
64
|
-
0.5 * ((
|
46
|
+
0.3 * ((1.0 - amd_expected_mean) ** 2 + 0.1 ** 2) +
|
47
|
+
0.2 * ((2.0 - amd_expected_mean) ** 2 + 0.2 ** 2) +
|
48
|
+
0.5 * ((3.0 - amd_expected_mean) ** 2 + 0.3 ** 2)
|
65
49
|
end
|
66
50
|
|
67
51
|
it 'should correctly calculate the mean of the mixture' do
|
@@ -71,13 +55,29 @@ describe ERV::MixtureDistribution do
|
|
71
55
|
it 'should correctly calculate the variance of the mixture' do
|
72
56
|
amd.variance.must_equal amd_expected_variance
|
73
57
|
end
|
58
|
+
|
59
|
+
let :samples do
|
60
|
+
0.upto(num_samples).collect { amd.sample }
|
61
|
+
end
|
62
|
+
|
63
|
+
it 'mean of a sample set should match the expected mean' do
|
64
|
+
sample_mean = samples.inject(0.0) {|s,x| s += x } / num_samples.to_f
|
65
|
+
sample_mean.must_be_within_epsilon amd.mean, 0.05
|
66
|
+
end
|
67
|
+
|
68
|
+
it 'variance of a sample set should match the expected variance' do
|
69
|
+
sample_variance = samples.inject(0.0) {|s,x| s += (x - amd.mean) ** 2 } / num_samples.to_f
|
70
|
+
sample_variance.must_be_within_epsilon amd.variance, 0.05
|
71
|
+
end
|
72
|
+
|
74
73
|
end
|
75
74
|
|
76
75
|
context 'with unnormalized weights' do
|
76
|
+
|
77
77
|
let :uwmd do
|
78
|
-
ERV::MixtureDistribution.new([ { distribution: :exponential, rate: 1.0, weight: 300 },
|
79
|
-
{ distribution: :exponential, rate: 2.0, weight: 200 },
|
80
|
-
{ distribution: :exponential, rate: 3.0, weight: 500 } ])
|
78
|
+
ERV::MixtureDistribution.new([ { distribution: :exponential, args: { rate: 1.0 }, weight: 300 },
|
79
|
+
{ distribution: :exponential, args: { rate: 2.0 }, weight: 200 },
|
80
|
+
{ distribution: :exponential, args: { rate: 3.0 }, weight: 500 } ])
|
81
81
|
end
|
82
82
|
|
83
83
|
let :uwmd_expected_mean do
|
@@ -98,6 +98,41 @@ describe ERV::MixtureDistribution do
|
|
98
98
|
uwmd.variance.must_equal uwmd_expected_variance
|
99
99
|
end
|
100
100
|
|
101
|
+
let :samples do
|
102
|
+
0.upto(num_samples).collect { uwmd.sample }
|
103
|
+
end
|
104
|
+
|
105
|
+
it 'mean of a sample set should match the expected mean' do
|
106
|
+
sample_mean = samples.inject(0.0) {|s,x| s += x } / num_samples.to_f
|
107
|
+
sample_mean.must_be_within_epsilon uwmd.mean, 0.05
|
108
|
+
end
|
109
|
+
|
110
|
+
it 'variance of a sample set should match the expected variance' do
|
111
|
+
sample_variance = samples.inject(0.0) {|s,x| s += (x - uwmd.mean) ** 2 } / num_samples.to_f
|
112
|
+
sample_variance.must_be_within_epsilon uwmd.variance, 0.05
|
113
|
+
end
|
114
|
+
|
115
|
+
end
|
116
|
+
|
117
|
+
end
|
118
|
+
|
119
|
+
context 'mixture of mixtures' do
|
120
|
+
let :momd do
|
121
|
+
ERV::MixtureDistribution.new([ { distribution: :mixture,
|
122
|
+
args: [ { distribution: :exponential, args: { rate: 4.0 }, weight: 300 },
|
123
|
+
{ distribution: :exponential, args: { rate: 5.0 }, weight: 200 },
|
124
|
+
{ distribution: :exponential, args: { rate: 6.0 }, weight: 500 } ],
|
125
|
+
weight: 200 },
|
126
|
+
{ distribution: :mixture,
|
127
|
+
args: [ { distribution: :exponential, args: { rate: 7.0 }, weight: 300 },
|
128
|
+
{ distribution: :exponential, args: { rate: 8.0 }, weight: 200 },
|
129
|
+
{ distribution: :exponential, args: { rate: 9.0 }, weight: 500 } ],
|
130
|
+
weight: 300 },
|
131
|
+
], inspect: true)
|
132
|
+
end
|
133
|
+
|
134
|
+
it 'should allow sampling from the mixture' do
|
135
|
+
momd.sample
|
101
136
|
end
|
102
137
|
|
103
138
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: erv
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.3.
|
4
|
+
version: 0.3.3
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Mauro Tortonesi
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2017-
|
11
|
+
date: 2017-08-24 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|
@@ -80,7 +80,7 @@ dependencies:
|
|
80
80
|
- - "~>"
|
81
81
|
- !ruby/object:Gem::Version
|
82
82
|
version: 0.0.3
|
83
|
-
description: erv-0.3.
|
83
|
+
description: erv-0.3.3
|
84
84
|
email:
|
85
85
|
- mauro.tortonesi@unife.it
|
86
86
|
executables: []
|
@@ -100,7 +100,7 @@ files:
|
|
100
100
|
- lib/erv/exponential_distribution.rb
|
101
101
|
- lib/erv/gamma_distribution.rb
|
102
102
|
- lib/erv/gaussian_distribution.rb
|
103
|
-
- lib/erv/
|
103
|
+
- lib/erv/generalized_pareto_distribution.rb
|
104
104
|
- lib/erv/geometric_distribution.rb
|
105
105
|
- lib/erv/mixture_distribution.rb
|
106
106
|
- lib/erv/random_variable.rb
|
@@ -110,8 +110,10 @@ files:
|
|
110
110
|
- test/erv/constant_distribution_test.rb
|
111
111
|
- test/erv/discrete_uniform_distribution_test.rb
|
112
112
|
- test/erv/distribution_test.rb
|
113
|
+
- test/erv/exponential_distribution_test.rb
|
113
114
|
- test/erv/gamma_distribution_test.rb
|
114
|
-
- test/erv/
|
115
|
+
- test/erv/gaussian_distribution_test.rb
|
116
|
+
- test/erv/generalized_pareto_distribution_test.rb
|
115
117
|
- test/erv/geometric_distribution_test.rb
|
116
118
|
- test/erv/mixture_distribution_test.rb
|
117
119
|
- test/erv/random_variable_test.rb
|
@@ -144,8 +146,10 @@ test_files:
|
|
144
146
|
- test/erv/constant_distribution_test.rb
|
145
147
|
- test/erv/discrete_uniform_distribution_test.rb
|
146
148
|
- test/erv/distribution_test.rb
|
149
|
+
- test/erv/exponential_distribution_test.rb
|
147
150
|
- test/erv/gamma_distribution_test.rb
|
148
|
-
- test/erv/
|
151
|
+
- test/erv/gaussian_distribution_test.rb
|
152
|
+
- test/erv/generalized_pareto_distribution_test.rb
|
149
153
|
- test/erv/geometric_distribution_test.rb
|
150
154
|
- test/erv/mixture_distribution_test.rb
|
151
155
|
- test/erv/random_variable_test.rb
|