def test_smoothing(self):
        with self.test_session() as sess:
            ghmm = GaussianHMM(3,
                               transition_variances=[1., 2., 3.],
                               emission_variances=[4., 5., 6.])
            z_prev = tf.constant([1., 2.], dtype=tf.float32)
            xs = tf.constant([[1., 2.], [3., 4.], [5., 6.]], dtype=tf.float32)
            s_post1 = ghmm.smoothing(0, z_prev, xs)
            outs = sess.run([s_post1.mean(), s_post1.variance()])
            expected_outs = [[281. / 421., 410. / 421.],
                             [292. / 421., 292. / 421.]]
            self.assertAllClose(expected_outs, outs)

            expected_outs = [[149. / 73., 222. / 73.], [90. / 73., 90. / 73.]]
            s_post2 = ghmm.smoothing(1, z_prev, xs[1:])
            outs = sess.run([s_post2.mean(), s_post2.variance()])
            self.assertAllClose(expected_outs, outs)

            s_post3 = ghmm.smoothing(2, z_prev, xs[2:])
            outs = sess.run([s_post3.mean(), s_post3.variance()])
            expected_outs = [[7. / 3., 10. / 3.], [2., 2.]]
            self.assertAllClose(expected_outs, outs)
    def test_smoothing_with_weights(self):
        with self.test_session() as sess:
            x_weight = np.array([4, 5, 6, 7], dtype=np.float32)
            sigma_x = np.array([5, 6, 7, 8], dtype=np.float32)
            z_weight = np.array([1, 2, 3], dtype=np.float32)
            sigma_z = np.array([1, 2, 3, 4], dtype=np.float32)
            z_prev = np.array([1, 2], dtype=np.float32)
            batch_size = 2
            xs = np.array([[1, 2], [3, 4], [5, 6], [7, 8]], dtype=np.float32)

            z_cov, x_cov, z_x_cov = self._compute_covariance_matrices(
                x_weight, z_weight, sigma_x, sigma_z)

            expected_outs = []
            # Compute mean and variance for z_0 when we don't condition
            # on previous zs.
            sigma_12 = z_x_cov[0, :]
            sigma_12_22 = np.dot(sigma_12, np.linalg.inv(x_cov))
            mean = np.dot(sigma_12_22, xs)
            variance = np.squeeze(z_cov[0, 0] - np.dot(sigma_12_22, sigma_12))
            expected_outs.append([mean, np.tile(variance, [batch_size])])

            # Compute mean and variance for remaining z_ts.
            for t in xrange(1, 4):
                sigma_12 = np.concatenate([[z_cov[t, t - 1]], z_x_cov[t, t:]])
                sigma_22 = np.vstack(
                    (np.hstack((z_cov[t - 1, t - 1], z_x_cov[t - 1, t:])),
                     np.hstack((np.transpose([z_x_cov[t - 1,
                                                      t:]]), x_cov[t:, t:]))))
                sigma_12_22 = np.dot(sigma_12, np.linalg.inv(sigma_22))
                mean = np.dot(sigma_12_22, np.vstack((z_prev, xs[t:])))
                variance = np.squeeze(z_cov[t, t] -
                                      np.dot(sigma_12_22, sigma_12))
                expected_outs.append([mean, np.tile(variance, [batch_size])])

            ghmm = GaussianHMM(4,
                               transition_variances=sigma_z,
                               emission_variances=sigma_x,
                               transition_weights=z_weight,
                               emission_weights=x_weight)
            out_dists = [
                ghmm.smoothing(t, z_prev, xs[t:]) for t in range(0, 4)
            ]
            outs = [[d.mean(), d.variance()] for d in out_dists]
            run_outs = sess.run(outs)
            self.assertAllClose(expected_outs, run_outs)