erv 0.3.5 → 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.
@@ -1,44 +1,18 @@
1
- require 'test_helper'
2
-
3
- require 'erv/exponential_distribution'
1
+ require 'erv/distribution_behaviour'
4
2
 
5
3
  describe ERV::ExponentialDistribution do
6
-
7
- let (:num_samples) { 10000 }
8
-
9
4
  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)
5
+ expect{ ERV::ExponentialDistribution.new() }.to raise_exception(ArgumentError)
17
6
  end
18
7
 
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
8
+ with 'sampling' do
9
+ let(:distribution) { ERV::ExponentialDistribution.new(rate: 20.0) }
36
10
 
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
11
+ let(:num_samples) { 200_000 }
12
+ let(:samples) { num_samples.times.map { distribution.sample } }
13
+ let(:epsilon) { 1E-2 }
41
14
 
15
+ include ERV::DistributionBehavior
42
16
  end
43
17
 
44
18
  end
@@ -1,47 +1,17 @@
1
- require 'test_helper'
2
-
3
- require 'erv/gamma_distribution'
1
+ require 'erv/distribution_behaviour'
4
2
 
5
3
  describe ERV::GammaDistribution do
6
-
7
- let (:num_samples) { 10000 }
8
-
9
4
  it 'should require the scale and shape parameters' do
10
- lambda do
11
- ERV::GammaDistribution.new()
12
- end.must_raise ArgumentError
5
+ expect{ ERV::GammaDistribution.new }.to raise_exception(ArgumentError)
13
6
  end
14
7
 
15
- context 'with a shape greater than one' do
16
-
17
- let :gsgtone do
18
- ERV::GammaDistribution.new(shape: 2.0, scale: 0.5)
19
- end
20
-
21
- context 'sampling' do
8
+ with 'sampling' do
9
+ let(:distribution) { ERV::GammaDistribution.new(shape: 2.0, scale: 0.5) }
22
10
 
23
- it 'should allow sampling' do
24
- gsgtone.sample
25
- end
11
+ let(:num_samples) { 200_000 }
12
+ let(:samples) { num_samples.times.map { distribution.sample } }
13
+ let(:epsilon) { 1E-2 }
26
14
 
27
- end
28
-
29
- context 'moments' do
30
- let :samples do
31
- 0.upto(num_samples).collect { gsgtone.sample }
32
- end
33
-
34
- it 'should have the expected mean' do
35
- sample_mean = samples.inject(0.0) {|s,x| s += x } / num_samples.to_f
36
- sample_mean.must_be_within_epsilon gsgtone.mean, 0.05
37
- end
38
-
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
41
- sample_variance.must_be_within_epsilon gsgtone.variance, 0.05
42
- end
43
-
44
- end
15
+ include ERV::DistributionBehavior
45
16
  end
46
-
47
17
  end
@@ -1,44 +1,17 @@
1
- require 'test_helper'
2
-
3
- require 'erv/gaussian_distribution'
1
+ require 'erv/distribution_behaviour'
4
2
 
5
3
  describe ERV::GaussianDistribution do
6
-
7
- let (:num_samples) { 10000 }
8
-
9
4
  it 'should require the scale and shape parameters' do
10
- lambda do
11
- ERV::GaussianDistribution.new()
12
- end.must_raise ArgumentError
5
+ expect{ ERV::GaussianDistribution.new }.to raise_exception(ArgumentError)
13
6
  end
14
7
 
15
- let :gd do
16
- ERV::GaussianDistribution.new(mean: 20.0, sd: 0.5)
17
- end
18
-
19
- context 'sampling' do
8
+ with 'sampling' do
9
+ let(:distribution) { ERV::GaussianDistribution.new(mean: 20.0, sd: 0.5) }
20
10
 
21
- it 'should allow sampling' do
22
- gd.sample
23
- end
11
+ let(:num_samples) { 200_000 }
12
+ let(:samples) { num_samples.times.map { distribution.sample } }
13
+ let(:epsilon) { 5E-3 }
24
14
 
15
+ include ERV::DistributionBehavior
25
16
  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
17
  end
@@ -1,82 +1,33 @@
1
- require 'test_helper'
2
-
3
- require 'erv/generalized_pareto_distribution'
1
+ require 'erv/distribution_behaviour'
4
2
 
5
3
  describe ERV::GpdDistribution do
6
-
7
- let (:num_samples) { 200000 }
8
-
9
- it 'should require scale and shape parameters' do
10
- lambda do
11
- ERV::GpdDistribution.new()
12
- end.must_raise ArgumentError
4
+ it 'should require the scale and shape parameters' do
5
+ expect{ ERV::GpdDistribution.new }.to raise_exception(ArgumentError)
13
6
  end
14
7
 
8
+ with 'a (default) 2-parameter distribution' do
9
+ # Caveat:
10
+ # 1) if shape >= 0.5, variance is infinite
11
+ # 2) if shape >= 0.25, the 4th moment is infinite - so the variance of the
12
+ # variance is infinite
13
+ let(:distribution) { ERV::GpdDistribution.new(scale: 1.0, shape: 0.1) }
15
14
 
16
- context 'a (default) 2-parameter distribution' do
17
-
18
- let :gpd_2params do
19
- ERV::GpdDistribution.new(scale: 1.0, shape: 0.3)
20
- end
21
-
22
- context 'sampling' do
23
-
24
- it 'should allow sampling' do
25
- gpd_2params.sample
26
- end
27
-
28
- end
29
-
30
- context 'moments' do
31
- let :samples do
32
- 0.upto(num_samples).collect { gpd_2params.sample }
33
- end
34
-
35
- it 'should have the expected mean' do
36
- sample_mean = samples.inject(0.0) {|s,x| s += x } / num_samples.to_f
37
- sample_mean.must_be_within_epsilon gpd_2params.mean, 0.1
38
- end
15
+ let(:num_samples) { 200_000 }
16
+ let(:samples) { num_samples.times.map { distribution.sample } }
17
+ let(:epsilon) { 1E-2 }
39
18
 
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
42
- sample_variance.must_be_within_epsilon gpd_2params.variance, 0.1
43
- end
44
-
45
- end
19
+ include ERV::DistributionBehavior
46
20
  end
47
21
 
22
+ with 'a 3-parameter distribution' do
23
+ let(:distribution) { ERV::GpdDistribution.new(scale: 1.0,
24
+ shape: 0.1,
25
+ location: 1.0) }
48
26
 
49
- context 'a 3-parameter distribution' do
50
-
51
- let :gpd_3params do
52
- ERV::GpdDistribution.new(scale: 1.0,
53
- shape: 0.3,
54
- location: 1.0)
55
- end
56
-
57
- context 'sampling' do
58
-
59
- it 'should allow sampling' do
60
- gpd_3params.sample
61
- end
62
-
63
- end
64
-
65
- context 'moments' do
66
- let :samples do
67
- 0.upto(num_samples).collect { gpd_3params.sample }
68
- end
69
-
70
- it 'should have the expected mean' do
71
- sample_mean = samples.inject(0.0) {|s,x| s += x } / num_samples.to_f
72
- sample_mean.must_be_within_epsilon gpd_3params.mean, 0.1
73
- end
74
-
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
77
- sample_variance.must_be_within_epsilon gpd_3params.variance, 0.1
78
- end
27
+ let(:num_samples) { 200_000 }
28
+ let(:samples) { num_samples.times.map { distribution.sample } }
29
+ let(:epsilon) { 1E-2 }
79
30
 
80
- end
31
+ include ERV::DistributionBehavior
81
32
  end
82
33
  end
@@ -1,44 +1,17 @@
1
- require 'test_helper'
2
-
3
- require 'erv/geometric_distribution'
1
+ require 'erv/distribution_behaviour'
4
2
 
5
3
  describe ERV::GeometricDistribution do
6
-
7
- let (:num_samples) { 10000 }
8
-
9
4
  it 'should require at least a probability of success parameter' do
10
- lambda do
11
- ERV::GeometricDistribution.new()
12
- end.must_raise ArgumentError
5
+ expect{ ERV::GeometricDistribution.new }.to raise_exception(ArgumentError)
13
6
  end
14
7
 
15
- let :gd do
16
- ERV::GeometricDistribution.new(probability_of_success: 0.5)
17
- end
18
-
19
- context 'sampling' do
8
+ with 'sampling' do
9
+ let(:distribution) { ERV::GeometricDistribution.new(probability_of_success: 0.5) }
20
10
 
21
- it 'should allow sampling' do
22
- gd.sample
23
- end
11
+ let(:num_samples) { 200_000 }
12
+ let(:samples) { num_samples.times.map { distribution.sample } }
13
+ let(:epsilon) { 5E-3 }
24
14
 
15
+ include ERV::DistributionBehavior
25
16
  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
17
  end
@@ -0,0 +1,17 @@
1
+ require 'erv/distribution_behaviour'
2
+
3
+ describe ERV::LogNormDistribution do
4
+ it 'should require the mu and sigma parameters' do
5
+ expect{ ERV::LogNormDistribution.new }.to raise_exception(ArgumentError)
6
+ end
7
+
8
+ with 'sampling' do
9
+ let(:distribution) { ERV::LogNormDistribution.new(mu: 0.0, sigma: 0.25) }
10
+
11
+ let(:num_samples) { 200_000 }
12
+ let(:samples) { num_samples.times.map { distribution.sample } }
13
+ let(:epsilon) { 1E-2 }
14
+
15
+ include ERV::DistributionBehavior
16
+ end
17
+ end
@@ -1,123 +1,97 @@
1
- require 'test_helper'
2
-
3
- require 'erv/mixture_distribution'
1
+ require 'erv/distribution_behaviour'
4
2
 
5
3
  describe ERV::MixtureDistribution do
6
4
 
7
5
  let (:num_samples) { 10000 }
8
6
 
9
7
  it 'should require at least two distributions' do
10
- lambda do
8
+ expect{
11
9
  ERV::MixtureDistribution.new([ { distribution: :exponential, args: { rate: 1.0 }, weight: 0.5 } ])
12
- end.must_raise ArgumentError
10
+ }.to raise_exception(ArgumentError)
13
11
  end
14
12
 
15
- context 'sampling' do
16
-
17
- let :md do
13
+ with 'sampling' do
14
+ let(:distribution) do
18
15
  ERV::MixtureDistribution.new([ { distribution: :exponential, args: { rate: 1.0 }, weight: 0.3 },
19
16
  { distribution: :exponential, args: { rate: 2.0 }, weight: 0.2 },
20
17
  { distribution: :exponential, args: { rate: 3.0 }, weight: 0.5 } ])
21
18
  end
22
19
 
23
20
  it 'should allow sampling from the mixture' do
24
- md.sample
21
+ expect{ distribution.sample }.not.to raise_exception(ArgumentError).and(! be_nil)
25
22
  end
26
-
27
23
  end
28
24
 
29
- context 'moments' do
30
-
31
- context 'with normalized weights' do
32
-
33
- let :amd do
25
+ with 'moments' do
26
+ with 'with normalized weights' do
27
+ let(:distribution) do
34
28
  ERV::MixtureDistribution.new([ { distribution: :gaussian, args: { mean: 1.0, sd: 0.1 }, weight: 0.3 },
35
29
  { distribution: :gaussian, args: { mean: 2.0, sd: 0.2 }, weight: 0.2 },
36
30
  { distribution: :gaussian, args: { mean: 3.0, sd: 0.3 }, weight: 0.5 } ])
37
31
  end
38
32
 
39
- let :amd_expected_mean do
33
+ let(:expected_mean) do
40
34
  0.3 * 1.0 +
41
35
  0.2 * 2.0 +
42
36
  0.5 * 3.0
43
37
  end
44
38
 
45
- let :amd_expected_variance do
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)
39
+ let(:expected_variance) do
40
+ 0.3 * ((1.0 - expected_mean) ** 2 + 0.1 ** 2) +
41
+ 0.2 * ((2.0 - expected_mean) ** 2 + 0.2 ** 2) +
42
+ 0.5 * ((3.0 - expected_mean) ** 2 + 0.3 ** 2)
49
43
  end
50
44
 
51
45
  it 'should correctly calculate the mean of the mixture' do
52
- amd.mean.must_equal amd_expected_mean
46
+ expect(distribution.mean).to be == expected_mean
53
47
  end
54
48
 
55
49
  it 'should correctly calculate the variance of the mixture' do
56
- amd.variance.must_equal amd_expected_variance
50
+ expect(distribution.variance).to be == expected_variance
57
51
  end
58
52
 
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
53
+ let(:num_samples) { 200_000 }
54
+ let(:samples) { num_samples.times.map { distribution.sample } }
55
+ let(:epsilon) { 5E-2 }
72
56
 
57
+ include ERV::DistributionBehavior
73
58
  end
74
59
 
75
- context 'with unnormalized weights' do
76
-
77
- let :uwmd do
60
+ with 'with unnormalized weights' do
61
+ let(:distribution) do
78
62
  ERV::MixtureDistribution.new([ { distribution: :exponential, args: { rate: 1.0 }, weight: 300 },
79
63
  { distribution: :exponential, args: { rate: 2.0 }, weight: 200 },
80
64
  { distribution: :exponential, args: { rate: 3.0 }, weight: 500 } ])
81
65
  end
82
66
 
83
- let :uwmd_expected_mean do
67
+ let(:expected_mean) do
84
68
  0.3 * 1/1.0 + 0.2 * 1/2.0 + 0.5 * 1/3.0
85
69
  end
86
70
 
87
- let :uwmd_expected_variance do
88
- 0.3 * ((1/1.0 - uwmd_expected_mean) ** 2 + (1/1.0) ** 2) +
89
- 0.2 * ((1/2.0 - uwmd_expected_mean) ** 2 + (1/2.0) ** 2) +
90
- 0.5 * ((1/3.0 - uwmd_expected_mean) ** 2 + (1/3.0) ** 2)
71
+ let(:expected_variance) do
72
+ 0.3 * ((1/1.0 - expected_mean) ** 2 + (1/1.0) ** 2) +
73
+ 0.2 * ((1/2.0 - expected_mean) ** 2 + (1/2.0) ** 2) +
74
+ 0.5 * ((1/3.0 - expected_mean) ** 2 + (1/3.0) ** 2)
91
75
  end
92
76
 
93
77
  it 'should correctly calculate the mean of the mixture' do
94
- uwmd.mean.must_equal uwmd_expected_mean
78
+ expect(distribution.mean).to be == expected_mean
95
79
  end
96
80
 
97
81
  it 'should correctly calculate the variance of the mixture' do
98
- uwmd.variance.must_equal uwmd_expected_variance
82
+ expect(distribution.variance).to be == expected_variance
99
83
  end
100
84
 
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
85
+ let(:num_samples) { 200_000 }
86
+ let(:samples) { num_samples.times.map { distribution.sample } }
87
+ let(:epsilon) { 5E-2 }
114
88
 
89
+ include ERV::DistributionBehavior
115
90
  end
116
-
117
91
  end
118
92
 
119
- context 'mixture of mixtures' do
120
- let :momd do
93
+ with 'mixture of mixtures' do
94
+ let(:distribution) do
121
95
  ERV::MixtureDistribution.new([ { distribution: :mixture,
122
96
  args: [ { distribution: :exponential, args: { rate: 4.0 }, weight: 300 },
123
97
  { distribution: :exponential, args: { rate: 5.0 }, weight: 200 },
@@ -132,9 +106,7 @@ describe ERV::MixtureDistribution do
132
106
  end
133
107
 
134
108
  it 'should allow sampling from the mixture' do
135
- momd.sample
109
+ expect{ distribution.sample }.not.to raise_exception(ArgumentError).and(! be_nil)
136
110
  end
137
-
138
111
  end
139
-
140
112
  end
@@ -1,19 +1,13 @@
1
- require 'test_helper'
2
-
3
- require 'erv/random_variable'
4
-
5
1
  describe ERV::SequentialRandomVariable do
6
2
 
7
3
  it 'should require the :first_value parameter' do
8
- lambda do
9
- ERV::SequentialRandomVariable.new
10
- end.must_raise ArgumentError
4
+ expect{ ERV::SequentialRandomVariable.new }.to raise_exception(ArgumentError)
11
5
  end
12
6
 
13
7
  it 'should consider starting value' do
14
8
  first = 1.0
15
9
  srv = ERV::SequentialRandomVariable.new(first_value: first, distribution: :exponential, args: { rate: 2.0 })
16
- srv.next.must_be :>, first
10
+ expect(srv.next).to (be > first)
17
11
  end
18
12
 
19
13
  it 'should consider previous sample' do
@@ -22,7 +16,7 @@ describe ERV::SequentialRandomVariable do
22
16
  previous_sample = srv.next
23
17
  10.times do
24
18
  new_sample = srv.next
25
- new_sample.must_be :>, previous_sample
19
+ expect(new_sample).to (be > previous_sample)
26
20
  previous_sample = new_sample
27
21
  end
28
22
  end