예제 #1
0
 def test_rbf_scaling_invariance(self):
     dim = 5
     ker_par = np.array([[1, 3, 3, 3, 3, 3]], dtype=np.float)
     tf = GaussianProcessTransform(dim, 1, ker_par)
     w0 = tf.weights([1] + dim * [1000])
     w1 = tf.weights([358.0] + dim * [1000.0])
     self.assertTrue(
         np.alltrue([np.array_equal(a, b) for a, b in zip(w0, w1)]))
예제 #2
0
    def __init__(self,
                 dyn,
                 obs,
                 kern_par_dyn,
                 kern_par_obs,
                 point_hyp=None,
                 dof=4.0,
                 fixed_dof=True):
        """
        Student filter with Gaussian Process quadrature moment transforms using fully-symmetric sigma-point set.

        Parameters
        ----------
        dyn : TransitionModel

        obs : MeasurementModel

        kern_par_dyn : numpy.ndarray
            Kernel parameters for the GPQ moment transform of the dynamics.

        kern_par_obs : numpy.ndarray
            Kernel parameters for the GPQ moment transform of the measurement function.

        point_hyp : dict
            Point set parameters with keys:
              * `'degree'`: Degree (order) of the quadrature rule.
              * `'kappa'`: Tuning parameter of controlling spread of sigma-points around the center.

        dof : float
            Desired degree of freedom for the filtered density.

        fixed_dof : bool
            If `True`, DOF will be fixed for all time steps, which preserves the heavy-tailed behaviour of the filter.
            If `False`, DOF will be increasing after each measurement update, which means the heavy-tailed behaviour is
            not preserved and therefore converges to a Gaussian filter.
        """

        # degrees of freedom for SSM noises
        _, _, q_dof = dyn.noise_rv.get_stats()
        _, _, r_dof = obs.noise_rv.get_stats()

        # add DOF of the noises to the sigma-point parameters
        if point_hyp is None:
            point_hyp = dict()
        point_hyp_dyn = point_hyp
        point_hyp_obs = point_hyp
        point_hyp_dyn.update({'dof': q_dof})
        point_hyp_obs.update({'dof': r_dof})

        # init moment transforms
        t_dyn = GaussianProcessTransform(dyn.dim_in, kern_par_dyn,
                                         'rbf-student', 'fs', point_hyp_dyn)
        t_obs = GaussianProcessTransform(obs.dim_in, kern_par_obs,
                                         'rbf-student', 'fs', point_hyp_obs)
        super(GPQStudent, self).__init__(dyn, obs, t_dyn, t_obs, dof,
                                         fixed_dof)
예제 #3
0
 def test_integral_variance(self):
     dim = 2
     ker_par = np.array([[1, 3, 3]], dtype=np.float)
     tf = GaussianProcessTransform(dim, 1, ker_par, point_str='sr')
     ivar0 = tf.model.integral_variance([1, 600, 6])
     ivar1 = tf.model.integral_variance([1.1, 600, 6])
     # expected model variance must be positive even for numerically unpleasant settings
     self.assertTrue(np.alltrue(np.array([ivar0, ivar1]) >= 0))
예제 #4
0
 def test_expected_model_variance(self):
     dim = 2
     ker_par = np.array([[1, 3, 3]], dtype=np.float)
     tf = GaussianProcessTransform(dim, 1, ker_par, point_str='sr')
     emv0 = tf.model.exp_model_variance(ker_par)
     emv1 = tf.model.exp_model_variance(ker_par)
     # expected model variance must be positive even for numerically unpleasant settings
     self.assertTrue(np.alltrue(np.array([emv0, emv1]) >= 0))
예제 #5
0
    def test_weights_rbf(self):
        dim = 1
        khyp = np.array([[1, 3]], dtype=np.float)
        phyp = {'kappa': 0.0, 'alpha': 1.0}
        tf = GaussianProcessTransform(dim, 1, khyp, point_par=phyp)
        wm, wc, wcc = tf.wm, tf.Wc, tf.Wcc
        print('wm = \n{}\nwc = \n{}\nwcc = \n{}'.format(wm, wc, wcc))
        self.assertTrue(np.allclose(wc, wc.T),
                        "Covariance weight matrix not symmetric.")
        # print 'GP model variance: {}'.format(tf.model.exp_model_variance())

        dim = 2
        khyp = np.array([[1, 3, 3]], dtype=np.float)
        phyp = {'kappa': 0.0, 'alpha': 1.0}
        tf = GaussianProcessTransform(dim, 1, khyp, point_par=phyp)
        wm, wc, wcc = tf.wm, tf.Wc, tf.Wcc
        print('wm = \n{}\nwc = \n{}\nwcc = \n{}'.format(wm, wc, wcc))
        self.assertTrue(np.allclose(wc, wc.T),
                        "Covariance weight matrix not symmetric.")
예제 #6
0
    def test_apply(self):
        for mod in self.models:
            f = mod.dyn_eval
            dim = mod.dim_in
            ker_par = np.hstack((np.ones((1, 1)), 3 * np.ones((1, dim))))
            tf = GaussianProcessTransform(dim, dim, ker_par)
            mean, cov = np.zeros(dim, ), np.eye(dim)
            tmean, tcov, tccov = tf.apply(f, mean, cov, np.atleast_1d(1.0))
            print("Transformed moments\nmean: {}\ncov: {}\nccov: {}".format(
                tmean, tcov, tccov))

            self.assertTrue(tf.I_out.shape == (dim, dim))
            # test positive definiteness
            try:
                la.cholesky(tcov)
            except la.LinAlgError:
                self.fail("Output covariance not positive definite.")

            # test symmetry
            self.assertTrue(np.allclose(tcov, tcov.T),
                            "Output covariance not closely symmetric.")
예제 #7
0
    def test_einsum_dot(self):
        # einsum and dot give different results?

        dim_in, dim_out = 2, 1
        ker_par_mo = np.hstack((np.ones((dim_out, 1)), 1 * np.ones((dim_out, dim_in))))
        tf_mo = GaussianProcessTransform(dim_in, dim_out, ker_par_mo, point_str='sr')
        iK, Q = tf_mo.model.iK, tf_mo.model.Q

        C1 = iK.dot(Q).dot(iK)
        C2 = np.einsum('ab, bc, cd', iK, Q, iK)

        self.assertTrue(np.allclose(C1, C2), "MAX DIFF: {:.4e}".format(np.abs(C1 - C2).max()))
예제 #8
0
def gpq_int_var_demo():
    """Compares integral variances of GPQ and GPQ+D by plotting."""
    d = 1
    f = UNGMTransition(GaussRV(d), GaussRV(d)).dyn_eval
    mean = np.zeros(d)
    cov = np.eye(d)
    kpar = np.array([[10.0] + d * [0.7]])
    gpq = GaussianProcessTransform(d,
                                   1,
                                   kern_par=kpar,
                                   kern_str='rbf',
                                   point_str='ut',
                                   point_par={'kappa': 0.0})
    gpqd = GaussianProcessDerTransform(d,
                                       1,
                                       kern_par=kpar,
                                       point_str='ut',
                                       point_par={'kappa': 0.0})
    mct = MonteCarloTransform(d, n=1e4)
    mean_gpq, cov_gpq, cc_gpq = gpq.apply(f, mean, cov, np.atleast_1d(1.0))
    mean_gpqd, cov_gpqd, cc_gpqd = gpqd.apply(f, mean, cov, np.atleast_1d(1.0))
    mean_mc, cov_mc, cc_mc = mct.apply(f, mean, cov, np.atleast_1d(1.0))

    xmin_gpq = norm.ppf(0.0001, loc=mean_gpq, scale=gpq.model.integral_var)
    xmax_gpq = norm.ppf(0.9999, loc=mean_gpq, scale=gpq.model.integral_var)
    xmin_gpqd = norm.ppf(0.0001, loc=mean_gpqd, scale=gpqd.model.integral_var)
    xmax_gpqd = norm.ppf(0.9999, loc=mean_gpqd, scale=gpqd.model.integral_var)
    xgpq = np.linspace(xmin_gpq, xmax_gpq, 500)
    ygpq = norm.pdf(xgpq, loc=mean_gpq, scale=gpq.model.integral_var)
    xgpqd = np.linspace(xmin_gpqd, xmax_gpqd, 500)
    ygpqd = norm.pdf(xgpqd, loc=mean_gpqd, scale=gpqd.model.integral_var)
    plt.figure()
    plt.plot(xgpq, ygpq, lw=2, label='gpq')
    plt.plot(xgpqd, ygpqd, lw=2, label='gpq+d')
    plt.gca().add_line(
        Line2D([mean_mc, mean_mc], [0, 150], linewidth=2, color='k'))
    plt.legend()
    plt.show()
예제 #9
0
    def test_cho_dot_ein(self):
        # attempt to compute the transformed covariance using cholesky decomposition

        # integrand
        # input moments
        mean_in = np.array([6500.4, 349.14, 1.8093, 6.7967, 0.6932])
        cov_in = np.diag([1e-6, 1e-6, 1e-6, 1e-6, 1])

        f = ReentryVehicle2DTransition(GaussRV(5, mean_in, cov_in), GaussRV(3)).dyn_eval
        dim_in, dim_out = ReentryVehicle2DTransition.dim_state, 1

        # transform
        ker_par_mo = np.hstack((np.ones((dim_out, 1)), 25 * np.ones((dim_out, dim_in))))
        tf_so = GaussianProcessTransform(dim_in, dim_out, ker_par_mo, point_str='sr')

        # Monte-Carlo for ground truth
        # tf_ut = UnscentedTransform(dim_in)
        # tf_ut.apply(f, mean_in, cov_in, np.atleast_1d(1), None)
        tf_mc = MonteCarloTransform(dim_in, 1000)
        mean_mc, cov_mc, ccov_mc = tf_mc.apply(f, mean_in, cov_in, np.atleast_1d(1))
        C_MC = cov_mc + np.outer(mean_mc, mean_mc.T)

        # evaluate integrand
        x = mean_in[:, None] + la.cholesky(cov_in).dot(tf_so.model.points)
        Y = np.apply_along_axis(f, 0, x, 1.0, None)

        # covariance via np.dot
        iK, Q = tf_so.model.iK, tf_so.model.Q
        C1 = iK.dot(Q).dot(iK)
        C1 = Y.dot(C1).dot(Y.T)

        # covariance via np.einsum
        C2 = np.einsum('ab, bc, cd', iK, Q, iK)
        C2 = np.einsum('ab,bc,cd', Y, C2, Y.T)

        # covariance via np.dot and cholesky
        K = tf_so.model.kernel.eval(tf_so.model.kernel.par, tf_so.model.points)
        L_lower = la.cholesky(K)
        Lq = la.cholesky(Q)
        phi = la.solve(L_lower, Lq)
        psi = la.solve(L_lower, Y.T)
        bet = psi.T.dot(phi)
        C3_dot = bet.dot(bet.T)
        C3_ein = np.einsum('ij, jk', bet, bet.T)

        logging.debug("MAX DIFF: {:.4e}".format(np.abs(C1 - C2).max()))
        logging.debug("MAX DIFF: {:.4e}".format(np.abs(C3_dot - C3_ein).max()))
        self.assertTrue(np.allclose(C1, C2), "MAX DIFF: {:.4e}".format(np.abs(C1 - C2).max()))
        self.assertTrue(np.allclose(C3_dot, C3_ein), "MAX DIFF: {:.4e}".format(np.abs(C3_dot - C3_ein).max()))
        self.assertTrue(np.allclose(C1, C3_dot), "MAX DIFF: {:.4e}".format(np.abs(C1 - C3_dot).max()))
예제 #10
0
    def test_single_vs_multi_output(self):
        # results of the GPQ and GPQMO should be same if parameters properly chosen, GPQ is a special case of GPQMO
        m0 = np.array([6500.4, 349.14, -1.8093, -6.7967, 0.6932])
        P0 = np.diag([1e-6, 1e-6, 1e-6, 1e-6, 1])
        x0 = GaussRV(5, m0, P0)
        dyn = ReentryVehicle2DTransition(x0, GaussRV(5))
        f = dyn.dyn_eval
        dim_in, dim_out = dyn.dim_in, dyn.dim_state

        # input mean and covariance
        mean_in, cov_in = m0, P0

        # single-output GPQ
        ker_par_so = np.hstack((np.ones((1, 1)), 25 * np.ones((1, dim_in))))
        tf_so = GaussianProcessTransform(dim_in, dim_out, ker_par_so)

        # multi-output GPQ
        ker_par_mo = np.hstack((np.ones((dim_out, 1)), 25 * np.ones(
            (dim_out, dim_in))))
        tf_mo = MultiOutputGaussianProcessTransform(dim_in, dim_out,
                                                    ker_par_mo)

        # transformed moments
        # FIXME: transformed covariances different
        mean_so, cov_so, ccov_so = tf_so.apply(f, mean_in, cov_in,
                                               np.atleast_1d(0))
        mean_mo, cov_mo, ccov_mo = tf_mo.apply(f, mean_in, cov_in,
                                               np.atleast_1d(0))

        print('mean delta: {}'.format(np.abs(mean_so - mean_mo).max()))
        print('cov delta: {}'.format(np.abs(cov_so - cov_mo).max()))
        print('ccov delta: {}'.format(np.abs(ccov_so - ccov_mo).max()))

        # results of GPQ and GPQMO should be the same
        self.assertTrue(np.array_equal(mean_so, mean_mo))
        self.assertTrue(np.array_equal(cov_so, cov_mo))
        self.assertTrue(np.array_equal(ccov_so, ccov_mo))
예제 #11
0
def gpq_sos_demo():
    """Sum of squares analytical moments compared with GPQ, GPQ+D and Spherical Radial transforms."""
    # input dimensions
    dims = [1, 5, 10, 25]
    sos_data = np.zeros((6, len(dims)))
    ivar_data = np.zeros((3, len(dims)))
    ivar_data[0, :] = dims
    for di, d in enumerate(dims):
        # input mean and covariance
        mean_in, cov_in = np.zeros(d), np.eye(d)
        # unit sigma-points
        pts = SphericalRadialTransform.unit_sigma_points(d)
        # derivative mask, which derivatives to use
        dmask = np.arange(pts.shape[1])
        # RBF kernel hyper-parameters
        hyp = {
            'gpq': np.array([[1.0] + d * [10.0]]),
            'gpqd': np.array([[1.0] + d * [10.0]]),
        }
        transforms = (
            SphericalRadialTransform(d),
            GaussianProcessTransform(d, 1, kern_par=hyp['gpq'],
                                     point_str='sr'),
            GaussianProcessDerTransform(d,
                                        1,
                                        kern_par=hyp['gpqd'],
                                        point_str='sr',
                                        which_der=dmask),
        )
        ivar_data[1, di] = transforms[1].model.integral_var
        ivar_data[2, di] = transforms[2].model.integral_var
        mean_true, cov_true = d, 2 * d
        # print "{:<15}:\t {:.4f} \t{:.4f}".format("True moments", mean_true, cov_true)
        for ti, t in enumerate(transforms):
            m, c, cc = t.apply(sos, mean_in, cov_in, None)
            sos_data[ti, di] = np.asscalar(m)
            sos_data[ti + len(transforms), di] = np.asscalar(c)
            # print "{:<15}:\t {:.4f} \t{:.4f}".format(t.__class__.__name__, np.asscalar(m), np.asscalar(c))
    row_labels = [t.__class__.__name__ for t in transforms]
    col_labels = [str(d) for d in dims]
    sos_table = pd.DataFrame(sos_data,
                             index=row_labels * 2,
                             columns=col_labels)
    ivar_table = pd.DataFrame(ivar_data[1:, :],
                              index=['GPQ', 'GPQ+D'],
                              columns=col_labels)
    return sos_table, ivar_table, ivar_data
예제 #12
0
def taylor_gpqd_demo(f):
    """Compares performance of GPQ+D-RBF transform w/ finite lengthscale and Linear transform."""
    d = 2  # dimension

    ker_par_gpqd_taylor = np.array([[1.0, 1.0]])  # alpha = 1.0, ell_1 = 1.0
    ker_par_gpq = np.array([[1.0] + d * [1.0]])
    # function to test on
    f = toa  # sum_of_squares
    transforms = (
        LinearizationTransform(d),
        TaylorGPQDTransform(d, ker_par_gpqd_taylor),
        GaussianProcessTransform(d, 1, point_str='ut', kern_par=ker_par_gpq),
        GaussianProcessDerTransform(d, point_str='ut', kern_par=ker_par_gpq),
        UnscentedTransform(d, kappa=0.0),
        # MonteCarlo(d, n=int(1e4)),
    )
    mean = np.array([3, 0])
    cov = np.array([[1, 0], [0, 10]])
    for ti, t in enumerate(transforms):
        mean_f, cov_f, cc = t.apply(f, mean, cov, None)
        print("{}: mean: {}, cov: {}").format(t.__class__.__name__, mean_f,
                                              cov_f)
예제 #13
0
def gpq_polar2cartesian_demo():
    dim = 2

    # Initialize transforms
    # high el[0], because the function is linear given x[1]
    kpar = np.array([[1.0, 600, 6]])
    tf_gpq = GaussianProcessTransform(dim,
                                      1,
                                      kpar,
                                      kern_str='rbf',
                                      point_str='sr')
    tf_sr = SphericalRadialTransform(dim)
    tf_mc = MonteCarloTransform(dim, n=1e4)  # 10k samples

    # Input mean and covariance
    mean_in = np.array([1, np.pi / 2])
    cov_in = np.diag([0.05**2, (np.pi / 10)**2])
    # mean_in = np.array([10, 0])
    # cov_in = np.diag([0.5**2, (5*np.pi/180)**2])

    # Mapped samples
    x = np.random.multivariate_normal(mean_in, cov_in, size=int(1e3)).T
    fx = np.apply_along_axis(polar2cartesian, 0, x, None)

    # MC transformed moments
    mean_mc, cov_mc, cc_mc = tf_mc.apply(polar2cartesian, mean_in, cov_in,
                                         None)
    ellipse_mc = ellipse_points(mean_mc, cov_mc)

    # GPQ transformed moments with ellipse points
    mean_gpq, cov_gpq, cc = tf_gpq.apply(polar2cartesian, mean_in, cov_in,
                                         None)
    ellipse_gpq = ellipse_points(mean_gpq, cov_gpq)

    # SR transformed moments with ellipse points
    mean_sr, cov_sr, cc = tf_sr.apply(polar2cartesian, mean_in, cov_in, None)
    ellipse_sr = ellipse_points(mean_sr, cov_sr)

    # Plots
    plt.figure()

    # MC ground truth mean w/ covariance ellipse
    plt.plot(mean_mc[0], mean_mc[1], 'ro', markersize=6, lw=2)
    plt.plot(ellipse_mc[0, :], ellipse_mc[1, :], 'r--', lw=2, label='MC')

    # GPQ transformed mean w/ covariance ellipse
    plt.plot(mean_gpq[0], mean_gpq[1], 'go', markersize=6)
    plt.plot(ellipse_gpq[0, :], ellipse_gpq[1, :], color='g', label='GPQ')

    # SR transformed mean w/ covariance ellipse
    plt.plot(mean_sr[0], mean_sr[1], 'bo', markersize=6)
    plt.plot(ellipse_sr[0, :], ellipse_sr[1, :], color='b', label='SR')

    # Transformed samples of the input random variable
    plt.plot(fx[0, :], fx[1, :], 'k.', alpha=0.15)
    plt.axes().set_aspect('equal')
    plt.legend()
    plt.show()

    np.set_printoptions(precision=2)
    print("GPQ")
    print("Mean weights: {}".format(tf_gpq.wm))
    print("Cov weight matrix eigvals: {}".format(la.eigvals(tf_gpq.Wc)))
    print("Integral variance: {:.2e}".format(
        tf_gpq.model.integral_variance(None)))
    print("Expected model variance: {:.2e}".format(
        tf_gpq.model.exp_model_variance(None)))
    print("SKL Score:")
    print("SR: {:.2e}".format(
        symmetrized_kl_divergence(mean_mc, cov_mc, mean_sr, cov_sr)))
    print("GPQ: {:.2e}".format(
        symmetrized_kl_divergence(mean_mc, cov_mc, mean_gpq, cov_gpq)))
예제 #14
0
def polar2cartesian_skl_demo():
    num_dim = 2

    # create spiral in polar domain
    r_spiral = lambda x: 10 * x
    theta_min, theta_max = 0.25 * np.pi, 2.25 * np.pi

    # equidistant points on a spiral
    num_mean = 10
    theta_pt = np.linspace(theta_min, theta_max, num_mean)
    r_pt = r_spiral(theta_pt)

    # samples from normal RVs centered on the points of the spiral
    mean = np.array([r_pt, theta_pt])
    r_std = 0.5

    # multiple azimuth covariances in increasing order
    num_cov = 10
    theta_std = np.deg2rad(np.linspace(6, 36, num_cov))
    cov = np.zeros((num_dim, num_dim, num_cov))
    for i in range(num_cov):
        cov[..., i] = np.diag([r_std**2, theta_std[i]**2])

    # COMPARE moment transforms
    ker_par = np.array([[1.0, 60, 6]])
    moment_tforms = OrderedDict([
        ('gpq-sr',
         GaussianProcessTransform(num_dim,
                                  1,
                                  ker_par,
                                  kern_str='rbf',
                                  point_str='sr')),
        ('sr', SphericalRadialTransform(num_dim)),
    ])
    baseline_mtf = MonteCarloTransform(num_dim, n=10000)
    num_tforms = len(moment_tforms)

    # initialize storage of SKL scores
    skl_dict = dict([(mt_str, np.zeros((num_mean, num_cov)))
                     for mt_str in moment_tforms.keys()])

    # for each mean
    for i in range(num_mean):

        # for each covariance
        for j in range(num_cov):
            mean_in, cov_in = mean[..., i], cov[..., j]

            # calculate baseline using Monte Carlo
            mean_out_mc, cov_out_mc, cc = baseline_mtf.apply(
                polar2cartesian, mean_in, cov_in, None)

            # for each MT
            for mt_str in moment_tforms.keys():

                # calculate the transformed moments
                mean_out, cov_out, cc = moment_tforms[mt_str].apply(
                    polar2cartesian, mean_in, cov_in, None)

                # compute SKL
                skl_dict[mt_str][i, j] = symmetrized_kl_divergence(
                    mean_out_mc, cov_out_mc, mean_out, cov_out)

    # PLOT the SKL score for each MT and position on the spiral
    plt.style.use('seaborn-deep')
    printfig = FigurePrint()
    fig = plt.figure()

    # Average over mean indexes
    ax1 = fig.add_subplot(121)
    index = np.arange(num_mean) + 1
    for mt_str in moment_tforms.keys():
        ax1.plot(index,
                 skl_dict[mt_str].mean(axis=1),
                 marker='o',
                 label=mt_str.upper())
    ax1.set_xlabel('Position index')
    ax1.set_ylabel('SKL')

    # Average over azimuth variances
    ax2 = fig.add_subplot(122, sharey=ax1)
    for mt_str in moment_tforms.keys():
        ax2.plot(np.rad2deg(theta_std),
                 skl_dict[mt_str].mean(axis=0),
                 marker='o',
                 label=mt_str.upper())
    ax2.set_xlabel(r'Azimuth STD [$ \circ $]')
    ax2.legend()
    fig.tight_layout(pad=0)

    # save figure
    printfig.savefig('polar2cartesian_skl')
예제 #15
0
def polar2cartesian_skl_demo():
    dim = 2

    # create spiral in polar domain
    r_spiral = lambda x: 10 * x
    theta_min, theta_max = 0.25 * np.pi, 2.25 * np.pi

    # equidistant points on a spiral
    num_mean = 10
    theta_pt = np.linspace(theta_min, theta_max, num_mean)
    r_pt = r_spiral(theta_pt)

    # setup input moments: means are placed on the points of the spiral
    num_cov = 10  # num_cov covariances are considered for each mean
    r_std = 0.5
    theta_std = np.deg2rad(np.linspace(6, 36, num_cov))
    mean = np.array([r_pt, theta_pt])
    cov = np.zeros((dim, dim, num_cov))
    for i in range(num_cov):
        cov[..., i] = np.diag([r_std**2, theta_std[i]**2])

    # COMPARE moment transforms
    ker_par = np.array([[1.0, 60, 6]])
    mul_ind = np.hstack((np.zeros(
        (dim, 1)), np.eye(dim), 2 * np.eye(dim))).astype(np.int)
    tforms = OrderedDict([
        ('bsq-ut',
         BayesSardTransform(dim,
                            dim,
                            ker_par,
                            mul_ind,
                            point_str='ut',
                            point_par={
                                'kappa': 2,
                                'alpha': 1
                            })),
        ('gpq-ut',
         GaussianProcessTransform(dim,
                                  dim,
                                  ker_par,
                                  point_str='ut',
                                  point_par={
                                      'kappa': 2,
                                      'alpha': 1
                                  })),
        ('ut', UnscentedTransform(dim, kappa=2, alpha=1, beta=0)),
    ])
    baseline_mtf = MonteCarloTransform(dim, n=10000)
    num_tforms = len(tforms)

    # initialize storage of SKL scores
    skl_dict = dict([(mt_str, np.zeros((num_mean, num_cov)))
                     for mt_str in tforms.keys()])

    # for each mean
    for i in range(num_mean):

        # for each covariance
        for j in range(num_cov):
            mean_in, cov_in = mean[..., i], cov[..., j]

            # calculate baseline using Monte Carlo
            mean_out_mc, cov_out_mc, cc = baseline_mtf.apply(
                polar2cartesian, mean_in, cov_in, None)

            # for each moment transform
            for mt_str in tforms.keys():

                # calculate the transformed moments
                mean_out, cov_out, cc = tforms[mt_str].apply(
                    polar2cartesian, mean_in, cov_in, None)

                # compute SKL
                skl_dict[mt_str][i, j] = symmetrized_kl_divergence(
                    mean_out_mc, cov_out_mc, mean_out, cov_out)

    # PLOT the SKL score for each MT and position on the spiral
    plt.style.use('seaborn-deep')
    printfig = FigurePrint()
    fig = plt.figure()

    # Average over mean indexes
    ax1 = fig.add_subplot(121)
    index = np.arange(num_mean) + 1
    for mt_str in tforms.keys():
        ax1.plot(index,
                 skl_dict[mt_str].mean(axis=1),
                 marker='o',
                 label=mt_str.upper())
    ax1.set_xlabel('Position index')
    ax1.set_ylabel('SKL')

    # Average over azimuth variances
    ax2 = fig.add_subplot(122, sharey=ax1)
    for mt_str in tforms.keys():
        ax2.plot(np.rad2deg(theta_std),
                 skl_dict[mt_str].mean(axis=0),
                 marker='o',
                 label=mt_str.upper())
    ax2.set_xlabel('Azimuth STD [$ \circ $]')
    ax2.legend()
    fig.tight_layout(pad=0)
    plt.show()

    # save figure
    printfig.savefig('polar2cartesian_skl')
예제 #16
0
def gpq_kl_demo():
    """Compares moment transforms in terms of symmetrized KL divergence."""

    # input dimension
    d = 2
    # unit sigma-points
    pts = SphericalRadialTransform.unit_sigma_points(d)
    # derivative mask, which derivatives to use
    dmask = np.arange(pts.shape[1])
    # RBF kernel hyper-parameters
    hyp = {
        'sos': np.array([[10.0] + d * [6.0]]),
        'rss': np.array([[10.0] + d * [0.2]]),
        'toa': np.array([[10.0] + d * [3.0]]),
        'doa': np.array([[1.0] + d * [2.0]]),
        'rdr': np.array([[10.0] + d * [5.0]]),
    }
    # baseline: Monte Carlo transform w/ 20,000 samples
    mc_baseline = MonteCarloTransform(d, n=2e4)
    # tested functions
    # rss has singularity at 0, therefore no derivative at 0
    # toa does not have derivative at 0, for d = 1
    # rss, toa and sos can be tested for all d > 0; physically d=2,3 make sense
    # radar and doa only for d = 2
    test_functions = (
        # sos,
        toa,
        rss,
        doa,
        rdr,
    )

    # fix seed
    np.random.seed(3)

    # moments of the input Gaussian density
    mean = np.zeros(d)
    cov_samples = 100
    # space allocation for KL divergence
    kl_data = np.zeros((3, len(test_functions), cov_samples))
    re_data_mean = np.zeros((3, len(test_functions), cov_samples))
    re_data_cov = np.zeros((3, len(test_functions), cov_samples))
    print(
        'Calculating symmetrized KL-divergences using {:d} covariance samples...'
        .format(cov_samples))
    for i in trange(cov_samples):
        # random PD matrix
        a = np.random.randn(d, d)
        cov = a.dot(a.T)
        a = np.diag(1.0 / np.sqrt(np.diag(cov)))  # 1 on diagonal
        cov = a.dot(cov).dot(a.T)
        for idf, f in enumerate(test_functions):
            # print "Testing {}".format(f.__name__)
            mean[:d - 1] = 0.2 if f.__name__ in 'rss' else mean[:d - 1]
            mean[:d - 1] = 3.0 if f.__name__ in 'doa rdr' else mean[:d - 1]
            jitter = 1e-8 * np.eye(
                2) if f.__name__ == 'rdr' else 1e-8 * np.eye(1)
            # baseline moments using Monte Carlo
            mean_mc, cov_mc, cc = mc_baseline.apply(f, mean, cov, None)
            # tested moment transforms
            transforms = (
                SphericalRadialTransform(d),
                GaussianProcessTransform(d,
                                         1,
                                         kern_par=hyp[f.__name__],
                                         point_str='sr'),
                GaussianProcessDerTransform(d,
                                            1,
                                            kern_par=hyp[f.__name__],
                                            point_str='sr',
                                            which_der=dmask),
            )
            for idt, t in enumerate(transforms):
                # apply transform
                mean_t, cov_t, cc = t.apply(f, mean, cov, None)
                # calculate KL distance to the baseline moments
                kl_data[idt, idf, i] = kl_div_sym(mean_mc, cov_mc + jitter,
                                                  mean_t, cov_t + jitter)
                re_data_mean[idt, idf, i] = rel_error(mean_mc, mean_t)
                re_data_cov[idt, idf, i] = rel_error(cov_mc, cov_t)

    # average over MC samples
    kl_data = kl_data.mean(axis=2)
    re_data_mean = re_data_mean.mean(axis=2)
    re_data_cov = re_data_cov.mean(axis=2)

    # put into pandas dataframe for nice printing and latex output
    row_labels = [t.__class__.__name__ for t in transforms]
    col_labels = [f.__name__ for f in test_functions]
    kl_df = pd.DataFrame(kl_data, index=row_labels, columns=col_labels)
    re_mean_df = pd.DataFrame(re_data_mean,
                              index=row_labels,
                              columns=col_labels)
    re_cov_df = pd.DataFrame(re_data_cov, index=row_labels, columns=col_labels)
    return kl_df, re_mean_df, re_cov_df