def check_membership( self, parameterization: TParameterization, raise_error: bool = False ) -> bool: """Whether the given parameterization belongs in the search space. Checks that the given parameter values have the same name/type as search space parameters, are contained in the search space domain, and satisfy the parameter constraints. Args: parameterization: Dict from parameter name to value to validate. raise_error: If true parameterization does not belong, raises an error with detailed explanation of why. Returns: Whether the parameterization is contained in the search space. """ if len(parameterization) != len(self._parameters): if raise_error: raise ValueError( f"Parameterization has {len(parameterization)} parameters " f"but search space has {len(self._parameters)}." ) return False for name, value in parameterization.items(): if name not in self._parameters: if raise_error: raise ValueError( f"Parameter {name} not defined in search space" f"with parameters {self._parameters}" ) return False if not self._parameters[name].validate(value): if raise_error: raise ValueError( f"{value} is not a valid value for " f"parameter {self._parameters[name]}" ) return False # parameter constraints only accept numeric parameters numerical_param_dict = { # pyre-fixme[6]: Expected `typing.Union[...oat]` but got `unknown`. name: float(value) for name, value in parameterization.items() if self._parameters[name].is_numeric } for constraint in self._parameter_constraints: if not constraint.check(numerical_param_dict): if raise_error: raise ValueError(f"Parameter constraint {constraint} is violated.") return False return True
def check_types( self, parameterization: TParameterization, allow_none: bool = True, raise_error: bool = False, ) -> bool: """Checks that the given parameterization's types match the search space. Args: parameterization: Dict from parameter name to value to validate. allow_none: Whether None is a valid parameter value. raise_error: If true and parameterization does not belong, raises an error with detailed explanation of why. Returns: Whether the parameterization has valid types. """ for name, value in parameterization.items(): if name not in self._parameters: if raise_error: raise ValueError( f"Parameter {name} not defined in search space") return False if value is None and allow_none: continue if not self._parameters[name].is_valid_type(value): if raise_error: raise ValueError(f"{value} is not a valid value for " f"parameter {self._parameters[name]}") return False return True
def _numpy_types_to_python_types( parameterization: TParameterization, ) -> TParameterization: """If applicable, coerce values of the parameterization from Numpy int/float to Python int/float. """ return { name: numpy_type_to_python_type(value) for name, value in parameterization.items() }
def _parameterization_probability( parameterization: TParameterization, coefficients: Dict[str, Dict[TParamValue, float]], noise_var: float = 0.0, ) -> float: z = 0.0 for factor, level in parameterization.items(): if factor not in coefficients.keys(): raise ValueError("{} not in supplied coefficients".format(factor)) if level not in coefficients[factor].keys(): raise ValueError("{} not a valid level of {}".format(level, factor)) z += coefficients[factor][level] z += np.sqrt(noise_var) * np.random.randn() return np.exp(z) / (1 + np.exp(z))
def md5hash(parameters: TParameterization) -> str: """Return unique identifier for arm's parameters. Args: parameters: Parameterization; mapping of param name to value. Returns: Hash of arm's parameters. """ for k, v in parameters.items(): parameters[k] = numpy_type_to_python_type(v) parameters_str = json.dumps(parameters, sort_keys=True) return hashlib.md5(parameters_str.encode("utf-8")).hexdigest()
def check_types( self, parameterization: TParameterization, allow_none: bool = True, raise_error: bool = False, ) -> bool: """Checks that the given parameterization's types match the search space. Checks that the names of the parameterization match those specified in the search space, and the given values are of the correct type. Args: parameterization: Dict from parameter name to value to validate. allow_none: Whether None is a valid parameter value. raise_error: If true and parameterization does not belong, raises an error with detailed explanation of why. Returns: Whether the parameterization has valid types. """ if len(parameterization) != len(self._parameters): if raise_error: raise ValueError( f"Parameterization has {len(parameterization)} parameters " f"but search space has {len(self._parameters)}.\n" f"Parameterization: {parameterization}.\n" f"Search Space: {self._parameters}." ) return False for name, value in parameterization.items(): if name not in self._parameters: if raise_error: raise ValueError(f"Parameter {name} not defined in search space") return False if value is None and allow_none: continue if not self._parameters[name].is_valid_type(value): if raise_error: raise ValueError( f"{value} is not a valid value for " f"parameter {self._parameters[name]}" ) return False return True
def _format_dict(param_dict: TParameterization, name: str = "Parameterization") -> str: """Format a dictionary for labels. Args: param_dict: Dictionary to be formatted name: String name of the thing being formatted. Returns: stringified blob. """ if len(param_dict) >= 10: blob = "{} has too many items to render on hover ({}).".format( name, len(param_dict)) else: blob = "<br><em>{}:</em><br>{}".format( name, "<br>".join("{}: {}".format(n, v) for n, v in param_dict.items())) return blob
def _cast_parameterization( self, parameters: TParameterization, check_all_parameters_present: bool = True, ) -> TParameterization: """Cast parameterization (of an arm, observation features, etc.) to the hierarchical structure of this search space. Args: parameters: Parameterization to cast to hierarchical structure. check_all_parameters_present: Whether to raise an error if a paramete that is expected to be present (according to values of other parameters and the hierarchical structure of the search space) is not specified. """ def _find_applicable_parameters(root: Parameter) -> Set[str]: applicable = {root.name} if check_all_parameters_present and root.name not in parameters: raise RuntimeError( f"Parameter '{root.name}' not in parameterization to cast." ) if not root.is_hierarchical: return applicable for val, deps in root.dependents.items(): if parameters[root.name] == val: for dep in deps: applicable.update( _find_applicable_parameters(root=self[dep])) return applicable applicable_paramers = _find_applicable_parameters(root=self.root) if not all(k in parameters for k in applicable_paramers): raise RuntimeError( f"Parameters {applicable_paramers- set(parameters.keys())} " "missing from the arm.") return { k: v for k, v in parameters.items() if k in applicable_paramers }
def _filter_dict(param_dict: TParameterization, subset_keys: List[str]) -> TParameterization: """Filter a dictionary to keys present in a given list.""" return {k: v for k, v in param_dict.items() if k in subset_keys}