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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: f73f2bc514e8d23844ca2e1652bd0801f661679a
4
- data.tar.gz: a772550f0c889fcbf411038c830add3fa144876c
3
+ metadata.gz: 2c01ff8ee7e228352bd7e91cf37398ac1c9a4599
4
+ data.tar.gz: 1df36e92cac62835249f6b3be46e6b15ee23609c
5
5
  SHA512:
6
- metadata.gz: 90c953b59a635bb02e4ee5e079147804b14a7d54033a0230f6d749bd9c3d67750ac6b3d722dfbb1d4a453c1158d1b51d311c348d0e5a3f67bcf3330715ae7d27
7
- data.tar.gz: 0420a2bc62b45cf9453070a57b24dc7b7731de3fac657df3500f7404e5cf78de4d621d3c1043e00d9a6e6c1b8cdfc35fc0be7d7bbc207eb65ac4bb8b52188d97
6
+ metadata.gz: 61281fab1ea61ce27f999075719b1ad7a4cd955ab2cc5d48ec8d790eee445024a880329e3fea1f2d65e0d3eb014dc1d41e289533e2caec05a815b0b554c18916
7
+ data.tar.gz: b6db99c3a1a4babc7fdbb56028b16e9b865eadb95159269a5e63e8c6618a99a5950932c75e02fae7046c22523a40a33393bad5d02e8fb378567e597c0c3c11cc
data/LICENSE CHANGED
@@ -1,6 +1,6 @@
1
1
  The MIT License (MIT)
2
2
 
3
- Copyright (c) 2014 Mauro Tortonesi
3
+ Copyright (c) 2014-2017 Mauro Tortonesi
4
4
 
5
5
  Permission is hereby granted, free of charge, to any person obtaining a copy of
6
6
  this software and associated documentation files (the "Software"), to deal in
@@ -3,7 +3,7 @@ require 'erv/distribution'
3
3
  module ERV
4
4
 
5
5
  class ConstantDistribution < Distribution
6
- def initialize(opts)
6
+ def initialize(opts={})
7
7
  super(opts)
8
8
 
9
9
  raise ArgumentError unless opts[:value]
@@ -7,7 +7,7 @@ module ERV
7
7
  class DiscreteUniformDistribution < Distribution
8
8
  attr_reader :mean, :variance
9
9
 
10
- def initialize(opts)
10
+ def initialize(opts={})
11
11
  super(opts)
12
12
 
13
13
  raise ArgumentError unless opts[:max_value]
@@ -1,7 +1,7 @@
1
1
  module ERV
2
2
 
3
3
  class Distribution
4
- def initialize(opts)
4
+ def initialize(opts={})
5
5
  # use provided RNG or create a new one
6
6
  if opts[:rng]
7
7
  @rng = opts[:rng]
@@ -7,7 +7,7 @@ module ERV
7
7
  class ExponentialDistribution < Distribution
8
8
  attr_reader :mean, :variance
9
9
 
10
- def initialize(opts)
10
+ def initialize(opts={})
11
11
  super(opts)
12
12
 
13
13
  @rate = opts[:rate].try(:to_f)
@@ -13,7 +13,7 @@ module ERV
13
13
  class GammaDistribution < Distribution
14
14
  attr_accessor :mean, :variance
15
15
 
16
- def initialize(opts)
16
+ def initialize(opts={})
17
17
  super(opts)
18
18
 
19
19
  raise ArgumentError unless opts[:scale] and opts[:shape]
@@ -4,7 +4,7 @@ require 'erv/distribution'
4
4
  module ERV
5
5
 
6
6
  class GaussianDistribution < Distribution
7
- def initialize(opts)
7
+ def initialize(opts={})
8
8
  super(opts)
9
9
 
10
10
  raise ArgumentError unless opts[:mean] and opts[:sd]
@@ -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) / (((1.0 - @shape) ** 2) * (1.0 - 2 * @shape))
26
+ (@scale ** 2.0) / (1.0 - @shape) ** 2 / (1.0 - 2 * @shape)
27
27
  else
28
28
  Infinity
29
29
  end
@@ -11,7 +11,7 @@ module ERV
11
11
  class GeometricDistribution < Distribution
12
12
  attr_accessor :mean, :variance
13
13
 
14
- def initialize(opts)
14
+ def initialize(opts={})
15
15
  super(opts)
16
16
 
17
17
  raise ArgumentError unless opts[:probability_of_success]
@@ -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/general_pareto_distribution'
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!" unless confs.length >= 2
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 << { amplitude: amplitude, weight: weight, distribution: distribution }
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][:amplitude] * @mixture[i][:distribution].sample
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
- s += (# the following formula was taken from
80
- # https://en.wikipedia.org/wiki/Mixture_Distribution#Moments
81
- x[:weight] *
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
- s += (# the following formula was taken from
90
- # https://en.wikipedia.org/wiki/Mixture_Distribution#Moments
91
- x[:weight] *
92
- # remember: E[aX] = a E[X]
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
@@ -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/general_pareto_distribution'
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
- def initialize(opts)
16
+
17
+ extend Forwardable
18
+
19
+ def_delegators :@dist, :mean, :variance
20
+
21
+ def initialize(args={})
17
22
  # get distribution name
18
- dist_name = opts[:distribution].try(:to_s)
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(opts)
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[:first_value]
36
- @most_recent = first.nil? ? 0.0 : first
37
- @var = RandomVariable.new(args.reject{|k,v| k == :first_value })
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
@@ -5,7 +5,7 @@ require 'erv/support/try'
5
5
  module ERV
6
6
 
7
7
  class UniformDistribution < Distribution
8
- def initialize(opts)
8
+ def initialize(opts={})
9
9
  super(opts)
10
10
 
11
11
  raise ArgumentError unless opts[:max_value]
data/lib/erv/version.rb CHANGED
@@ -1,3 +1,3 @@
1
1
  module ERV
2
- VERSION = '0.3.2'
2
+ VERSION = '0.3.3'
3
3
  end
@@ -4,7 +4,7 @@ require 'erv/discrete_uniform_distribution'
4
4
 
5
5
  describe ERV::DiscreteUniformDistribution do
6
6
 
7
- NUM_SAMPLES = 10000
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(NUM_SAMPLES).collect { zero_to_sixty.sample }
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 } / NUM_SAMPLES.to_f
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 } / NUM_SAMPLES.to_f
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(NUM_SAMPLES).collect { ten_to_ninety.sample }
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 } / NUM_SAMPLES.to_f
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 } / NUM_SAMPLES.to_f
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
- NUM_SAMPLES = 20000
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(NUM_SAMPLES).collect { gsgtone.sample }
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 } / NUM_SAMPLES.to_f
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 } / NUM_SAMPLES.to_f
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
@@ -1,10 +1,10 @@
1
1
  require 'test_helper'
2
2
 
3
- require 'erv/general_pareto_distribution'
3
+ require 'erv/generalized_pareto_distribution'
4
4
 
5
5
  describe ERV::GpdDistribution do
6
6
 
7
- NUM_SAMPLES = 50000
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(NUM_SAMPLES).collect { gpd_2params.sample }
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 } / NUM_SAMPLES.to_f
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 } / NUM_SAMPLES.to_f
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(NUM_SAMPLES).collect { gpd_3params.sample }
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 } / NUM_SAMPLES.to_f
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 } / NUM_SAMPLES.to_f
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
- NUM_SAMPLES = 10000
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(NUM_SAMPLES).collect { gd.sample }
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 } / NUM_SAMPLES.to_f
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 } / NUM_SAMPLES.to_f
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 default amplitude' do
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, amplitude: 3.0, mean: 1.0, sd: 0.1, weight: 0.3 },
51
- { distribution: :gaussian, amplitude: 5.0, mean: 2.0, sd: 0.2, weight: 0.2 },
52
- { distribution: :gaussian, amplitude: 7.0, mean: 3.0, sd: 0.3, weight: 0.5 } ])
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 * 3.0 * 1.0 +
57
- 0.2 * 5.0 * 2.0 +
58
- 0.5 * 7.0 * 3.0
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 * ((3.0 * 1.0 - amd_expected_mean) ** 2 + (3.0 * 0.1) ** 2) +
63
- 0.2 * ((5.0 * 2.0 - amd_expected_mean) ** 2 + (5.0 * 0.2) ** 2) +
64
- 0.5 * ((7.0 * 3.0 - amd_expected_mean) ** 2 + (7.0 * 0.3) ** 2)
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.2
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-06-26 00:00:00.000000000 Z
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.2
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/general_pareto_distribution.rb
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/general_pareto_distribution_test.rb
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/general_pareto_distribution_test.rb
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