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
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())
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