def _filter_X_observed( Xs: List[Tensor], objective_weights: Tensor, bounds: List[Tuple[float, float]], outcome_constraints: Optional[Tuple[Tensor, Tensor]] = None, linear_constraints: Optional[Tuple[Tensor, Tensor]] = None, fixed_features: Optional[Dict[int, float]] = None, ) -> Optional[Tensor]: r"""Filter input points to those appearing in objective or constraints. Args: Xs: The input tensors of a model. objective_weights: The objective is to maximize a weighted sum of the columns of f(x). These are the weights. bounds: A list of (lower, upper) tuples for each column of X. outcome_constraints: A tuple of (A, b). For k outcome constraints and m outputs at f(x), A is (k x m) and b is (k x 1) such that A f(x) <= b. (Not used by single task models) linear_constraints: A tuple of (A, b). For k linear constraints on d-dimensional x, A is (k x d) and b is (k x 1) such that A x <= b. (Not used by single task models) fixed_features: A map {feature_index: value} for features that should be fixed to a particular value during generation. Returns: Tensor: All points that are feasible and appear in the objective or the constraints. None if there are no such points. """ # Get points observed for all objective and constraint outcomes X_obs = get_observed( Xs=Xs, objective_weights=objective_weights, outcome_constraints=outcome_constraints, ) # Filter to those that satisfy constraints. X_obs = filter_constraints_and_fixed_features( X=X_obs, bounds=bounds, linear_constraints=linear_constraints, fixed_features=fixed_features, ) if len(X_obs) > 0: return torch.as_tensor(X_obs) # please the linter
def best_point( self, bounds: List[Tuple[float, float]], objective_weights: Tensor, outcome_constraints: Optional[Tuple[Tensor, Tensor]] = None, linear_constraints: Optional[Tuple[Tensor, Tensor]] = None, fixed_features: Optional[Dict[int, float]] = None, model_gen_options: Optional[TConfig] = None, target_fidelities: Optional[Dict[int, float]] = None, ) -> Optional[Tensor]: """ Identify the current best point, satisfying the constraints in the same format as to gen. Return None if no such point can be identified. Args: bounds: A list of (lower, upper) tuples for each column of X. objective_weights: The objective is to maximize a weighted sum of the columns of f(x). These are the weights. outcome_constraints: A tuple of (A, b). For k outcome constraints and m outputs at f(x), A is (k x m) and b is (k x 1) such that A f(x) <= b. linear_constraints: A tuple of (A, b). For k linear constraints on d-dimensional x, A is (k x d) and b is (k x 1) such that A x <= b. fixed_features: A map {feature_index: value} for features that should be fixed to a particular value in the best point. model_gen_options: A config dictionary that can contain model-specific options. target_fidelities: A map {feature_index: value} of fidelity feature column indices to their respective target fidelities. Used for multi-fidelity optimization. Returns: d-tensor of the best point. """ options = model_gen_options or {} fixed_features = fixed_features or {} acf_options = options.get("acquisition_function_kwargs", {}) optimizer_options = options.get("optimizer_kwargs", {}) X_observed = get_observed( Xs=self.Xs, objective_weights=objective_weights, outcome_constraints=outcome_constraints, ) acq_function, non_fixed_idcs = self._get_best_point_acqf( mc_samples=acf_options.get("mc_samples", 512), objective_weights=objective_weights, outcome_constraints=outcome_constraints, X_observed=X_observed, seed_inner=acf_options.get("seed_inner", None), fixed_features=fixed_features, target_fidelities=target_fidelities, qmc=acf_options.get("qmc", True), ) inequality_constraints = _to_inequality_constraints(linear_constraints) # TODO: update optimizers to handle inequality_constraints # (including transforming constraints b/c of fixed features) if inequality_constraints is not None: raise UnsupportedError("Inequality constraints are not supported!") return_best_only = optimizer_options.get("return_best_only", True) bounds_ = torch.tensor(bounds, dtype=self.dtype, device=self.device) bounds_ = bounds_.transpose(-1, -2) if non_fixed_idcs is not None: bounds_ = bounds_[..., non_fixed_idcs] candidates, _ = optimize_acqf( acq_function=acq_function, bounds=bounds_, q=1, num_restarts=optimizer_options.get("num_restarts", 60), raw_samples=optimizer_options.get("raw_samples", 1024), inequality_constraints=inequality_constraints, fixed_features=None, # handled inside the acquisition function options={ "batch_limit": optimizer_options.get("batch_limit", 8), "maxiter": optimizer_options.get("maxiter", 200), "nonnegative": optimizer_options.get("nonnegative", False), "method": "L-BFGS-B", }, return_best_only=return_best_only, ) rec_point = candidates.detach().cpu() if isinstance(acq_function, FixedFeatureAcquisitionFunction): rec_point = acq_function._construct_X_full(rec_point) if return_best_only: rec_point = rec_point.view(-1) return rec_point