示例#1
0
 def test_crash(self):
     d = 1
     tmc = MonteCarloTransform(d, n=1e4)
     f = UNGMTransition(GaussRV(1, cov=1.0), GaussRV(1, cov=10.0)).dyn_eval
     mean = np.zeros(d)
     cov = np.eye(d)
     # does it crash ?
     tmc.apply(f, mean, cov, np.atleast_1d(1.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()))
示例#3
0
 def test_increasing_samples(self):
     d = 1
     tmc = (
         MonteCarloTransform(d, n=1e1),
         MonteCarloTransform(d, n=1e2),
         MonteCarloTransform(d, n=1e3),
         MonteCarloTransform(d, n=1e4),
         MonteCarloTransform(d, n=1e5),
     )
     f = sum_of_squares  # UNGM().dyn_eval
     mean = np.zeros(d)
     cov = np.eye(d)
     # does it crash ?
     for t in tmc:
         print(t.apply(f, mean, cov, np.atleast_1d(1.0)))
示例#4
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()
示例#5
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)))
示例#6
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')
示例#7
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')
示例#8
0
def mt_trunc_demo(mt_trunc, mt, dim=None, full_input_cov=True, **kwargs):
    """
    Comparison of truncated MT and vanilla MT on polar2cartesian transform for increasing state dimensions. The
    truncated MT is aware of the effective dimension, so we expect it to be closer to the true covariance

    Observation: Output covariance of the Truncated UT stays closer to the MC baseline than the covariance
    produced by the vanilla UT.

    There's some merit to the idea, but the problem is with computing the input-output cross-covariance.


    Parameters
    ----------
    mt_trunc
    mt
    dim
    full_input_cov : boolean
        If `False`, a diagonal input covariance is used, otherwise a full covariance is used.
    kwargs

    Returns
    -------

    """

    assert issubclass(mt_trunc, MomentTransform) and issubclass(mt, MomentTransform)

    # state dimensions and effective dimension
    dim = [2, 3, 4, 5] if dim is None else dim
    d_eff = 2

    # nonlinear integrand
    f = polar2cartesian

    # input mean and covariance
    mean_eff, cov_eff = np.array([1, np.pi / 2]), np.diag([0.05 ** 2, (np.pi / 10) ** 2])

    if full_input_cov:
        A = np.random.rand(d_eff, d_eff)
        cov_eff = A.dot(cov_eff).dot(A.T)

    # use MC transform with lots of samples to compute the true transformed moments
    tmc = MonteCarloTransform(d_eff, n=1e4)
    M_mc, C_mc, cc_mc = tmc.apply(f, mean_eff, cov_eff, None)
    # transformed samples
    x = np.random.multivariate_normal(mean_eff, cov_eff, size=int(1e3)).T
    fx = np.apply_along_axis(f, 0, x, None)
    X_mc = ellipse_points(M_mc, C_mc)

    M = np.zeros((2, len(dim), 2))
    C = np.zeros((2, 2, len(dim), 2))
    X = np.zeros((2, 50, len(dim), 2))
    for i, d in enumerate(dim):
        t = mt_trunc(d, d_eff, **kwargs)
        s = mt(d, **kwargs)

        # input mean and covariance
        mean, cov = np.zeros(d), np.eye(d)
        mean[:d_eff], cov[:d_eff, :d_eff] = mean_eff, cov_eff

        # transformed moments (w/o cross-covariance)
        M[:, i, 0], C[..., i, 0], cc = t.apply(f, mean, cov, None)
        M[:, i, 1], C[..., i, 1], cc = s.apply(f, mean, cov, None)

        # points on the ellipse defined by the transformed mean and covariance for plotting
        X[..., i, 0] = ellipse_points(M[:, i, 0], C[..., i, 0])
        X[..., i, 1] = ellipse_points(M[:, i, 1], C[..., i, 1])

    # PLOTS: transformed samples, MC mean and covariance ground truth
    fig, ax = plt.subplots(1, 2)
    ax[0].plot(fx[0, :], fx[1, :], 'k.', alpha=0.15)
    ax[0].plot(M_mc[0], M_mc[1], 'ro', markersize=6, lw=2)
    ax[0].plot(X_mc[0, :], X_mc[1, :], 'r--', lw=2, label='MC')

    # SR and SR-T mean and covariance for various state dimensions
    # TODO: it's more effective to plot SKL between the transformed and baseline covariances.
    for i, d in enumerate(dim):
        ax[0].plot(M[0, i, 0], M[1, i, 0], 'b+', markersize=10, lw=2)
        ax[0].plot(X[0, :, i, 0], X[1, :, i, 0], color='b', label='mt-trunc (d={})'.format(d))
    for i, d in enumerate(dim):
        ax[0].plot(M[0, i, 1], M[1, i, 1], 'go', markersize=6)
        ax[0].plot(X[0, :, i, 1], X[1, :, i, 1], color='g', label='mt (d={})'.format(d))
    ax[0].set_aspect('equal')
    plt.legend()

    # symmetrized KL-divergence
    skl = np.zeros((len(dim), 2))
    for i, d in enumerate(dim):
        skl[i, 0] = symmetrized_kl_divergence(M_mc, C_mc, M[:, i, 0], C[..., i, 0])
        skl[i, 1] = symmetrized_kl_divergence(M_mc, C_mc, M[:, i, 1], C[..., i, 1])
    plt_opt = {'lw': 2, 'marker': 'o'}
    ax[1].plot(dim, skl[:, 0], label='truncated', **plt_opt)
    ax[1].plot(dim, skl[:, 1], label='original', **plt_opt)
    ax[1].set_xticks(dim)
    ax[1].set_xlabel('Dimension')
    ax[1].set_ylabel('SKL')
    plt.legend()
    plt.show()
示例#9
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