def test_lu_leja_interpolation(self):
        num_vars = 2
        degree = 15

        poly = PolynomialChaosExpansion()
        var_trans = define_iid_random_variable_transformation(
            stats.uniform(), num_vars)
        opts = define_poly_options_from_variable_transformation(var_trans)
        poly.configure(opts)
        indices = compute_hyperbolic_indices(num_vars, degree, 1.0)
        poly.set_indices(indices)

        # candidates must be generated in canonical PCE space
        num_candidate_samples = 10000
        def generate_candidate_samples(n): return np.cos(
            np.random.uniform(0., np.pi, (num_vars, n)))

        # must use canonical_basis_matrix to generate basis matrix
        num_leja_samples = indices.shape[1]-1
        def precond_func(matrix, samples): return christoffel_weights(matrix)
        samples, data_structures = get_lu_leja_samples(
            poly.canonical_basis_matrix, generate_candidate_samples,
            num_candidate_samples, num_leja_samples,
            preconditioning_function=precond_func)
        samples = var_trans.map_from_canonical_space(samples)

        assert samples.max() <= 1 and samples.min() >= 0.

        c = np.random.uniform(0., 1., num_vars)
        c *= 20/c.sum()
        w = np.zeros_like(c)
        w[0] = np.random.uniform(0., 1., 1)
        genz_function = GenzFunction('oscillatory', num_vars, c=c, w=w)
        values = genz_function(samples)

        # Ensure coef produce an interpolant
        coef = interpolate_lu_leja_samples(samples, values, data_structures)

        # Ignore basis functions (columns) that were not considered during the
        # incomplete LU factorization
        poly.set_indices(poly.indices[:, :num_leja_samples])
        poly.set_coefficients(coef)

        assert np.allclose(poly(samples), values)

        quad_w = get_quadrature_weights_from_lu_leja_samples(
            samples, data_structures)
        values_at_quad_x = values[:, 0]

        # will get closer if degree is increased
        # print (np.dot(values_at_quad_x,quad_w),genz_function.integrate())
        assert np.allclose(
            np.dot(values_at_quad_x, quad_w), genz_function.integrate(),
            atol=1e-4)
Example #2
0
    def test_fekete_rosenblatt_interpolation(self):
        np.random.seed(2)
        degree=3

        __,__,joint_density,limits = rosenblatt_example_2d(num_samples=1)
        num_vars=len(limits)//2

        rosenblatt_opts = {'limits':limits,'num_quad_samples_1d':20}
        var_trans_1 = RosenblattTransformation(
            joint_density,num_vars,rosenblatt_opts)
        # rosenblatt maps to [0,1] but polynomials of bounded variables
        # are in [-1,1] so add second transformation for this second mapping
        var_trans_2 = define_iid_random_variable_transformation(
            uniform(),num_vars)
        var_trans = TransformationComposition([var_trans_1, var_trans_2])

        poly = PolynomialChaosExpansion()
        poly.configure({'poly_type':'jacobi','alpha_poly':0.,
                        'beta_poly':0.,'var_trans':var_trans})
        indices = compute_hyperbolic_indices(num_vars,degree,1.0)
        poly.set_indices(indices)
        
        num_candidate_samples = 10000
        generate_candidate_samples=lambda n: np.cos(
            np.random.uniform(0.,np.pi,(num_vars,n)))

        precond_func = lambda matrix, samples: christoffel_weights(matrix)
        canonical_samples, data_structures = get_fekete_samples(
            poly.canonical_basis_matrix,generate_candidate_samples,
            num_candidate_samples,preconditioning_function=precond_func)
        samples = var_trans.map_from_canonical_space(canonical_samples)
        assert np.allclose(
            canonical_samples,var_trans.map_to_canonical_space(samples))

        assert samples.max()<=1 and samples.min()>=0.

        c = np.random.uniform(0.,1.,num_vars)
        c*=20/c.sum()
        w = np.zeros_like(c); w[0] = np.random.uniform(0.,1.,1)
        genz_function = GenzFunction('oscillatory',num_vars,c=c,w=w)
        values = genz_function(samples)
        # function = lambda x: np.sum(x**2,axis=0)[:,np.newaxis]
        # values = function(samples)
        
        # Ensure coef produce an interpolant
        coef = interpolate_fekete_samples(
            canonical_samples,values,data_structures)
        poly.set_coefficients(coef)
        
        assert np.allclose(poly(samples),values)

        # compare mean computed using quadrature and mean computed using
        # first coefficient of expansion. This is not testing that mean
        # is correct because rosenblatt transformation introduces large error
        # which makes it hard to compute accurate mean from pce or quadrature
        quad_w = get_quadrature_weights_from_fekete_samples(
            canonical_samples,data_structures)
        values_at_quad_x = values[:,0]
        assert np.allclose(
            np.dot(values_at_quad_x,quad_w),poly.mean())
Example #3
0
    def test_fekete_interpolation(self):
        num_vars=2
        degree=15

        poly = PolynomialChaosExpansion()
        var_trans = define_iid_random_variable_transformation(
            uniform(),num_vars)
        opts = define_poly_options_from_variable_transformation(var_trans)
        poly.configure(opts)
        indices = compute_hyperbolic_indices(num_vars,degree,1.0)
        poly.set_indices(indices)


        # candidates must be generated in canonical PCE space
        num_candidate_samples = 10000
        generate_candidate_samples=lambda n: np.cos(
            np.random.uniform(0.,np.pi,(num_vars,n)))

        # must use canonical_basis_matrix to generate basis matrix
        precond_func = lambda matrix, samples: christoffel_weights(matrix)
        samples, data_structures = get_fekete_samples(
            poly.canonical_basis_matrix,generate_candidate_samples,
            num_candidate_samples,preconditioning_function=precond_func)
        samples = var_trans.map_from_canonical_space(samples)

        assert samples.max()<=1 and samples.min()>=0.

        c = np.random.uniform(0.,1.,num_vars)
        c*=20/c.sum()
        w = np.zeros_like(c); w[0] = np.random.uniform(0.,1.,1)
        genz_function = GenzFunction('oscillatory',num_vars,c=c,w=w)
        values = genz_function(samples)
        
        # Ensure coef produce an interpolant
        coef = interpolate_fekete_samples(samples,values,data_structures)
        poly.set_coefficients(coef)
        assert np.allclose(poly(samples),values)

        quad_w = get_quadrature_weights_from_fekete_samples(
            samples,data_structures)
        values_at_quad_x = values[:,0]
        # increase degree if want smaller atol
        assert np.allclose(
            np.dot(values_at_quad_x,quad_w),genz_function.integrate(),
            atol=1e-4)
Example #4
0
def bivariate_uniform_example():
        
    num_vars = 2
    var_trans = define_iid_random_variable_transformation(
        uniform(),num_vars)
    c = np.random.uniform(0.,1.,num_vars)
    c*=20/c.sum()
    w = np.zeros_like(c); w[0] = np.random.uniform(0.,1.,1)
    model = GenzFunction( "oscillatory", num_vars,c=c,w=w)
    generate_parameter_sweeps_and_plot(
        model,{'ranges':var_trans.get_ranges()},
        "parameter-sweeps-test-dir/genz-parameter-sweeps-test.npz",
        'hypercube',num_sweeps=2,show=False)
    # png file save in test-dir do not remove dir if want to check png file
    shutil.rmtree('parameter-sweeps-test-dir/')
    plt.show()
Example #5
0
    def test_oli_leja_interpolation(self):
        num_vars=2
        degree=5
        
        poly = PolynomialChaosExpansion()
        var_trans = define_iid_random_variable_transformation(
            uniform(),num_vars)
        opts = define_poly_options_from_variable_transformation(var_trans)
        poly.configure(opts)
        indices = compute_hyperbolic_indices(num_vars,degree,1.0)
        poly.set_indices(indices)

        # candidates must be generated in canonical PCE space
        num_candidate_samples = 10000
        generate_candidate_samples=lambda n: np.cos(
            np.random.uniform(0.,np.pi,(num_vars,n)))
        generate_candidate_samples=lambda n: (np.cos(
            np.random.uniform(0.,np.pi,(num_vars,n)))+1)/2.

        # must use canonical_basis_matrix to generate basis matrix
        num_leja_samples = indices.shape[1]-1
        precond_func = lambda samples: 1./christoffel_function(
            samples,poly.basis_matrix)
        samples, data_structures = get_oli_leja_samples(
            poly,generate_candidate_samples,
            num_candidate_samples,num_leja_samples,
            preconditioning_function=precond_func)
        #samples = var_trans.map_from_canonical_space(samples)

        assert samples.max()<=1 and samples.min()>=0.

        c = np.random.uniform(0.,1.,num_vars)
        c*=20/c.sum()
        w = np.zeros_like(c); w[0] = np.random.uniform(0.,1.,1)
        genz_function = GenzFunction('oscillatory',num_vars,c=c,w=w)
        values = genz_function(samples)
        
        # Ensure we have produced an interpolant
        oli_solver = data_structures[0]
        poly = oli_solver.get_current_interpolant(samples,values)
        assert np.allclose(poly(samples),values)
Example #6
0
def setup_genz_function(nvars, test_name, coefficients=None):
    r"""
    Setup the Genz Benchmarks.

    For example, the two-dimensional oscillatory Genz problem can be defined 
    using

    >>> from pyapprox.benchmarks.benchmarks import setup_benchmark
    >>> benchmark=setup_benchmark('genz',nvars=2,test_name='oscillatory')
    >>> print(benchmark.keys())
    dict_keys(['fun', 'mean', 'variable'])

    Parameters
    ----------
    nvars : integer
        The number of variables of the Genz function

    test_name : string
        The test_name of the specific Genz function. See notes
        for options the string needed is given in brackets
        e.g. ('oscillatory')

    coefficients : tuple (ndarray (nvars), ndarray (nvars))
        The coefficients :math:`c_i` and :math:`w_i`
        If None (default) then 
        :math:`c_j = \hat{c}_j\left(\sum_{i=1}^d \hat{c}_i\right)^{-1}` where 
        :math:`\hat{c}_i=(10^{-15\left(\frac{i}{d}\right)^2)})`

    Returns
    -------
    benchmark : pya.Benchmark
       Object containing the benchmark attributes

    References
    ----------
    .. [Genz1984] `Genz, A. Testing multidimensional integration routines. In Proc. of international conference on Tools, methods and languages for scientific and engineering computation (pp. 81-94), 1984 <https://dl.acm.org/doi/10.5555/2837.2842>`_

    Notes
    -----

    Corner Peak ('corner-peak')

    .. math:: f(z)=\left( 1+\sum_{i=1}^d c_iz_i\right)^{-(d+1)}

    Oscillatory ('oscillatory')

    .. math:: f(z) = \cos\left(2\pi w_1 + \sum_{i=1}^d c_iz_i\right) 

    Gaussian Peak ('gaussian-peak')

    .. math:: f(z) = \exp\left( -\sum_{i=1}^d c_i^2(z_i-w_i)^2\right)

    Continuous ('continuous')

    .. math:: f(z) = \exp\left( -\sum_{i=1}^d c_i\lvert z_i-w_i\rvert\right)

    Product Peak ('product-peak')

    .. math:: f(z) = \prod_{i=1}^d \left(c_i^{-2}+(z_i-w_i)^2\right)^{-1}

    Discontinuous ('discontinuous')

    .. math:: f(z) = \begin{cases}0 & x_1>u_1 \;\mathrm{or}\; x_2>u_2\\\exp\left(\sum_{i=1}^d c_iz_i\right) & \mathrm{otherwise}\end{cases}

    """
    genz = GenzFunction(test_name, nvars)
    univariate_variables = [stats.uniform(0, 1)] * nvars
    variable = pya.IndependentMultivariateRandomVariable(univariate_variables)
    if coefficients is None:
        genz.set_coefficients(1, 'squared-exponential-decay', 0)
    else:
        genz.c, genz.w = coefficients
    attributes = {'fun': genz, 'mean': genz.integrate(), 'variable': variable}
    if test_name == 'corner-peak':
        attributes['variance'] = genz.variance()
        from scipy.optimize import OptimizeResult
    return Benchmark(attributes)
def genz_example(max_num_samples, precond_type):
    error_tol = 1e-12

    univariate_variables = [uniform(), beta(3, 3)]
    variable = IndependentMultivariateRandomVariable(univariate_variables)
    var_trans = AffineRandomVariableTransformation(variable)

    c = np.array([10, 0.00])
    model = GenzFunction("oscillatory",
                         variable.num_vars(),
                         c=c,
                         w=np.zeros_like(c))
    # model.set_coefficients(4,'exponential-decay')

    validation_samples = generate_independent_random_samples(
        var_trans.variable, int(1e3))
    validation_values = model(validation_samples)

    errors = []
    num_samples = []

    def callback(pce):
        error = compute_l2_error(validation_samples, validation_values, pce)
        errors.append(error)
        num_samples.append(pce.samples.shape[1])

    candidate_samples = -np.cos(
        np.random.uniform(0, np.pi, (var_trans.num_vars(), int(1e4))))
    pce = AdaptiveLejaPCE(var_trans.num_vars(),
                          candidate_samples,
                          factorization_type='fast')
    if precond_type == 'density':

        def precond_function(basis_matrix, samples):
            trans_samples = var_trans.map_from_canonical_space(samples)
            vals = np.ones(samples.shape[1])
            for ii in range(len(univariate_variables)):
                rv = univariate_variables[ii]
                vals *= np.sqrt(rv.pdf(trans_samples[ii, :]))
            return vals
    elif precond_type == 'christoffel':
        precond_function = chistoffel_preconditioning_function
    else:
        raise Exception(f'Preconditioner: {precond_type} not supported')
    pce.set_preconditioning_function(precond_function)

    max_level = np.inf
    max_level_1d = [max_level] * (pce.num_vars)

    admissibility_function = partial(max_level_admissibility_function,
                                     max_level, max_level_1d, max_num_samples,
                                     error_tol)

    growth_rule = partial(constant_increment_growth_rule, 2)
    #growth_rule = clenshaw_curtis_rule_growth
    pce.set_function(model, var_trans)
    pce.set_refinement_functions(variance_pce_refinement_indicator,
                                 admissibility_function, growth_rule)

    while (not pce.active_subspace_queue.empty()
           or pce.subspace_indices.shape[1] == 0):
        pce.refine()
        pce.recompute_active_subspace_priorities()
        if callback is not None:
            callback(pce)

    from pyapprox.sparse_grid import plot_sparse_grid_2d
    plot_sparse_grid_2d(pce.samples, np.ones(pce.samples.shape[1]),
                        pce.pce.indices, pce.subspace_indices)

    plt.figure()
    plt.loglog(num_samples, errors, 'o-')
    plt.show()
Example #8
0
        error /= np.linalg.norm(validation_values, axis=0)

    return error


np.random.seed(1)

#%%
# Our goal is to demonstrate how to use a polynomial chaos expansion (PCE) to approximate a function :math:`f(z): \reals^d \rightarrow \reals` parameterized by the random variables :math:`z=(z_1,\ldots,z_d)`. with the joint probability density function :math:`\pdf(\V{\rv})`. In the following we will use a function commonly used in the literature, the oscillatory Genz function. This function is well suited for testing as the number of variables and the non-linearity can be adjusted. We define the random variables and the function with the following code

univariate_variables = [uniform(), beta(3, 3)]
variable = pya.IndependentMultivariateRandomVariable(univariate_variables)

c = np.array([10, 0.01])
model = GenzFunction("oscillatory",
                     variable.num_vars(),
                     c=c,
                     w=np.zeros_like(c))

#%%
# Here we have intentionally set the coefficients :math:`c`: of the Genz function to be highly anisotropic, to emphasize the properties of the adaptive algorithm.
#
# PCE represent the model output :math:`f(\V{\rv})` as an expansion in orthonormal polynomials,
#
# .. math::
#
#   \begin{align*}
#   f(\V{\rv}) &\approx f_N(\V{\rv}) = \sum_{\lambda\in\Lambda}\alpha_{\lambda}\phi_{\lambda}(\V{\rv}), & |\Lambda| &= N.
#   \end{align*}
#
# where :math:`\lambda=(\lambda_1\ldots,\lambda_d)\in\mathbb{N}_0^d` is a multi-index and :math:`\Lambda` specifies the terms included in the expansion. In :ref:`Polynomial Chaos Regression` we set :math:`\Lambda` to be a total degree expansion. This choice was somewhat arbitray. The exact indices in :math:`\Lambda` should be chosen with more care. The number of terms in a PCE dictates how many samples are need to accurately compute the coefficients of the expansion. Consequently we should choose the index set :math:`\Lambda` in a way that minimizes error for a fixed computational budget. In this tutorial we use an adaptive algorithm to construct an index set that greedily minimizes the error in the PCE. Before starting the adaptive algorithm we must first define the PCE.
Example #9
0
    def test_lu_leja_interpolation_with_intial_samples(self):
        num_vars=2
        degree=15
        
        poly = PolynomialChaosExpansion()
        var_trans = define_iid_random_variable_transformation(
            uniform(),num_vars)
        opts = define_poly_options_from_variable_transformation(var_trans)
        poly.configure(opts)
        indices = compute_hyperbolic_indices(num_vars,degree,1.0)
        poly.set_indices(indices)

        # candidates must be generated in canonical PCE space
        num_candidate_samples = 10000
        generate_candidate_samples=lambda n: np.cos(
            np.random.uniform(0.,np.pi,(num_vars,n)))

        # enforcing lu interpolation to interpolate a set of initial points
        # before selecting best samples from candidates can cause ill conditioning
        # to avoid this issue build a leja sequence and use this as initial
        # samples and then recompute sequence with different candidates
        
        # must use canonical_basis_matrix to generate basis matrix
        num_initial_samples = 5
        initial_samples = None
        num_leja_samples = indices.shape[1]-1
        precond_func = lambda matrix, samples: christoffel_weights(matrix)
        initial_samples, data_structures = get_lu_leja_samples(
            poly.canonical_basis_matrix,generate_candidate_samples,
            num_candidate_samples,num_initial_samples,
            preconditioning_function=precond_func,
            initial_samples=initial_samples)

        samples, data_structures = get_lu_leja_samples(
            poly.canonical_basis_matrix,generate_candidate_samples,
            num_candidate_samples,num_leja_samples,
            preconditioning_function=precond_func,
            initial_samples=initial_samples)

        assert np.allclose(samples[:,:num_initial_samples],initial_samples)
        
        samples = var_trans.map_from_canonical_space(samples)

        assert samples.max()<=1 and samples.min()>=0.

        c = np.random.uniform(0.,1.,num_vars)
        c*=20/c.sum()
        w = np.zeros_like(c); w[0] = np.random.uniform(0.,1.,1)
        genz_function = GenzFunction('oscillatory',num_vars,c=c,w=w)
        values = genz_function(samples)
        
        # Ensure coef produce an interpolant
        coef = interpolate_lu_leja_samples(samples,values,data_structures)
        
        # Ignore basis functions (columns) that were not considered during the
        # incomplete LU factorization
        poly.set_indices(poly.indices[:,:num_leja_samples])
        poly.set_coefficients(coef)

        assert np.allclose(poly(samples),values)

        quad_w = get_quadrature_weights_from_lu_leja_samples(
            samples,data_structures)
        values_at_quad_x = values[:,0]
        assert np.allclose(
            np.dot(values_at_quad_x,quad_w),genz_function.integrate(),
            atol=1e-4)