fathom 0.2.2 → 0.2.3
Sign up to get free protection for your applications and to get access to all the features.
- 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
|
+
|