def test_approximate_gaussian_process(self): from sklearn.gaussian_process.kernels import Matern num_vars = 1 univariate_variables = [stats.uniform(-1, 2)] * num_vars variable = pya.IndependentMultivariateRandomVariable( univariate_variables) num_samples = 100 train_samples = pya.generate_independent_random_samples( variable, num_samples) # Generate random function nu = np.inf # 2.5 kernel = Matern(0.5, nu=nu) X = np.linspace(-1, 1, 1000)[np.newaxis, :] alpha = np.random.normal(0, 1, X.shape[1]) train_vals = kernel(train_samples.T, X.T).dot(alpha)[:, np.newaxis] gp = approximate(train_samples, train_vals, "gaussian_process", { "nu": nu, "noise_level": 1e-8 }).approx error = np.linalg.norm(gp(X)[:, 0]-kernel(X.T, X.T).dot(alpha)) /\ np.sqrt(X.shape[1]) assert error < 1e-5
def help_cross_validate_pce_degree(self, solver_type, solver_options): print(solver_type, solver_options) num_vars = 2 univariate_variables = [stats.uniform(-1, 2)] * num_vars variable = pya.IndependentMultivariateRandomVariable( univariate_variables) var_trans = pya.AffineRandomVariableTransformation(variable) poly = pya.PolynomialChaosExpansion() poly_opts = pya.define_poly_options_from_variable_transformation( var_trans) poly.configure(poly_opts) degree = 3 poly.set_indices(pya.compute_hyperbolic_indices(num_vars, degree, 1.0)) # factor of 2 does not pass test but 2.2 does num_samples = int(poly.num_terms() * 2.2) coef = np.random.normal(0, 1, (poly.indices.shape[1], 2)) coef[pya.nchoosek(num_vars + 2, 2):, 0] = 0 # for first qoi make degree 2 the best degree poly.set_coefficients(coef) train_samples = pya.generate_independent_random_samples( variable, num_samples) train_vals = poly(train_samples) true_poly = poly poly = approximate( train_samples, train_vals, "polynomial_chaos", { "basis_type": "hyperbolic_cross", "variable": variable, "options": { "verbose": 3, "solver_type": solver_type, "min_degree": 1, "max_degree": degree + 1, "linear_solver_options": solver_options } }).approx num_validation_samples = 10 validation_samples = pya.generate_independent_random_samples( variable, num_validation_samples) assert np.allclose(poly(validation_samples), true_poly(validation_samples)) poly = copy.deepcopy(true_poly) approx_res = cross_validate_pce_degree( poly, train_samples, train_vals, 1, degree + 1, solver_type=solver_type, linear_solver_options=solver_options) assert np.allclose(approx_res.degrees, [2, 3])
def test_pce_basis_expansion(self): num_vars = 2 univariate_variables = [stats.uniform(-1, 2)] * num_vars variable = pya.IndependentMultivariateRandomVariable( univariate_variables) var_trans = pya.AffineRandomVariableTransformation(variable) poly = pya.PolynomialChaosExpansion() poly_opts = pya.define_poly_options_from_variable_transformation( var_trans) poly.configure(poly_opts) degree, hcross_strength = 7, 0.4 poly.set_indices( pya.compute_hyperbolic_indices(num_vars, degree, hcross_strength)) num_samples = poly.num_terms() * 2 degrees = poly.indices.sum(axis=0) coef = np.random.normal( 0, 1, (poly.indices.shape[1], 2)) / (degrees[:, np.newaxis] + 1)**2 # set some coefficients to zero to make sure that different qoi # are treated correctly. II = np.random.permutation(coef.shape[0])[:coef.shape[0] // 2] coef[II, 0] = 0 II = np.random.permutation(coef.shape[0])[:coef.shape[0] // 2] coef[II, 1] = 0 poly.set_coefficients(coef) train_samples = pya.generate_independent_random_samples( variable, num_samples) train_vals = poly(train_samples) true_poly = poly poly = approximate( train_samples, train_vals, "polynomial_chaos", { "basis_type": "expanding_basis", "variable": variable, "options": { "max_num_expansion_steps_iter": 1, "verbose": 3, "max_num_terms": 1000, "max_num_step_increases": 2, "max_num_init_terms": 33 } }).approx num_validation_samples = 100 validation_samples = pya.generate_independent_random_samples( variable, num_validation_samples) validation_samples = train_samples error = np.linalg.norm( poly(validation_samples) - true_poly(validation_samples)) / np.sqrt(num_validation_samples) assert np.allclose(poly(validation_samples), true_poly(validation_samples), atol=1e-8), error
def test_approximate_neural_network(self): np.random.seed(2) benchmark = setup_benchmark("ishigami", a=7, b=0.1) nvars = benchmark.variable.num_vars() nqoi = 1 maxiter = 30000 print(benchmark.variable) # var_trans = pya.AffineRandomVariableTransformation( # [stats.uniform(-2, 4)]*nvars) var_trans = pya.AffineRandomVariableTransformation(benchmark.variable) network_opts = { "activation_func": "sigmoid", "layers": [nvars, 75, nqoi], "loss_func": "squared_loss", "var_trans": var_trans, "lag_mult": 0 } optimizer_opts = { "method": "L-BFGS-B", "options": { "maxiter": maxiter, "iprint": -1, "gtol": 1e-6 } } opts = { "network_opts": network_opts, "verbosity": 3, "optimizer_opts": optimizer_opts } ntrain_samples = 500 train_samples = pya.generate_independent_random_samples( var_trans.variable, ntrain_samples) train_samples = var_trans.map_from_canonical_space( np.cos(np.random.uniform(0, np.pi, (nvars, ntrain_samples)))) train_vals = benchmark.fun(train_samples) opts = { "network_opts": network_opts, "verbosity": 3, "optimizer_opts": optimizer_opts, "x0": 10 } approx = approximate(train_samples, train_vals, "neural_network", opts).approx nsamples = 100 error = compute_l2_error(approx, benchmark.fun, var_trans.variable, nsamples) print(error) assert error < 6e-2
def test_analyze_sensitivity_polynomial_chaos(self): from pyapprox.benchmarks.benchmarks import setup_benchmark from pyapprox.approximate import approximate benchmark = setup_benchmark("ishigami", a=7, b=0.1) num_samples = 1000 train_samples = pya.generate_independent_random_samples( benchmark.variable, num_samples) train_vals = benchmark.fun(train_samples) pce = approximate( train_samples, train_vals, 'polynomial_chaos', { 'basis_type': 'hyperbolic_cross', 'variable': benchmark.variable, 'options': { 'max_degree': 8 } }).approx res = analyze_sensitivity_polynomial_chaos(pce) assert np.allclose(res.main_effects, benchmark.main_effects, atol=2e-3)
def test_approximate_polynomial_chaos_custom_poly_type(self): benchmark = setup_benchmark("ishigami", a=7, b=0.1) nvars = benchmark.variable.num_vars() # this test purposefully select wrong variable to make sure # poly_type overide is activated univariate_variables = [stats.beta(5, 5, -np.pi, 2 * np.pi)] * nvars variable = pya.IndependentMultivariateRandomVariable( univariate_variables) var_trans = pya.AffineRandomVariableTransformation(variable) # specify correct basis so it is not chosen from var_trans.variable poly_opts = {"var_trans": var_trans} # but rather from another variable which will invoke Legendre polys basis_opts = pya.define_poly_options_from_variable( pya.IndependentMultivariateRandomVariable([stats.uniform()] * nvars)) poly_opts["poly_types"] = basis_opts options = { "poly_opts": poly_opts, "variable": variable, "options": { "max_num_step_increases": 1 } } ntrain_samples = 400 train_samples = np.random.uniform(-np.pi, np.pi, (nvars, ntrain_samples)) train_vals = benchmark.fun(train_samples) approx = approximate(train_samples, train_vals, method="polynomial_chaos", options=options).approx nsamples = 100 error = compute_l2_error(approx, benchmark.fun, approx.var_trans.variable, nsamples, rel=True) # print(error) assert error < 1e-4 assert np.allclose(approx.mean(), benchmark.mean, atol=error)
def test_cross_validate_approximation_after_regularization_selection(self): """ This test is useful as it shows how to use cross_validate_approximation to produce a list of approximations on each cross validation fold once regularization parameters have been chosen. These can be used to show variance in predictions of values, sensitivity indices, etc. Ideally this could be avoided if sklearn stored the coefficients and alphas for each fold and then we can just find the coefficients that correspond to the first time the path drops below the best_alpha """ num_vars = 2 univariate_variables = [stats.uniform(-1, 2)] * num_vars variable = pya.IndependentMultivariateRandomVariable( univariate_variables) var_trans = pya.AffineRandomVariableTransformation(variable) poly = pya.PolynomialChaosExpansion() poly_opts = pya.define_poly_options_from_variable_transformation( var_trans) poly.configure(poly_opts) degree, hcross_strength = 7, 0.4 poly.set_indices( pya.compute_hyperbolic_indices(num_vars, degree, hcross_strength)) num_samples = poly.num_terms() * 2 degrees = poly.indices.sum(axis=0) coef = np.random.normal( 0, 1, (poly.indices.shape[1], 2)) / (degrees[:, np.newaxis] + 1)**2 # set some coefficients to zero to make sure that different qoi # are treated correctly. II = np.random.permutation(coef.shape[0])[:coef.shape[0] // 2] coef[II, 0] = 0 II = np.random.permutation(coef.shape[0])[:coef.shape[0] // 2] coef[II, 1] = 0 poly.set_coefficients(coef) train_samples = pya.generate_independent_random_samples( variable, num_samples) train_vals = poly(train_samples) # true_poly = poly result = approximate(train_samples, train_vals, "polynomial_chaos", { "basis_type": "expanding_basis", "variable": variable }) # Even with the same folds, iterative methods such as Lars, LarsLasso # and OMP will not have cv_score from approximate and cross validate # approximation exactly the same because iterative methods interpolate # residuals to compute cross validation scores nfolds = 10 linear_solver_options = [{ "alpha": result.reg_params[0] }, { "alpha": result.reg_params[1] }] indices = [ result.approx.indices[:, np.where(np.absolute(c) > 0)[0]] for c in result.approx.coefficients.T ] options = { "basis_type": "fixed", "variable": variable, "options": { "linear_solver_options": linear_solver_options, "indices": indices } } approx_list, residues_list, cv_score = \ cross_validate_approximation( train_samples, train_vals, options, nfolds, "polynomial_chaos", random_folds="sklearn") assert (np.all(cv_score < 6e-14) and np.all(result.scores < 4e-13))
def test_analytic_sobol_indices_from_gaussian_process(self): from pyapprox.benchmarks.benchmarks import setup_benchmark from pyapprox.approximate import approximate benchmark = setup_benchmark("ishigami", a=7, b=0.1) nvars = benchmark.variable.num_vars() ntrain_samples = 500 # train_samples = pya.generate_independent_random_samples( # benchmark.variable, ntrain_samples) train_samples = pya.sobol_sequence(nvars, ntrain_samples, variable=benchmark.variable) train_vals = benchmark.fun(train_samples) approx = approximate(train_samples, train_vals, 'gaussian_process', { 'nu': np.inf, 'normalize_y': True, 'alpha': 1e-10 }).approx nsobol_samples = int(1e4) from pyapprox.approximate import compute_l2_error error = compute_l2_error(approx, benchmark.fun, benchmark.variable, nsobol_samples, rel=True) print(error) order = 2 interaction_terms = compute_hyperbolic_indices(nvars, order) interaction_terms = interaction_terms[:, np.where( interaction_terms.max( axis=0) == 1)[0]] result = analytic_sobol_indices_from_gaussian_process( approx, benchmark.variable, interaction_terms, ngp_realizations=1000, stat_functions=(np.mean, np.std), ninterpolation_samples=2000, ncandidate_samples=3000, use_cholesky=False, alpha=1e-8) mean_mean = result['mean']['mean'] mean_sobol_indices = result['sobol_indices']['mean'] mean_total_effects = result['total_effects']['mean'] mean_main_effects = mean_sobol_indices[:nvars] print(result['mean']['values'][-1]) print(result['variance']['values'][-1]) print(benchmark.main_effects[:, 0] - mean_main_effects) print(benchmark.total_effects[:, 0] - mean_total_effects) print(benchmark.sobol_indices[:-1, 0] - mean_sobol_indices) assert np.allclose(mean_mean, benchmark.mean, rtol=1e-3, atol=3e-3) assert np.allclose(mean_main_effects, benchmark.main_effects[:, 0], rtol=1e-3, atol=3e-3) assert np.allclose(mean_total_effects, benchmark.total_effects[:, 0], rtol=1e-3, atol=3e-3) assert np.allclose(mean_sobol_indices, benchmark.sobol_indices[:-1, 0], rtol=1e-3, atol=3e-3)
def test_sampling_based_sobol_indices_from_gaussian_process(self): from pyapprox.benchmarks.benchmarks import setup_benchmark from pyapprox.approximate import approximate benchmark = setup_benchmark("ishigami", a=7, b=0.1) nvars = benchmark.variable.num_vars() # nsobol_samples and ntrain_samples effect assert tolerances ntrain_samples = 500 nsobol_samples = int(1e4) train_samples = pya.generate_independent_random_samples( benchmark.variable, ntrain_samples) # from pyapprox import CholeskySampler # sampler = CholeskySampler(nvars, 10000, benchmark.variable) # kernel = pya.Matern( # np.array([1]*nvars), length_scale_bounds='fixed', nu=np.inf) # sampler.set_kernel(kernel) # train_samples = sampler(ntrain_samples)[0] train_vals = benchmark.fun(train_samples) approx = approximate(train_samples, train_vals, 'gaussian_process', { 'nu': np.inf, 'normalize_y': True }).approx from pyapprox.approximate import compute_l2_error error = compute_l2_error(approx, benchmark.fun, benchmark.variable, nsobol_samples, rel=True) print('error', error) # assert error < 4e-2 order = 2 interaction_terms = compute_hyperbolic_indices(nvars, order) interaction_terms = interaction_terms[:, np.where( interaction_terms.max( axis=0) == 1)[0]] result = sampling_based_sobol_indices_from_gaussian_process( approx, benchmark.variable, interaction_terms, nsobol_samples, sampling_method='sobol', ngp_realizations=1000, normalize=True, nsobol_realizations=3, stat_functions=(np.mean, np.std), ninterpolation_samples=1000, ncandidate_samples=2000) mean_mean = result['mean']['mean'] mean_sobol_indices = result['sobol_indices']['mean'] mean_total_effects = result['total_effects']['mean'] mean_main_effects = mean_sobol_indices[:nvars] print(benchmark.mean - mean_mean) print(benchmark.main_effects[:, 0] - mean_main_effects) print(benchmark.total_effects[:, 0] - mean_total_effects) print(benchmark.sobol_indices[:-1, 0] - mean_sobol_indices) assert np.allclose(mean_mean, benchmark.mean, atol=3e-2) assert np.allclose(mean_main_effects, benchmark.main_effects[:, 0], atol=1e-2) assert np.allclose(mean_total_effects, benchmark.total_effects[:, 0], atol=1e-2) assert np.allclose(mean_sobol_indices, benchmark.sobol_indices[:-1, 0], atol=1e-2)
for jj in inds: a, b = variable.all_variables()[jj].interval(1) x, w = gauss_jacobi_pts_wts_1D(nquad_samples_1d, 0, 0) x = (x+1)/2 # map to [0, 1] x = (b-a)*x+a # map to [a,b] quad_rules.append((x, w)) funs = [identity_fun]*len(inds) basis_opts['basis%d' % ii] = {'poly_type': 'product_indpnt_vars', 'var_nums': [ii], 'funs': funs, 'quad_rules': quad_rules} cnt += 1 poly_opts = {'var_trans': re_var_trans} poly_opts['poly_types'] = basis_opts #var_trans.set_identity_maps(identity_map_indices) #wrong re_var_trans.set_identity_maps(identity_map_indices) #right indices = compute_hyperbolic_indices(re_variable.num_vars(), degree) nterms = total_degree_space_dimension(samples_adjust.shape[0], degree) options = {'basis_type': 'fixed', 'variable': re_variable, 'poly_opts': poly_opts, 'options': {'linear_solver_options': dict(), 'indices': indices, 'solver_type': 'lstsq'}} approx_res = approximate(samples_adjust[:, 0:(2 * nterms)], values[0:(2 * nterms)], 'polynomial_chaos', options).approx y_hat = approx_res(samples_adjust[:, 2 * nterms:]) print((y_hat - values[2 * nterms:]).mean()) print(f'Mean of samples: {values.mean()}') print(f'Mean of pce: {approx_res.mean()}')
import numpy as np import pyapprox as pya from pyapprox.benchmarks.benchmarks import setup_benchmark from pyapprox.approximate import approximate benchmark = setup_benchmark("ishigami", a=7, b=0.1) num_samples = 1000 train_samples = pya.generate_independent_random_samples( benchmark.variable, num_samples) train_vals = benchmark.fun(train_samples) approx_res = approximate( train_samples, train_vals, 'polynomial_chaos', { 'basis_type': 'hyperbolic_cross', 'variable': benchmark.variable, 'options': { 'max_degree': 8 } }) pce = approx_res.approx res = pya.analyze_sensitivity_polynomial_chaos(pce) #%% #Now lets compare the estimated values with the exact value print(res.main_effects[:, 0]) print(benchmark.main_effects[:, 0]) #%% #We can visualize the sensitivity indices using the following