croupier 1.6.0 → 2.0.0.rc1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/README.md +2 -2
- data/Rakefile +7 -0
- data/lib/croupier/distribution.rb +115 -36
- data/lib/croupier/distribution_generator.rb +57 -0
- data/lib/croupier/distribution_generators/enumerator_block_generator.rb +23 -0
- data/lib/croupier/distribution_generators/enumerator_generator.rb +21 -0
- data/lib/croupier/distribution_generators/inverse_cdf_generator.rb +21 -0
- data/lib/croupier/distribution_generators/minimum_sample_generator.rb +24 -0
- data/lib/croupier/distribution_generators.rb +18 -0
- data/lib/croupier/distributions/bernoulli.rb +18 -25
- data/lib/croupier/distributions/binomial.rb +30 -29
- data/lib/croupier/distributions/cauchy.rb +22 -19
- data/lib/croupier/distributions/credit_card.rb +39 -29
- data/lib/croupier/distributions/degenerate.rb +16 -19
- data/lib/croupier/distributions/exponential.rb +18 -19
- data/lib/croupier/distributions/gamma.rb +66 -37
- data/lib/croupier/distributions/geometric.rb +19 -20
- data/lib/croupier/distributions/nbinomial.rb +22 -33
- data/lib/croupier/distributions/normal.rb +30 -34
- data/lib/croupier/distributions/poisson.rb +26 -25
- data/lib/croupier/distributions/triangular.rb +39 -25
- data/lib/croupier/distributions/uniform.rb +43 -19
- data/lib/croupier/distributions.rb +3 -4
- data/lib/croupier/version.rb +1 -1
- data/lib/croupier.rb +43 -6
- data/test/minitest/distribution_class/test_class_methods.rb +142 -0
- data/test/{test_distribution_class.rb → minitest/distribution_class/test_instance_methods.rb} +26 -28
- data/test/minitest/distribution_generator_class/test_class_methods.rb +24 -0
- data/test/minitest/distribution_generator_class/test_instance_methods.rb +35 -0
- data/test/minitest/distribution_generators/test_enumerator_block_generator.rb +31 -0
- data/test/minitest/distribution_generators/test_enumerator_generator.rb +33 -0
- data/test/minitest/distribution_generators/test_inverse_cdf_generator.rb +36 -0
- data/test/minitest/distribution_generators/test_minimum_sample_generator.rb +33 -0
- data/test/minitest/distributions/test_bernoulli_distribution.rb +13 -0
- data/test/minitest/distributions/test_binomial_distribution.rb +18 -0
- data/test/minitest/distributions/test_cauchy_distribution.rb +18 -0
- data/test/{distributions/minitest/test_credit_card.rb → minitest/distributions/test_credit_card_distribution.rb} +5 -0
- data/test/{distributions/minitest → minitest/distributions}/test_degenerate_distribution.rb +2 -2
- data/test/minitest/distributions/test_exponential_distribution.rb +13 -0
- data/test/minitest/distributions/test_gamma_distribution.rb +23 -0
- data/test/minitest/distributions/test_geometric_distribution.rb +13 -0
- data/test/minitest/distributions/test_normal_distribution.rb +17 -0
- data/test/minitest/distributions/test_poisson_distribution.rb +13 -0
- data/test/minitest/distributions/test_triangular_distribution.rb +26 -0
- data/test/minitest/distributions/test_uniform_distribution.rb +54 -0
- data/test/{test_croupier_module.rb → minitest/test_croupier_module.rb} +0 -0
- data/test/minitest/test_distribution_generators_module.rb +37 -0
- data/test/{test_distributions_module.rb → minitest/test_distributions_module.rb} +0 -0
- data/test/rtests.R +1 -0
- metadata +62 -44
- data/test/distributions/R_tests/test_bernoulli.R +0 -17
- data/test/distributions/R_tests/test_binomial.R +0 -17
- data/test/distributions/R_tests/test_cauchy.R +0 -28
- data/test/distributions/R_tests/test_exponential.R +0 -28
- data/test/distributions/R_tests/test_gamma.R +0 -27
- data/test/distributions/R_tests/test_geometric.R +0 -23
- data/test/distributions/R_tests/test_nbinomial.R +0 -17
- data/test/distributions/R_tests/test_normal.R +0 -52
- data/test/distributions/R_tests/test_poisson.R +0 -17
- data/test/distributions/R_tests/test_triangular.R +0 -28
- data/test/distributions/R_tests/test_uniform.R +0 -30
- data/test/testsuite.R +0 -37
@@ -6,30 +6,27 @@ module Croupier
|
|
6
6
|
# Discrete probability distribution that returns the same value.
|
7
7
|
class Degenerate < ::Croupier::Distribution
|
8
8
|
|
9
|
-
|
10
|
-
@name = "Degenerate distribution"
|
11
|
-
@description = "Discrete probability distribution that returns the same value each time."
|
12
|
-
configure(options)
|
13
|
-
end
|
9
|
+
distribution_name "Degenerate distribution"
|
14
10
|
|
15
|
-
|
16
|
-
params[:constant]
|
17
|
-
end
|
11
|
+
distribution_description "Discrete probability distribution that returns the same value each time."
|
18
12
|
|
19
|
-
|
20
|
-
|
21
|
-
|
13
|
+
cli_name "degenerate"
|
14
|
+
|
15
|
+
cli_options({
|
16
|
+
options: [
|
17
|
+
[:constant, 'value to be returned', {type: :float, default: 42.0}]
|
18
|
+
],
|
19
|
+
banner: "Degenerate distribution. Discrete probability distribution that returns the same value each time."
|
20
|
+
})
|
22
21
|
|
23
|
-
|
24
|
-
|
22
|
+
enumerator_block do |y|
|
23
|
+
loop do
|
24
|
+
y << params[:constant]
|
25
|
+
end
|
25
26
|
end
|
26
27
|
|
27
|
-
def
|
28
|
-
|
29
|
-
[:constant, 'value to be returned', {:type=>:float, :default => 42.0}]
|
30
|
-
],
|
31
|
-
:banner => "Degenerate distribution. Discrete probability distribution that returns the same value each time."
|
32
|
-
}
|
28
|
+
def initialize(options={})
|
29
|
+
super(options)
|
33
30
|
end
|
34
31
|
end
|
35
32
|
end
|
@@ -8,31 +8,30 @@ module Croupier
|
|
8
8
|
#
|
9
9
|
class Exponential < ::Croupier::Distribution
|
10
10
|
|
11
|
-
|
12
|
-
@name = "Exponential distribution"
|
13
|
-
@description = "Continuous probability distribution with a lambda param rate describing the time between events in a Poisson process"
|
14
|
-
configure(options)
|
15
|
-
raise Croupier::InputParamsError, "Invalid interval values" if params[:lambda] <= 0
|
16
|
-
end
|
11
|
+
distribution_name "Exponential distribution"
|
17
12
|
|
18
|
-
|
19
|
-
(-1/params[:lambda]) * Math.log(n)
|
20
|
-
end
|
13
|
+
distribution_description "Continuous probability distribution with a lambda param rate describing the time between events in a Poisson process"
|
21
14
|
|
22
|
-
|
23
|
-
|
15
|
+
cli_name "exponential"
|
16
|
+
|
17
|
+
cli_options({
|
18
|
+
options: [
|
19
|
+
[:lambda, 'rate param', {type: :float, default: 1.0}]
|
20
|
+
],
|
21
|
+
banner: "Exponential distribution. Generate numbers following a exponential distribution for a given lambda rate"
|
22
|
+
})
|
23
|
+
|
24
|
+
inv_cdf do |n|
|
25
|
+
(-1 / lambda) * Math.log(1 - n)
|
24
26
|
end
|
25
27
|
|
26
|
-
def
|
27
|
-
|
28
|
+
def initialize(options={})
|
29
|
+
super(options)
|
30
|
+
raise Croupier::InputParamsError, "lambda cannot be negative" if params[:lambda] <= 0
|
28
31
|
end
|
29
32
|
|
30
|
-
def
|
31
|
-
|
32
|
-
[:lambda, 'rate param', {:type=>:float, :default => 1.0}]
|
33
|
-
],
|
34
|
-
:banner => "Exponential distribution. Generate numbers following a exponential distribution for a given lambda rate"
|
35
|
-
}
|
33
|
+
def lambda
|
34
|
+
params[:lambda]
|
36
35
|
end
|
37
36
|
end
|
38
37
|
end
|
@@ -7,58 +7,87 @@ module Croupier
|
|
7
7
|
# (defaults to 1) and scale (defaults to 1).
|
8
8
|
class Gamma < ::Croupier::Distribution
|
9
9
|
|
10
|
+
distribution_name "Gamma distribution"
|
11
|
+
|
12
|
+
distribution_description "Family of continuous distributions with two parameters, shape and scale"
|
13
|
+
|
14
|
+
cli_name "gamma"
|
15
|
+
|
16
|
+
cli_options({
|
17
|
+
options: [
|
18
|
+
[:shape, 'shape of the distribution', {type: :float, default: 1.0}],
|
19
|
+
[:scale, 'scale of the distribution', {type: :float, default: 1.0}]
|
20
|
+
],
|
21
|
+
banner: "Family of continuous distributions with two parameters, shape and scale."
|
22
|
+
})
|
23
|
+
|
24
|
+
enumerator do |c|
|
25
|
+
c.degenerate(constant: scale).to_enum.lazy.zip(xi_enum, adjust_enum).map do |s,x,a|
|
26
|
+
s * (x - a)
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
10
30
|
def initialize(options={})
|
11
|
-
|
12
|
-
@description = "Family of continuous distributions with two parameters, shape and scale"
|
13
|
-
configure(options)
|
31
|
+
super(options)
|
14
32
|
end
|
15
33
|
|
16
|
-
def
|
17
|
-
params[:
|
34
|
+
def shape
|
35
|
+
params[:shape]
|
18
36
|
end
|
19
37
|
|
20
|
-
def
|
21
|
-
|
38
|
+
def scale
|
39
|
+
params[:scale]
|
22
40
|
end
|
23
41
|
|
24
|
-
def
|
25
|
-
|
42
|
+
def delta
|
43
|
+
@delta ||= shape - shape.floor
|
26
44
|
end
|
27
45
|
|
28
|
-
def
|
29
|
-
|
30
|
-
[:shape, 'shape of the distribution', {:type=>:float, :default => 1.0}],
|
31
|
-
[:scale, 'scale of the distribution', {:type=>:float, :default => 1.0}]
|
32
|
-
],
|
33
|
-
:banner => "Family of continuous distributions with two parameters, shape and scale."
|
34
|
-
}
|
46
|
+
def v_0
|
47
|
+
@v_0 ||= Math::E / (delta + Math::E)
|
35
48
|
end
|
36
49
|
|
37
50
|
protected
|
51
|
+
|
52
|
+
def adjust_enum
|
53
|
+
uniform.map{|n| Math.log(n) }.each_slice(shape.floor).map do |slice|
|
54
|
+
slice.inject &:+
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
38
58
|
# Based on Ahrens-Dieter acceptance-rejection method
|
39
59
|
# as described on Wikipedia:
|
40
60
|
# http://en.wikipedia.org/wiki/Gamma_distribution#Generating_gamma-distributed_random_variables
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
61
|
+
|
62
|
+
def xi_enum
|
63
|
+
uniform.zip(uniform, uniform).map do |v1, v2, v3|
|
64
|
+
x = xi v1, v2, v3
|
65
|
+
[x, eta(x, v1, v2, v3)]
|
66
|
+
end.reject do |x,e|
|
67
|
+
e > (x** (delta - 1)) * (Math.exp(-x))
|
68
|
+
end.map do |x,e|
|
69
|
+
x
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
73
|
+
def xi v1, v2, v3
|
74
|
+
if v1 < v_0
|
75
|
+
v2** (1/delta)
|
76
|
+
else
|
77
|
+
1 - Math.log(v2)
|
78
|
+
end
|
79
|
+
end
|
80
|
+
|
81
|
+
def eta xi, v1, v2, v3
|
82
|
+
if v1 < v_0
|
83
|
+
v3 * (xi** (delta - 1))
|
84
|
+
else
|
85
|
+
v3 * Math.exp(-xi)
|
86
|
+
end
|
87
|
+
end
|
88
|
+
|
89
|
+
def uniform
|
90
|
+
::Croupier::Distributions.uniform(included: 1, excluded: 0).to_enum.lazy
|
62
91
|
end
|
63
92
|
end
|
64
93
|
end
|
@@ -12,33 +12,32 @@ module Croupier
|
|
12
12
|
# (The Art of Computer Programming, Volume 2, 3.4.1.F )
|
13
13
|
class Geometric < ::Croupier::Distribution
|
14
14
|
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
15
|
+
distribution_name "Geometric distribution"
|
16
|
+
|
17
|
+
distribution_description "Discrete probability distribution that expresses the number of X Bernoulli trials needed to get one success, supported on the set { 1, 2, 3, ...}"
|
18
|
+
|
19
|
+
cli_name "geometric"
|
20
|
+
|
21
|
+
cli_options({
|
22
|
+
options: [
|
23
|
+
[:success, 'success probability of each trial', {type: :float, short: "-p", default: 0.5}]
|
24
|
+
],
|
25
|
+
banner: "Geometric distribution. Discrete probability distribution that expresses the number of X Bernoulli trials needed to get one success, supported on the set { 1, 2, 3, ...} }"
|
26
|
+
})
|
21
27
|
|
22
28
|
# Fair point: it is not the inverse of the cdf,
|
23
29
|
# but it generates the distribution from an uniform.
|
24
|
-
|
25
|
-
(Math.log(1-n) / Math.log(1-
|
26
|
-
end
|
27
|
-
|
28
|
-
def default_parameters
|
29
|
-
{:success => 0.5}
|
30
|
+
inv_cdf do |n|
|
31
|
+
(Math.log(1.0-n) / Math.log(1.0-success)).ceil
|
30
32
|
end
|
31
33
|
|
32
|
-
def
|
33
|
-
|
34
|
+
def initialize(options={})
|
35
|
+
super(options)
|
36
|
+
raise Croupier::InputParamsError, "Probability of success must be in the interval [0,1]" if params[:success] > 1 || params[:success] < 0
|
34
37
|
end
|
35
38
|
|
36
|
-
def
|
37
|
-
|
38
|
-
[:success, 'success probability of each trial', {:type=>:float, :short => "-p", :default => 0.5}]
|
39
|
-
],
|
40
|
-
:banner => "Geometric distribution. Discrete probability distribution that expresses the number of X Bernoulli trials needed to get one success, supported on the set { 1, 2, 3, ...} }"
|
41
|
-
}
|
39
|
+
def success
|
40
|
+
params[:success]
|
42
41
|
end
|
43
42
|
end
|
44
43
|
end
|
@@ -10,49 +10,38 @@ module Croupier
|
|
10
10
|
# Wikipedia -- http://en.wikipedia.org/wiki/Negative_binomial_distribution
|
11
11
|
class Nbinomial < ::Croupier::Distribution
|
12
12
|
|
13
|
-
|
14
|
-
@name = "Negative binomial distribution"
|
15
|
-
@description = "Discrete probability distribution of the number of successes in a sequence of Bernoulli trials before a specified (non-random) number of failures (denoted size) occur."
|
16
|
-
configure(options)
|
17
|
-
raise Croupier::InputParamsError, "Probability of success must be in the interval [0,1]" if params[:success] > 1 || params[:success] < 0
|
18
|
-
end
|
13
|
+
distribution_name "Negative binomial distribution"
|
19
14
|
|
20
|
-
|
21
|
-
# but it generates the distribution from an uniform.
|
22
|
-
def generate_sample n=1
|
23
|
-
generate_geometrics(n).each_slice(params[:size]).map do |sample|
|
24
|
-
sample.inject(-params[:size], &:+) # Inject starts on -size because
|
25
|
-
# this way it is equivalent to:
|
26
|
-
# sample.map{|x| x - 1}.inject(&:+)
|
27
|
-
end
|
28
|
-
end
|
15
|
+
distribution_description "Discrete probability distribution of the number of successes in a sequence of Bernoulli trials before a specified (non-random) number of failures (denoted size) occur."
|
29
16
|
|
30
|
-
|
31
|
-
{:success => 0.5, :size => 1}
|
32
|
-
end
|
17
|
+
cli_name "nbinomial"
|
33
18
|
|
34
|
-
|
35
|
-
|
36
|
-
|
19
|
+
cli_options({
|
20
|
+
options: [
|
21
|
+
[:size, 'number of errors', {type: :integer, default: 1}],
|
22
|
+
[:success, 'success probability of each trial', {type: :float, short: "-p", default: 0.5}]
|
23
|
+
],
|
24
|
+
banner: "Negative binomial distribution. Discrete probability distribution of the number of successes in a sequence of Bernoulli trials before a specified (non-random) number of failures (denoted size) occur."
|
25
|
+
})
|
37
26
|
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
],
|
43
|
-
:banner => "Negative binomial distribution. Discrete probability distribution of the number of successes in a sequence of Bernoulli trials before a specified (non-random) number of failures (denoted size) occur."
|
44
|
-
}
|
27
|
+
enumerator do |c|
|
28
|
+
c.geometric(success: success).to_enum.lazy.each_slice(size).map do |x|
|
29
|
+
x.inject(-size,&:+)
|
30
|
+
end
|
45
31
|
end
|
46
32
|
|
47
|
-
|
48
|
-
|
49
|
-
|
33
|
+
def initialize(options={})
|
34
|
+
super(options)
|
35
|
+
raise Croupier::InputParamsError, "Probability of success must be in the interval [0,1]" if params[:success] > 1 || params[:success] < 0
|
50
36
|
end
|
51
37
|
|
52
|
-
def
|
53
|
-
|
38
|
+
def success
|
39
|
+
params[:success]
|
54
40
|
end
|
55
41
|
|
42
|
+
def size
|
43
|
+
params[:size]
|
44
|
+
end
|
56
45
|
end
|
57
46
|
end
|
58
47
|
end
|
@@ -8,48 +8,44 @@ module Croupier
|
|
8
8
|
#
|
9
9
|
class Normal < ::Croupier::Distribution
|
10
10
|
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
11
|
+
distribution_name "Normal distribution"
|
12
|
+
|
13
|
+
distribution_description "Continuous distribution (mu,sigma) (defaults to (0,1) ) where mu is the mean and sigma the standard deviation."
|
14
|
+
|
15
|
+
cli_name "normal"
|
16
|
+
|
17
|
+
cli_options({
|
18
|
+
options: [
|
19
|
+
[:mean, 'mean of the distribution', {type: :float, default: 0.0}],
|
20
|
+
[:std, 'standard deviation of the distribution', {type: :float, default: 1.0}]
|
21
|
+
],
|
22
|
+
banner: "Normal distribution. Generate numbers following a continuous distribution in the real line with mean :mean and standard deviation :std."
|
23
|
+
})
|
24
|
+
|
25
|
+
minimum_sample do
|
26
|
+
x, y = 1 - ::Croupier.rand, 1 - ::Croupier.rand
|
27
|
+
[
|
28
|
+
Math.sqrt(-2*Math.log(x)) * Math.cos(2*Math::PI*y),
|
29
|
+
Math.sqrt(-2*Math.log(x)) * Math.sin(2*Math::PI*y)
|
30
|
+
]
|
15
31
|
end
|
16
32
|
|
17
|
-
def
|
18
|
-
|
19
|
-
|
20
|
-
# Generate
|
21
|
-
gen = (1..sample).map do |x|
|
22
|
-
1 - rand # because uniform need to be in (0,1]
|
23
|
-
end.each_slice(2).flat_map do |x, y|
|
24
|
-
[
|
25
|
-
Math.sqrt(-2*Math.log(x)) * Math.cos(2*Math::PI*y),
|
26
|
-
Math.sqrt(-2*Math.log(x)) * Math.sin(2*Math::PI*y)
|
27
|
-
]
|
28
|
-
end
|
29
|
-
|
30
|
-
# Adjust parameters.
|
31
|
-
gen.map!{ |x| x * params[:std] } if params[:std] != 1
|
32
|
-
gen.map!{ |x| x + params[:mean] } if params[:mean] != 0
|
33
|
-
|
34
|
-
# Adjust length
|
35
|
-
n.odd? ? gen[0..-2] : gen
|
33
|
+
def initialize(options={})
|
34
|
+
super(options)
|
36
35
|
end
|
37
36
|
|
38
|
-
def
|
39
|
-
|
37
|
+
def std
|
38
|
+
params[:std]
|
40
39
|
end
|
41
40
|
|
42
|
-
def
|
43
|
-
|
41
|
+
def mean
|
42
|
+
params[:mean]
|
44
43
|
end
|
45
44
|
|
46
|
-
def
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
],
|
51
|
-
:banner => "Normal distribution. Generate numbers following a continuous distribution in the real line with mean :mean and standard deviation :std."
|
52
|
-
}
|
45
|
+
def to_enum
|
46
|
+
@generator.to_enum.
|
47
|
+
map {|x| x * std}. # Adjust standard deviation
|
48
|
+
map {|x| x + mean} # Adjust mean
|
53
49
|
end
|
54
50
|
end
|
55
51
|
end
|
@@ -4,43 +4,44 @@ module Croupier
|
|
4
4
|
#####################################################################
|
5
5
|
# Poisson Distribution
|
6
6
|
# Discrete probability distribution that expresses the probability
|
7
|
-
# of a given number of event
|
7
|
+
# of a given number of event occurring in a fixed interval of time
|
8
8
|
# and/or space if these events occur with a known average rate
|
9
9
|
# and independently of the time since the las event.
|
10
10
|
#
|
11
11
|
# Wikipedia http://en.wikipedia.org/wiki/Poisson_distribution
|
12
12
|
class Poisson < ::Croupier::Distribution
|
13
13
|
|
14
|
-
|
15
|
-
@name = "Poisson distribution"
|
16
|
-
@description = "Discrete probability distribution that expresses the probability of a given number of events occurring in a fixed interval of time."
|
17
|
-
configure(options)
|
18
|
-
end
|
14
|
+
distribution_name "Poisson distribution"
|
19
15
|
|
20
|
-
|
21
|
-
l = Math.exp(-params[:lambda])
|
22
|
-
k = 0; p = 1;
|
23
|
-
while p > l
|
24
|
-
p *= rand
|
25
|
-
k += 1;
|
26
|
-
end
|
27
|
-
k-1
|
28
|
-
end
|
16
|
+
distribution_description "Discrete probability distribution that expresses the probability of a given number of events occurring in a fixed interval of time."
|
29
17
|
|
30
|
-
|
31
|
-
|
18
|
+
cli_name "poisson"
|
19
|
+
|
20
|
+
cli_options({
|
21
|
+
options: [
|
22
|
+
[:lambda, 'rate parameter (equal to the mean of the distribution)', {type: :integer, default: 50}]
|
23
|
+
],
|
24
|
+
banner: "Poisson distribution. Discrete probability distribution that expresses the probability of a given number of events occurring in a fixed interval of time."
|
25
|
+
})
|
26
|
+
|
27
|
+
enumerator_block do |y|
|
28
|
+
l = Math.exp(-lambda)
|
29
|
+
loop do
|
30
|
+
k = 0; p = 1
|
31
|
+
while p > l
|
32
|
+
p *= ::Croupier.rand
|
33
|
+
k += 1
|
34
|
+
end
|
35
|
+
y << (k-1)
|
36
|
+
end
|
32
37
|
end
|
33
38
|
|
34
|
-
def
|
35
|
-
|
39
|
+
def initialize(options={})
|
40
|
+
super(options)
|
36
41
|
end
|
37
42
|
|
38
|
-
def
|
39
|
-
|
40
|
-
[:lambda, 'rate parameter (equal to the mean of the distribution)', {:type=>:integer, :default => 50}]
|
41
|
-
],
|
42
|
-
:banner => "Poisson distribution. Discrete probability distribution that expresses the probability of a given number of events occurring in a fixed interval of time."
|
43
|
-
}
|
43
|
+
def lambda
|
44
|
+
params[:lambda]
|
44
45
|
end
|
45
46
|
end
|
46
47
|
end
|
@@ -7,42 +7,56 @@ module Croupier
|
|
7
7
|
# is a, upper limit b and mode c (a <= c <= b).
|
8
8
|
class Triangular < ::Croupier::Distribution
|
9
9
|
|
10
|
+
distribution_name "Triangular distribution"
|
11
|
+
|
12
|
+
distribution_description "Continuous probability distribution whose lower limit is a, upper limit b and mode c (a <= c <= b)"
|
13
|
+
|
14
|
+
cli_name "triangular"
|
15
|
+
|
16
|
+
cli_options({
|
17
|
+
options: [
|
18
|
+
[:lower, 'lower limit', {type: :float, short: '-a', default: 0.0}],
|
19
|
+
[:upper, 'upper limit', {type: :float, short: '-b', default: 1.0}],
|
20
|
+
[:mode, 'mode', {type: :float, short: '-c', default: 0.5}]
|
21
|
+
],
|
22
|
+
banner: "Triangular distribution. Continuous distribution whose support is the interval (a,b), with mode c."
|
23
|
+
})
|
24
|
+
|
25
|
+
inv_cdf do |n|
|
26
|
+
if n < @F_c
|
27
|
+
lower + Math.sqrt( n * range * (mode - lower) )
|
28
|
+
else
|
29
|
+
upper - Math.sqrt( (1-n) * range * (upper - mode) )
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
10
33
|
def initialize(options={})
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
34
|
+
super(options)
|
35
|
+
if params[:lower] >= params[:upper]
|
36
|
+
warn("Lower limit is greater than upper limit. Changing their values.")
|
37
|
+
params[:lower], params[:upper] = params[:upper], params[:lower]
|
38
|
+
end
|
39
|
+
if params[:mode] < params[:lower] || params[:upper] < params[:mode]
|
16
40
|
warn("Mode is not in the support. Mode value will be change to median.")
|
17
|
-
params[:
|
41
|
+
params[:mode] = (params[:lower]+params[:upper])/2.0;
|
18
42
|
end
|
19
|
-
@F_c = (params[:
|
43
|
+
@F_c = (params[:mode]-params[:lower]).to_f/(params[:upper]-params[:lower])
|
20
44
|
end
|
21
45
|
|
22
|
-
def
|
23
|
-
|
24
|
-
params[:a] + Math.sqrt( n * (params[:b] - params[:a]) * (params[:c] - params[:a]) )
|
25
|
-
else
|
26
|
-
params[:b] - Math.sqrt( (1-n) * (params[:b] - params[:a]) * (params[:b] - params[:c]) )
|
27
|
-
end
|
46
|
+
def lower
|
47
|
+
params[:lower]
|
28
48
|
end
|
29
49
|
|
30
|
-
def
|
31
|
-
|
50
|
+
def upper
|
51
|
+
params[:upper]
|
32
52
|
end
|
33
53
|
|
34
|
-
def
|
35
|
-
|
54
|
+
def mode
|
55
|
+
params[:mode]
|
36
56
|
end
|
37
57
|
|
38
|
-
def
|
39
|
-
|
40
|
-
[:a, 'lower limit', {:type=>:float, :default => 0.0}],
|
41
|
-
[:b, 'upper limit', {:type=>:float, :default => 1.0}],
|
42
|
-
[:c, 'mode' , {:type=>:float, :default => 0.5}]
|
43
|
-
],
|
44
|
-
:banner => "Triangular distribution. Continuous distribution whose support is the interval (a,b), with mode c."
|
45
|
-
}
|
58
|
+
def range
|
59
|
+
@range ||= upper - lower
|
46
60
|
end
|
47
61
|
end
|
48
62
|
end
|
@@ -3,37 +3,61 @@ module Croupier
|
|
3
3
|
|
4
4
|
#####################################################################
|
5
5
|
# Uniform Distribution
|
6
|
-
#
|
6
|
+
# Continuous distribution where all points in an interval have
|
7
7
|
# the same probability.
|
8
8
|
#
|
9
9
|
class Uniform < ::Croupier::Distribution
|
10
10
|
|
11
|
+
distribution_name "Uniform distribution"
|
12
|
+
|
13
|
+
distribution_description "Continuous distribution on [a,b] (defaults to [0,1]) where all points in the interval are equally likely"
|
14
|
+
|
15
|
+
cli_name "uniform"
|
16
|
+
|
17
|
+
cli_options({
|
18
|
+
options: [
|
19
|
+
[:included, 'interval included value', {type: :float, short: "-i", default: 0.0}],
|
20
|
+
[:excluded, 'interval excluded value', {type: :float, short: "-e", default: 1.0}]
|
21
|
+
],
|
22
|
+
banner: "Uniform distribution. Generate numbers following a continuous distribution on [a,b] (given a=min(included, excluded) and b=max(included,excluded)) where all points in the interval are equally likely."
|
23
|
+
})
|
24
|
+
|
11
25
|
def initialize(options={})
|
12
|
-
|
13
|
-
@
|
14
|
-
|
26
|
+
super options
|
27
|
+
@exclude_value = if self.inverted?
|
28
|
+
->(n) { 1-n }
|
29
|
+
else
|
30
|
+
->(n) { n }
|
31
|
+
end
|
32
|
+
@min, @max = if self.inverted?
|
33
|
+
[params[:excluded], params[:included]]
|
34
|
+
else
|
35
|
+
[params[:included], params[:excluded]]
|
36
|
+
end
|
37
|
+
@range = @max - @min
|
15
38
|
end
|
16
39
|
|
17
|
-
|
18
|
-
raise Croupier::InputParamsError, "Invalid interval values" if params[:b] < params[:a]
|
19
|
-
rand Range.new(params[:a], params[:b])
|
20
|
-
end
|
40
|
+
attr_reader :exclude_value, :min, :max, :range
|
21
41
|
|
22
|
-
def
|
23
|
-
|
42
|
+
def inverted?
|
43
|
+
params[:included] > params[:excluded]
|
24
44
|
end
|
25
45
|
|
26
|
-
def
|
27
|
-
|
46
|
+
def to_enum
|
47
|
+
@enum ||= base_enum.lazy.
|
48
|
+
map(&exclude_value).
|
49
|
+
map do |n|
|
50
|
+
min + range * n
|
51
|
+
end
|
28
52
|
end
|
29
53
|
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
54
|
+
protected
|
55
|
+
def base_enum
|
56
|
+
Enumerator.new do |y|
|
57
|
+
loop do
|
58
|
+
y << Croupier.rand
|
59
|
+
end
|
60
|
+
end
|
37
61
|
end
|
38
62
|
end
|
39
63
|
end
|