def test_ma1(self): b = [0.6] ma1 = Arma([], b) zeros = ma1.calculate_zeros() self.assertEqual(len(zeros), 1) self.assertAlmostEqual(zeros[0], -b[0])
def test_number_of_poles_matches_ar_order(self): p = 6 rng = default_rng(4) ar = Arma(rng.normal(size=p), []) poles = ar.calculate_poles() self.assertEqual(len(poles), p)
def test_ar1(self): a = [0.7] ar1 = Arma(a, []) poles = ar1.calculate_poles() self.assertEqual(len(poles), 1) self.assertAlmostEqual(poles[0], a[0])
def test_trivial_arma_with_bias_no_noise(self): bias = 0.75 arma = Arma([], [], bias=bias) y = arma.transform(X=np.zeros(15)) np.testing.assert_allclose(y, bias)
class TestArmaSourceScaling(unittest.TestCase): def setUp(self): self.source_scaling = 1.3 self.rng = np.random.default_rng(1) self.n = 1000 self.source_data = self.rng.normal(size=self.n) self.a = [-1.1, -0.6, -0.1] self.b = [0.5, 0.3] self.arma = Arma(self.a, self.b, source_scaling=self.source_scaling) self.arma_alt = Arma(self.a, self.b, source_scaling=1) self.y, self.x = self.arma.transform(X=self.source_data, return_input=True) self.y_alt, self.x_alt = self.arma_alt.transform(X=self.source_data, return_input=True) def test_output_scaled_by_appropriate_factor(self): np.testing.assert_allclose(self.y, self.source_scaling * self.y_alt) def test_input_not_scaled(self): np.testing.assert_allclose(self.x_alt, self.x) def test_default_scaling_is_one(self): arma_def = Arma(self.a, self.b) y_def = arma_def.transform(X=self.source_data) np.testing.assert_allclose(y_def, self.y_alt)
def test_default_initial_conditions_are_zero(self): n1 = 5 n2 = 8 usage_seq = np.hstack((np.ones(n2, dtype=int), np.zeros(n1, dtype=int))) seqs = [] for i in range(2): if i == 0: ic = ([0.0], [0.0, 0.0]) else: ic = None arma1 = Arma( [0.9], [0.1, -0.2], default_source=sources.GaussianNoise(), ) arma2 = Arma( [0.1, -0.2], [0.3, 0.4, 0.5], default_source=sources.GaussianNoise(), ) seq = sample_switching_models([arma1, arma2], usage_seq, initial_conditions=ic) seqs.append(seq) np.testing.assert_allclose(seqs[0], seqs[1])
def test_number_of_zeros_matches_ma_order(self): q = 5 rng = default_rng(3) ma = Arma([], rng.normal(size=q)) zeros = ma.calculate_zeros() self.assertEqual(len(zeros), q)
def test_model_histories_do_not_matter(self): n1 = 5 n2 = 8 usage_seq = np.hstack((np.ones(n2, dtype=int), np.zeros(n1, dtype=int))) seqs = [] for i in range(2): if i == 0: ic1 = ([0.3], [-0.2, 0.2]) ic2 = ([0.2, 0.1], [-0.1, 0.2, 0.0]) else: ic1 = None ic2 = None arma1 = Arma( [0.9], [0.1, -0.2], default_source=sources.GaussianNoise(), initial_conditions=ic1, ) arma2 = Arma( [0.1, -0.2], [0.3, 0.4, 0.5], default_source=sources.GaussianNoise(), initial_conditions=ic2, ) seq = sample_switching_models([arma1, arma2], usage_seq) seqs.append(seq) np.testing.assert_allclose(seqs[0], seqs[1])
def test_inverse_recovers_input_with_nonzero_bias(self): arma = Arma([1.3, -0.8, 0.2, -0.1], [-0.3, 0.5], bias=0.6) inv_arma = arma.inverse() y = arma.transform(X=self.u) u_again = inv_arma.transform(X=y) np.testing.assert_allclose(self.u, u_again)
def test_inverse_recovers_input_with_zero_bias(self): arma = Arma([-1.1, -0.6, -0.1], [0.5, 0.3]) inv_arma = arma.inverse() y = arma.transform(X=self.u) u_again = inv_arma.transform(X=y) np.testing.assert_allclose(self.u, u_again)
def setUp(self): self.rng = np.random.default_rng(1) self.n = 253 self.source_data = self.rng.normal(size=self.n) self.a = [-1.1, -0.6, -0.1] self.b = [0.5, 0.3] self.arma = Arma(self.a, self.b)
def test_inverse_arma_switches_orders(self): arma = Arma([-1.1, -0.6, -0.1], [0.5, 0.3]) inv_arma = arma.inverse() self.assertEqual(inv_arma.p, arma.q) self.assertEqual(inv_arma.q, arma.p) self.assertEqual(len(inv_arma.a), inv_arma.p) self.assertEqual(len(inv_arma.b), inv_arma.q)
def test_ar1_zero_input(self): alpha = 0.78 y0 = 1.0 ar = Arma([alpha], [], initial_conditions=([y0], [])) n = 10 y = ar.transform(n, X=lambda size: np.zeros(size)) y_exp = y0 * alpha**np.arange(1, n + 1) np.testing.assert_allclose(y, y_exp)
def test_single_model(self): n = 20 a = [0.9] b = [0.1, -0.2] arma1 = Arma(a, b, default_source=sources.GaussianNoise()) seq_exp = arma1.transform(n) arma2 = Arma(a, b, default_source=sources.GaussianNoise()) seq = sample_switching_models([arma2], np.zeros(n, dtype=int)) np.testing.assert_allclose(seq, seq_exp)
def test_ma2(self): b = [-0.5, -0.3] ma2 = Arma([], b) zeros = ma2.calculate_zeros() self.assertEqual(len(zeros), 2) zero_prod = np.prod(zeros) zero_sum = np.sum(zeros) np.testing.assert_allclose(zero_sum, -b[0], atol=1e-8) np.testing.assert_allclose(zero_prod, b[1], atol=1e-8)
def test_ar2(self): a = [0.5, -0.7] ar2 = Arma(a, []) poles = ar2.calculate_poles() self.assertEqual(len(poles), 2) pole_prod = np.prod(poles) pole_sum = np.sum(poles) np.testing.assert_allclose(pole_sum, a[0], atol=1e-8) np.testing.assert_allclose(pole_prod, -a[1], atol=1e-8)
def test_asymptotic_value_constant_noise(self): bias = 0.32 arma = Arma([-1.1, -0.6, -0.1], [0.5, 0.3], bias=bias) # the asymptotic value y0 should be given by # y0 * (1 - sum(a)) = bias + x0 * (1 + sum(b)) # so: y0 = (bias + x0 * (1 + sum(b))) / (1 - sum(a)) x0 = -0.5 # give it enough time to converge n = 1000 y = arma.transform(X=x0 * np.ones(n)) y0 = (bias + x0 * (1 + np.sum(arma.b))) / (1 - np.sum(arma.a)) self.assertAlmostEqual(y[-1], y0)
class TestArmaMonitor(unittest.TestCase): def setUp(self): self.rng = np.random.default_rng(1) self.n = 253 self.source_data = self.rng.normal(size=self.n) self.a = [-1.1, -0.6, -0.1] self.b = [0.5, 0.3] self.arma = Arma(self.a, self.b) def test_monitor_output_matches_transform_retval(self): monitor = AttributeMonitor(["output_"]) y_out = self.arma.transform(X=self.source_data, monitor=monitor) self.assertTrue(hasattr(monitor.history_, "output_")) np.testing.assert_allclose(monitor.history_.output_, y_out) def test_monitor_input_matches_actual_input(self): monitor = AttributeMonitor(["input_"]) self.arma.transform(X=self.source_data, monitor=monitor) self.assertTrue(hasattr(monitor.history_, "input_")) np.testing.assert_allclose(monitor.history_.input_, self.source_data) def test_monitor_is_initialized_on_zero_n_samples(self): monitor = AttributeMonitor(["input_", "output_"]) self.arma.transform(0, monitor=monitor) self.assertTrue(hasattr(monitor.history_, "input_")) self.assertTrue(hasattr(monitor.history_, "output_")) def test_monitor_is_initialized_on_empty_U(self): monitor = AttributeMonitor(["input_", "output_"]) self.arma.transform(X=[], monitor=monitor) self.assertTrue(hasattr(monitor.history_, "input_")) self.assertTrue(hasattr(monitor.history_, "output_")) def test_chunk_hint_does_not_affect_monitoring(self): names = ["input_", "output_"] monitor1 = AttributeMonitor(names) self.arma.transform(X=self.source_data, monitor=monitor1, chunk_hint=11) monitor2 = AttributeMonitor(names) arma2 = Arma(self.a, self.b) arma2.transform(X=self.source_data, monitor=monitor2, chunk_hint=23) np.testing.assert_allclose(monitor1.history_.input_, monitor2.history_.input_) np.testing.assert_allclose(monitor1.history_.output_, monitor2.history_.output_)
def test_chunk_hint_does_not_affect_monitoring(self): names = ["input_", "output_"] monitor1 = AttributeMonitor(names) self.arma.transform(X=self.source_data, monitor=monitor1, chunk_hint=11) monitor2 = AttributeMonitor(names) arma2 = Arma(self.a, self.b) arma2.transform(X=self.source_data, monitor=monitor2, chunk_hint=23) np.testing.assert_allclose(monitor1.history_.input_, monitor2.history_.input_) np.testing.assert_allclose(monitor1.history_.output_, monitor2.history_.output_)
def createArma(default_source: Optional[Callable] = None): return Arma( [-1.1, -0.6, -0.1], [0.5, 0.3], bias=-0.41, default_source=default_source, )
def setUp(self): self.source_scaling = 1.3 self.rng = np.random.default_rng(1) self.n = 1000 self.source_data = self.rng.normal(size=self.n) self.a = [-1.1, -0.6, -0.1] self.b = [0.5, 0.3] self.arma = Arma(self.a, self.b, source_scaling=self.source_scaling) self.arma_alt = Arma(self.a, self.b, source_scaling=1) self.y, self.x = self.arma.transform(X=self.source_data, return_input=True) self.y_alt, self.x_alt = self.arma_alt.transform(X=self.source_data, return_input=True)
def test_ma_is_convolution(self): rng = default_rng(1) q = 3 b = rng.normal(size=q) ma = Arma([], b) n = 52 x = rng.normal(size=n) y = ma.transform(X=x) x_padded = np.hstack((np.zeros(q), x)) b_ext = np.hstack(([1], b)) y_exp = np.convolve(x_padded, b_ext, mode="valid") np.testing.assert_allclose(y, y_exp)
def test_product_of_monomials_based_on_zeros_recovers_ma_coeffs(self): p = 4 q = 4 rng = default_rng(2) arma = Arma(rng.normal(size=p), rng.normal(size=q)) zeros = arma.calculate_zeros() coeffs = np.polynomial.polynomial.polyfromroots(zeros) # make sure the coefficients are real, up to tolerance self.assertLess(np.max(np.abs(np.imag(coeffs))), 1e-6) # ensure that the coefficients are ordered in the proper way coeffs = np.flip(coeffs.real) np.testing.assert_allclose(coeffs[1:], arma.b)
def test_transform_only_one_retval_by_default(self): arma_hsmm = ArmaHSMM(self.armas) n = 16 y_exp, _, _ = arma_hsmm.transform(n, return_input=True, return_usage_seq=True) arma1 = Arma([0.9], [], default_source=sources.GaussianNoise()) arma2 = Arma([0.2, -0.1], [0.3], default_source=sources.GaussianNoise()) arma_hsmm2 = ArmaHSMM([arma1, arma2]) y = arma_hsmm2.transform(n) np.testing.assert_allclose(y, y_exp)
def test_multiple_models(self): n1 = 13 n2 = 23 rng = np.random.default_rng(2) X = rng.normal(size=n1 + n2) arma1 = Arma([0.9], [0.1, -0.2]) arma2 = Arma([0.1, -0.2], [0.3]) _, X_ret = sample_switching_models( [arma1, arma2], np.hstack((np.zeros(n1, dtype=int), np.ones(n2, dtype=int))), X=X, return_input=True, ) np.testing.assert_allclose(X, X_ret)
def test_multiple_models_callable_source(self): n1 = 13 n2 = 23 seed = 12 src = sources.GaussianNoise(seed) X_exp = src(size=n1 + n2) arma1 = Arma([0.9], [0.1, -0.2]) arma2 = Arma([0.1, -0.2], [0.3]) _, X_ret = sample_switching_models( [arma1, arma2], np.hstack((np.zeros(n1, dtype=int), np.ones(n2, dtype=int))), X=sources.GaussianNoise(seed), return_input=True, ) np.testing.assert_allclose(X_exp, X_ret)
def test_initial_conditions_parameter_is_obeyed(self): a = [0.8] b = [0.1, 0.2] n = 32 ic = ([-0.5], [-0.5, 0.3]) arma = Arma(a, b, default_source=sources.GaussianNoise(), initial_conditions=ic) seq_exp = arma.transform(n) arma = Arma(a, b, default_source=sources.GaussianNoise()) seq = sample_switching_models([arma], np.zeros(n, dtype=int), initial_conditions=ic) np.testing.assert_allclose(seq, seq_exp)
def test_correct_history_used_at_switch_point(self): n1 = 13 n2 = 5 arma1 = Arma([0.9], [0.1, -0.2], default_source=sources.GaussianNoise()) a2 = [0.1, -0.2] b2 = [0.3] arma2 = Arma(a2, b2, default_source=sources.GaussianNoise()) seq, X = sample_switching_models( [arma1, arma2], np.hstack((np.zeros(n1, dtype=int), np.ones(n2, dtype=int))), return_input=True, ) exp_ar = np.dot(np.flip(a2), seq[n1 - len(a2):n1]) exp_ma = np.dot(np.flip(b2), X[n1 - len(b2):n1]) + X[n1] self.assertAlmostEqual(exp_ar + exp_ma, seq[n1])
def test_second_model_history_is_not_default(self): n1 = 13 n2 = 23 # these will get overridden seq = [0] seq1_exp = [1] seq2_exp = [2] for i in range(2): arma1 = Arma([0.9], [0.1, -0.2], default_source=sources.GaussianNoise()) arma2 = Arma([0.1, -0.2], [0.3], default_source=sources.GaussianNoise()) if i == 0: seq1_exp = arma1.transform(n1) seq2_exp = arma2.transform(n2) else: seq = sample_switching_models( [arma1, arma2], np.hstack((np.zeros(n1, dtype=int), np.ones(n2, dtype=int))), ) np.testing.assert_allclose(seq[:n1], seq1_exp) self.assertGreater(np.max(np.abs(seq[n1:] - seq2_exp)), 0)
class TestArmaTransformZeroSamples(unittest.TestCase): def setUp(self): # this also implicitly tests that this works without default_source self.arma = Arma([1, 0.5], [-0.3]) def test_zero_samples_returns_empty_output(self): y = self.arma.transform(0) self.assertEqual(len(y), 0) def test_zero_samples_returns_empty_output_and_input_when_return_input_true( self): y, x = self.arma.transform(0, return_input=True) self.assertEqual(len(y), 0) self.assertEqual(len(x), 0) def test_empty_x_returns_empty(self): y, x = self.arma.transform(X=[], return_input=True) self.assertEqual(len(y), 0) self.assertEqual(len(x), 0)