erv 0.3.2 → 0.3.3

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