Exemplo n.º 1
0
    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
Exemplo n.º 2
0
    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
Exemplo n.º 3
0
    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}.")
Exemplo n.º 4
0
    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)
Exemplo n.º 5
0
    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
Exemplo n.º 6
0
 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
Exemplo n.º 7
0
    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
Exemplo n.º 8
0
    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
Exemplo n.º 9
0
    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
Exemplo n.º 10
0
    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)