fathom 0.2.2 → 0.2.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.
- data/Gemfile +1 -0
- data/Gemfile.lock +4 -0
- data/TODO.md +140 -0
- data/VERSION +1 -1
- data/lib/fathom.rb +13 -12
- data/lib/fathom/data_node.rb +3 -32
- data/lib/fathom/distributions.rb +8 -0
- data/lib/fathom/distributions/discrete_gaussian.rb +44 -0
- data/lib/fathom/distributions/discrete_uniform.rb +46 -0
- data/lib/fathom/distributions/gaussian.rb +46 -0
- data/lib/fathom/distributions/uniform.rb +35 -0
- data/lib/fathom/{basic_node.rb → enforced_name.rb} +5 -1
- data/lib/fathom/ext/string.rb +27 -0
- data/lib/fathom/inverter.rb +1 -2
- data/lib/fathom/monte_carlo_set.rb +26 -3
- data/lib/fathom/node.rb +90 -0
- data/lib/fathom/numeric_methods.rb +50 -0
- data/lib/fathom/plausible_range.rb +11 -15
- data/spec/fathom/data_node_spec.rb +45 -4
- data/spec/fathom/distributions/discrete_gaussian_spec.rb +64 -0
- data/spec/fathom/distributions/discrete_uniform_spec.rb +0 -0
- data/spec/fathom/distributions/gaussian_spec.rb +64 -0
- data/spec/fathom/distributions/uniform_spec.rb +0 -0
- data/spec/fathom/enforced_name_spec.rb +15 -0
- data/spec/fathom/monte_carlo_set_spec.rb +12 -1
- data/spec/fathom/node_spec.rb +129 -0
- data/spec/fathom/numeric_methods_spec.rb +82 -0
- data/spec/fathom/plausible_range_spec.rb +1 -2
- data/spec/support/dummy_numeric_node.rb +8 -0
- metadata +30 -7
- data/lib/fathom/combined_plausibilities.rb +0 -12
- data/lib/fathom/node_utilities.rb +0 -8
@@ -0,0 +1,27 @@
|
|
1
|
+
# From ActiveSupport
|
2
|
+
class String
|
3
|
+
if Module.method(:const_get).arity == 1
|
4
|
+
def constantize
|
5
|
+
names = self.split('::')
|
6
|
+
names.shift if names.empty? || names.first.empty?
|
7
|
+
|
8
|
+
constant = Object
|
9
|
+
names.each do |name|
|
10
|
+
constant = constant.const_defined?(name) ? constant.const_get(name) : constant.const_missing(name)
|
11
|
+
end
|
12
|
+
constant
|
13
|
+
end
|
14
|
+
else
|
15
|
+
def constantize #:nodoc:
|
16
|
+
names = self.split('::')
|
17
|
+
names.shift if names.empty? || names.first.empty?
|
18
|
+
|
19
|
+
constant = Object
|
20
|
+
names.each do |name|
|
21
|
+
constant = constant.const_defined?(name, false) ? constant.const_get(name) : constant.const_missing(name)
|
22
|
+
end
|
23
|
+
constant
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
end
|
data/lib/fathom/inverter.rb
CHANGED
@@ -54,19 +54,42 @@ class Fathom::MonteCarloSet
|
|
54
54
|
raise "No fields are defined. Have you processed this model yet?" if fields.empty?
|
55
55
|
raise ArgumentError, "#{field} is not a field in this set." unless fields.include?(field)
|
56
56
|
vector = self.send(field)
|
57
|
+
return vector unless vector.is_a?(GSL::Vector)
|
57
58
|
{
|
58
59
|
:coefficient_of_variation => (vector.sd / vector.mean),
|
59
60
|
:max => vector.max,
|
60
61
|
:mean => vector.mean,
|
61
62
|
:min => vector.min,
|
62
|
-
:sd => vector.sd
|
63
|
+
:sd => vector.sd,
|
64
|
+
:upper_bound => upper_bound(:mean => vector.mean, :sd => vector.sd),
|
65
|
+
:lower_bound => lower_bound(:mean => vector.mean, :sd => vector.sd)
|
63
66
|
}
|
64
67
|
end
|
68
|
+
|
69
|
+
def inverse_cdf(opts={})
|
70
|
+
mean = opts[:mean]
|
71
|
+
sd = opts[:sd]
|
72
|
+
lower = opts.fetch(:lower, true)
|
73
|
+
confidence_interval = opts.fetch(:confidence_interval, 0.05)
|
74
|
+
value = lower ? GSL::Cdf.gaussian_Pinv(confidence_interval, sd) : GSL::Cdf.gaussian_Qinv(confidence_interval, sd)
|
75
|
+
value + mean
|
76
|
+
end
|
77
|
+
alias :lower_bound :inverse_cdf
|
78
|
+
|
79
|
+
def upper_bound(opts={})
|
80
|
+
inverse_cdf(opts.merge(:lower => false))
|
81
|
+
end
|
82
|
+
|
83
|
+
def interval_values(opts={})
|
84
|
+
confidence_interval = opts.fetch(:confidence_interval, 0.9)
|
85
|
+
bound = (1 - confidence_interval) / 2.0
|
86
|
+
[lower_bound(opts.merge(:confidence_interval, bound)), upper_bound(opts.merge(:confidence_interval, bound))]
|
87
|
+
end
|
65
88
|
|
66
89
|
def assert_sample_vectors
|
67
90
|
vectors = @samples.inject({}) do |h, o|
|
68
|
-
key,
|
69
|
-
h[key] = GSL::Vector.ary_to_gv(
|
91
|
+
key, obj = o.first, o.last
|
92
|
+
h[key] = (obj.is_a?(Array) and obj.first.is_a?(Numeric)) ? GSL::Vector.ary_to_gv(obj) : obj
|
70
93
|
h
|
71
94
|
end
|
72
95
|
@samples = vectors
|
data/lib/fathom/node.rb
ADDED
@@ -0,0 +1,90 @@
|
|
1
|
+
require File.expand_path(File.join(File.dirname(__FILE__), '..', 'fathom'))
|
2
|
+
class Fathom::Node
|
3
|
+
|
4
|
+
attr_reader :name, :distribution, :description, :values
|
5
|
+
|
6
|
+
def initialize(opts={})
|
7
|
+
@name = opts[:name]
|
8
|
+
assert_distribution(opts)
|
9
|
+
@description = opts[:description]
|
10
|
+
@values = opts[:values]
|
11
|
+
assert_links(opts)
|
12
|
+
end
|
13
|
+
|
14
|
+
def name_sym
|
15
|
+
return nil unless self.name
|
16
|
+
@name_sym ||= self.name.to_s.downcase.gsub(/\s+|-+/, '_').to_sym
|
17
|
+
end
|
18
|
+
|
19
|
+
def parents
|
20
|
+
@parents ||= []
|
21
|
+
end
|
22
|
+
|
23
|
+
def add_parent(parent)
|
24
|
+
self.parents << parent
|
25
|
+
parent.register_child(self)
|
26
|
+
end
|
27
|
+
|
28
|
+
def register_child(child)
|
29
|
+
raise "Cannot register a child if this node is not a parent already. Use add_parent to the other node or add_child to this node." unless
|
30
|
+
child.parents.include?(self)
|
31
|
+
children << child unless children.include?(child)
|
32
|
+
true
|
33
|
+
end
|
34
|
+
|
35
|
+
def children
|
36
|
+
@children ||= []
|
37
|
+
end
|
38
|
+
|
39
|
+
def add_child(child)
|
40
|
+
self.children << child
|
41
|
+
child.register_parent(self)
|
42
|
+
end
|
43
|
+
|
44
|
+
def register_parent(parent)
|
45
|
+
raise "Cannot register a parent if this node is not a child already. Use add_child to the other node or add_parent to this node." unless
|
46
|
+
parent.children.include?(self)
|
47
|
+
parents << parent unless parents.include?(parent)
|
48
|
+
true
|
49
|
+
end
|
50
|
+
|
51
|
+
protected
|
52
|
+
|
53
|
+
def assert_links(opts)
|
54
|
+
found = opts[:parents]
|
55
|
+
found ||= opts[:parent]
|
56
|
+
found ||= []
|
57
|
+
found = [found] unless found.is_a?(Array)
|
58
|
+
found.each do |parent|
|
59
|
+
add_parent(parent)
|
60
|
+
end
|
61
|
+
|
62
|
+
|
63
|
+
found = opts[:children]
|
64
|
+
found ||= opts[:child]
|
65
|
+
found ||= []
|
66
|
+
found = [found] unless found.is_a?(Array)
|
67
|
+
found.each do |child|
|
68
|
+
add_child(child)
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
72
|
+
def assert_distribution(opts)
|
73
|
+
case opts[:distribution]
|
74
|
+
when Class
|
75
|
+
@distribution = opts[:distribution]
|
76
|
+
when Symbol
|
77
|
+
class_name = opts[:distribution].to_s.downcase.split(/_+/).map {|t| t[0].chr.upcase + t[1..-1]}.join
|
78
|
+
if Fathom::Distributions.constants.include?(class_name)
|
79
|
+
@distribution = "Fathom::Distributions::#{class_name}".constantize
|
80
|
+
end
|
81
|
+
end
|
82
|
+
@distribution ||= Fathom::Distributions::Gaussian
|
83
|
+
end
|
84
|
+
end
|
85
|
+
|
86
|
+
if __FILE__ == $0
|
87
|
+
include Fathom
|
88
|
+
# TODO: Is there anything you want to do to run this file on its own?
|
89
|
+
# Node.new
|
90
|
+
end
|
@@ -0,0 +1,50 @@
|
|
1
|
+
require File.expand_path(File.join(File.dirname(__FILE__), '..', 'fathom'))
|
2
|
+
module Fathom
|
3
|
+
module NumericMethods
|
4
|
+
def initialize(opts={})
|
5
|
+
super(opts)
|
6
|
+
end
|
7
|
+
|
8
|
+
def rand
|
9
|
+
return nil unless vector
|
10
|
+
distribution.rand(sd) + mean
|
11
|
+
end
|
12
|
+
|
13
|
+
def vector
|
14
|
+
return @vector if @vector
|
15
|
+
return nil unless values
|
16
|
+
case values
|
17
|
+
when Array
|
18
|
+
@vector = GSL::Vector.ary_to_gv(values)
|
19
|
+
when GSL::Vector
|
20
|
+
@vector = values
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
def standard_deviation
|
25
|
+
return nil unless vector
|
26
|
+
vector.sd
|
27
|
+
end
|
28
|
+
alias :std :standard_deviation
|
29
|
+
alias :sd :standard_deviation
|
30
|
+
|
31
|
+
def mean
|
32
|
+
return nil unless vector
|
33
|
+
vector.mean
|
34
|
+
end
|
35
|
+
|
36
|
+
def inverse_cdf(opts={})
|
37
|
+
distribution.inverse_cdf(opts.merge(:mean => mean, :sd => sd))
|
38
|
+
end
|
39
|
+
alias :lower_bound :inverse_cdf
|
40
|
+
|
41
|
+
def upper_bound(opts={})
|
42
|
+
distribution.upper_bound(opts.merge(:mean => mean, :sd => sd))
|
43
|
+
end
|
44
|
+
|
45
|
+
def interval_values(opts={})
|
46
|
+
distribution.interval_values(opts.merge(:mean => mean, :sd => sd))
|
47
|
+
end
|
48
|
+
|
49
|
+
end
|
50
|
+
end
|
@@ -1,12 +1,13 @@
|
|
1
1
|
require File.expand_path(File.join(File.dirname(__FILE__), '..', 'fathom'))
|
2
2
|
module Fathom
|
3
|
-
class PlausibleRange
|
3
|
+
class PlausibleRange < Node
|
4
4
|
|
5
|
-
include
|
5
|
+
include NumericMethods
|
6
6
|
|
7
|
-
attr_reader :upper_bound, :lower_bound, :confidence_interval, :
|
7
|
+
attr_reader :upper_bound, :lower_bound, :confidence_interval, :hard_lower_bound, :hard_upper_bound
|
8
8
|
|
9
9
|
def initialize(opts={})
|
10
|
+
super(opts)
|
10
11
|
|
11
12
|
opts = OptionsHash.new(opts)
|
12
13
|
|
@@ -28,9 +29,6 @@ module Fathom
|
|
28
29
|
@confidence_interval ||= opts[:ci]
|
29
30
|
@confidence_interval ||= 0.9
|
30
31
|
|
31
|
-
@name = opts[:name]
|
32
|
-
@description = opts[:description]
|
33
|
-
|
34
32
|
end
|
35
33
|
|
36
34
|
alias :min :lower_bound
|
@@ -40,21 +38,22 @@ module Fathom
|
|
40
38
|
def midpoint
|
41
39
|
@midpoint ||= lower_bound + (range / 2.0)
|
42
40
|
end
|
41
|
+
alias :mean :midpoint
|
43
42
|
|
44
43
|
def range
|
45
44
|
@range ||= upper_bound - lower_bound
|
46
45
|
end
|
47
46
|
|
48
47
|
def standard_deviation
|
49
|
-
@standard_deviation ||= range /
|
48
|
+
@standard_deviation ||= range / distribution.standard_deviations_under(confidence_interval)
|
50
49
|
end
|
51
50
|
alias :std :standard_deviation
|
51
|
+
alias :sd :standard_deviation
|
52
52
|
|
53
|
-
# Not using specific distributions yet
|
54
53
|
def rand
|
55
54
|
value = get_rand
|
56
55
|
until is_bounded?(value) do
|
57
|
-
value= get_rand
|
56
|
+
value = get_rand
|
58
57
|
end
|
59
58
|
value
|
60
59
|
end
|
@@ -82,17 +81,14 @@ module Fathom
|
|
82
81
|
end
|
83
82
|
end
|
84
83
|
|
84
|
+
# Uses the distribution system, but doesn't use a vector to determine the sd, mean, etc.
|
85
|
+
# So keeping this part in-house.
|
85
86
|
def get_rand
|
86
|
-
|
87
|
+
distribution.rand(sd) + mean
|
87
88
|
end
|
88
89
|
|
89
|
-
def rng
|
90
|
-
@rng ||= GSL::Rng.alloc(GSL::Rng::MT19937_1999, Kernel.rand(100_000))
|
91
|
-
end
|
92
90
|
end
|
93
91
|
|
94
|
-
class R < PlausibleRange
|
95
|
-
end
|
96
92
|
end
|
97
93
|
|
98
94
|
if __FILE__ == $0
|
@@ -25,11 +25,9 @@ describe DataNode do
|
|
25
25
|
@dn.name.should eql("Demo Name")
|
26
26
|
end
|
27
27
|
|
28
|
-
# Note, the distributions aren't defined here yet, so this will eventually be
|
29
|
-
# Some sort of Fathom::Distribution::Constant eventually.
|
30
28
|
it "should take an optional distribiution" do
|
31
|
-
@dn = DataNode.new(@opts.merge(:distribution => :
|
32
|
-
@dn.distribution.should eql(
|
29
|
+
@dn = DataNode.new(@opts.merge(:distribution => :gaussian))
|
30
|
+
@dn.distribution.should eql(Fathom::Distributions::Gaussian)
|
33
31
|
end
|
34
32
|
|
35
33
|
it "should create a vector from the values" do
|
@@ -58,4 +56,47 @@ describe DataNode do
|
|
58
56
|
dn.name_sym.should eql(:demo_node)
|
59
57
|
end
|
60
58
|
|
59
|
+
it "should offer the lower bounds at a default confidence level of 0.05" do
|
60
|
+
GSL::Cdf.should_receive(:gaussian_Pinv).with(0.05, @dn.vector.sd).and_return(0.0)
|
61
|
+
@dn.inverse_cdf
|
62
|
+
end
|
63
|
+
|
64
|
+
it "should offer the lower bounds at an arbitrary confidence level" do
|
65
|
+
GSL::Cdf.should_receive(:gaussian_Pinv).with(0.95, @dn.vector.sd).and_return(0.0)
|
66
|
+
@dn.inverse_cdf(:confidence_interval => 0.95)
|
67
|
+
end
|
68
|
+
|
69
|
+
it "should be able to calculate the upper bound by passing upper as a parameter" do
|
70
|
+
GSL::Cdf.should_receive(:gaussian_Qinv).with(0.05, @dn.vector.sd).and_return(0.0)
|
71
|
+
@dn.inverse_cdf(:confidence_interval => 0.05, :upper => true)
|
72
|
+
end
|
73
|
+
|
74
|
+
it "should be able to calculate a lower_bound, an alias for inverse_cdf" do
|
75
|
+
GSL::Cdf.should_receive(:gaussian_Pinv).with(0.05, @dn.vector.sd).and_return(0.0)
|
76
|
+
@dn.lower_bound
|
77
|
+
end
|
78
|
+
|
79
|
+
it "should be able to pass arguments to lower_bound" do
|
80
|
+
GSL::Cdf.should_receive(:gaussian_Pinv).with(0.1, @dn.vector.sd).and_return(0.0)
|
81
|
+
@dn.lower_bound(:confidence_interval => 0.1)
|
82
|
+
end
|
83
|
+
|
84
|
+
it "should be able to calculate an upper_bound, a shortcut for inverse_cdf(confidence_interval, false)" do
|
85
|
+
GSL::Cdf.should_receive(:gaussian_Qinv).with(0.05, @dn.vector.sd).and_return(0.0)
|
86
|
+
@dn.upper_bound
|
87
|
+
end
|
88
|
+
|
89
|
+
it "should be able to pass arguments to upper_bound" do
|
90
|
+
GSL::Cdf.should_receive(:gaussian_Qinv).with(0.1, @dn.vector.sd).and_return(0.0)
|
91
|
+
@dn.upper_bound(:confidence_interval => 0.1)
|
92
|
+
end
|
93
|
+
|
94
|
+
it "should offset the cdf results by the mean" do
|
95
|
+
@dn.lower_bound.should eql(GSL::Cdf.gaussian_Pinv(0.05, @dn.vector.sd) + @dn.vector.mean)
|
96
|
+
end
|
97
|
+
|
98
|
+
it "should return the lower and upper bounds of a confidence interval" do
|
99
|
+
@dn.interval_values.should eql([@dn.lower_bound, @dn.upper_bound])
|
100
|
+
end
|
101
|
+
|
61
102
|
end
|
@@ -0,0 +1,64 @@
|
|
1
|
+
require File.expand_path(File.dirname(__FILE__) + '/../../spec_helper')
|
2
|
+
|
3
|
+
include Fathom::Distributions
|
4
|
+
|
5
|
+
describe DiscreteGaussian do
|
6
|
+
|
7
|
+
# before do
|
8
|
+
# @opts = {:mean => 0, :sd => 0.1, :confidence_interval => 0.05}
|
9
|
+
# end
|
10
|
+
#
|
11
|
+
# it "should provide a GSL::Rng through rng" do
|
12
|
+
# Gaussian.rng.should be_a(GSL::Rng)
|
13
|
+
# end
|
14
|
+
#
|
15
|
+
# it "should be able to generate a random variable through GSL::Rng#gaussian" do
|
16
|
+
# Gaussian.rng.should_receive(:gaussian).and_return(0.5)
|
17
|
+
# Gaussian.rand(1)
|
18
|
+
# end
|
19
|
+
#
|
20
|
+
# it "should be able to generate an inverse CDF" do
|
21
|
+
# Gaussian.inverse_cdf(@opts).should be_close(-0.16448, 0.00001)
|
22
|
+
# end
|
23
|
+
#
|
24
|
+
# it "should require mean as an option for an inverse CDF" do
|
25
|
+
# @opts.delete(:mean)
|
26
|
+
# lambda{Gaussian.inverse_cdf(@opts)}.should raise_error
|
27
|
+
# end
|
28
|
+
#
|
29
|
+
# it "should require a standard deviation for an inverse CDF" do
|
30
|
+
# @opts.delete(:sd)
|
31
|
+
# lambda{Gaussian.inverse_cdf(@opts)}.should raise_error
|
32
|
+
# end
|
33
|
+
#
|
34
|
+
# it "should take std as an alias for sd when creating an inverse CDF" do
|
35
|
+
# @opts.delete(:sd)
|
36
|
+
# Gaussian.inverse_cdf(@opts.merge(:std => 0.1)).should be_close(-0.16448, 0.00001)
|
37
|
+
# end
|
38
|
+
#
|
39
|
+
# it "should take standard_deviation as an alias for sd when creating an inverse CDF" do
|
40
|
+
# @opts.delete(:sd)
|
41
|
+
# Gaussian.inverse_cdf(@opts.merge(:standard_deviation => 0.1)).should be_close(-0.16448, 0.00001)
|
42
|
+
# end
|
43
|
+
#
|
44
|
+
# it "should be able to set upper to true and get Q instead of P" do
|
45
|
+
# Gaussian.inverse_cdf(@opts.merge(:upper =>true)).should be_close(0.16448, 0.00001)
|
46
|
+
# end
|
47
|
+
#
|
48
|
+
# it "should be able to take a different confidence interval" do
|
49
|
+
# Gaussian.inverse_cdf(@opts.merge(:confidence_interval => 0.1)).should be_close(-0.12815, 0.00001)
|
50
|
+
# end
|
51
|
+
#
|
52
|
+
# it "should have a lower_bound alias for inverse_cdf" do
|
53
|
+
# Gaussian.lower_bound(@opts).should eql(Gaussian.inverse_cdf(@opts))
|
54
|
+
# end
|
55
|
+
#
|
56
|
+
# it "should have an upper_bound shortcut for inverse_cdf(:upper => true, ...)" do
|
57
|
+
# Gaussian.upper_bound(@opts).should eql(Gaussian.inverse_cdf(@opts.merge(:upper => true)))
|
58
|
+
# end
|
59
|
+
#
|
60
|
+
# it "should provide interval values, an array of the lower and upper bounds" do
|
61
|
+
# Gaussian.interval_values(@opts.merge(:confidence_interval => 0.9)).should eql([Gaussian.lower_bound(@opts), Gaussian.upper_bound(@opts)])
|
62
|
+
# end
|
63
|
+
end
|
64
|
+
|
File without changes
|
@@ -0,0 +1,64 @@
|
|
1
|
+
require File.expand_path(File.dirname(__FILE__) + '/../../spec_helper')
|
2
|
+
|
3
|
+
include Fathom::Distributions
|
4
|
+
|
5
|
+
describe Gaussian do
|
6
|
+
|
7
|
+
before do
|
8
|
+
@opts = {:mean => 0, :sd => 0.1, :confidence_interval => 0.05}
|
9
|
+
end
|
10
|
+
|
11
|
+
it "should provide a GSL::Rng through rng" do
|
12
|
+
Gaussian.rng.should be_a(GSL::Rng)
|
13
|
+
end
|
14
|
+
|
15
|
+
it "should be able to generate a random variable through GSL::Rng#gaussian" do
|
16
|
+
Gaussian.rng.should_receive(:gaussian).and_return(0.5)
|
17
|
+
Gaussian.rand(1)
|
18
|
+
end
|
19
|
+
|
20
|
+
it "should be able to generate an inverse CDF" do
|
21
|
+
Gaussian.inverse_cdf(@opts).should be_close(-0.16448, 0.00001)
|
22
|
+
end
|
23
|
+
|
24
|
+
it "should require mean as an option for an inverse CDF" do
|
25
|
+
@opts.delete(:mean)
|
26
|
+
lambda{Gaussian.inverse_cdf(@opts)}.should raise_error
|
27
|
+
end
|
28
|
+
|
29
|
+
it "should require a Gaussian deviation for an inverse CDF" do
|
30
|
+
@opts.delete(:sd)
|
31
|
+
lambda{Gaussian.inverse_cdf(@opts)}.should raise_error
|
32
|
+
end
|
33
|
+
|
34
|
+
it "should take std as an alias for sd when creating an inverse CDF" do
|
35
|
+
@opts.delete(:sd)
|
36
|
+
Gaussian.inverse_cdf(@opts.merge(:std => 0.1)).should be_close(-0.16448, 0.00001)
|
37
|
+
end
|
38
|
+
|
39
|
+
it "should take standard_deviation as an alias for sd when creating an inverse CDF" do
|
40
|
+
@opts.delete(:sd)
|
41
|
+
Gaussian.inverse_cdf(@opts.merge(:standard_deviation => 0.1)).should be_close(-0.16448, 0.00001)
|
42
|
+
end
|
43
|
+
|
44
|
+
it "should be able to set upper to true and get Q instead of P" do
|
45
|
+
Gaussian.inverse_cdf(@opts.merge(:upper =>true)).should be_close(0.16448, 0.00001)
|
46
|
+
end
|
47
|
+
|
48
|
+
it "should be able to take a different confidence interval" do
|
49
|
+
Gaussian.inverse_cdf(@opts.merge(:confidence_interval => 0.1)).should be_close(-0.12815, 0.00001)
|
50
|
+
end
|
51
|
+
|
52
|
+
it "should have a lower_bound alias for inverse_cdf" do
|
53
|
+
Gaussian.lower_bound(@opts).should eql(Gaussian.inverse_cdf(@opts))
|
54
|
+
end
|
55
|
+
|
56
|
+
it "should have an upper_bound shortcut for inverse_cdf(:upper => true, ...)" do
|
57
|
+
Gaussian.upper_bound(@opts).should eql(Gaussian.inverse_cdf(@opts.merge(:upper => true)))
|
58
|
+
end
|
59
|
+
|
60
|
+
it "should provide interval values, an array of the lower and upper bounds" do
|
61
|
+
Gaussian.interval_values(@opts.merge(:confidence_interval => 0.9)).should eql([Gaussian.lower_bound(@opts), Gaussian.upper_bound(@opts)])
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|