Esempio n. 1
0
    def test_hessian_vector_multiply_operator_with_randomized_svd(self):
        num_dims = 100
        rank = 21
        num_qoi = 30
        concurrency = 10

        model = QuadraticMisfitModel(num_dims, rank, num_qoi)

        # --------------------------------- #
        # compute with exact misfit Hessian #
        # --------------------------------- #
        np.random.seed(2)
        Amatrix = model.Amatrix
        operator = MatVecOperator(np.dot(Amatrix.T, Amatrix))
        adaptive_svd_opts = {
            'tolerance': 1e-8,
            'num_extra_samples': 10,
            'max_num_iter_error_increase': 20,
            'verbosity': 0,
            'max_num_samples': 100,
            'concurrency': concurrency
        }
        svd_opts = {'adaptive_opts': adaptive_svd_opts}
        U, S, V = randomized_svd(operator, svd_opts)
        Utrue, Strue, Vtrue = np.linalg.svd(np.dot(Amatrix.T, Amatrix),
                                            full_matrices=False)
        Utrue, Vtrue = adjust_sign_svd(Utrue, Vtrue)
        J = np.where(Strue > 1e-9)[0]
        assert J.shape[0] == rank
        assert np.allclose(Strue[J], S[J])
        assert np.allclose(Utrue[:, J], U[:, J])
        assert np.allclose(Vtrue[J, :], V[J, :])

        # -------------------------------------------------------------- #
        # compute with finite difference approximation of Hessian action #
        # -------------------------------------------------------------- #
        np.random.seed(2)
        map_point = np.zeros(num_dims)
        operator = MisfitHessianVecOperator(model, map_point, fd_eps=1e-7)
        U, S, V = randomized_svd(operator, svd_opts)
        Utrue, Strue, Vtrue = np.linalg.svd(np.dot(Amatrix.T, Amatrix),
                                            full_matrices=False)
        Utrue, Vtrue = adjust_sign_svd(Utrue, Vtrue)
        J = np.where(Strue > 1e-9)[0]
        assert J.shape[0] == rank
        assert np.allclose(Strue[J], S[J])
        assert np.allclose(Utrue[:, J], U[:, J])
        assert np.allclose(Vtrue[J, :], V[J, :])
Esempio n. 2
0
def posterior_covariance_helper(prior,
                                rank,
                                comparison_tol,
                                test_sampling=False,
                                plot=False):
    """
    Test that the Laplace posterior approximation can be obtained using
    the action of the sqrt prior covariance computed using a PDE solve

    Parameters
    ----------
    prior : MultivariateGaussian object
        The model which must be able to compute the action of the sqrt of the
        prior covariance (and its tranpose) on a set of vectors

    rank : integer
        The rank of the linear model used to generate the observations

    comparision_tol : 
        tolerances for each of the internal comparisons. This allows different
        accuracy for PDE based operators
    """

    # Define prior sqrt covariance and covariance operators
    L_op = prior.sqrt_covariance_operator

    # Extract prior information required for computing exact posterior
    # mean and covariance
    num_vars = prior.num_vars()
    prior_mean = np.zeros((num_vars), float)
    L = L_op(np.eye(num_vars), False)
    L_T = L_op(np.eye(num_vars), True)
    assert_ndarray_allclose(L.T,
                            L_T,
                            rtol=comparison_tol,
                            atol=0,
                            msg='Comparing prior sqrt and transpose')

    prior_covariance = np.dot(L, L_T)
    prior_pointwise_variance = prior.pointwise_variance()
    assert_ndarray_allclose(np.diag(prior_covariance),
                            prior_pointwise_variance,
                            rtol=1e-14,
                            atol=0,
                            msg='Comparing prior pointwise variance')

    misfit_model, noise_covariance_inv, obs = setup_quadratic_misfit_problem(
        prior, rank, noise_sigma2=1)

    # Get analytical mean and covariance
    prior_hessian = np.linalg.inv(prior_covariance)
    exact_laplace_mean, exact_laplace_covariance = \
      laplace_posterior_approximation_for_linear_models(
          misfit_model.Amatrix, prior.mean, prior_hessian,
          noise_covariance_inv, obs)

    # Define prior conditioned misfit operator
    sample = np.zeros(num_vars)
    misfit_hessian_operator = MisfitHessianVecOperator(misfit_model,
                                                       sample,
                                                       fd_eps=None)
    LHL_op = PriorConditionedHessianMatVecOperator(L_op,
                                                   misfit_hessian_operator)

    # For testing purposes build entire L*H*L matrix using operator
    # and compare to result based upon explicit matrix mutiplication
    LHL_op = LHL_op.apply(np.eye(num_vars), transpose=False)
    H = misfit_model.hessian(sample)
    assert np.allclose(
        H,
        np.dot(np.dot(misfit_model.Amatrix.T, noise_covariance_inv),
               misfit_model.Amatrix))
    LHL_mat = np.dot(L_T, np.dot(H, L))
    assert_ndarray_allclose(
        LHL_mat,
        LHL_op,
        rtol=comparison_tol,
        msg='Comparing prior matrix and operator based LHL')

    # Test singular values obtained by randomized svd using operator
    # are the same as those obtained using singular decomposition
    Utrue, Strue, Vtrue = np.linalg.svd(LHL_mat)
    Utrue, Vtrue = adjust_sign_svd(Utrue, Vtrue)
    standard_svd_opts = {'num_singular_values': rank, 'num_extra_samples': 10}
    svd_opts = {'single_pass': True, 'standard_opts': standard_svd_opts}
    L_post_op = get_laplace_covariance_sqrt_operator(L_op,
                                                     misfit_hessian_operator,
                                                     svd_opts,
                                                     weights=None,
                                                     min_singular_value=0.0)
    #print np.max((Strue[:rank]-L_post_op.e_r)/Strue[0])
    max_error = np.max(Strue[:rank] - L_post_op.e_r)
    assert max_error / Strue[0] < comparison_tol, max_error / Strue[0]
    assert_ndarray_allclose(Vtrue.T[:, :rank],
                            L_post_op.V_r,
                            rtol=1e-6,
                            msg='Comparing eigenvectors')

    L_post_op.V_r = Vtrue.T[:, :rank]

    # Test posterior sqrt covariance operator transpose is the same as
    # explicit matrix transpose of matrix obtained by prior sqrt
    # covariance operator
    L_post = L_post_op.apply(np.eye(num_vars), transpose=False)
    L_post_T = L_post_op.apply(np.eye(num_vars), transpose=True)
    assert_ndarray_allclose(L_post.T,
                            L_post_T,
                            rtol=comparison_tol,
                            msg='Comparing posterior sqrt and transpose')

    # Test posterior covariance operator produced matrix is the same
    # as the exact posterior covariance obtained using analytical formula
    if rank == num_vars:
        # this test only makes sense if entire set of directions is found
        # if low rank approx is used then this will ofcourse induce errors
        post_covariance = np.dot(L_post, L_post_T)
        assert_ndarray_allclose(
            exact_laplace_covariance,
            post_covariance,
            rtol=comparison_tol,
            atol=0.,
            msg='Comparing matrix and operator based posterior covariance')

    # Test pointwise covariance of posterior
    post_pointwise_variance, prior_pointwise_variance=\
      get_pointwise_laplace_variance_using_prior_variance(
        prior, L_post_op, prior_pointwise_variance)
    assert_ndarray_allclose(np.diag(exact_laplace_covariance),
                            post_pointwise_variance,
                            rtol=comparison_tol,
                            atol=0.,
                            msg='Comparing pointwise variance')

    if not test_sampling:
        return
    num_samples = int(2e5)
    posterior_samples = sample_from_laplace_posterior(exact_laplace_mean,
                                                      L_post_op,
                                                      num_vars,
                                                      num_samples,
                                                      weights=None)
    assert_ndarray_allclose(exact_laplace_covariance,
                            np.cov(posterior_samples),
                            atol=1e-2 * exact_laplace_covariance.max(),
                            rtol=0.,
                            msg='Comparing posterior samples covariance')
    assert_ndarray_allclose(exact_laplace_mean.squeeze(),
                            np.mean(posterior_samples, axis=1),
                            atol=2e-2,
                            rtol=0.,
                            msg='Comparing posterior samples mean')

    if plot:
        # plot marginals of posterior using orginal ordering
        from pyapprox.visualization import plot_multiple_2d_gaussian_slices
        texfilename = 'slices.tex'
        plot_multiple_2d_gaussian_slices(
            exact_laplace_mean[:10],
            np.diag(exact_laplace_covariance)[:10],
            texfilename,
            reference_gaussian_data=(0., 1.),
            show=False)

        # plot marginals of posterior in rotated coordinates
        # from most to least important.
        # The following is not feasiable in practice as we cannot compute
        # entire covariance matrix in full space. But we have
        # C_r = V_r*L*V_r*D*V_r.T*L.T*V_r.T
        # is we compute matrix products from right to left we only have to
        # compute at most (d x r) matrices. And if only want first 20 say
        # variances then can apply C_r to vectors e_i i=1,...,20
        # then we need at most (dx20 matrices)
        texfilename = 'rotated-slices.tex'
        V_r = L_post_op.V_r
        plot_multiple_2d_gaussian_slices(
            np.dot(V_r.T, exact_laplace_mean[:10]),
            np.diag(np.dot(V_r.T, np.dot(exact_laplace_covariance, V_r)))[:10],
            texfilename,
            reference_gaussian_data=(0., 1.),
            show=True)