예제 #1
0
def plot_discrete_distribution_surface_2d(rv1, rv2, ax=None):
    """
    Only works if rv1 and rv2 are defined on consecutive integers
    """
    from matplotlib import cm
    from pyapprox.utilities import cartesian_product, outer_product
    from pyapprox.variables import get_probability_masses

    if ax is None:
        fig = plt.figure(figsize=(8, 6))
        ax = fig.add_subplot(111, projection='3d')
    x_1d = [get_probability_masses(rv)[0] for rv in [rv1, rv2]]
    w_1d = [get_probability_masses(rv)[1] for rv in [rv1, rv2]]
    samples = cartesian_product(x_1d)
    weights = outer_product(w_1d)

    dz = weights
    cmap = cm.get_cmap('jet')  # Get desired colormap - you can change this!
    max_height = np.max(dz)    # get range of colorbars so we can normalize
    min_height = np.min(dz)
    # scale each z to [0,1], and get their rgb values
    rgba = [cmap((k-min_height)/max_height) for k in dz]
    # Only works if rv1 and rv2 are defined on consecutive integers
    dx, dy = 1, 1
    ax.bar3d(samples[0, :], samples[1, :], 0, dx, dy, dz, color=rgba,
             zsort='average')

    angle = 45
    ax.view_init(10, angle)
    ax.set_axis_off()
예제 #2
0
def compute_multivariate_orthonormal_basis_product(product_coefs_1d,poly_index_ii,poly_index_jj,max_degrees1,max_degrees2,tol=2*np.finfo(float).eps):
    """
    Compute the product of two multivariate orthonormal bases and re-express 
    as an expansion using the orthnormal basis.
    """
    num_vars = poly_index_ii.shape[0]
    poly_index= poly_index_ii+poly_index_jj
    active_vars = np.where(poly_index>0)[0]
    if active_vars.shape[0]>0:
        coefs_1d = []
        for dd in active_vars:
            pii,pjj=poly_index_ii[dd],poly_index_jj[dd]
            if pii<pjj:
                tmp=pjj; pjj=pii; pii=tmp
            kk = flattened_rectangular_lower_triangular_matrix_index(
                pii,pjj,max_degrees1[dd]+1,max_degrees2[dd]+1)
            coefs_1d.append(product_coefs_1d[dd][kk][:,0])
        indices_1d = [np.arange(poly_index[dd]+1) 
                      for dd in active_vars]
        product_coefs = outer_product(coefs_1d)[:,np.newaxis]
        active_product_indices = cartesian_product(indices_1d)
        II = np.where(np.absolute(product_coefs)>tol)[0]
        active_product_indices = active_product_indices[:,II]
        product_coefs = product_coefs[II]
        product_indices = np.zeros(
            (num_vars,active_product_indices.shape[1]),dtype=int)
        product_indices[active_vars]=active_product_indices
    else:
        product_coefs = np.ones((1,1))
        product_indices = np.zeros([num_vars,1],dtype=int)

    return product_indices, product_coefs
예제 #3
0
def compute_tensor_product_level_indices(num_vars, degree, max_norm=True):
    indices = cartesian_product([np.arange(degree+1)]*num_vars, 1)
    if max_norm:
        II = np.where(np.linalg.norm(indices, axis=0, ord=np.inf) == degree)[0]
    else:
        II = np.where(indices.sum(axis=0) == degree)[0]
    return indices[:, II]
예제 #4
0
def product_of_independent_random_variables_pdf(pdf,gauss_quadrature_rules,zz):
    """
    Compute PDF of Z = X_1*X_2*...*X_d
    Parameters
    ---------
    pdf : callable
        PDF of X_1
    
    gauss_quadrature_rules : list [x,w]
        List of gaussian quadrature rules which integrate with respect to PDFs
        of X_2,...X_d

    zz : np.ndarray (num_samples)
       The locations to evaluate the pdf of Z
    """
    num_vars = len(gauss_quadrature_rules)+1
    xx = cartesian_product(
        [gauss_quadrature_rules[ii][0] for ii in range(num_vars-1)])
    ww = outer_product(
        [gauss_quadrature_rules[ii][1] for ii in range(num_vars-1)])
    
    vals = np.zeros_like(zz)
    for ii in range(vals.shape[0]):
        vals[ii] = np.dot(
            ww,pdf(zz[ii]/xx.prod(axis=0))/np.absolute(xx.prod(axis=0)))
    return vals
def predictor_corrector_function_of_independent_variables(
        nterms, univariate_quad_rules, fun):
    """
    Use predictor corrector method to compute the recursion coefficients
    of a univariate orthonormal polynomial orthogonal to the density
    associated with a scalar function of a set of independent 1D
    variables

    Parameters
    ----------
    nterms : integer
        The number of coefficients requested

    univariate_quad_rules : callable
        The univariate quadrature rules which include weights of
        each indendent variable

    fun : callable
        The function mapping indendent variables into a scalar variable
    """

    ab = np.zeros((nterms, 2))
    x_1d = [rule[0] for rule in univariate_quad_rules]
    w_1d = [rule[1] for rule in univariate_quad_rules]
    quad_samples = cartesian_product(x_1d, 1)
    quad_weights = outer_product(w_1d)

    # for probablity measures the following will always be one, but
    # this is not true for other measures
    ab[0, 1] = np.sqrt(quad_weights.sum())

    for ii in range(1, nterms):
        # predict
        ab[ii, 1] = ab[ii - 1, 1]
        if ii > 1:
            ab[ii - 1, 0] = ab[ii - 2, 0]
        else:
            ab[ii - 1, 0] = 0

        def integrand(x):
            y = fun(x).squeeze()
            pvals = evaluate_orthonormal_polynomial_1d(y, ii, ab)
            # measure not included in integral because it is assumed to
            # be in the quadrature rules
            return pvals[:, ii] * pvals[:, ii - 1]

        G_ii_iim1 = integrand(quad_samples).dot(quad_weights)
        ab[ii - 1, 0] += ab[ii - 1, 1] * G_ii_iim1

        def integrand(x):
            y = fun(x).squeeze()
            pvals = evaluate_orthonormal_polynomial_1d(y, ii, ab)
            # measure not included in integral because it is assumed to
            # be in the quadrature rules
            return pvals[:, ii]**2

        G_ii_ii = integrand(quad_samples).dot(quad_weights)
        ab[ii, 1] *= np.sqrt(G_ii_ii)

    return ab
예제 #6
0
    def test_get_chebyhsev_center_of_inactive_subspace(self):
        # Define an active subspace
        num_vars = 6
        num_active_vars = 2

        W, W1, W2 = get_random_active_subspace_eigenvecs(
            num_vars, num_active_vars)

        num_active_samples = 100
        # generate samples in the active subspace zonotope
        samples = np.random.uniform(-1., 1., (num_vars, num_active_samples))
        active_samples = np.dot(W1.T, samples)
        # get active coordinates of hypercube vertices.
        # Warning. Because of approximate nature of find_zonotope_vertices
        # algorithm not all mapped vertices may lie within the
        # linear constraints that the find vertices algorithm generates
        hypercube_vertices_1d = np.array([-1., 1.])
        hypercube_vertices = cartesian_product(
            [hypercube_vertices_1d]*num_vars, 1)
        mapped_vertices = np.dot(W1.T, hypercube_vertices)
        active_samples = np.hstack((active_samples, mapped_vertices))
        samples = transform_active_subspace_samples_to_original_coordinates(
            active_samples, W)
        # check the sample in the original space fits inside the
        # hypercube. Allow for slight machine precision error
        assert np.all(
            np.absolute(samples) <= 1+4*np.finfo(float).eps)
예제 #7
0
    def test_leja_objective_2d(self):
        num_vars = 2
        alpha_stat, beta_stat = [2, 2]
        #alpha_stat,beta_stat = [1,1]

        weight_function, weight_function_deriv, poly = self.setup(
            num_vars, alpha_stat, beta_stat)

        leja_sequence = np.array([[-1.0, -1.0], [1.0, 1.0]]).T
        degree = 1
        indices = compute_hyperbolic_indices(num_vars, degree, 1.0)
        # sort lexographically to make testing easier
        I = np.lexsort((indices[0, :], indices[1, :], indices.sum(axis=0)))
        indices = indices[:, I]
        poly.set_indices(indices[:, :2])
        new_indices = indices[:, 2:3]

        coeffs = compute_coefficients_of_leja_interpolant(
            leja_sequence, poly, new_indices, weight_function)

        sample = np.asarray([0.5, -0.5])[:, np.newaxis]
        func = partial(leja_objective,
                       leja_sequence=leja_sequence,
                       poly=poly,
                       new_indices=new_indices,
                       coeff=coeffs,
                       weight_function=weight_function,
                       weight_function_deriv=weight_function_deriv)
        fd_eps = 1e-7
        fd_deriv = compute_finite_difference_derivative(func,
                                                        sample,
                                                        fd_eps=fd_eps)

        residual, jacobian = leja_objective_and_gradient(sample,
                                                         leja_sequence,
                                                         poly,
                                                         new_indices,
                                                         coeffs,
                                                         weight_function,
                                                         weight_function_deriv,
                                                         deriv_order=1)

        grad = np.dot(jacobian.T, residual)
        assert np.allclose(fd_deriv, grad, atol=fd_eps * 100)

        num_samples = 20
        samples = np.linspace(-1, 1, num_samples)
        samples = cartesian_product([samples] * num_vars)
        objective_vals = func(samples)
        f, ax = plt.subplots(1, 1, figsize=(8, 6))
        X = samples[0, :].reshape(num_samples, num_samples)
        Y = samples[1, :].reshape(num_samples, num_samples)
        Z = objective_vals.reshape(num_samples, num_samples)
        cset = ax.contourf(X,
                           Y,
                           Z,
                           levels=np.linspace(Z.min(), Z.max(), 30),
                           cmap=None)
        plt.colorbar(cset)
        plt.plot(leja_sequence[0, :], leja_sequence[1, :], 'ko', ms=20)
    def test_inner_products_on_active_subspace(self):
        num_vars=4; num_active_vars = 2; degree=3;
        A = np.random.normal(0,1,(num_vars,num_vars))
        Q, R = np.linalg.qr( A )
        W1 = Q[:,:num_active_vars]
        
        as_poly_indices = np.asarray([
            [0,0],[1,0],[0,1],[2,0],[1,1],[0,2]
            ]).T

        x1d,w1d = np.polynomial.legendre.leggauss(10)
        w1d /=2
        gl_samples = cartesian_product([x1d]*num_vars)
        gl_weights = outer_product([w1d]*num_vars)
        as_gl_samples = np.dot(W1.T,gl_samples)

        inner_product_indices = np.empty(
            (num_active_vars,as_poly_indices.shape[1]**2),dtype=int)
        for ii in range(as_poly_indices.shape[1]):
            for jj in range(as_poly_indices.shape[1]):
                inner_product_indices[:,ii*as_poly_indices.shape[1]+jj]=\
                    as_poly_indices[:,ii]+as_poly_indices[:,jj]

        vandermonde = monomial_basis_matrix(inner_product_indices,as_gl_samples)

        inner_products = inner_products_on_active_subspace(
            W1.T,as_poly_indices,monomial_mean_uniform_variables)

        for ii in range(as_poly_indices.shape[1]):
            for jj in range(as_poly_indices.shape[1]):
                assert np.allclose(
                    inner_products[ii,jj],
                    np.dot(vandermonde[:,ii*as_poly_indices.shape[1]+jj],
                           gl_weights))
예제 #9
0
    def test_tensor_product_lagrange_interpolation(self):
        nvars = 5
        level = 10
        x = gauss_hermite_pts_wts_1D(level + 1)[0]
        #active_vars = np.arange(nvars)
        active_vars = np.hstack([np.arange(2), np.arange(3, nvars)])
        nactive_vars = active_vars.shape[0]
        abscissa_1d = [x] * nactive_vars

        power = x.shape[0] - 2

        def fun(samples):
            return np.sum(samples[active_vars, :]**power, axis=0)[:, None]

        nsamples = 1000
        validation_samples = np.random.normal(0, 1, (nvars, nsamples))

        zz = abscissa_1d.copy()
        zz.insert(2, np.zeros(1))
        train_samples = cartesian_product(zz)
        values = fun(train_samples)
        approx_values = tensor_product_lagrange_interpolation(
            validation_samples, abscissa_1d, active_vars, values)

        barycentric_weights_1d = [
            compute_barycentric_weights_1d(x) for x in abscissa_1d
        ]
        poly_vals = multivariate_barycentric_lagrange_interpolation(
            validation_samples, abscissa_1d, barycentric_weights_1d, values,
            active_vars)

        assert np.allclose(approx_values, fun(validation_samples))
        assert np.allclose(poly_vals, fun(validation_samples))
예제 #10
0
def tensor_product_indices(degrees):
    num_vars = len(degrees)
    indices_1d = []
    for ii in range(num_vars):
        indices_1d.append(np.arange(degrees[ii]+1))
    indices = cartesian_product(indices_1d, 1)
    return indices
예제 #11
0
def tensor_product_lagrange_interpolation(samples, abscissa_1d, active_vars,
                                          values):
    assert len(abscissa_1d) == len(active_vars)
    active_indices = cartesian_product(
        [np.arange(x.shape[0]) for x in abscissa_1d])
    basis_vals_1d = precompute_tensor_product_lagrange_polynomial_basis(
        samples, abscissa_1d, active_vars)
    return __tensor_product_lagrange_polynomial_basis(samples, basis_vals_1d,
                                                      active_vars, values,
                                                      active_indices)
예제 #12
0
def get_tensor_product_points(level,var_trans,quad_type):
    abscissa_1d = []
    num_vars = var_trans.num_vars()
    if quad_type == 'CC':
        x, w = clenshaw_curtis_pts_wts_1D(level)
    elif quad_type == 'GH':
        x, w = gauss_hermite_pts_wts_1D(level)
    for dd in range( num_vars ):
        abscissa_1d.append( x )
    pts = cartesian_product( abscissa_1d, 1 )
    pts = var_trans.map_from_canonical_space( pts )
    return pts
def plot_tensor_product_lagrange_basis_2d(level, ii, jj, ax=None):
    abscissa, tmp = clenshaw_curtis_pts_wts_1D(level)
    abscissa_1d = [abscissa, abscissa]
    barycentric_weights_1d = [compute_barycentric_weights_1d(abscissa_1d[0]),
                              compute_barycentric_weights_1d(abscissa_1d[1])]
    training_samples = cartesian_product(abscissa_1d, 1)
    fn_vals = np.zeros((training_samples.shape[1], 1))
    idx = jj*abscissa_1d[1].shape[0]+ii
    fn_vals[idx] = 1.

    def f(samples): return multivariate_barycentric_lagrange_interpolation(
        samples, abscissa_1d, barycentric_weights_1d, fn_vals,
        np.array([0, 1]))

    plot_limits = [-1, 1, -1, 1]
    num_pts_1d = 101
    X, Y, Z = get_meshgrid_function_data(f, plot_limits, num_pts_1d)
    if ax is None:
        ax = create_3d_axis()
    cmap = mpl.cm.coolwarm

    plot_surface(X, Y, Z, ax, axis_labels=None, limit_state=None,
                 alpha=0.3, cmap=mpl.cm.coolwarm, zorder=3, plot_axes=False)
    num_contour_levels = 30
    offset = -(Z.max()-Z.min())/2
    cmap = mpl.cm.gray
    ax.contourf(
        X, Y, Z, zdir='z', offset=offset,
        levels=np.linspace(Z.min(), Z.max(), num_contour_levels),
        cmap=cmap, zorder=-1)
    ax.plot(training_samples[0, :], training_samples[1, :],
            offset*np.ones(training_samples.shape[1]), 'o',
            zorder=100, color='b')

    x = np.linspace(-1, 1, 100)
    y = training_samples[1, idx]*np.ones((x.shape[0]))
    z = f(np.vstack((x[np.newaxis, :], y[np.newaxis, :])))[:, 0]
    ax.plot(x, Y.max()*np.ones((x.shape[0])), z, '-r')
    ax.plot(abscissa_1d[0], Y.max()*np.ones(
        (abscissa_1d[0].shape[0])), np.zeros(abscissa_1d[0].shape[0]), 'or')

    y = np.linspace(-1, 1, 100)
    x = training_samples[0, idx]*np.ones((y.shape[0]))
    z = f(np.vstack((x[np.newaxis, :], y[np.newaxis, :])))[:, 0]
    ax.plot(X.min()*np.ones((x.shape[0])), y, z, '-r')
    ax.plot(X.min()*np.ones(
        (abscissa_1d[1].shape[0])), abscissa_1d[1],
        np.zeros(abscissa_1d[1].shape[0]), 'or')
def ortho_polynomial_grammian_bounded_continuous_variable(
        var, ab, degree, tol, integrate_fun=None):
    """
    Compute the inner product of all polynomials up to and including
    degree. Useful for testing that the polynomials are orthonormal.
    The grammian should always be the identity (modulo errors due to
    quadrature)
    """
    if ab.shape[0] < degree + 1:
        raise ValueError("Not enough recursion coefficients")

    loc, scale = transform_scale_parameters(var)
    if is_bounded_continuous_variable(var):
        can_lb, can_ub = -1, 1
    else:
        lb, ub = var.interval(1)
        can_lb = (lb - loc) / scale
        can_ub = (ub - loc) / scale

    def default_integrate(integrand):
        result = scipy.integrate.quad(integrand,
                                      can_lb,
                                      can_ub,
                                      epsabs=tol,
                                      epsrel=tol)
        return result[0]

    if integrate_fun is None:
        integrate = default_integrate
    else:
        integrate = partial(integrate_fun, can_lb, can_ub)

    def fun(order1, order2):
        order = max(order1, order2)

        def integrand(x):
            x = np.atleast_1d(x)
            basis_mat = evaluate_orthonormal_polynomial_1d(x, order, ab)
            return var.pdf(x * scale + loc) * scale * (basis_mat[:, order1] *
                                                       basis_mat[:, order2])

        return integrate(integrand)

    vec_fun = np.vectorize(fun)
    indices = cartesian_product((np.arange(degree + 1), np.arange(degree + 1)))
    gram_mat = vec_fun(indices[0, :], indices[1, :])
    return gram_mat.reshape((degree + 1, degree + 1))
예제 #15
0
    def test_inner_products_on_active_subspace_using_samples(self):

        def generate_samples(num_samples):
            from pyapprox.low_discrepancy_sequences import \
                transformed_halton_sequence
            samples = transformed_halton_sequence(None, num_vars, num_samples)
            samples = samples*2.-1.
            return samples

        num_vars = 4
        num_active_vars = 2
        degree = 3
        A = np.random.normal(0, 1, (num_vars, num_vars))
        Q, R = np.linalg.qr(A)
        W1 = Q[:, :num_active_vars]

        as_poly_indices = np.asarray([
            [0, 0], [1, 0], [0, 1], [2, 0], [1, 1], [0, 2]
        ]).T

        x1d, w1d = np.polynomial.legendre.leggauss(10)
        w1d /= 2
        gl_samples = cartesian_product([x1d]*num_vars)
        gl_weights = outer_product([w1d]*num_vars)
        as_gl_samples = np.dot(W1.T, gl_samples)

        inner_product_indices = np.empty(
            (num_active_vars, as_poly_indices.shape[1]**2), dtype=int)
        for ii in range(as_poly_indices.shape[1]):
            for jj in range(as_poly_indices.shape[1]):
                inner_product_indices[:, ii*as_poly_indices.shape[1]+jj] =\
                    as_poly_indices[:, ii]+as_poly_indices[:, jj]

        vandermonde = monomial_basis_matrix(
            inner_product_indices, as_gl_samples)

        num_sobol_samples = 100000
        inner_products = sample_based_inner_products_on_active_subspace(
            W1, monomial_basis_matrix, as_poly_indices, num_sobol_samples,
            generate_samples)

        for ii in range(as_poly_indices.shape[1]):
            for jj in range(as_poly_indices.shape[1]):
                assert np.allclose(
                    inner_products[ii, jj],
                    np.dot(vandermonde[:, ii*as_poly_indices.shape[1]+jj],
                           gl_weights), atol=1e-4)
예제 #16
0
 def integrate(self, mesh_values, order=None):
     if order is None:
         order = self.order
     # Get Gauss-Legendre rule
     gl_pts, gl_wts = gauss_jacobi_pts_wts_1D(order, 0, 0)
     pts_1d, wts_1d = [], []
     lims = self.xlim+self.ylim
     for ii in range(2):
         # Scale points from [-1,1] to to physical domain
         x_range = lims[2*ii+1]-lims[2*ii]
         # Remove factor of 0.5 from weights and shift to [a,b]
         wts_1d.append(gl_wts*x_range)
         pts_1d.append(x_range*(gl_pts+1.)/2.+lims[2*ii])
     # Interpolate mesh values onto quadrature nodes
     pts = cartesian_product(pts_1d)
     wts = outer_product(wts_1d)
     gl_vals = self.interpolate(mesh_values, pts)
     # Compute and return integral
     return np.dot(gl_vals[:, 0], wts)
예제 #17
0
def evaluate_active_subspace_density_1d_example(density_fn, tol, test=False):
    from pyapprox.visualization import plot_2d_polygon, \
        get_meshgrid_function_data

    num_quad_samples = 100
    points_for_eval, quad_weights = np.polynomial.legendre.leggauss(
        num_quad_samples)

    # for varing rotations make sure density on 1d active subspace
    # integrates to 1
    n = 10
    r = 1
    num_rotations = 23
    angles = np.linspace(0., np.pi * 2., num_rotations)
    import matplotlib.pyplot as plt
    f, axs = plt.subplots(1, 2, sharey=False, figsize=(16, 6))
    for i in range(1, angles.shape[0]):
        W = np.array([[np.cos(angles[i]), -np.sin(angles[i])],
                      [np.sin(angles[i]), np.cos(angles[i])]])
        density_vals, subspace_1d_bounds = \
            evaluate_active_subspace_density_1d(
                W,density_fn,points_for_eval,num_quad_samples,False)
        integral_density = np.dot(density_vals, quad_weights)
        # Gauss legendre weights must be scaled to correct for length of
        # subspace interval. If integrating
        # int_a^b f(t)dt but gauss points are x in [-1,1] then dt=(b-a)/2 dx
        integral_density *= (subspace_1d_bounds[1] - subspace_1d_bounds[0]) / 2
        #print abs(1-integral_density)
        assert np.allclose(integral_density, 1., atol=tol)

        if not test:
            axs[0].plot(map_m11_to_ab(points_for_eval, subspace_1d_bounds[0],
                                      subspace_1d_bounds[1]),
                        density_vals,
                        'k',
                        lw=2)
        hypercube_vertices_1d = np.array([-1., 1.])
        hypercube_vertices = cartesian_product([hypercube_vertices_1d] * 2, 1)
        mapped_vertices = np.dot(W, hypercube_vertices)
        if not test:
            plot_2d_polygon(mapped_vertices, axs[1])
    if not test:
        plt.show()
예제 #18
0
    def test_moments_of_active_subspace_II(self):
        num_vars=4; num_active_vars = 2; degree=12;
        A = np.random.normal(0,1,(num_vars,num_vars))
        Q, R = np.linalg.qr( A )
        W1 = Q[:,:num_active_vars]
        
        as_poly_indices = compute_hyperbolic_indices(num_active_vars,degree,1.0)
        moments = moments_of_active_subspace(
            W1.T, as_poly_indices, monomial_mean_uniform_variables)

        x1d,w1d = np.polynomial.legendre.leggauss(10)
        w1d /=2
        gl_samples = cartesian_product([x1d]*num_vars)
        gl_weights = outer_product([w1d]*num_vars)
        as_gl_samples = np.dot(W1.T,gl_samples)

        vandermonde = monomial_basis_matrix(as_poly_indices,as_gl_samples)
        quad_poly_moments  = np.empty(vandermonde.shape[1])
        for ii in range(vandermonde.shape[1]):
            quad_poly_moments[ii] = np.dot(vandermonde[:,ii],gl_weights)
        assert np.allclose(moments,quad_poly_moments)
예제 #19
0
def get_subspace_polynomial_indices(subspace_index,
                                    growth_rule_1d,
                                    config_variables_idx=None):
    """
    Get the polynomial indices of a tensor-product nodal subspace.

    Parameters
    ----------
    subspace index : np.ndarray (num_vars)
        The subspace index [l_1,...,l_d]

    growth_rule_1d : list of callable functions
        Function which takes a level l_i as its only argument and returns
        the number of samples in the 1D quadrature rule of the specified level.

    Return
    ------
    poly_indices : np.ndarray (num_vars x num_subspace_samples)
        The polynomial indices of the tensor-product subspace.
    """
    subspace_index = np.asarray(subspace_index)
    num_vars = subspace_index.shape[0]
    if np.all(subspace_index == 0):
        return np.zeros((num_vars, 1), dtype=int)

    if config_variables_idx is None:
        config_variables_idx = num_vars
    assert len(growth_rule_1d) == config_variables_idx

    poly_indices_1d = []
    for ii in range(num_vars):
        if ii < config_variables_idx:
            poly_indices_1d.append(
                np.arange(growth_rule_1d[ii](subspace_index[ii])))
        else:
            # for config variables just set value equal to subspace index value
            poly_indices_1d.append(np.asarray([subspace_index[ii]]))

    poly_indices = cartesian_product(poly_indices_1d, 1)
    return poly_indices
예제 #20
0
    def initialize(self, order, bndry_cond=None, lims=None):
        # 1d model transforms mesh pts 1d from are on [-1,1] to [a,b]
        # I will asssume that second physical dimension is also [a,b]
        super(SteadyStateDiffusionEquation2D, self).initialize(order,
                                                               bndry_cond[:2],
                                                               lims[:2])
        self.ylim = lims[2:]
        self.bndry_cond = bndry_cond
        self.order = order
        self.mesh_pts_1d = self.mesh_pts
        self.mesh_pts = cartesian_product([self.mesh_pts_1d]*2, 1)

        # note scaling of self.derivative_matrix to [a,b] happens at base class
        self.determine_boundary_indices()
        # form derivative (in x1-direction) matrix of a 2d polynomial
        # this assumes that 2d-mesh_pts varies in x1 faster than x2,
        # e.g. points are
        # [[x11,x21],[x12,x21],[x13,x12],[x11,x22],[x12,x22],...]
        Ident = np.eye(self.order+1)
        derivative_matrix_1d = self.get_derivative_matrix()
        self.derivative_matrix_1 = np.kron(Ident, derivative_matrix_1d)
        # form derivative (in x2-direction) matrix of a 2d polynomial
        self.derivative_matrix_2 = np.kron(derivative_matrix_1d, Ident)
def error_vs_cost(model, generate_random_samples, validation_levels):
    #import sys
    #sys.setrecursionlimit(10)
    #model=WorkTrackingModel(model,model.base_model)
    num_samples = 10
    validation_levels = np.asarray(validation_levels)
    assert len(validation_levels) == model.base_model.num_config_vars
    config_vars = cartesian_product(
        [np.arange(ll) for ll in validation_levels])

    random_samples = generate_random_samples(num_samples)
    samples = get_all_sample_combinations(random_samples, config_vars)

    reference_samples = samples[:, ::config_vars.shape[1]].copy()
    reference_samples[-model.base_model.num_config_vars:,:]=\
            validation_levels[:,np.newaxis]

    reference_values = model(reference_samples)
    reference_mean = reference_values[:, 0].mean()

    values = model(samples)

    # put keys in order returned by cartesian product
    keys = sorted(model.work_tracker.costs.keys(), key=lambda x: x[::-1])
    keys = keys[:
                -1]  # remove validation key associated with validation samples
    costs, ndofs, means, errors = [], [], [], []
    for ii in range(len(keys)):
        key = keys[ii]
        costs.append(np.median(model.work_tracker.costs[key]))
        nx, ny, dt = model.base_model.get_degrees_of_freedom_and_timestep(
            np.asarray(key))
        ndofs.append(nx * ny * model.base_model.final_time / dt)
        print(key, ndofs[-1], nx, ny, model.base_model.final_time / dt)
        means.append(np.mean(values[ii::config_vars.shape[1], 0]))
        errors.append(abs(means[-1] - reference_mean) / abs(reference_mean))

    times = costs.copy()
    # make costs relative
    costs /= costs[-1]

    n1, n2, n3 = validation_levels
    indices = np.reshape(np.arange(len(keys), dtype=int), (n1, n2, n3),
                         order='F')
    costs = np.reshape(np.array(costs), (n1, n2, n3), order='F')
    ndofs = np.reshape(np.array(ndofs), (n1, n2, n3), order='F')
    errors = np.reshape(np.array(errors), (n1, n2, n3), order='F')
    times = np.reshape(np.array(times), (n1, n2, n3), order='F')

    validation_index = reference_samples[-model.base_model.num_config_vars:, 0]
    validation_time = np.median(
        model.work_tracker.costs[tuple(validation_levels)])
    validation_cost = validation_time / costs[-1]
    validation_ndof = np.prod(reference_values[:, -2:], axis=1)

    data = {
        "costs": costs,
        "errors": errors,
        "indices": indices,
        "times": times,
        "validation_index": validation_index,
        "validation_cost": validation_cost,
        "validation_ndof": validation_ndof,
        "validation_time": validation_time,
        "ndofs": ndofs
    }

    return data
예제 #22
0
def evaluate_active_subspace_density_1d(W,
                                        density_fn,
                                        points_for_eval=None,
                                        num_quad_points=100,
                                        plot_steps=True):
    """
    Assume we have hypercube on [-1,1]^d, d=2
    W: matrix (d x d)
       rotation matrix usually the transpose of activesubspace eigenvectors
    num_quad_points: int
       number of quadrature points used to integrate 2d density along a line
    points_for_eval: vector (d)
       points at which to evalute the 1d active subspace density

    """
    assert W.shape[0] == W.shape[1] == 2

    num_dims = 2
    #Split rotation matrix into active subspace eigenvector
    W1 = W[0, :]
    # and inactive subspace eigenvector
    W2 = W[1, :]

    # define hypercube vertices
    hypercube_vertices_1d = np.array([-1., 1.])
    hypercube_vertices = cartesian_product([hypercube_vertices_1d] * num_dims,
                                           1)

    # compute location of each hypercube vertices in the 1d active subspace.
    # multiple vertices may map to the same point
    mapped_vertices = np.dot(W1, hypercube_vertices).squeeze()
    mapped_vertices = np.sort(mapped_vertices)

    subspace_1d_bounds = mapped_vertices.min(), mapped_vertices.max()

    # compute location of each hypercube vertices in the rotated
    # (but still full dimensional) active subspace coordinates.
    rotated_vertices = np.dot(W, hypercube_vertices)
    # sort vertices for plotting
    rotated_vertices = sort_2d_vertices_by_polar_angle(rotated_vertices)

    # define points for plotting in 1d active subspace
    if points_for_eval is None:
        num_points_for_eval = 102
        delta = (subspace_1d_bounds[1] -
                 subspace_1d_bounds[0]) / (num_points_for_eval)
        points_for_eval = np.linspace(subspace_1d_bounds[0] + delta / 2.,
                                      subspace_1d_bounds[1] - delta / 2.,
                                      num_points_for_eval)
    else:
        # map subspace eval points from [-1,1] to [lb,ub]
        assert points_for_eval.min() >= -1 and points_for_eval.max() <= 1
        points_for_eval = map_m11_to_ab(points_for_eval, subspace_1d_bounds[0],
                                        subspace_1d_bounds[1])

    # Initialize memory and counters
    cnt_all = 0
    density_vals = np.zeros(points_for_eval.shape[0], float)
    for i in range(mapped_vertices.shape[0] - 1):
        # Find points in 1d active subspace that map to the
        # current edge of the two dimensional hypercube
        I = np.where((points_for_eval >= mapped_vertices[i])
                     & (points_for_eval < mapped_vertices[i + 1]))[0]
        points_for_eval_in_interval = points_for_eval[I]
        num_points_for_eval_in_interval = points_for_eval_in_interval.shape[0]

        # Check that no points for eval coincide with the location of
        # the mappeed hypercube vertices. Such points will mess up search
        # for perpendicular line
        assert np.all(points_for_eval_in_interval != mapped_vertices[i])
        assert np.all(points_for_eval_in_interval != mapped_vertices[i + 1])

        # integrate desity on zonotope along the line perpendicular to the
        # active subspace that runs through the point
        # points_for_eval_in_interval[i] and extends to edges on original
        # hypercube. At some locations line may only touch
        # the boundary of the hyercube on one side of the active subspace
        for j in range(num_points_for_eval_in_interval):
            line = find_line_perpendicular_to_active_subspace(
                W, points_for_eval_in_interval[j])

            density = integrate_density_a_2d_function_long_a_line(
                W,
                line,
                points_for_eval_in_interval[j],
                density_fn,
                num_quad_points=num_quad_points)

            points_for_eval[cnt_all] = points_for_eval_in_interval[j]
            density_vals[cnt_all] = density

            cnt_all += 1

            if plot_steps:
                plot_evaluate_active_subspace_density_1d_step(
                    line, points_for_eval_in_interval[j], rotated_vertices,
                    density_fn, points_for_eval, cnt_all, W, mapped_vertices,
                    density_vals)
                plt.show()
    assert cnt_all == points_for_eval.shape[0]

    return density_vals, subspace_1d_bounds
예제 #23
0
    def test_discrete_induced_sampling(self):
        degree = 3

        nmasses1 = 10
        mass_locations1 = np.geomspace(1.0, 512.0, num=nmasses1)
        #mass_locations1 = np.arange(0,nmasses1)
        masses1 = np.ones(nmasses1, dtype=float) / nmasses1
        var1 = float_rv_discrete(name='float_rv_discrete',
                                 values=(mass_locations1, masses1))()

        nmasses2 = 10
        mass_locations2 = np.arange(0, nmasses2)
        # if increase from 16 unmodififed becomes ill conditioned
        masses2 = np.geomspace(1.0, 16.0, num=nmasses2)
        #masses2  = np.ones(nmasses2,dtype=float)/nmasses2

        masses2 /= masses2.sum()
        var2 = float_rv_discrete(name='float_rv_discrete',
                                 values=(mass_locations2, masses2))()

        var_trans = AffineRandomVariableTransformation([var1, var2])
        pce_opts = define_poly_options_from_variable_transformation(var_trans)

        pce = PolynomialChaosExpansion()
        pce.configure(pce_opts)
        indices = compute_hyperbolic_indices(pce.num_vars(), degree, 1.0)
        pce.set_indices(indices)

        num_samples = int(1e4)
        np.random.seed(1)
        canonical_samples = generate_induced_samples(pce, num_samples)
        samples = var_trans.map_from_canonical_space(canonical_samples)

        np.random.seed(1)
        canonical_xk = [
            2 * get_distribution_info(var1)[2]['xk'] - 1,
            2 * get_distribution_info(var2)[2]['xk'] - 1
        ]
        basis_matrix_generator = partial(basis_matrix_generator_1d, pce,
                                         degree)
        canonical_samples1 = discrete_induced_sampling(
            basis_matrix_generator, pce.indices, canonical_xk,
            [var1.dist.pk, var2.dist.pk], num_samples)
        samples1 = var_trans.map_from_canonical_space(canonical_samples1)

        def density(x):
            return var1.pdf(x[0, :]) * var2.pdf(x[1, :])

        envelope_factor = 30

        def generate_proposal_samples(n):
            samples = np.vstack([var1.rvs(n), var2.rvs(n)])
            return samples

        proposal_density = density

        # unlike fekete and leja sampling can and should use
        # pce.basis_matrix here. If use canonical_basis_matrix then
        # densities must be mapped to this space also which can be difficult
        samples2 = random_induced_measure_sampling(num_samples, pce.num_vars(),
                                                   pce.basis_matrix, density,
                                                   proposal_density,
                                                   generate_proposal_samples,
                                                   envelope_factor)

        def induced_density(x):
            vals = density(x) * christoffel_function(x, pce.basis_matrix, True)
            return vals

        from pyapprox.utilities import cartesian_product, outer_product
        from pyapprox.polynomial_sampling import christoffel_function
        quad_samples = cartesian_product([var1.dist.xk, var2.dist.xk])
        quad_weights = outer_product([var1.dist.pk, var2.dist.pk])

        #print(canonical_samples.min(axis=1),canonical_samples.max(axis=1))
        #print(samples.min(axis=1),samples.max(axis=1))
        #print(canonical_samples1.min(axis=1),canonical_samples1.max(axis=1))
        #print(samples1.min(axis=1),samples1.max(axis=1))
        # import matplotlib.pyplot as plt
        # plt.plot(quad_samples[0,:],quad_samples[1,:],'s')
        # plt.plot(samples[0,:],samples[1,:],'o')
        # plt.plot(samples1[0,:],samples1[1,:],'*')
        # plt.show()

        rtol = 1e-2
        assert np.allclose(quad_weights, density(quad_samples))
        assert np.allclose(density(quad_samples).sum(), 1)
        assert np.allclose(
            christoffel_function(quad_samples, pce.basis_matrix,
                                 True).dot(quad_weights), 1.0)
        true_induced_mean = quad_samples.dot(induced_density(quad_samples))
        print(true_induced_mean)
        print(samples.mean(axis=1))
        print(samples1.mean(axis=1))
        print(samples2.mean(axis=1))
        print(
            samples1.mean(axis=1) - true_induced_mean,
            true_induced_mean * rtol)
        #print(samples2.mean(axis=1))
        assert np.allclose(samples.mean(axis=1), true_induced_mean, rtol=rtol)
        assert np.allclose(samples1.mean(axis=1), true_induced_mean, rtol=rtol)
        assert np.allclose(samples2.mean(axis=1), true_induced_mean, rtol=rtol)
예제 #24
0
    def help_compare_prediction_based_oed(self, deviation_fun,
                                          gauss_deviation_fun,
                                          use_gauss_quadrature,
                                          ninner_loop_samples, ndesign_vars,
                                          tol):
        ncandidates_1d = 5
        design_candidates = cartesian_product(
            [np.linspace(-1, 1, ncandidates_1d)] * ndesign_vars)
        ncandidates = design_candidates.shape[1]

        # Define model used to predict likely observable data
        indices = compute_hyperbolic_indices(ndesign_vars, 1)[:, 1:]
        Amat = monomial_basis_matrix(indices, design_candidates)
        obs_fun = partial(linear_obs_fun, Amat)

        # Define model used to predict unobservable QoI
        qoi_fun = exponential_qoi_fun

        # Define the prior PDF of the unknown variables
        nrandom_vars = indices.shape[1]
        prior_variable = IndependentMultivariateRandomVariable(
            [stats.norm(0, 0.5)] * nrandom_vars)

        # Define the independent observational noise
        noise_std = 1

        # Define initial design
        init_design_indices = np.array([ncandidates // 2])

        # Define OED options
        nouter_loop_samples = 100
        if use_gauss_quadrature:
            # 301 needed for cvar deviation
            # only 31 needed for variance deviation
            ninner_loop_samples_1d = ninner_loop_samples
            var_trans = AffineRandomVariableTransformation(prior_variable)
            x_quad, w_quad = gauss_hermite_pts_wts_1D(ninner_loop_samples_1d)
            x_quad = cartesian_product([x_quad] * nrandom_vars)
            w_quad = outer_product([w_quad] * nrandom_vars)
            x_quad = var_trans.map_from_canonical_space(x_quad)
            ninner_loop_samples = x_quad.shape[1]

            def generate_inner_prior_samples(nsamples):
                assert nsamples == x_quad.shape[1], (nsamples, x_quad.shape)
                return x_quad, w_quad
        else:
            # use default Monte Carlo sampling
            generate_inner_prior_samples = None

        # Define initial design
        init_design_indices = np.array([ncandidates // 2])

        # Setup OED problem
        oed = BayesianBatchDeviationOED(design_candidates,
                                        obs_fun,
                                        noise_std,
                                        prior_variable,
                                        qoi_fun,
                                        nouter_loop_samples,
                                        ninner_loop_samples,
                                        generate_inner_prior_samples,
                                        deviation_fun=deviation_fun)
        oed.populate()
        oed.set_collected_design_indices(init_design_indices)

        prior_mean = oed.prior_variable.get_statistics('mean')
        prior_cov = np.diag(prior_variable.get_statistics('var')[:, 0])
        prior_cov_inv = np.linalg.inv(prior_cov)
        selected_indices = init_design_indices

        # Generate experimental design
        nexperiments = 3
        for step in range(len(init_design_indices), nexperiments):
            # Copy current state of OED before new data is determined
            # This copy will be used to compute Laplace based utility and
            # evidence values for testing
            oed_copy = copy.deepcopy(oed)

            # Update the design
            utility_vals, selected_indices = oed.update_design()

            utility, deviations, evidences, weights = \
                oed_copy.compute_expected_utility(
                    oed_copy.collected_design_indices, selected_indices, True)

            exact_deviations = np.empty(nouter_loop_samples)
            for jj in range(nouter_loop_samples):
                # only test intermediate quantities associated with design
                # chosen by the OED step
                idx = oed.collected_design_indices
                obs_jj = oed_copy.outer_loop_obs[jj:jj + 1, idx]

                noise_cov_inv_jj = np.eye(idx.shape[0]) / noise_std**2
                exact_post_mean_jj, exact_post_cov_jj = \
                    laplace_posterior_approximation_for_linear_models(
                        Amat[idx, :],
                        prior_mean, prior_cov_inv, noise_cov_inv_jj, obs_jj.T)

                exact_deviations[jj] = gauss_deviation_fun(
                    exact_post_mean_jj, exact_post_cov_jj)
            print('d',
                  np.absolute(exact_deviations - deviations[:, 0]).max(), tol)
            # print(exact_deviations, deviations[:, 0])
            assert np.allclose(exact_deviations, deviations[:, 0], atol=tol)
            assert np.allclose(utility_vals[selected_indices],
                               -np.mean(exact_deviations),
                               atol=tol)
    def test_evaluate_multivariate_orthonormal_polynomial(self):
        num_vars = 2
        alpha = 0.
        beta = 0.
        degree = 2
        deriv_order = 1
        probability_measure = True

        ab = jacobi_recurrence(degree + 1,
                               alpha=alpha,
                               beta=beta,
                               probability=probability_measure)

        x, w = np.polynomial.legendre.leggauss(degree)
        samples = cartesian_product([x] * num_vars, 1)

        indices = compute_hyperbolic_indices(num_vars, degree, 1.0)

        # sort lexographically to make testing easier
        II = np.lexsort((indices[0, :], indices[1, :], indices.sum(axis=0)))
        indices = indices[:, II]

        basis_matrix = evaluate_multivariate_orthonormal_polynomial(
            samples, indices, ab, deriv_order)

        exact_basis_vals_1d = []
        exact_basis_derivs_1d = []
        for dd in range(num_vars):
            x = samples[dd, :]
            exact_basis_vals_1d.append(
                np.asarray([1 + 0. * x, x, 0.5 * (3. * x**2 - 1)]).T)
            exact_basis_derivs_1d.append(
                np.asarray([0. * x, 1.0 + 0. * x, 3. * x]).T)
            exact_basis_vals_1d[-1] /= np.sqrt(1. /
                                               (2 * np.arange(degree + 1) + 1))
            exact_basis_derivs_1d[-1] /= np.sqrt(
                1. / (2 * np.arange(degree + 1) + 1))

        exact_basis_matrix = np.asarray([
            exact_basis_vals_1d[0][:, 0], exact_basis_vals_1d[0][:, 1],
            exact_basis_vals_1d[1][:, 1], exact_basis_vals_1d[0][:, 2],
            exact_basis_vals_1d[0][:, 1] * exact_basis_vals_1d[1][:, 1],
            exact_basis_vals_1d[1][:, 2]
        ]).T

        # x1 derivative
        exact_basis_matrix = np.vstack(
            (exact_basis_matrix,
             np.asarray([
                 0. * x, exact_basis_derivs_1d[0][:, 1], 0. * x,
                 exact_basis_derivs_1d[0][:, 2],
                 exact_basis_derivs_1d[0][:, 1] * exact_basis_vals_1d[1][:, 1],
                 0. * x
             ]).T))

        # x2 derivative
        exact_basis_matrix = np.vstack(
            (exact_basis_matrix,
             np.asarray([
                 0. * x, 0. * x, exact_basis_derivs_1d[1][:, 1], 0. * x,
                 exact_basis_vals_1d[0][:, 1] * exact_basis_derivs_1d[1][:, 1],
                 exact_basis_derivs_1d[1][:, 2]
             ]).T))

        def func(x):
            return evaluate_multivariate_orthonormal_polynomial(
                x, indices, ab, 0)

        basis_matrix_derivs = basis_matrix[samples.shape[1]:]
        basis_matrix_derivs_fd = np.empty_like(basis_matrix_derivs)
        for ii in range(samples.shape[1]):
            basis_matrix_derivs_fd[ii::samples.shape[1], :] = approx_fprime(
                samples[:, ii:ii + 1], func, 1e-7)
        assert np.allclose(exact_basis_matrix[samples.shape[1]:],
                           basis_matrix_derivs_fd)

        assert np.allclose(exact_basis_matrix, basis_matrix)
예제 #26
0
    def test_multivariate_barycentric_lagrange_interpolation(self):
        def f(x):
            return np.sum(x**2, axis=0)

        eps = 1e-14

        # test 1d barycentric lagrange interpolation
        level = 5
        #abscissa, __ = clenshaw_curtis_pts_wts_1D( level )
        #barycentric_weights_1d = [clenshaw_curtis_barycentric_weights(level)]
        abscissa, __ = clenshaw_curtis_in_polynomial_order(level, False)
        abscissa_1d = [abscissa]
        barycentric_weights_1d = [
            compute_barycentric_weights_1d(abscissa_1d[0])
        ]
        fn_vals = f(np.array(abscissa).reshape(1,
                                               abscissa.shape[0]))[:,
                                                                   np.newaxis]
        pts = np.linspace(-1., 1., 3).reshape(1, 3)
        poly_vals = multivariate_barycentric_lagrange_interpolation(
            pts, abscissa_1d, barycentric_weights_1d, fn_vals, np.array([0]))

        #import pylab
        # print poly_vals.squeeze().shape
        # pylab.plot(pts[0,:],poly_vals.squeeze())
        # pylab.plot(abscissa_1d[0],fn_vals.squeeze(),'ro')
        # print np.linalg.norm( poly_vals - f( pts ) )
        # pylab.show()
        assert np.allclose(poly_vals, f(pts)[:, np.newaxis], eps)

        # test 2d barycentric lagrange interpolation
        # with the same abscissa in each dimension
        a = -3.0
        b = 3.0
        x = np.linspace(a, b, 21)
        [X, Y] = np.meshgrid(x, x)
        pts = np.vstack((X.reshape((1, X.shape[0] * X.shape[1])),
                         Y.reshape((1, Y.shape[0] * Y.shape[1]))))

        num_abscissa = [10, 10]
        abscissa_1d = [
            np.linspace(a, b, num_abscissa[0]),
            np.linspace(a, b, num_abscissa[1])
        ]

        abscissa = cartesian_product(abscissa_1d, 1)
        fn_vals = f(abscissa)
        barycentric_weights_1d = [
            compute_barycentric_weights_1d(abscissa_1d[0]),
            compute_barycentric_weights_1d(abscissa_1d[1])
        ]

        poly_vals = multivariate_barycentric_lagrange_interpolation(
            pts, abscissa_1d, barycentric_weights_1d, fn_vals[:, np.newaxis],
            np.array([0, 1]))

        assert np.allclose(poly_vals, f(pts)[:, np.newaxis], eps)

        # test 2d barycentric lagrange interpolation
        # with different abscissa in each dimension
        a = -1.0
        b = 1.0
        x = np.linspace(a, b, 21)
        [X, Y] = np.meshgrid(x, x)
        pts = np.vstack((X.reshape((1, X.shape[0] * X.shape[1])),
                         Y.reshape((1, Y.shape[0] * Y.shape[1]))))

        level = [1, 2]
        nodes_0, tmp = clenshaw_curtis_pts_wts_1D(level[0])
        nodes_1, tmp = clenshaw_curtis_pts_wts_1D(level[1])
        abscissa_1d = [nodes_0, nodes_1]
        barycentric_weights_1d = [
            clenshaw_curtis_barycentric_weights(level[0]),
            clenshaw_curtis_barycentric_weights(level[1])
        ]
        abscissa = cartesian_product(abscissa_1d, 1)
        fn_vals = f(abscissa)

        poly_vals = multivariate_barycentric_lagrange_interpolation(
            pts, abscissa_1d, barycentric_weights_1d, fn_vals[:, np.newaxis],
            np.array([0, 1]))

        assert np.allclose(poly_vals, f(pts)[:, np.newaxis], eps)

        # test 3d barycentric lagrange interpolation
        # with different abscissa in each dimension
        num_dims = 3
        a = -1.0
        b = 1.0
        pts = np.random.uniform(-1., 1., (num_dims, 10))

        level = [1, 1, 1]
        nodes_0, tmp = clenshaw_curtis_pts_wts_1D(level[0])
        nodes_1, tmp = clenshaw_curtis_pts_wts_1D(level[1])
        nodes_2, tmp = clenshaw_curtis_pts_wts_1D(level[2])
        abscissa_1d = [nodes_0, nodes_1, nodes_2]
        barycentric_weights_1d = [
            clenshaw_curtis_barycentric_weights(level[0]),
            clenshaw_curtis_barycentric_weights(level[1]),
            clenshaw_curtis_barycentric_weights(level[2])
        ]
        abscissa = cartesian_product(abscissa_1d, 1)
        fn_vals = f(abscissa)

        poly_vals = multivariate_barycentric_lagrange_interpolation(
            pts, abscissa_1d, barycentric_weights_1d, fn_vals[:, np.newaxis],
            np.array([0, 1, 2]))
        assert np.allclose(poly_vals, f(pts)[:, np.newaxis], eps)

        # test 3d barycentric lagrange interpolation
        # with different abscissa in each dimension
        # and only two active dimensions (0 and 2)
        num_dims = 3
        a = -1.0
        b = 1.0
        pts = np.random.uniform(-1., 1., (num_dims, 5))

        level = [2, 0, 1]
        # to get fn_vals we must specify abscissa for all three dimensions
        # but only the abscissa of the active dimensions should get passed
        # to the interpolation function
        nodes_0, tmp = clenshaw_curtis_pts_wts_1D(level[0])
        nodes_1, tmp = clenshaw_curtis_pts_wts_1D(level[1])
        nodes_2, tmp = clenshaw_curtis_pts_wts_1D(level[2])
        abscissa_1d = [nodes_0, nodes_1, nodes_2]
        abscissa = cartesian_product(abscissa_1d, 1)
        abscissa_1d = [nodes_0, nodes_2]
        barycentric_weights_1d = [
            clenshaw_curtis_barycentric_weights(level[0]),
            clenshaw_curtis_barycentric_weights(level[2])
        ]
        fn_vals = f(abscissa)

        poly_vals = multivariate_barycentric_lagrange_interpolation(
            pts, abscissa_1d, barycentric_weights_1d, fn_vals[:, np.newaxis],
            np.array([0, 2]))
        pts[1, :] = 0.
        assert np.allclose(poly_vals, f(pts)[:, np.newaxis], eps)

        # test 3d barycentric lagrange interpolation
        # with different abscissa in each dimension
        # and only two active dimensions (0 and 1)
        num_dims = 3
        a = -1.0
        b = 1.0
        pts = np.random.uniform(-1., 1., (num_dims, 5))

        level = [2, 3, 0]
        # to get fn_vals we must specify abscissa for all three dimensions
        # but only the abscissa of the active dimensions should get passed
        # to the interpolation function
        nodes_0, tmp = clenshaw_curtis_pts_wts_1D(level[0])
        nodes_1, tmp = clenshaw_curtis_pts_wts_1D(level[1])
        nodes_2, tmp = clenshaw_curtis_pts_wts_1D(level[2])
        abscissa_1d = [nodes_0, nodes_1, nodes_2]
        abscissa = cartesian_product(abscissa_1d, 1)
        abscissa_1d = [nodes_0, nodes_1]
        barycentric_weights_1d = [
            clenshaw_curtis_barycentric_weights(level[0]),
            clenshaw_curtis_barycentric_weights(level[1])
        ]
        fn_vals = f(abscissa)

        poly_vals = multivariate_barycentric_lagrange_interpolation(
            pts, abscissa_1d, barycentric_weights_1d, fn_vals[:, np.newaxis],
            np.array([0, 1]))
        # The interpolant will only be correct on the plane involving
        # the active dimensions so we must set the coordinate of the inactive
        # dimension to the abscissa coordinate of the inactive dimension.
        # The interpoolation algorithm is efficient in the sense that it
        # ignores all dimensions involving only one point because the
        # interpolant will be a constant in that direction
        pts[2, :] = 0.
        assert np.allclose(poly_vals, f(pts)[:, np.newaxis], eps)

        # test 3d barycentric lagrange interpolation
        # with different abscissa in each dimension
        # and only two active dimensions (1 and 2)
        num_dims = 3
        a = -1.0
        b = 1.0
        pts = np.random.uniform(-1., 1., (num_dims, 5))

        level = [0, 2, 4]
        # to get fn_vals we must specify abscissa for all three dimensions
        # but only the abscissa of the active dimensions should get passed
        # to the interpolation function
        nodes_0, tmp = clenshaw_curtis_pts_wts_1D(level[0])
        nodes_1, tmp = clenshaw_curtis_pts_wts_1D(level[1])
        nodes_2, tmp = clenshaw_curtis_pts_wts_1D(level[2])
        abscissa_1d = [nodes_0, nodes_1, nodes_2]
        abscissa = cartesian_product(abscissa_1d, 1)
        abscissa_1d = [nodes_1, nodes_2]
        barycentric_weights_1d = [
            clenshaw_curtis_barycentric_weights(level[1]),
            clenshaw_curtis_barycentric_weights(level[2])
        ]
        fn_vals = f(abscissa)

        poly_vals = multivariate_barycentric_lagrange_interpolation(
            pts, abscissa_1d, barycentric_weights_1d, fn_vals[:, np.newaxis],
            np.array([1, 2]))
        pts[0, :] = 0.
        assert np.allclose(poly_vals, f(pts)[:, np.newaxis], eps)

        # test 2d barycentric lagrange interpolation
        # with different abscissa in each dimension and only some of
        # the coefficients of the basis terms being non-zero. This situation
        # arises in hierarchical interpolation. In these cases we need
        # to construct the basis functions on all abscissa but we only
        # need to add the basis functions that are one at the hierachical
        # nodes
        a = -1.0
        b = 1.0
        #x = np.linspace( a, b, 21 )
        x = np.linspace(a, b, 5)
        [X, Y] = np.meshgrid(x, x)
        pts = np.vstack((X.reshape((1, X.shape[0] * X.shape[1])),
                         Y.reshape((1, Y.shape[0] * Y.shape[1]))))

        poly_vals = np.ones((pts.shape[1], 1), np.double) * \
            f(np.array([[0.0, 0.0]]).T)[:, np.newaxis]

        level = [1]
        nodes_0, tmp = clenshaw_curtis_pts_wts_1D(level[0])
        abscissa_1d = [nodes_0]
        barycentric_weights_1d = [
            compute_barycentric_weights_1d(abscissa_1d[0])
        ]
        sets = copy.copy(abscissa_1d)
        sets.append(np.array([0.0]))
        abscissa = cartesian_product(sets, 1)
        hier_indices = np.array([[0, 2]], np.int32)
        abscissa = abscissa[:, hier_indices[0]]
        fn_vals = f(abscissa)
        poly_vals_increment = \
            multivariate_hierarchical_barycentric_lagrange_interpolation(
                pts, abscissa_1d, barycentric_weights_1d,
                (fn_vals - np.ones((abscissa.shape[1]), np.double) * f(
                    np.array([0.0, 0.0])))[:, np.newaxis],
                np.array([0]), hier_indices)
        poly_vals += poly_vals_increment

        level = [1]
        nodes_0, tmp = clenshaw_curtis_pts_wts_1D(level[0])
        abscissa_1d = [nodes_0]
        # barycentric_weights_1d = [barycentric_weights( np.array( [0.0] ) ),
        #                          barycentric_weights( abscissa_1d[0] )]
        barycentric_weights_1d = [
            compute_barycentric_weights_1d(abscissa_1d[0])
        ]

        sets = [np.array([0.0])]
        sets.append(nodes_0)
        abscissa = cartesian_product(sets, 1)
        hier_indices = np.array([[0, 2]], np.int32)
        abscissa = abscissa[:, hier_indices[0]]
        fn_vals = f(abscissa)
        poly_vals += \
            multivariate_hierarchical_barycentric_lagrange_interpolation(
                pts, abscissa_1d, barycentric_weights_1d,
                (fn_vals - np.ones((abscissa.shape[1]), np.double) * f(
                    np.array([[0.0, 0.0]]).T))[:, np.newaxis],
                np.array([1]), hier_indices)

        assert np.allclose(poly_vals, f(pts)[:, np.newaxis], eps)
예제 #27
0
    def help_discrete_induced_sampling(self, var1, var2, envelope_factor):
        degree = 3

        var_trans = AffineRandomVariableTransformation([var1, var2])
        pce_opts = define_poly_options_from_variable_transformation(var_trans)

        pce = PolynomialChaosExpansion()
        pce.configure(pce_opts)
        indices = compute_hyperbolic_indices(pce.num_vars(), degree, 1.0)
        pce.set_indices(indices)

        num_samples = int(3e4)
        np.random.seed(1)
        canonical_samples = generate_induced_samples(pce, num_samples)
        samples = var_trans.map_from_canonical_space(canonical_samples)

        np.random.seed(1)
        #canonical_xk = [2*get_distribution_info(var1)[2]['xk']-1,
        #                2*get_distribution_info(var2)[2]['xk']-1]
        xk = np.array([
            get_probability_masses(var)[0]
            for var in var_trans.variable.all_variables()
        ])
        pk = np.array([
            get_probability_masses(var)[1]
            for var in var_trans.variable.all_variables()
        ])
        canonical_xk = var_trans.map_to_canonical_space(xk)
        basis_matrix_generator = partial(basis_matrix_generator_1d, pce,
                                         degree)
        canonical_samples1 = discrete_induced_sampling(basis_matrix_generator,
                                                       pce.indices,
                                                       canonical_xk, pk,
                                                       num_samples)
        samples1 = var_trans.map_from_canonical_space(canonical_samples1)

        def univariate_pdf(var, x):
            if hasattr(var.dist, 'pdf'):
                return var.pdf(x)
            else:
                return var.pmf(x)
                xk, pk = get_probability_masses(var)
                x = np.atleast_1d(x)
                vals = np.zeros(x.shape[0])
                for jj in range(x.shape[0]):
                    for ii in range(xk.shape[0]):
                        if xk[ii] == x[jj]:
                            vals[jj] = pk[ii]
                            break
                return vals

        def density(x):
            # some issue with native scipy.pmf
            #assert np.allclose(var1.pdf(x[0, :]),var1.pmf(x[0, :]))
            return univariate_pdf(var1, x[0, :]) * univariate_pdf(
                var2, x[1, :])

        def generate_proposal_samples(n):
            samples = np.vstack([var1.rvs(n), var2.rvs(n)])
            return samples

        proposal_density = density

        # unlike fekete and leja sampling can and should use
        # pce.basis_matrix here. If use canonical_basis_matrix then
        # densities must be mapped to this space also which can be difficult
        samples2 = random_induced_measure_sampling(num_samples, pce.num_vars(),
                                                   pce.basis_matrix, density,
                                                   proposal_density,
                                                   generate_proposal_samples,
                                                   envelope_factor)

        def induced_density(x):
            vals = density(x) * christoffel_function(x, pce.basis_matrix, True)
            return vals

        from pyapprox.utilities import cartesian_product, outer_product
        from pyapprox.polynomial_sampling import christoffel_function
        quad_samples = cartesian_product([xk[0], xk[1]])
        quad_weights = outer_product([pk[0], pk[1]])

        # print(canonical_samples.min(axis=1),canonical_samples.max(axis=1))
        # print(samples.min(axis=1),samples.max(axis=1))
        # print(canonical_samples1.min(axis=1),canonical_samples1.max(axis=1))
        # print(samples1.min(axis=1),samples1.max(axis=1))
        # import matplotlib.pyplot as plt
        # plt.plot(quad_samples[0,:],quad_samples[1,:],'s')
        # plt.plot(samples[0,:],samples[1,:],'o')
        # plt.plot(samples1[0,:],samples1[1,:],'*')
        # plt.show()

        rtol = 1e-2
        assert np.allclose(quad_weights, density(quad_samples))
        assert np.allclose(density(quad_samples).sum(), 1)
        assert np.allclose(
            christoffel_function(quad_samples, pce.basis_matrix,
                                 True).dot(quad_weights), 1.0)
        true_induced_mean = quad_samples.dot(induced_density(quad_samples))
        # print(true_induced_mean)
        # print(samples.mean(axis=1))
        # print(samples1.mean(axis=1))
        # print(samples2.mean(axis=1))
        # print(samples1.mean(axis=1)-true_induced_mean, true_induced_mean*rtol)
        # print(samples2.mean(axis=1))
        assert np.allclose(samples.mean(axis=1), true_induced_mean, rtol=rtol)
        assert np.allclose(samples1.mean(axis=1), true_induced_mean, rtol=rtol)
        assert np.allclose(samples2.mean(axis=1), true_induced_mean, rtol=rtol)
    def test_pce_product_of_beta_variables(self):
        def fun(x):
            return np.sqrt(x.prod(axis=0))[:, None]

        dist_alpha1, dist_beta1 = 1, 1
        dist_alpha2, dist_beta2 = dist_alpha1 + 0.5, dist_beta1
        nvars = 2

        x_1d, w_1d = [], []
        nquad_samples_1d = 100
        x, w = gauss_jacobi_pts_wts_1D(nquad_samples_1d, dist_beta1 - 1,
                                       dist_alpha1 - 1)
        x = (x + 1) / 2
        x_1d.append(x)
        w_1d.append(w)
        x, w = gauss_jacobi_pts_wts_1D(nquad_samples_1d, dist_beta2 - 1,
                                       dist_alpha2 - 1)
        x = (x + 1) / 2
        x_1d.append(x)
        w_1d.append(w)

        quad_samples = cartesian_product(x_1d)
        quad_weights = outer_product(w_1d)

        mean = fun(quad_samples)[:, 0].dot(quad_weights)
        variance = (fun(quad_samples)[:, 0]**2).dot(quad_weights) - mean**2
        assert np.allclose(mean,
                           stats.beta(dist_alpha1 * 2, dist_beta1 * 2).mean())
        assert np.allclose(variance,
                           stats.beta(dist_alpha1 * 2, dist_beta1 * 2).var())

        degree = 10
        poly = PolynomialChaosExpansion()
        # the distribution and ranges of univariate variables is ignored
        # when var_trans.set_identity_maps([0]) is used
        initial_variables = [stats.uniform(0, 1)]
        # TODO get quad rules from initial variables
        quad_rules = [(x, w) for x, w in zip(x_1d, w_1d)]
        univariate_variables = [
            rv_function_indpndt_vars(fun, initial_variables, quad_rules)
        ]
        variable = IndependentMultivariateRandomVariable(univariate_variables)
        var_trans = AffineRandomVariableTransformation(variable)
        poly_opts = define_poly_options_from_variable_transformation(var_trans)
        poly.configure(poly_opts)
        poly.set_indices(tensor_product_indices([degree]))

        train_samples = (np.linspace(0, np.pi, 101)[None, :] + 1) / 2
        train_vals = train_samples.T
        coef = np.linalg.lstsq(poly.basis_matrix(train_samples),
                               train_vals,
                               rcond=None)[0]
        poly.set_coefficients(coef)
        assert np.allclose(poly.mean(),
                           stats.beta(dist_alpha1 * 2, dist_beta1 * 2).mean())
        assert np.allclose(poly.variance(),
                           stats.beta(dist_alpha1 * 2, dist_beta1 * 2).var())

        poly = PolynomialChaosExpansion()
        initial_variables = [stats.uniform(0, 1)]
        funs = [lambda x: np.sqrt(x)] * nvars
        quad_rules = [(x, w) for x, w in zip(x_1d, w_1d)]
        # TODO get quad rules from initial variables
        univariate_variables = [
            rv_product_indpndt_vars(funs, initial_variables, quad_rules)
        ]
        variable = IndependentMultivariateRandomVariable(univariate_variables)
        var_trans = AffineRandomVariableTransformation(variable)
        poly_opts = define_poly_options_from_variable_transformation(var_trans)
        poly.configure(poly_opts)
        poly.set_indices(tensor_product_indices([degree]))

        train_samples = (np.linspace(0, np.pi, 101)[None, :] + 1) / 2
        train_vals = train_samples.T
        coef = np.linalg.lstsq(poly.basis_matrix(train_samples),
                               train_vals,
                               rcond=None)[0]
        poly.set_coefficients(coef)
        assert np.allclose(poly.mean(),
                           stats.beta(dist_alpha1 * 2, dist_beta1 * 2).mean())
        assert np.allclose(poly.variance(),
                           stats.beta(dist_alpha1 * 2, dist_beta1 * 2).var())