require File.expand_path(File.dirname(__FILE__) + '/../../spec_helper') include Fathom describe DataNode do before do @values = [1,2,3,4,5] @opts = {:values => @values} @dn = DataNode.new(@opts) @vector = GSL::Vector.ary_to_gv(@values) end it "should initialize requiring values in the options" do lambda{DataNode.new}.should raise_error(/values/) lambda{DataNode.new(:values => @values)}.should_not raise_error end it "should make the values readable" do @dn.values.should eql(@values) end it "should allow an optional name for the node" do @dn = DataNode.new(:values => @values, :name => "Demo Name") @dn.name.should eql("Demo Name") end it "should take an optional distribiution" do @dn = DataNode.new(@opts.merge(:distribution => :gaussian)) @dn.distribution.should eql(Fathom::Distributions::Gaussian) end it "should create a vector from the values" do @dn.vector.should ==(@vector) end it "should provide the standard deviation" do @dn.standard_deviation.should ==(@vector.sd) end it "should alias sd and std for standard_deviation" do @dn.sd.should eql(@dn.standard_deviation) @dn.std.should eql(@dn.standard_deviation) end it "should be able to produce the mean" do @dn.mean.should eql(@vector.mean) end it "should generate a random variable that fits the data's distribution" do @dn.rand.should be_a(Float) end it "should have a name_sym method" do dn = DataNode.new(:name => "Demo Node", :values => [1,2,3]) dn.name_sym.should eql(:demo_node) end it "should offer the lower bounds at a default confidence level of 0.05" do GSL::Cdf.should_receive(:gaussian_Pinv).with(0.05, @dn.vector.sd).and_return(0.0) @dn.inverse_cdf end it "should offer the lower bounds at an arbitrary confidence level" do GSL::Cdf.should_receive(:gaussian_Pinv).with(0.95, @dn.vector.sd).and_return(0.0) @dn.inverse_cdf(:confidence_interval => 0.95) end it "should be able to calculate the upper bound by passing upper as a parameter" do GSL::Cdf.should_receive(:gaussian_Qinv).with(0.05, @dn.vector.sd).and_return(0.0) @dn.inverse_cdf(:confidence_interval => 0.05, :upper => true) end it "should be able to calculate a lower_bound, an alias for inverse_cdf" do GSL::Cdf.should_receive(:gaussian_Pinv).with(0.05, @dn.vector.sd).and_return(0.0) @dn.lower_bound end it "should be able to pass arguments to lower_bound" do GSL::Cdf.should_receive(:gaussian_Pinv).with(0.1, @dn.vector.sd).and_return(0.0) @dn.lower_bound(:confidence_interval => 0.1) end it "should be able to calculate an upper_bound, a shortcut for inverse_cdf(confidence_interval, false)" do GSL::Cdf.should_receive(:gaussian_Qinv).with(0.05, @dn.vector.sd).and_return(0.0) @dn.upper_bound end it "should be able to pass arguments to upper_bound" do GSL::Cdf.should_receive(:gaussian_Qinv).with(0.1, @dn.vector.sd).and_return(0.0) @dn.upper_bound(:confidence_interval => 0.1) end it "should offset the cdf results by the mean" do @dn.lower_bound.should eql(GSL::Cdf.gaussian_Pinv(0.05, @dn.vector.sd) + @dn.vector.mean) end it "should return the lower and upper bounds of a confidence interval" do @dn.interval_values.should eql([@dn.lower_bound, @dn.upper_bound]) end end