Example #1
0
def get_univariate_leja_quadrature_rule(
        variable,
        growth_rule,
        method='pdf',
        numerically_generated_poly_accuracy_tolerance=1e-12,
        initial_points=None):

    if not is_continuous_variable(variable):
        return get_discrete_univariate_leja_quadrature_rule(
            variable, growth_rule,
            numerically_generated_poly_accuracy_tolerance=numerically_generated_poly_accuracy_tolerance,
            initial_points=initial_points)

    if method == 'christoffel':
        return partial(
            univariate_christoffel_leja_quadrature_rule, variable, growth_rule,
            numerically_generated_poly_accuracy_tolerance=numerically_generated_poly_accuracy_tolerance, initial_points=initial_points)

    if method == 'pdf':
        return partial(
            univariate_pdf_weighted_leja_quadrature_rule,
            variable, growth_rule,
            numerically_generated_poly_accuracy_tolerance=numerically_generated_poly_accuracy_tolerance,
            initial_points=initial_points)

    assert method == 'deprecated'
    var_name, __, shapes = get_distribution_info(variable)
    if var_name == 'uniform':
        quad_rule = partial(
            beta_leja_quadrature_rule, 1, 1, growth_rule=growth_rule,
            samples_filename=None)
    elif var_name == 'beta':
        quad_rule = partial(
            beta_leja_quadrature_rule, shapes['a'], shapes['b'],
            growth_rule=growth_rule)
    elif var_name == 'norm':
        quad_rule = partial(
            gaussian_leja_quadrature_rule, growth_rule=growth_rule)
    else:
        raise Exception('var_name %s not implemented' % var_name)

    return quad_rule
Example #2
0
def get_univariate_leja_quadrature_rule(variable,
                                        growth_rule,
                                        method='pdf',
                                        orthonormality_tol=1e-8,
                                        initial_points=None,
                                        return_weights_for_all_levels=True,
                                        recursion_opts=None,
                                        minimizer_opts=None):

    if not is_continuous_variable(variable):
        return get_discrete_univariate_leja_quadrature_rule(
            variable,
            growth_rule,
            orthonormality_tol=orthonormality_tol,
            initial_points=initial_points,
            return_weights_for_all_levels=return_weights_for_all_levels,
            recursion_opts=recursion_opts)

    if method == 'christoffel':
        return partial(
            univariate_christoffel_leja_quadrature_rule,
            variable,
            growth_rule,
            orthonormality_tol=orthonormality_tol,
            initial_points=initial_points,
            return_weights_for_all_levels=return_weights_for_all_levels,
            recursion_opts=recursion_opts,
            minimizer_opts=minimizer_opts)

    if method == 'pdf':
        return partial(
            univariate_pdf_weighted_leja_quadrature_rule,
            variable,
            growth_rule,
            orthonormality_tol=orthonormality_tol,
            initial_points=initial_points,
            return_weights_for_all_levels=return_weights_for_all_levels,
            recursion_opts=recursion_opts,
            minimizer_opts=minimizer_opts)

    raise ValueError(f"Method {method} not supported")
Example #3
0
def univariate_christoffel_leja_quadrature_rule(
        variable,
        growth_rule,
        level,
        return_weights_for_all_levels=True,
        initial_points=None,
        orthonormality_tol=1e-12,
        recursion_opts=None,
        minimizer_opts=None):
    """
    Return the samples and weights of the Leja quadrature rule for any
    continuous variable using the inverse Christoffel weight function

    By construction these rules have polynomial ordering.

    Parameters
    ----------
    variable : scipy.stats.dist
        The variable used to construct an orthogonormal polynomial

    growth_rule : callable
        Function which returns the number of samples in the quadrature rule
        With signature

        `growth_rule(level) -> integer`

        where level is an integer

    level : integer
        The level of the univariate rule.

    return_weights_for_all_levels : boolean
        True  - return weights [w(0),w(1),...,w(level)]
        False - return w(level)

    initial_points : np.ndarray (1, ninit_samples)
        Any points that must be included in the Leja sequence. This argument
        is typically used to pass in previously computed sequence which
        is updated efficiently here. MUST be in the canonical domain

    Return
    ------
    ordered_samples_1d : np.ndarray (num_samples_1d)
        The reordered samples.

    ordered_weights_1d : np.ndarray (num_samples_1d)
        The reordered weights.
    """
    if not is_continuous_variable(variable):
        raise Exception('Only supports continuous variables')

    name, scales, shapes = get_distribution_info(variable)
    max_nsamples = growth_rule(level)
    if recursion_opts is None:
        recursion_opts = {"orthonormality_tol": orthonormality_tol}
    ab = get_recursion_coefficients_from_variable(variable, max_nsamples + 1,
                                                  recursion_opts)
    basis_fun = partial(evaluate_orthonormal_polynomial_deriv_1d, ab=ab)

    initial_points, bounds = transform_initial_samples(variable,
                                                       initial_points)

    if minimizer_opts is None:
        minimizer_opts = {'gtol': 1e-8, 'verbose': False}

    if ("artificial_bounds" not in minimizer_opts
            and not is_bounded_continuous_variable(variable)):
        # make bounds twice that of gauss quadrature points
        xg, wg = gauss_quadrature(ab, max_nsamples)
        artificial_bounds = bounds.copy()
        if not np.isfinite(bounds[0]):
            artificial_bounds[0] = xg.min()
            artificial_bounds[0] = artificial_bounds[0] - abs(
                artificial_bounds[0])
        if not np.isfinite(bounds[1]):
            artificial_bounds[1] = xg.max()
            artificial_bounds[1] = artificial_bounds[1] + abs(
                artificial_bounds[1])
        minimizer_opts["artificial_bounds"] = artificial_bounds

    leja_sequence = get_christoffel_leja_sequence_1d(max_nsamples,
                                                     initial_points,
                                                     bounds,
                                                     basis_fun,
                                                     minimizer_opts,
                                                     callback=None)

    __basis_fun = partial(basis_fun, nmax=max_nsamples - 1, deriv_order=0)
    ordered_weights_1d = get_christoffel_leja_quadrature_weights_1d(
        leja_sequence, growth_rule, __basis_fun, level, True)
    if return_weights_for_all_levels:
        return leja_sequence[0, :], ordered_weights_1d
    return leja_sequence[0, :], ordered_weights_1d[-1]
Example #4
0
def univariate_pdf_weighted_leja_quadrature_rule(
        variable, growth_rule, level, return_weights_for_all_levels=True,
        initial_points=None,
        numerically_generated_poly_accuracy_tolerance=1e-12):
    """
    Return the samples and weights of the Leja quadrature rule for any 
    continuous variable using the PDF of the random variable as the 
    weight function

    By construction these rules have polynomial ordering.

    Parameters
    ----------
    variable : scipy.stats.dist
        The variable used to construct an orthogonormal polynomial

    growth_rule : callable
        Function which returns the number of samples in the quadrature rule
        With signature

        `growth_rule(level) -> integer`

        where level is an integer

    level : integer
        The level of the univariate rule.

    return_weights_for_all_levels : boolean
        True  - return weights [w(0),w(1),...,w(level)]
        False - return w(level)

    initial_points : np.ndarray (1, ninit_samples)
        Any points that must be included in the Leja sequence. This argument
        is typically used to pass in previously computed sequence which
        is updated efficiently here.

    Return
    ------
    ordered_samples_1d : np.ndarray (num_samples_1d)
        The reordered samples.

    ordered_weights_1d : np.ndarray (num_samples_1d)
        The reordered weights.
    """
    if not is_continuous_variable(variable):
        raise Exception('Only supports continuous variables')

    name, scales, shapes = get_distribution_info(variable)
    opts = {'rv_type': name, 'shapes': shapes,
            'var_nums': variable}
    max_nsamples = growth_rule(level)
    ab = get_recursion_coefficients(
        opts, max_nsamples+1, numerically_generated_poly_accuracy_tolerance)
    basis_fun = partial(evaluate_orthonormal_polynomial_deriv_1d, ab=ab)

    pdf, pdf_jac = get_pdf_weight_functions(variable)

    if is_bounded_continuous_variable(variable):
        bounds = variable.interval(1.)
        canonical_bounds = [-1, 1]
        if initial_points is None:
            initial_points = np.asarray(
                [[variable.ppf(0.5)]]).T
            loc, scale = scales['loc'], scales['scale']
            lb, ub = -1, 1
            scale /= (ub-lb)
            loc = loc-scale*lb
            initial_points = (initial_points-loc)/scale
        assert np.all((initial_points >= canonical_bounds[0]) &
                      (initial_points <= canonical_bounds[1]))
        # always produce sequence in canonical space
        bounds = canonical_bounds
    else:
        bounds = list(variable.interval(1))
        if initial_points is None:
            initial_points = np.asarray(
                [[variable.ppf(0.5)]]).T
            loc, scale = scales['loc'], scales['scale']
            initial_points = (initial_points-loc)/scale

    leja_sequence = get_pdf_weighted_leja_sequence_1d(
        max_nsamples, initial_points, bounds, basis_fun, pdf, pdf_jac,
        {'gtol': 1e-8, 'verbose': False}, callback=None)

    __basis_fun = partial(basis_fun, nmax=max_nsamples-1, deriv_order=0)
    ordered_weights_1d = get_pdf_weighted_leja_quadrature_weights_1d(
        leja_sequence, growth_rule, pdf, __basis_fun, level, True)

    return leja_sequence[0, :], ordered_weights_1d
Example #5
0
def get_recursion_coefficients_from_variable(var, num_coefs, opts):
    """
    Generate polynomial recursion coefficients by inspecting a random variable.
    """
    var_name, _, shapes = get_distribution_info(var)
    if var_name == "continuous_monomial":
        return None

    loc, scale = transform_scale_parameters(var)

    if var_name == "rv_function_indpndt_vars":
        shapes["loc"] = loc
        shapes["scale"] = scale
        return get_function_independent_vars_recursion_coefficients(
            shapes, num_coefs)

    if var_name == "rv_product_indpndt_vars":
        shapes["loc"] = loc
        shapes["scale"] = scale
        return get_product_independent_vars_recursion_coefficients(
            shapes, num_coefs)

    if (var_name in askey_variable_names
            and opts.get("numeric", False) is False):
        return get_askey_recursion_coefficients_from_variable(var, num_coefs)

    orthonormality_tol = opts.get("orthonormality_tol", 1e-8)
    truncated_probability_tol = opts.get("truncated_probability_tol", 0)
    if (not is_continuous_variable(var)):
        if hasattr(shapes, "xk"):
            xk, pk = shapes["xk"], shapes["pk"]
        else:
            xk, pk = get_probability_masses(var, truncated_probability_tol)
        xk = (xk - loc) / scale

        return get_numerically_generated_recursion_coefficients_from_samples(
            xk, pk, num_coefs, orthonormality_tol, truncated_probability_tol)

    # integration performed in canonical domain so need to map back to
    # domain of pdf
    lb, ub = var.interval(1)

    # Get version var.pdf without error checking which runs much faster
    pdf = get_pdf(var)

    def canonical_pdf(x):
        # print(x, lb, ub, x*scale+loc)
        # print(var.pdf(x*scale+loc)*scale)
        # assert np.all(x*scale+loc >= lb) and np.all(x*scale+loc <= ub)
        return pdf(x * scale + loc) * scale
        # return var.pdf(x*scale+loc)*scale

    if (is_bounded_continuous_variable(var)
            or is_bounded_discrete_variable(var)):
        can_lb, can_ub = -1, 1
    elif is_continuous_variable(var):
        can_lb = (lb - loc) / scale
        can_ub = (ub - loc) / scale

    return predictor_corrector_known_pdf(num_coefs, can_lb, can_ub,
                                         canonical_pdf, opts)