def compute_grammian_matrix_using_combination_sparse_grid( basis_matrix_function, dummy_indices, var_trans, max_num_samples, error_tol=0, density_function=None, quad_rule_opts=None): num_vars = var_trans.num_vars() sparse_grid = CombinationSparseGrid(num_vars) admissibility_function = partial(max_level_admissibility_function, np.inf, [np.inf] * num_vars, max_num_samples, error_tol, verbose=True) if quad_rule_opts is None: quad_rules, growth_rules, unique_quadrule_indices = \ get_sparse_grid_univariate_leja_quadrature_rules_economical( var_trans) else: quad_rules = quad_rule_opts['quad_rules'] growth_rules = quad_rule_opts['growth_rules'] unique_quadrule_indices = quad_rule_opts.get('unique_quadrule_indices') if density_function is None: density_function = lambda samples: np.ones(samples.shape[1]) def function(samples): #need to make sure that basis_matrix_function takes #points in user domain and not canonical domain basis_matrix = basis_matrix_function(samples) pdf_vals = density_function(samples) vals = [] for ii in range(basis_matrix.shape[1]): for jj in range(ii, basis_matrix.shape[1]): vals.append(basis_matrix[:, ii] * basis_matrix[:, jj] * pdf_vals) return np.asarray(vals).T sparse_grid.setup(function, None, partial(variance_refinement_indicator), admissibility_function, growth_rules, quad_rules, var_trans, unique_quadrule_indices=unique_quadrule_indices) sparse_grid.build() #todo allow level to be passed in per dimension so I can base it on #sparse_grid.subspace_indices.max(axis=1) from pyapprox.sparse_grid import get_sparse_grid_samples_and_weights samples, weights = get_sparse_grid_samples_and_weights( num_vars, sparse_grid.subspace_indices.max(), sparse_grid.univariate_quad_rule, sparse_grid.univariate_growth_rule, sparse_grid.subspace_indices)[:2] samples = var_trans.map_from_canonical_space(samples) weights *= density_function(samples) basis_matrix = basis_matrix_function(samples) moment_matrix = np.dot(basis_matrix.T * weights, basis_matrix) return moment_matrix
def adaptive_approximate_sparse_grid( fun, univariate_variables, callback=None, refinement_indicator=variance_refinement_indicator, univariate_quad_rule_info=None, max_nsamples=100, tol=0, verbose=0, config_variables_idx=None, config_var_trans=None, cost_function=None, max_level_1d=None): """ Compute a sparse grid approximation of a function. Parameters ---------- fun : callable The function to be minimized ``fun(z) -> np.ndarray`` where ``z`` is a 2D np.ndarray with shape (nvars,nsamples) and the output is a 2D np.ndarray with shape (nsamples,nqoi) univariate_variables : list A list of scipy.stats random variables of size (nvars) callback : callable Function called after each iteration with the signature ``callback(approx_k)`` where approx_k is the current approximation object. refinement_indicator : callable A function that retuns an estimate of the error of a sparse grid subspace with signature ``refinement_indicator(subspace_index,nnew_subspace_samples,sparse_grid) -> float, float`` where ``subspace_index`` is 1D np.ndarray of size (nvars), ``nnew_subspace_samples`` is an integer specifying the number of new samples that will be added to the sparse grid by adding the subspace specified by subspace_index and ``sparse_grid`` is the current :class:`pyapprox.adaptive_sparse_grid.CombinationSparseGrid` object. The two outputs are, respectively, the indicator used to control refinement of the sparse grid and the change in error from adding the current subspace. The indicator is typically but now always dependent on the error. univariate_quad_rule_info : list List containing two entries. The first entry is a list (or single callable) of univariate quadrature rules for each variable with signature ``quad_rule(l)->np.ndarray,np.ndarray`` where the integer ``l`` specifies the level of the quadrature rule and ``x`` and ``w`` are 1D np.ndarray of size (nsamples) containing the quadrature rule points and weights, respectively. The second entry is a list (or single callable) of growth rules with signature ``growth_rule(l)->integer`` where the output ``nsamples`` specifies the number of samples in the quadrature rule of level ``l``. If either entry is a callable then the same quad or growth rule is applied to every variable. max_nsamples : float If ``cost_function==None`` then this argument is the maximum number of evaluations of fun. If fun has configure variables If ``cost_function!=None`` Then max_nsamples is the maximum cost of constructing the sparse grid, i.e. the sum of the cost of evaluating each point in the sparse grid. The ``cost_function!=None` same behavior as ``cost_function==None`` can be obtained by setting cost_function = lambda config_sample: 1. This is particularly useful if ``fun`` has configure variables and evaluating ``fun`` at these different values of these configure variables has different cost. For example if there is one configure variable that can take two different values with cost 0.5, and 1 then 10 samples of both models will be measured as 15 samples and so if max_nsamples is 19 the algorithm will not terminate because even though the number of samples is the sparse grid is 20. tol : float Tolerance for termination. The construction of the sparse grid is terminated when the estimate error in the sparse grid (determined by ``refinement_indicator`` is below tol. verbose : integer Controls messages printed during construction. config_variable_idx : integer The position in a sample array that the configure variables start config_var_trans : pyapprox.adaptive_sparse_grid.ConfigureVariableTransformation An object that takes configure indices in [0,1,2,3...] and maps them to the configure values accepted by ``fun`` cost_function : callable A function with signature ``cost_function(config_sample) -> float`` where config_sample is a np.ndarray of shape (nconfig_vars). The output is the cost of evaluating ``fun`` at ``config_sample``. The units can be anything but the units must be consistent with the units of max_nsamples which specifies the maximum cost of constructing the sparse grid. max_level_1d : np.ndarray (nvars) The maximum level of the sparse grid in each dimension. If None There is no limit Returns ------- sparse_grid : :class:`pyapprox.adaptive_sparse_grid.CombinationSparseGrid` The sparse grid approximation """ variable = IndependentMultivariateRandomVariable(univariate_variables) var_trans = AffineRandomVariableTransformation(variable) nvars = var_trans.num_vars() if config_var_trans is not None: nvars += config_var_trans.num_vars() sparse_grid = CombinationSparseGrid(nvars) if univariate_quad_rule_info is None: quad_rules, growth_rules, unique_quadrule_indices = \ get_sparse_grid_univariate_leja_quadrature_rules_economical( var_trans) else: quad_rules, growth_rules = univariate_quad_rule_info unique_quadrule_indices = None if max_level_1d is None: max_level_1d = [np.inf] * nvars assert len(max_level_1d) == nvars admissibility_function = partial(max_level_admissibility_function, np.inf, max_level_1d, max_nsamples, tol, verbose=verbose) sparse_grid.setup(fun, config_variables_idx, refinement_indicator, admissibility_function, growth_rules, quad_rules, var_trans, unique_quadrule_indices=unique_quadrule_indices, verbose=verbose, cost_function=cost_function, config_var_trans=config_var_trans) sparse_grid.build(callback) return sparse_grid
def initialize_surrogate(self, node, refinement_indicator=None, univariate_quad_rule_info=None, max_nsamples=100, tol=0, verbose=0, config_variables_idx=None, config_var_trans=None, cost_function=None, max_level_1d=None, quad_method='pdf', enforce_variable_bounds=False, growth_incr=2): """ Initialize an adaptive sparse grid surrogate of a component. Parameters ---------- node : :class:`networkx.Node` The node repesenting the component of interest options : dict Arguments necessary to initialize each surrogate. See documentation of :func:`pyapprox.approximate.adaptive_approximate_sparse_grid` Returns ------- approx : :class:`pyapprox.adaptive_sparse_grid.CombinationSparseGrid` The sparse grid approximation """ variables = self.get_node_variables(node) var_trans, quad_rules, growth_rules, unique_quadrule_indices = \ self.get_univariate_quadrature_rules( variables, enforce_variable_bounds, univariate_quad_rule_info, quad_method, growth_incr) nvars = var_trans.num_vars() if config_var_trans is not None: nvars += config_var_trans.num_vars() if max_level_1d is None: max_level_1d = [np.inf] * nvars elif np.isscalar(max_level_1d): max_level_1d = [max_level_1d] * nvars assert len(max_level_1d) == nvars admissibility_function = partial(max_level_admissibility_function, np.inf, max_level_1d, max_nsamples, tol, verbose=verbose) if refinement_indicator is None: refinement_indicator = self.__refinement_indicator sparse_grid = CombinationSparseGrid(nvars) sparse_grid.setup(node['functions'], config_variables_idx, refinement_indicator, admissibility_function, growth_rules, quad_rules, var_trans, unique_quadrule_indices=unique_quadrule_indices, verbose=verbose, cost_function=cost_function, config_var_trans=config_var_trans) if self.verbose > 0: print('------------------------------------') print(f'Initializing component {node["label"]}') print('--') sparse_grid.initialize() if self.verbose > 0: print('------------------------------------') return sparse_grid
def approximate_sparse_grid(fun, univariate_variables, callback=None, refinement_indicator=variance_refinement_indicator, univariate_quad_rule_info=None, max_nsamples=100, tol=0, verbose=False): """ Compute a sparse grid approximation of a function. Parameters ---------- fun : callable The function to be minimized ``fun(z) -> np.ndarray`` where ``z`` is a 2D np.ndarray with shape (nvars,nsamples) and the output is a 2D np.ndarray with shaoe (nsamples,nqoi) univariate_variables : list A list of scipy.stats random variables of size (nvars) callback : callable Function called after each iteration with the signature ``callback(approx_k)`` where approx_k is the current approximation object. refinement_indicator : callable A function that retuns an estimate of the error of a sparse grid subspace with signature ``refinement_indicator(subspace_index,nnew_subspace_samples,sparse_grid) -> float, float`` where ``subspace_index`` is 1D np.ndarray of size (nvars), ``nnew_subspace_samples`` is an integer specifying the number of new samples that will be added to the sparse grid by adding the subspace specified by subspace_index and ``sparse_grid`` is the current :class:`pyapprox.adaptive_sparse_grid.CombinationSparseGrid` object. The two outputs are, respectively, the indicator used to control refinement of the sparse grid and the change in error from adding the current subspace. The indicator is typically but now always dependent on the error. univariate_quad_rule_info : list List containing two entries. The first entry is a list (or single callable) of univariate quadrature rules for each variable with signature ``quad_rule(l)->np.ndarray,np.ndarray`` where the integer ``l`` specifies the level of the quadrature rule and ``x`` and ``w`` are 1D np.ndarray of size (nsamples) containing the quadrature rule points and weights, respectively. The second entry is a list (or single callable) of growth rules with signature ``growth_rule(l)->integer`` where the output ``nsamples`` specifies the number of samples in the quadrature rule of level``l``. If either entry is a callable then the same quad or growth rule is applied to every variable. max_nsamples : integer The maximum number of evaluations of fun. tol : float Tolerance for termination. The construction of the sparse grid is terminated when the estimate error in the sparse grid (determined by ``refinement_indicator`` is below tol. verbose: boolean Controls messages printed during construction. Returns ------- sparse_grid : :class:`pyapprox.adaptive_sparse_grid.CombinationSparseGrid` The sparse grid approximation """ variable = IndependentMultivariateRandomVariable(univariate_variables) var_trans = AffineRandomVariableTransformation(variable) nvars = var_trans.num_vars() sparse_grid = CombinationSparseGrid(nvars) if univariate_quad_rule_info is None: quad_rules, growth_rules, unique_quadrule_indices = \ get_sparse_grid_univariate_leja_quadrature_rules_economical( var_trans) else: quad_rules, growth_rules = univariate_quad_rule_info unique_quadrule_indices = None admissibility_function = partial(max_level_admissibility_function, np.inf, [np.inf] * nvars, max_nsamples, tol, verbose=verbose) sparse_grid.setup(fun, None, variance_refinement_indicator, admissibility_function, growth_rules, quad_rules, var_trans, unique_quadrule_indices=unique_quadrule_indices) sparse_grid.build(callback) return sparse_grid