def scalarized_objective_to_sqa( self, objective: ScalarizedObjective) -> SQAMetric: """Convert Ax Scalarized Objective to SQLAlchemy. Returns a parent SQAMetric, whose children are the SQAMetrics corresponding to metrics attribute of Scalarized Objective. The parent is used as a placeholder for storage purposes.""" metrics, weights = objective.metrics, objective.weights if metrics is None or weights is None or len(metrics) != len(weights): raise SQAEncodeError("Metrics and weights in scalarized objective \ must be lists of equal length.") # pragma: no cover # pyre-fixme[9]: Expected SQABase type of an attribute; # re-defined to be SQAMetric. metrics_by_name: Dict[str, Tuple[Metric, float, SQAMetric, Tuple[ int, Dict[str, Any]]]] = { metric.name: ( metric, weight, self.config.class_to_sqa_class[Metric], self.get_metric_type_and_properties(metric=metric), ) for (metric, weight) in zip(metrics, weights) } # Constructing children SQAMetric classes children_metrics = [ # pyre-fixme[29]: `SQAMetric` is not a function. metric_class( name=metric_name, metric_type=metrics_type_and_properties[0], intent=MetricIntent.OBJECTIVE, minimize=objective.minimize, properties=metrics_type_and_properties[1], lower_is_better=metric.lower_is_better, scalarized_objective_weight=weight, ) for metric_name, ( metric, weight, metric_class, metrics_type_and_properties, ) in metrics_by_name.items() ] # Constructing a parent SQAMetric class # pyre-fixme: Expected `Base` for 1st...t `typing.Type[Metric]`. parent_metric: SQAMetric = self.config.class_to_sqa_class[Metric] # pyre-fixme[29]: `SQAMetric` is not a function. parent_metric = parent_metric( name="scalarized_objective", metric_type=METRIC_REGISTRY[Metric], intent=MetricIntent.SCALARIZED_OBJECTIVE, minimize=objective.minimize, lower_is_better=objective.minimize, scalarized_objective_children_metrics=children_metrics, ) return parent_metric
def scalarized_objective_to_sqa( self, objective: ScalarizedObjective) -> Tuple[SQAMetric, T_OBJ_TO_SQA]: """Convert Ax Scalarized Objective to SQLAlchemy and compile a list of (object, sqa_counterpart) tuples to set `db_id` on user-facing classes after the conversion is complete and the SQL session is flushed (SQLAlchemy classes receive their `id` attributes during `session.flush()`). Returns: A parent `SQAMetric`, whose children are the `SQAMetric`-s corresponding to `metrics` attribute of `ScalarizedObjective`. NOTE: The parent is used as a placeholder for storage purposes. """ metrics, weights = objective.metrics, objective.weights if (not (metrics and weights)) or len(metrics) != len(weights): raise SQAEncodeError( # pragma: no cover "Metrics and weights in scalarized objective " "must be lists of equal length.") metrics_by_name = self.get_children_metrics_by_name(metrics=metrics, weights=weights) # Constructing children SQAMetric classes (these are the real metrics in # the `ScalarizedObjective`). # Children metrics will not have experiment_id set children_metrics, obj_to_sqa = [], [] for metric_name in metrics_by_name: m, w, metric_cls, type_and_properties = metrics_by_name[ metric_name] children_metrics.append( metric_cls( # pyre-ignore[29]: `SQAMetric` is not a function. id=m.db_id, name=metric_name, metric_type=type_and_properties[0], intent=MetricIntent.OBJECTIVE, minimize=objective.minimize, properties=type_and_properties[1], lower_is_better=m.lower_is_better, scalarized_objective_weight=w, )) obj_to_sqa.append((m, children_metrics[-1])) # Constructing a parent SQAMetric class parent_metric_cls = cast(SQAMetric, self.config.class_to_sqa_class[Metric]) parent_metric = parent_metric_cls( # pyre-ignore[29]: `SQAMetric` not a func. id=objective.db_id, name="scalarized_objective", metric_type=METRIC_REGISTRY[Metric], intent=MetricIntent.SCALARIZED_OBJECTIVE, minimize=objective.minimize, lower_is_better=objective.minimize, scalarized_objective_children_metrics=children_metrics, ) # NOTE: No need to append parent metric to `obj_to_sqa`, because it does not # have a corresponding user-facing `Metric` object. return parent_metric, obj_to_sqa
def get_enum_value(self, value: Optional[str], enum: Optional[Enum]) -> Optional[int]: """Given an enum name (string) and an enum (of ints), return the corresponding enum value. If the name is not present in the enum, throw an error. """ if value is None or enum is None: return None try: return enum[value].value # pyre-ignore T29651755 except KeyError: raise SQAEncodeError(f"Value {value} is invalid for enum {enum}.")
def runner_to_sqa(self, runner: Runner) -> SQARunner: """Convert Ax Runner to SQLAlchemy.""" runner_type = RUNNER_REGISTRY.get(type(runner)) if runner_type is None: raise SQAEncodeError( "Cannot encode runner to SQLAlchemy because runner's " "subclass is invalid.") # pragma: no cover properties = get_object_properties(object=runner) # pyre-fixme: Expected `Base` for 1st...t `typing.Type[Runner]`. runner_class: SQARunner = self.config.class_to_sqa_class[Runner] # pyre-fixme[29]: `SQARunner` is not a function. return runner_class(runner_type=runner_type, properties=properties)
def scalarized_outcome_constraint_to_sqa( self, outcome_constraint: ScalarizedOutcomeConstraint ) -> Tuple[SQAMetric, T_OBJ_TO_SQA]: """Convert Ax SCalarized OutcomeConstraint to SQLAlchemy.""" metrics, weights = outcome_constraint.metrics, outcome_constraint.weights if metrics is None or weights is None or len(metrics) != len(weights): raise SQAEncodeError( "Metrics and weights in scalarized OutcomeConstraint \ must be lists of equal length.") # pragma: no cover metrics_by_name = self.get_children_metrics_by_name(metrics=metrics, weights=weights) # Constructing children SQAMetric classes (these are the real metrics in # the `ScalarizedObjective`). children_metrics, con_to_sqa = [], [] for metric_name in metrics_by_name: m, w, metric_cls, type_and_properties = metrics_by_name[ metric_name] children_metrics.append( metric_cls( # pyre-ignore[29]: `SQAMetric` is not a function. id=m.db_id, name=metric_name, metric_type=type_and_properties[0], intent=MetricIntent.OUTCOME_CONSTRAINT, properties=type_and_properties[1], lower_is_better=m.lower_is_better, scalarized_outcome_constraint_weight=w, bound=outcome_constraint.bound, op=outcome_constraint.op, relative=outcome_constraint.relative, )) con_to_sqa.append((m, children_metrics[-1])) # Constructing a parent SQAMetric class parent_metric_cls = cast(SQAMetric, self.config.class_to_sqa_class[Metric]) parent_metric = parent_metric_cls( # pyre-ignore[29]: `SQAMetric` not a func. id=outcome_constraint.db_id, name="scalarized_outcome_constraint", metric_type=METRIC_REGISTRY[Metric], intent=MetricIntent.SCALARIZED_OUTCOME_CONSTRAINT, bound=outcome_constraint.bound, op=outcome_constraint.op, relative=outcome_constraint.relative, scalarized_outcome_constraint_children_metrics=children_metrics, ) # NOTE: No need to append parent metric to `obj_to_sqa`, because it does not # have a corresponding user-facing `Metric` object. return parent_metric, con_to_sqa
def parameter_to_sqa(self, parameter: Parameter) -> SQAParameter: """Convert Ax Parameter to SQLAlchemy.""" # pyre-fixme: Expected `Base` for 1st...typing.Type[Parameter]`. parameter_class: SQAParameter = self.config.class_to_sqa_class[ Parameter] if isinstance(parameter, RangeParameter): # pyre-fixme[29]: `SQAParameter` is not a function. return parameter_class( id=parameter.db_id, name=parameter.name, domain_type=DomainType.RANGE, parameter_type=parameter.parameter_type, lower=float(parameter.lower), upper=float(parameter.upper), log_scale=parameter.log_scale, digits=parameter.digits, is_fidelity=parameter.is_fidelity, target_value=parameter.target_value, ) elif isinstance(parameter, ChoiceParameter): # pyre-fixme[29]: `SQAParameter` is not a function. return parameter_class( id=parameter.db_id, name=parameter.name, domain_type=DomainType.CHOICE, parameter_type=parameter.parameter_type, choice_values=parameter.values, is_ordered=parameter.is_ordered, is_task=parameter.is_task, is_fidelity=parameter.is_fidelity, target_value=parameter.target_value, ) elif isinstance(parameter, FixedParameter): # pyre-fixme[29]: `SQAParameter` is not a function. return parameter_class( id=parameter.db_id, name=parameter.name, domain_type=DomainType.FIXED, parameter_type=parameter.parameter_type, fixed_value=parameter.value, is_fidelity=parameter.is_fidelity, target_value=parameter.target_value, ) else: raise SQAEncodeError( "Cannot encode parameter to SQLAlchemy because parameter's " f"subclass ({type(parameter)}) is invalid." ) # pragma: no cover
def scalarized_objective_to_sqa( self, objective: ScalarizedObjective) -> SQAMetric: """Convert Ax Scalarized Objective to SQLAlchemy. Returns: A parent `SQAMetric`, whose children are the `SQAMetric`-s corresponding to `metrics` attribute of `ScalarizedObjective`. NOTE: The parent is used as a placeholder for storage purposes. """ metrics, weights = objective.metrics, objective.weights if (not (metrics and weights)) or len(metrics) != len(weights): raise SQAEncodeError( # pragma: no cover "Metrics and weights in scalarized objective " "must be lists of equal length.") metrics_by_name = self.get_children_metrics_by_name(metrics=metrics, weights=weights) # Constructing children SQAMetric classes (these are the real metrics in # the `ScalarizedObjective`). children_metrics = [] for metric_name in metrics_by_name: m, w, metric_cls, type_and_properties = metrics_by_name[ metric_name] children_metrics.append( metric_cls( # pyre-ignore[29]: `SQAMetric` is not a function. id=m.db_id, name=metric_name, metric_type=type_and_properties[0], intent=MetricIntent.OBJECTIVE, minimize=objective.minimize, properties=type_and_properties[1], lower_is_better=m.lower_is_better, scalarized_objective_weight=w, )) # Constructing a parent SQAMetric class parent_metric_cls = cast(SQAMetric, self.config.class_to_sqa_class[Metric]) parent_metric = parent_metric_cls( # pyre-ignore[29]: `SQAMetric` not a func. id=objective.db_id, name="scalarized_objective", metric_type=METRIC_REGISTRY[Metric], intent=MetricIntent.SCALARIZED_OBJECTIVE, minimize=objective.minimize, lower_is_better=objective.minimize, scalarized_objective_children_metrics=children_metrics, ) return parent_metric
def get_metric_type_and_properties( self, metric: Metric) -> Tuple[int, Dict[str, Any]]: """Given an Ax Metric, convert its type into a member of MetricType enum, and construct a dictionary to be stored in the database `properties` json blob. """ metric_type = METRIC_REGISTRY.get(type(metric)) if metric_type is None: raise SQAEncodeError( "Cannot encode metric to SQLAlchemy because metric's " "subclass is invalid.") # pragma: no cover # name and lower_is_better are stored directly on the metric, # so we don't need to include these in the properties blob properties = get_object_properties( object=metric, exclude_fields=["name", "lower_is_better"]) return metric_type, properties
def get_metric_type_and_properties( self, metric: Metric) -> Tuple[int, Dict[str, Any]]: """Given an Ax Metric, convert its type into a member of MetricType enum, and construct a dictionary to be stored in the database `properties` json blob. """ metric_class = type(metric) metric_type = METRIC_REGISTRY.get(metric_class) if metric_type is None: raise SQAEncodeError( "Cannot encode metric to SQLAlchemy because metric's " f"subclass ({metric_class}) is missing from the registry. " "The metric registry currently contains the following: " f"{','.join(map(str, METRIC_REGISTRY.keys()))}" ) # pragma: no cover properties = metric_class.serialize_init_args(metric=metric) return metric_type, properties
def runner_to_sqa(self, runner: Runner, trial_type: Optional[str] = None) -> SQARunner: """Convert Ax Runner to SQLAlchemy.""" runner_class = type(runner) runner_type = RUNNER_REGISTRY.get(runner_class) if runner_type is None: raise SQAEncodeError( "Cannot encode runner to SQLAlchemy because runner's " f"subclass ({runner_class}) is missing from the registry. " "The runner registry currently contains the following: " f"{','.join(map(str, RUNNER_REGISTRY.keys()))}" ) # pragma: no cover properties = runner_class.serialize_init_args(runner=runner) # pyre-fixme: Expected `Base` for 1st...t `typing.Type[Runner]`. runner_class: SQARunner = self.config.class_to_sqa_class[Runner] # pyre-fixme[29]: `SQARunner` is not a function. return runner_class(runner_type=runner_type, properties=properties, trial_type=trial_type)