Example #1
0
    def test_michaelis_menten_model_minimax_d_optimal_least_squares_design(
            self):
        """
        If theta_2 in [a,b] the minimax optimal design will be locally d-optimal
        at b. This can be proved with an application of Holders inequality to 
        show that the determinant of the fihser information matrix decreases
        with increasing theta_2.
        """
        num_design_pts = 7
        design_samples = np.linspace(0, 1, num_design_pts)
        noise_multiplier = None

        local_design_factors = \
            lambda p,x: michaelis_menten_model_grad_parameters(p,x).T
        xx1 = np.linspace(0.9, 1.1, 3)[-1:]  # theta_1 does not effect optimum
        xx2 = np.linspace(0.2, 1, 5)
        from pyapprox import cartesian_product
        parameter_samples = cartesian_product([xx1, xx2])
        opt_problem = AlphabetOptimalDesign('D', local_design_factors)
        mu = opt_problem.solve_nonlinear_minimax(parameter_samples,
                                                 design_samples[np.newaxis, :],
                                                 {
                                                     'iprint': 1,
                                                     'ftol': 1e-8
                                                 })
        I = np.where(mu > 1e-5)[0]
        # given largest theta_2=1 then optimal design will be at 1/3,1
        #with masses=0.5
        assert np.allclose(I, [2, 6])
        assert np.allclose(mu[I], np.ones(2) * 0.5)
def error_vs_cost(model, generate_random_samples, validation_levels,
                  num_samples=10):
    validation_levels = np.asarray(validation_levels)
    assert len(validation_levels) == model.base_model.num_config_vars
    config_vars = pya.cartesian_product(
        [np.arange(ll) for ll in validation_levels])

    random_samples = generate_random_samples(num_samples)
    samples = pya.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])
    # remove validation key associated with validation samples
    keys = keys[:-1]
    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))
        nx, ny = model.base_model.get_mesh_resolution(np.asarray(key)[:2])
        dt = model.base_model.get_timestep(key[2])
        ndofs.append(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
Example #3
0
    def test_heteroscedastic_quantile_bayesian_doptimal_design(self):
        """
        Create D-optimal designs, for least squares regression with 
        homoscedastic noise, and compare to known analytical solutions.
        See Theorem 4.3 in Dette & Trampisch, Optimal Designs for Quantile 
        Regression Models https://doi.org/10.1080/01621459.2012.695665
        """
        poly_degree = 2
        num_design_pts = 100
        x_lb, x_ub = 1e-3, 2000
        design_samples = np.linspace(x_lb, x_ub, num_design_pts)
        design_samples = np.sort(np.concatenate([design_samples, [754.4]]))
        n = 1  # possible values -2,1,0,1

        def link_function(z):
            return 1 / z**n

        def noise_multiplier(p, x):
            return link_function(michaelis_menten_model(p, x))
        local_design_factors = \
            lambda p, x: michaelis_menten_model_grad_parameters(p, x).T
        xx1 = np.array([10])  # theta_1 does not effect optimum
        #xx2 = np.linspace(100,2000,50)
        #parameter_samples = cartesian_product([xx1,xx2])

        p_lb, p_ub = 100, 2000
        local_design_factors = \
            lambda p, x: michaelis_menten_model_grad_parameters(p, x).T
        xx2, ww2 = pya.gauss_jacobi_pts_wts_1D(20, 0, 0)
        # transform from [-1,1] to [p_lb,p_ub]
        xx2 = (xx2 + 1) / 2 * (p_ub - p_lb) + p_lb
        parameter_samples = cartesian_product([xx1, xx2])

        opt_problem = AlphabetOptimalDesign('D',
                                            local_design_factors,
                                            noise_multiplier=noise_multiplier,
                                            regression_type='quantile')

        mu, res = opt_problem.solve_nonlinear_bayesian(
            parameter_samples,
            design_samples[np.newaxis, :],
            sample_weights=ww2,
            options={
                'iprint': 0,
                'ftol': 1e-8,
                'disp': True
            },
            return_full=True)

        # vals = []
        # for ii in range(design_samples.shape[0]):
        #     xopt = np.zeros(design_samples.shape[0])+1e-8;
        #     #xopt[-1]=.5; xopt[ii]=.5
        #     vals.append(res.obj_fun(xopt))
        #plt.plot(design_samples,vals); plt.show()

        I = np.where(mu > 1e-5)[0]
        assert np.allclose(design_samples[I], [754.4, x_ub])
        assert np.allclose(mu[I], [0.5, 0.5])
    def test_marginalize_polynomial_chaos_expansions(self):
        univariate_variables = [uniform(-1, 2), norm(0, 1), uniform(-1, 2)]
        variable = pya.IndependentMultivariateRandomVariable(
            univariate_variables)
        var_trans = pya.AffineRandomVariableTransformation(variable)
        num_vars = len(univariate_variables)

        poly = pya.PolynomialChaosExpansion()
        poly_opts = pya.define_poly_options_from_variable_transformation(
            var_trans)
        poly.configure(poly_opts)

        degree = 2
        indices = pya.compute_hyperbolic_indices(num_vars, degree, 1)
        poly.set_indices(indices)
        poly.set_coefficients(np.ones((indices.shape[1], 1)))

        pce_main_effects, pce_total_effects =\
            pya.get_main_and_total_effect_indices_from_pce(
                poly.get_coefficients(), poly.get_indices())
        print(poly.num_terms())

        for ii in range(num_vars):
            # Marginalize out 2 variables
            xx = np.linspace(-1, 1, 101)
            inactive_idx = np.hstack(
                (np.arange(ii), np.arange(ii + 1, num_vars)))
            marginalized_pce = pya.marginalize_polynomial_chaos_expansion(
                poly, inactive_idx, center=True)
            mvals = marginalized_pce(xx[None, :])
            variable_ii = variable.all_variables()[ii:ii + 1]
            var_trans_ii = pya.AffineRandomVariableTransformation(variable_ii)
            poly_ii = pya.PolynomialChaosExpansion()
            poly_opts_ii = \
                pya.define_poly_options_from_variable_transformation(
                    var_trans_ii)
            poly_ii.configure(poly_opts_ii)
            indices_ii = compute_hyperbolic_indices(1, degree, 1.)
            poly_ii.set_indices(indices_ii)
            poly_ii.set_coefficients(np.ones((indices_ii.shape[1], 1)))
            pvals = poly_ii(xx[None, :])
            # import matplotlib.pyplot as plt
            # plt.plot(xx, pvals)
            # plt.plot(xx, mvals, '--')
            # plt.show()
            assert np.allclose(mvals, pvals - poly.mean())
            assert np.allclose(poly_ii.variance() / poly.variance(),
                               pce_main_effects[ii])
            poly_ii.coefficients /= np.sqrt(poly.variance())
            assert np.allclose(poly_ii.variance(), pce_main_effects[ii])

            # Marginalize out 1 variable
            xx = pya.cartesian_product([xx] * 2)
            inactive_idx = np.array([ii])
            marginalized_pce = pya.marginalize_polynomial_chaos_expansion(
                poly, inactive_idx, center=True)
            mvals = marginalized_pce(xx)
            variable_ii = variable.all_variables()[:ii] +\
                variable.all_variables()[ii+1:]
            var_trans_ii = pya.AffineRandomVariableTransformation(variable_ii)
            poly_ii = pya.PolynomialChaosExpansion()
            poly_opts_ii = \
                pya.define_poly_options_from_variable_transformation(
                    var_trans_ii)
            poly_ii.configure(poly_opts_ii)
            indices_ii = pya.compute_hyperbolic_indices(2, degree, 1.)
            poly_ii.set_indices(indices_ii)
            poly_ii.set_coefficients(np.ones((indices_ii.shape[1], 1)))
            pvals = poly_ii(xx)
            assert np.allclose(mvals, pvals - poly.mean())
Example #5
0
    def help_test_michaelis_menten_model_minimax_optimal_design(
            self, criteria, heteroscedastic=False):
        """
        If theta_2 in [a,b] the minimax optimal design will be locally d-optimal
        at b. This can be proved with an application of Holders inequality to 
        show that the determinant of the fihser information matrix decreases
        with increasing theta_2.
        """
        iprint = 0
        num_design_pts = 30
        design_samples = np.linspace(1e-3, 1, num_design_pts)
        #pred_samples = design_samples
        pred_samples = np.linspace(0, 1, num_design_pts + 10)
        if heteroscedastic:
            n = 1
            link_function = lambda z: 1 / z**n
            noise_multiplier = lambda p, x: link_function(
                michaelis_menten_model(p, x))
        else:
            noise_multiplier = None
        maxiter = int(1e3)

        # come of these quantities are not used by every criteria but
        # always computing these simplifies the test
        beta = 0.75
        local_design_factors = \
            lambda p,x: michaelis_menten_model_grad_parameters(p,x).T
        local_pred_factors = local_design_factors
        opts = {
            'beta': beta,
            'pred_factors': local_pred_factors,
            'pred_samples': pred_samples[np.newaxis, :]
        }

        xx1 = np.linspace(0.9, 1.1, 3)[-1:]  # theta_1 does not effect optimum
        xx2 = np.linspace(0.2, 1, 5)
        from pyapprox import cartesian_product
        parameter_samples = cartesian_product([xx1, xx2])
        x0 = None
        minimax_opt_problem = AlphabetOptimalDesign(criteria,
                                                    local_design_factors,
                                                    noise_multiplier,
                                                    opts=opts)

        mu_minimax = minimax_opt_problem.solve_nonlinear_minimax(
            parameter_samples, design_samples[np.newaxis, :], {
                'iprint': iprint,
                'ftol': 1e-8,
                'maxiter': maxiter
            })

        import copy
        opts = copy.deepcopy(opts)
        mu_local_list = []
        for ii in range(parameter_samples.shape[1]):
            pred_factors = local_design_factors(parameter_samples[:, ii],
                                                pred_samples[np.newaxis, :])
            opts['pred_factors'] = pred_factors
            design_factors = local_design_factors(
                parameter_samples[:, ii], design_samples[np.newaxis, :])
            opt_problem = AlphabetOptimalDesign(criteria,
                                                design_factors,
                                                opts=opts)
            mu_local = opt_problem.solve({
                'iprint': iprint,
                'ftol': 1e-8,
                'maxiter': maxiter
            })
            mu_local_list.append(mu_local)

        constraints = minimax_opt_problem.minimax_nonlinear_constraints(
            parameter_samples, design_samples[np.newaxis, :])

        max_stat = []
        for mu in [mu_minimax] + mu_local_list:
            stats = []
            for ii in range(parameter_samples.shape[1]):
                # evaluate local design criterion f(mu)
                # constraint = t-f(mu) so f(mu)=t-constraint. Chooose any t,
                # i.e. 1
                stats.append(
                    1 -
                    constraints[ii].fun(np.concatenate([np.array([1]), mu])))
            stats = np.array(stats)
            max_stat.append(stats.max(axis=0))
        # check min max stat is obtained by minimax design
        # for d optimal design one local design will be optimal but because
        # of numerical precision it agrees only to 1e-6 with minimax design
        # so round answer and compare. argmin returns first instance of minimum
        max_stat = np.round(max_stat, 6)
        assert np.argmin(max_stat) == 0