statsample-timeseries 0.0.2
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/.document +5 -0
- data/.travis.yml +13 -0
- data/Gemfile +22 -0
- data/LICENSE.txt +22 -0
- data/README.rdoc +72 -0
- data/Rakefile +47 -0
- data/VERSION +1 -0
- data/bin/bio-statsample-timeseries +74 -0
- data/features/acf.feature +31 -0
- data/features/pacf.feature +42 -0
- data/features/step_definitions/bio-statsample-timeseries_steps.rb +0 -0
- data/features/step_definitions/step_definitions.rb +37 -0
- data/features/step_definitions/step_definitions_acf.rb +8 -0
- data/features/support/env.rb +15 -0
- data/lib/statsample-timeseries.rb +18 -0
- data/lib/statsample-timeseries/arima.rb +246 -0
- data/lib/statsample-timeseries/arima/kalman.rb +148 -0
- data/lib/statsample-timeseries/arima/likelihood.rb +101 -0
- data/lib/statsample-timeseries/timeseries.rb +291 -0
- data/lib/statsample-timeseries/timeseries/pacf.rb +164 -0
- data/lib/statsample-timeseries/utility.rb +154 -0
- data/test/fixtures/stock_data.csv +500 -0
- data/test/helper.rb +81 -0
- data/test/test_arima_ks.rb +106 -0
- data/test/test_arima_simulators.rb +186 -0
- data/test/test_matrix.rb +92 -0
- data/test/test_pacf.rb +52 -0
- data/test/test_tseries.rb +103 -0
- data/test/test_wald.rb +71 -0
- metadata +273 -0
data/test/helper.rb
ADDED
@@ -0,0 +1,81 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'bundler'
|
3
|
+
begin
|
4
|
+
Bundler.setup(:default, :development)
|
5
|
+
rescue Bundler::BundlerError => e
|
6
|
+
$stderr.puts e.message
|
7
|
+
$stderr.puts "Run `bundle install` to install missing gems"
|
8
|
+
exit e.status_code
|
9
|
+
end
|
10
|
+
require 'minitest/unit'
|
11
|
+
require 'shoulda'
|
12
|
+
require 'shoulda-context'
|
13
|
+
require 'mocha/setup'
|
14
|
+
|
15
|
+
#require 'statsample-timeseries'
|
16
|
+
|
17
|
+
$LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
|
18
|
+
$LOAD_PATH.unshift(File.dirname(__FILE__))
|
19
|
+
require 'statsample-timeseries'
|
20
|
+
module MiniTest
|
21
|
+
class Unit
|
22
|
+
class TestCase
|
23
|
+
include Shoulda::Context::Assertions
|
24
|
+
include Shoulda::Context::InstanceMethods
|
25
|
+
extend Shoulda::Context::ClassMethods
|
26
|
+
def self.should_with_gsl(name,&block)
|
27
|
+
should(name) do
|
28
|
+
if Statsample.has_gsl?
|
29
|
+
instance_eval(&block)
|
30
|
+
else
|
31
|
+
skip("Requires GSL")
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
module Assertions
|
39
|
+
def assert_similar_vector(exp, obs, delta=1e-10,msg=nil)
|
40
|
+
msg||="Different vectors #{exp} - #{obs}"
|
41
|
+
assert_equal(exp.size, obs.size)
|
42
|
+
exp.data_with_nils.each_with_index {|v,i|
|
43
|
+
assert_in_delta(v,obs[i],delta)
|
44
|
+
}
|
45
|
+
end
|
46
|
+
def assert_equal_vector(exp,obs,delta=1e-10,msg=nil)
|
47
|
+
assert_equal(exp.size, obs.size, "Different size.#{msg}")
|
48
|
+
exp.size.times {|i|
|
49
|
+
assert_in_delta(exp[i],obs[i],delta, "Different element #{i}. \nExpected:\n#{exp}\nObserved:\n#{obs}.#{msg}")
|
50
|
+
}
|
51
|
+
end
|
52
|
+
def assert_equal_matrix(exp,obs,delta=1e-10,msg=nil)
|
53
|
+
assert_equal(exp.row_size, obs.row_size, "Different row size.#{msg}")
|
54
|
+
assert_equal(exp.column_size, obs.column_size, "Different column size.#{msg}")
|
55
|
+
exp.row_size.times {|i|
|
56
|
+
exp.column_size.times {|j|
|
57
|
+
assert_in_delta(exp[i,j],obs[i,j], delta, "Different element #{i},#{j}\nExpected:\n#{exp}\nObserved:\n#{obs}.#{msg}")
|
58
|
+
}
|
59
|
+
}
|
60
|
+
end
|
61
|
+
alias :assert_raise :assert_raises unless method_defined? :assert_raise
|
62
|
+
alias :assert_not_equal :refute_equal unless method_defined? :assert_not_equal
|
63
|
+
alias :assert_not_same :refute_same unless method_defined? :assert_not_same
|
64
|
+
unless method_defined? :assert_nothing_raised
|
65
|
+
def assert_nothing_raised(msg=nil)
|
66
|
+
msg||="Nothing should be raised, but raised %s"
|
67
|
+
begin
|
68
|
+
yield
|
69
|
+
not_raised=true
|
70
|
+
rescue Exception => e
|
71
|
+
not_raised=false
|
72
|
+
msg=sprintf(msg,e)
|
73
|
+
end
|
74
|
+
assert(not_raised,msg)
|
75
|
+
end
|
76
|
+
end
|
77
|
+
end
|
78
|
+
end
|
79
|
+
|
80
|
+
MiniTest::Unit.autorun
|
81
|
+
|
@@ -0,0 +1,106 @@
|
|
1
|
+
require(File.expand_path(File.dirname(__FILE__)+'/helper.rb'))
|
2
|
+
|
3
|
+
class StatsampleArimaKSTestCase < MiniTest::Unit::TestCase
|
4
|
+
|
5
|
+
context("AR(0.5) simulation") do
|
6
|
+
#include Statsample::TimeSeries
|
7
|
+
setup do
|
8
|
+
@s = [-1.16025577,0.64758021,0.77158601,0.14989543,2.31358162,3.49213868,1.14826956,0.58169457,-0.30813868,-0.34741084,-1.41175595,0.06040081, -0.78230232,0.86734837,0.95015787,-0.49781397,0.53247330,1.56495187,0.30936619,0.09750217,1.09698829,-0.81315490,-0.79425607,-0.64568547,-1.06460320,1.24647894,0.66695937,1.50284551,1.17631218,1.64082872,1.61462736,0.06443761,-0.17583741,0.83918339,0.46610988,-0.54915270,-0.56417108,-1.27696654,0.89460084,1.49970338,0.24520493,0.26249138,-1.33744834,-0.57725961,1.55819543,1.62143157,0.44421891,-0.74000084 ,0.57866347,3.51189333,2.39135077,1.73046244,1.81783890,0.21454040,0.43520890,-1.42443856,-2.72124685,-2.51313877,-1.20243091,-1.44268002 ,-0.16777305,0.05780661,2.03533992,0.39187242,0.54987983,0.57865693,-0.96592469,-0.93278473,-0.75962671,-0.63216906,1.06776183, 0.17476059 ,0.06635860,0.94906227,2.44498583,-1.04990407,-0.88440073,-1.99838258,-1.12955558,-0.62654882,-1.36589161,-2.67456821,-0.97187696, -0.84431782 ,-0.10051809,0.54239549,1.34622861,1.25598105,0.19707759,3.29286114,3.52423499,1.69146333,-0.10150024,0.45222903,-0.01730516, -0.49828727, -1.18484684,-1.09531773,-1.17190808,0.30207662].to_ts
|
9
|
+
end
|
10
|
+
context "passed through the Kalman Filter" do
|
11
|
+
setup do
|
12
|
+
@kf=Statsample::TimeSeries::ARIMA.ks(@s,1,0,0)
|
13
|
+
end
|
14
|
+
should "return correct object" do
|
15
|
+
assert_instance_of Statsample::TimeSeries::Arima::KalmanFilter, @kf
|
16
|
+
end
|
17
|
+
should "return correct parameters" do
|
18
|
+
assert_equal @kf.p,1
|
19
|
+
assert_equal @kf.q,0
|
20
|
+
assert_equal @kf.i,0
|
21
|
+
end
|
22
|
+
should "return correct ar estimators" do
|
23
|
+
assert_equal @kf.ar.length,1
|
24
|
+
assert_in_delta @kf.ar[0], 0.700 #0.564
|
25
|
+
end
|
26
|
+
should "return correct ma estimators" do
|
27
|
+
assert_equal @kf.ma.length,0
|
28
|
+
end
|
29
|
+
end
|
30
|
+
context "passed through the Kalman Filter with AR(0.564)" do
|
31
|
+
setup do
|
32
|
+
@kf_likehood=Statsample::TimeSeries::Arima::KalmanFilter.log_likelihood([0.564],@s,1,0)
|
33
|
+
end
|
34
|
+
should "return correct object for log_likehood" do
|
35
|
+
assert_instance_of Statsample::TimeSeries::Arima::KF::LogLikelihood, @kf_likehood
|
36
|
+
end
|
37
|
+
should "return correct log_likehood" do
|
38
|
+
assert_in_delta -148.7003, @kf_likehood.log_likelihood
|
39
|
+
end
|
40
|
+
should "return correct sigma" do
|
41
|
+
assert_in_delta 1.137915, @kf_likehood.sigma
|
42
|
+
end
|
43
|
+
should "return correct AIC value" do
|
44
|
+
assert_in_delta 301.44, @kf_likehood.aic, 0.1
|
45
|
+
end
|
46
|
+
|
47
|
+
end
|
48
|
+
context "passed through the Kalman Filter with AR(0.2)" do
|
49
|
+
setup do
|
50
|
+
@kf_likehood=Statsample::TimeSeries::Arima::KalmanFilter.log_likelihood([0.2],@s,1,0)
|
51
|
+
end
|
52
|
+
should "return correct object for log_likehood" do
|
53
|
+
assert_instance_of Statsample::TimeSeries::Arima::KF::LogLikelihood, @kf_likehood
|
54
|
+
end
|
55
|
+
should "return correct log_likehood" do
|
56
|
+
assert_in_delta -66.40337-0.5*@s.size*(Math.log(2*Math::PI)), @kf_likehood.log_likelihood, 0.01
|
57
|
+
end
|
58
|
+
should "return correct sigma" do
|
59
|
+
assert_in_delta 1.378693, @kf_likehood.sigma, 0.01
|
60
|
+
end
|
61
|
+
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
context("ARMA(1, 1) process") do
|
66
|
+
setup do
|
67
|
+
@s = [-1.16025577,0.64758021,0.77158601,0.14989543,2.31358162,3.49213868,1.14826956,0.58169457,-0.30813868,-0.34741084,-1.41175595,0.06040081, -0.78230232,0.86734837,0.95015787,-0.49781397,0.53247330,1.56495187,0.30936619,0.09750217,1.09698829,-0.81315490,-0.79425607,-0.64568547,-1.06460320,1.24647894,0.66695937,1.50284551,1.17631218,1.64082872,1.61462736,0.06443761,-0.17583741,0.83918339,0.46610988,-0.54915270,-0.56417108,-1.27696654,0.89460084,1.49970338,0.24520493,0.26249138,-1.33744834,-0.57725961,1.55819543,1.62143157,0.44421891,-0.74000084 ,0.57866347,3.51189333,2.39135077,1.73046244,1.81783890,0.21454040,0.43520890,-1.42443856,-2.72124685,-2.51313877,-1.20243091,-1.44268002 ,-0.16777305,0.05780661,2.03533992,0.39187242,0.54987983,0.57865693,-0.96592469,-0.93278473,-0.75962671,-0.63216906,1.06776183, 0.17476059 ,0.06635860,0.94906227,2.44498583,-1.04990407,-0.88440073,-1.99838258,-1.12955558,-0.62654882,-1.36589161,-2.67456821,-0.97187696, -0.84431782 ,-0.10051809,0.54239549,1.34622861,1.25598105,0.19707759,3.29286114,3.52423499,1.69146333,-0.10150024,0.45222903,-0.01730516, -0.49828727, -1.18484684,-1.09531773,-1.17190808,0.30207662].to_ts
|
68
|
+
end
|
69
|
+
context "passed through the Kalman Filter" do
|
70
|
+
setup do
|
71
|
+
@kf = Statsample::TimeSeries::ARIMA.ks(@s, 2, 0, 1)
|
72
|
+
end
|
73
|
+
|
74
|
+
should "return correct parameters" do
|
75
|
+
assert_equal @kf.p, 2
|
76
|
+
assert_equal @kf.q, 1
|
77
|
+
assert_equal @kf.i, 0
|
78
|
+
end
|
79
|
+
should "return correct AR estimators" do
|
80
|
+
assert_equal @kf.ar.length, 2
|
81
|
+
assert_in_delta @kf.ar[0], 0.45, 0.01
|
82
|
+
assert_in_delta @kf.ar[1], 0.016, 0.01
|
83
|
+
end
|
84
|
+
should "return correct ma estimators" do
|
85
|
+
assert_equal @kf.ma.length, 1
|
86
|
+
assert_in_delta @kf.ma[0], 0.18, 0.01
|
87
|
+
end
|
88
|
+
end
|
89
|
+
|
90
|
+
context "passed through the LogLikelihood with ARMA([0.45, 0.16, 0.18])" do
|
91
|
+
setup do
|
92
|
+
@ll = Statsample::TimeSeries::Arima::KF::LogLikelihood.new([0.45, 0.16, 0.18], @s, 2, 1)
|
93
|
+
end
|
94
|
+
should "return correct log likelihood" do
|
95
|
+
assert_in_delta -149.55, @ll.log_likelihood, 0.01
|
96
|
+
end
|
97
|
+
should "return correct sigma" do
|
98
|
+
assert_in_delta 1.14, @ll.sigma, 0.1
|
99
|
+
end
|
100
|
+
should "return correct AIC value" do
|
101
|
+
assert_in_delta 307.11, @ll.aic, 0.01
|
102
|
+
end
|
103
|
+
end
|
104
|
+
end
|
105
|
+
|
106
|
+
end
|
@@ -0,0 +1,186 @@
|
|
1
|
+
require(File.expand_path(File.dirname(__FILE__)+'/helper.rb'))
|
2
|
+
|
3
|
+
class StatsampleArimaSimulatorsTest < MiniTest::Unit::TestCase
|
4
|
+
def generate_acf(simulation)
|
5
|
+
ts = simulation.to_ts
|
6
|
+
ts.acf
|
7
|
+
end
|
8
|
+
|
9
|
+
def generate_pacf(simulation)
|
10
|
+
ts = simulation.to_ts
|
11
|
+
ts.pacf
|
12
|
+
end
|
13
|
+
context("AR(1) simulations") do
|
14
|
+
include Statsample
|
15
|
+
|
16
|
+
setup do
|
17
|
+
@series = TimeSeries.arima
|
18
|
+
@ar_1_positive = @series.ar_sim(1500, [0.9], 2)
|
19
|
+
@ar_1_negative = @series.ar_sim(1500, [-0.9], 2)
|
20
|
+
|
21
|
+
#generating acf
|
22
|
+
@positive_acf = generate_acf(@ar_1_positive)
|
23
|
+
@negative_acf = generate_acf(@ar_1_negative)
|
24
|
+
|
25
|
+
#generating pacf
|
26
|
+
@positive_pacf = generate_pacf(@ar_1_positive)
|
27
|
+
@negative_pacf = generate_pacf(@ar_1_negative)
|
28
|
+
end
|
29
|
+
|
30
|
+
|
31
|
+
should "have exponential decay of acf on positive side with phi > 0" do
|
32
|
+
@acf = @positive_acf
|
33
|
+
assert_equal @acf[0], 1.0
|
34
|
+
assert_operator @acf[1], :>=, 0.7
|
35
|
+
assert_operator @acf[@acf.size - 1], :<=, 0.2
|
36
|
+
#visualization:
|
37
|
+
#https://dl.dropboxusercontent.com/u/102071534/sciruby/AR%281%29_positive_phi_acf.png
|
38
|
+
#https://dl.dropboxusercontent.com/u/102071534/sciruby/AR%281%29_positive_phi_acf_line.png
|
39
|
+
end
|
40
|
+
|
41
|
+
should "have series with alternating sign on acf starting on negative side with phi < 0" do
|
42
|
+
@acf = @negative_acf
|
43
|
+
assert_equal @acf[0], 1.0
|
44
|
+
#testing for alternating series
|
45
|
+
assert_operator @acf[1], :<, 0
|
46
|
+
assert_operator @acf[2], :>, 0
|
47
|
+
assert_operator @acf[3], :<, 0
|
48
|
+
assert_operator @acf[4], :>, 0
|
49
|
+
#visualization:
|
50
|
+
#https://dl.dropboxusercontent.com/u/102071534/sciruby/AR%281%29_negative_phi_acf.png
|
51
|
+
#https://dl.dropboxusercontent.com/u/102071534/sciruby/AR%281%29_negative_phi_acf_line.png
|
52
|
+
end
|
53
|
+
|
54
|
+
should "have positive spike on pacf at lag 1 for phi > 0" do
|
55
|
+
@pacf = @positive_pacf
|
56
|
+
assert_operator @pacf[1], :>=, 0.7
|
57
|
+
assert_operator @pacf[2], :<=, 0.2
|
58
|
+
assert_operator @pacf[3], :<=, 0.14
|
59
|
+
#visualization:
|
60
|
+
#https://dl.dropboxusercontent.com/u/102071534/sciruby/AR%281%29_postive_phi_pacf.png
|
61
|
+
#https://dl.dropboxusercontent.com/u/102071534/sciruby/AR%281%29_postive_phi_pacf_line.png
|
62
|
+
end
|
63
|
+
|
64
|
+
should "have negative spike on pacf at lag 1 for phi < 0" do
|
65
|
+
@pacf = @negative_pacf
|
66
|
+
assert_operator @pacf[1], :<=, 0
|
67
|
+
assert_operator @pacf[1], :<=, -0.5
|
68
|
+
assert_operator @pacf[2], :>=, -0.5
|
69
|
+
#visualizaton:
|
70
|
+
#https://dl.dropboxusercontent.com/u/102071534/sciruby/AR%281%29_negative_phi_pacf.png
|
71
|
+
#[hided @pacf[0] = 1 to convey accurate picture]
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
75
|
+
context("AR(p) simulations") do
|
76
|
+
include Statsample
|
77
|
+
|
78
|
+
setup do
|
79
|
+
@series = TimeSeries.arima
|
80
|
+
@ar_p_positive = @series.ar_sim(1500, [0.3, 0.5], 2)
|
81
|
+
@ar_p_negative = @series.ar_sim(1500, [-0.3, -0.5], 2)
|
82
|
+
end
|
83
|
+
|
84
|
+
|
85
|
+
should "have damped sine wave starting on positive side on acf" do
|
86
|
+
@ar = @ar_p_positive
|
87
|
+
@acf = generate_acf(@ar)
|
88
|
+
assert_operator @acf[0], :>=, @acf[1]
|
89
|
+
assert_operator @acf[1], :>=, 0.0
|
90
|
+
#caution: sine curve can split on cartesian plane,
|
91
|
+
#visualization:
|
92
|
+
#https://dl.dropboxusercontent.com/u/102071534/sciruby/AR(p)_positive_phi_sine_wave.png
|
93
|
+
end
|
94
|
+
|
95
|
+
should "have damped sine wave starting on negative side on acf" do
|
96
|
+
@ar = @ar_p_negative
|
97
|
+
@acf = generate_acf(@ar)
|
98
|
+
assert_operator @acf[0], :>=, @acf[1]
|
99
|
+
assert_operator @acf[1], :<=, 0.0
|
100
|
+
assert_operator @acf[1], :>=, @acf[2]
|
101
|
+
#caution: sine curve can split on cartesian plane,
|
102
|
+
#visualization:
|
103
|
+
#https://dl.dropboxusercontent.com/u/102071534/sciruby/AR%28p%29_negative_phi_acf_sine_wave.png
|
104
|
+
end
|
105
|
+
|
106
|
+
should "have spikes from 1 to p for pacf" do
|
107
|
+
#here p = 2
|
108
|
+
@ar = @ar_p_positive
|
109
|
+
@pacf = generate_pacf(@ar)
|
110
|
+
assert_equal @pacf[0], 1.0
|
111
|
+
assert_operator @pacf[1], :>, @pacf[3]
|
112
|
+
assert_operator @pacf[1], :>, @pacf[4]
|
113
|
+
assert_operator @pacf[1], :>, @pacf[5]
|
114
|
+
assert_operator @pacf[2], :>, @pacf[3]
|
115
|
+
assert_operator @pacf[2], :>, @pacf[4]
|
116
|
+
#visualization:
|
117
|
+
#https://dl.dropboxusercontent.com/u/102071534/sciruby/AR(p)_positive_phi_pacf_spikes.png
|
118
|
+
end
|
119
|
+
end
|
120
|
+
|
121
|
+
|
122
|
+
context("MA(1) simulations") do
|
123
|
+
include Statsample
|
124
|
+
setup do
|
125
|
+
@series = TimeSeries.arima
|
126
|
+
@ma_positive = @series.ar_sim(1500, [0.5], 2)
|
127
|
+
@ma_negative = @series.ar_sim(1500, [-0.5], 2)
|
128
|
+
end
|
129
|
+
|
130
|
+
should "have one positive spike at lag 1 on acf at positive theta" do
|
131
|
+
@acf = generate_acf(@ma_positive)
|
132
|
+
assert_equal @acf[0], 1.0
|
133
|
+
assert_operator @acf[1], :>=, 0 #test if positive
|
134
|
+
#test if spike
|
135
|
+
assert_operator @acf[2], :>=, 0.1
|
136
|
+
assert_operator @acf[3], :<=, 0.2
|
137
|
+
assert_operator @acf[4], :<=, 0.2
|
138
|
+
#visualization:
|
139
|
+
#https://dl.dropboxusercontent.com/u/102071534/sciruby/MA%281%29_postive_acf.png
|
140
|
+
end
|
141
|
+
|
142
|
+
should "have one negative spike at lag 1 on acf at negative theta" do
|
143
|
+
@acf = generate_acf(@ma_negative)
|
144
|
+
assert_operator @acf[1], :<, 0
|
145
|
+
assert_operator @acf[2], :>=, @acf[1]
|
146
|
+
assert_operator @acf[3], :>=, @acf[1]
|
147
|
+
#visualization:
|
148
|
+
#https://dl.dropboxusercontent.com/u/102071534/sciruby/MA%281%29_negative_acf.png
|
149
|
+
#positive_vs_negative:
|
150
|
+
#https://dl.dropboxusercontent.com/u/102071534/sciruby/MA%281%29_acf_positive_vs_negative.png
|
151
|
+
end
|
152
|
+
|
153
|
+
end
|
154
|
+
|
155
|
+
context("MA(q) simulations") do
|
156
|
+
include Statsample
|
157
|
+
setup do
|
158
|
+
@series = TimeSeries.arima
|
159
|
+
@ma_positive = @series.ar_sim(1500, [0.5, 0.3, 0.2], 2)
|
160
|
+
@ma_negative = @series.ar_sim(1500, [-0.5], 2)
|
161
|
+
end
|
162
|
+
|
163
|
+
should "have q positive spikes at lag 1 to q on acf at positive thetas" do
|
164
|
+
@acf = generate_acf(@ma_positive)
|
165
|
+
assert_operator @acf[1], :>=, @acf[2]
|
166
|
+
assert_operator @acf[2], :>=, @acf[3]
|
167
|
+
assert_operator @acf[3], :>=, @acf[4]
|
168
|
+
#Visualization: http://jsfiddle.net/YeK2c/
|
169
|
+
end
|
170
|
+
|
171
|
+
should "have damped sine wave on pacf at positive thetas" do
|
172
|
+
#visualization: http://jsfiddle.net/7keHK/2/
|
173
|
+
end
|
174
|
+
end
|
175
|
+
|
176
|
+
context("Yule walker estimations") do
|
177
|
+
include Statsample
|
178
|
+
|
179
|
+
setup do
|
180
|
+
@timeseries = 100.times.map { rand }.to_ts
|
181
|
+
@arma_simulation =->(n) { @timeseries.ar(n, k)}
|
182
|
+
end
|
183
|
+
#to write test
|
184
|
+
end
|
185
|
+
end
|
186
|
+
|
data/test/test_matrix.rb
ADDED
@@ -0,0 +1,92 @@
|
|
1
|
+
require(File.expand_path(File.dirname(__FILE__)+'/helper.rb'))
|
2
|
+
class StatsampleMatrixTestCase < MiniTest::Unit::TestCase
|
3
|
+
|
4
|
+
def setup_square_matrix(arr, n)
|
5
|
+
#returns n * n matrix by slicing arr
|
6
|
+
return Matrix.rows(arr.each_slice(n).to_a)
|
7
|
+
end
|
8
|
+
def setup
|
9
|
+
@arr_square = (1..16)
|
10
|
+
@mat_non_symmetric = setup_square_matrix(@arr_square, 4)
|
11
|
+
|
12
|
+
@arr_non_square = (1..12).to_a
|
13
|
+
#this is a 4 X 3 matrix
|
14
|
+
@mat_non_square = Matrix.rows(@arr_non_square.each_slice(3).to_a)
|
15
|
+
end
|
16
|
+
|
17
|
+
#TESTS for matrix symmetricity - Matrix#symmetric?
|
18
|
+
context("symmetric?") do
|
19
|
+
|
20
|
+
should "return false for non-symmetric matrix" do
|
21
|
+
assert_equal @mat_non_symmetric.symmetric?, false
|
22
|
+
end
|
23
|
+
|
24
|
+
should "return false for non-square matrix" do
|
25
|
+
assert_equal @mat_non_square.symmetric?, false
|
26
|
+
end
|
27
|
+
|
28
|
+
should "return true for symmetrix matrix" do
|
29
|
+
arr = %w[4 12 -16 12 37 -43 -16 -43 93].map(&:to_i)
|
30
|
+
mat = setup_square_matrix(arr, 3)
|
31
|
+
assert_equal mat.symmetric?, true
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
#TESTS for cholesky decomposition - Matrix#cholesky
|
36
|
+
context("Cholesky Decomposition") do
|
37
|
+
|
38
|
+
should "raise error for non symmetric matrix" do
|
39
|
+
assert_raises(ArgumentError) { @mat_non_symmetric.cholesky }
|
40
|
+
end
|
41
|
+
|
42
|
+
should "raise raise error if non-square matix" do
|
43
|
+
arr = (1..12).to_a
|
44
|
+
mat = Matrix.rows(arr.each_slice(3).to_a)
|
45
|
+
assert_raises(ArgumentError) { @mat_non_square.cholesky }
|
46
|
+
end
|
47
|
+
|
48
|
+
should "give hermitian cholesky decomposed matrix for symmetrix matrix" do
|
49
|
+
arr = %w[4 12 -16 12 37 -43 -16 -43 93].map(&:to_i)
|
50
|
+
mat = setup_square_matrix(arr, 3)
|
51
|
+
assert_equal Matrix[[2.0, 0, 0], [6.0, 1.0, 0], [-8.0, 5.0, 2.0]], mat.cholesky
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
#TESTS for matrix squares of sum - Matrix#squares_of_sum
|
56
|
+
context("Squares of sum") do
|
57
|
+
|
58
|
+
should "return array of size 4 for matrix - #{@mat_non_symmetric}" do
|
59
|
+
#equal to column size
|
60
|
+
assert_equal @mat_non_symmetric.squares_of_sum.size, 4
|
61
|
+
end
|
62
|
+
|
63
|
+
should "return [784, 1024, 1296, 1600] for matrix - #{@mat_non_symmetric}" do
|
64
|
+
assert_equal @mat_non_symmetric.squares_of_sum, [784, 1024, 1296, 1600]
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
#TESTS for adding constants to matrix
|
69
|
+
context("Add constant") do
|
70
|
+
|
71
|
+
should "prepend all rows with ones" do
|
72
|
+
mat = @mat_non_symmetric.add_constant
|
73
|
+
assert_equal @mat_non_symmetric.column_size, 4
|
74
|
+
assert_equal mat.column_size, 5
|
75
|
+
assert_equal mat.column(0).to_a, [1.0, 1.0,1.0,1.0]
|
76
|
+
end
|
77
|
+
|
78
|
+
should "append all rows with ones if prepend = false" do
|
79
|
+
mat = @mat_non_symmetric.add_constant(false)
|
80
|
+
assert_equal @mat_non_symmetric.column_size, 4
|
81
|
+
assert_equal mat.column_size, 5
|
82
|
+
assert_equal mat.column(mat.column_size - 1).to_a, [1.0, 1.0,1.0,1.0]
|
83
|
+
end
|
84
|
+
|
85
|
+
should "not append/prepend if a column of ones already exists in matrix" do
|
86
|
+
matrix = Matrix[[1, 2, 1, 4], [5, 6, 1, 8], [9, 10, 1, 12]]
|
87
|
+
const_mat = matrix.add_constant
|
88
|
+
assert_equal matrix.column_size, const_mat.column_size
|
89
|
+
assert_equal matrix.row_size, const_mat.row_size
|
90
|
+
end
|
91
|
+
end
|
92
|
+
end
|