示例#1
0
def schemaToSearchSpaceHelper(longName, 
                              schema:Schema, 
                              relevantFields:Optional[Set[str]],
                              pgo_freqs:pgo_part=None)->Optional[SearchSpace]:
    if not is_false_schema(schema) and not schema:
        return None
    else:
        return schemaToSearchSpaceHelper_(longName, longName, schema, relevantFields, pgo_freqs=pgo_freqs)
 def schemaToSearchSpaceHelper(
     self,
     longName,
     schema: Optional[JsonSchema],
     relevantFields: Optional[Set[str]],
     pgo_freqs: pgo_part = None,
 ) -> Optional[SearchSpace]:
     if schema is None or is_false_schema(schema):
         return None
     else:
         return self.schemaToSearchSpaceHelper_(
             longName, longName, schema, relevantFields, pgo_freqs=pgo_freqs
         )
示例#3
0
    def schemaToSearchSpaceHelper_(
        self,
        longName,
        path: str,
        schema: JsonSchema,
        relevantFields: Optional[Set[str]],
        pgo_freqs: pgo_part = None,
        sub_space: bool = True,
    ) -> Optional[SearchSpace]:
        # TODO: handle degenerate cases
        # right now, this handles only a very fixed form

        if is_false_schema(schema):
            return None

        typ: Optional[str] = None
        typ = schema.get("laleType", None)
        if typ is None:
            typ = schema.get("type", None)
        else:
            typ = typ

        if "enum" in schema and typ != "operator":
            vals = schema["enum"]
            return SearchSpaceEnum(vals,
                                   pgo=asFreqs(pgo_freqs),
                                   default=get_default(schema))

        if typ is not None:
            if typ == "boolean":
                return SearchSpaceBool(pgo=asFreqs(pgo_freqs),
                                       default=get_default(schema))
            elif typ == "number" or typ == "integer":
                exclusive_minimum = False
                minimum = schema.get("minimumForOptimizer", None)
                if minimum is not None:
                    exclusive_minimum = schema.get(
                        "exclusiveMinimumForOptimizer", False)
                else:
                    minimum = schema.get("minimum", None)
                    if minimum is not None:
                        exclusive_minimum = schema.get("exclusiveMinimum",
                                                       False)

                exclusive_maximum = False
                maximum = schema.get("maximumForOptimizer", None)
                if maximum is not None:
                    exclusive_maximum = schema.get(
                        "exclusiveMaximumForOptimizer", False)
                else:
                    maximum = schema.get("maximum", None)
                    if maximum is not None:
                        exclusive_maximum = schema.get("exclusiveMaximum",
                                                       False)

                distribution = schema.get("distribution", None)

                laleType = schema.get("laleType", None)
                if laleType is None:
                    laleType = typ

                if laleType == "number":
                    discrete = False
                elif laleType == "integer":
                    discrete = True
                else:
                    raise OperatorSchemaError(
                        path,
                        f"specified laleType should be a number or integer, not: {laleType}.",
                    )

                pgo: Freqs

                return SearchSpaceNumber(
                    minimum=minimum,
                    exclusiveMinimum=exclusive_minimum,
                    maximum=maximum,
                    exclusiveMaximum=exclusive_maximum,
                    discrete=discrete,
                    distribution=distribution,
                    pgo=asFreqs(pgo_freqs),
                    default=get_default(schema),
                )
            elif typ == "array" or typ == "tuple":
                laleType = schema.get("laleType", None)
                if laleType is None:
                    laleType = typ

                is_tuple: bool = laleType == "tuple"

                min_items = schema.get("minItemsForOptimizer", None)
                if min_items is None:
                    min_items = schema.get("minItems", None)
                    if min_items is None:
                        min_items = 0
                max_items = schema.get("maxItemsForOptimizer", None)
                if max_items is None:
                    max_items = schema.get("maxItems", None)

                items_schema = schema.get("itemsForOptimizer", None)
                if items_schema is None:
                    items_schema = schema.get("items", None)
                    if items_schema is None:
                        raise OperatorSchemaError(
                            path,
                            f"An array type was found without a provided schema for the items in the schema {schema}. Please provide a schema for the items (consider using itemsForOptimizer)",
                        )

                # we can search an empty list even without schemas
                if max_items == 0:
                    if is_tuple:
                        return SearchSpaceConstant([()])
                    else:
                        return SearchSpaceConstant([[]])

                prefix: Optional[List[SearchSpace]] = None
                additional: Optional[SearchSpace] = None
                if isinstance(items_schema, list):
                    prefix = []
                    for i, sub_schema in enumerate(items_schema):
                        sub = self.schemaToSearchSpaceHelper_(
                            longName, path + "_" + str(i), sub_schema,
                            relevantFields)
                        if sub is None:
                            return None
                        else:
                            prefix.append(sub)
                    prefix_len = len(prefix)
                    additional_items_schema = schema.get(
                        "additionalItemsForOptimizer", None)
                    if additional_items_schema is None:
                        additional_items_schema = schema.get(
                            "additionalItems", None)
                    if additional_items_schema is None:
                        if max_items is None or max_items > prefix_len:
                            raise OperatorSchemaError(
                                path,
                                f"An array type was found with provided schemas for {prefix_len} elements, but either an unspecified or too high a maxItems, and no schema for the additionalItems.  Please constraing maxItems to <= {prefix_len} (you can set maxItemsForOptimizer), or provide a schema for additionalItems",
                            )
                    elif additional_items_schema is False:
                        if max_items is None:
                            max_items = prefix_len
                        else:
                            max_items = min(max_items, prefix_len)
                    else:
                        additional = self.schemaToSearchSpaceHelper_(
                            longName,
                            path + "-",
                            additional_items_schema,
                            relevantFields,
                        )
                        # if items_schema is None:
                        #     raise ValueError(f"an array type was found without a provided schema for the items in the schema {schema}.  Please provide a schema for the items (consider using itemsForOptimizer)")
                else:
                    additional = self.schemaToSearchSpaceHelper_(
                        longName, path + "-", items_schema, relevantFields)

                if max_items is None:
                    raise OperatorSchemaError(
                        path,
                        f"An array type was found without a provided maximum number of items in the schema {schema}, and it is not a list with 'additionalItems' set to False.  Please provide a maximum (consider using maxItemsForOptimizer), or, if you are using a list, set additionalItems to False",
                    )

                return SearchSpaceArray(
                    prefix=prefix,
                    minimum=min_items,
                    maximum=max_items,
                    additional=additional,
                    is_tuple=is_tuple,
                )

            elif typ == "object":
                if "properties" not in schema:
                    return SearchSpaceObject(longName, [], [])
                o = self.JsonSchemaToSearchSpaceHelper(
                    longName,
                    path,
                    schema,
                    relevantFields,
                    pgo_freqs=pgo_freqs,
                    sub_space=sub_space,
                )
                if sub_space:
                    return SearchSpaceDict(o)
                else:
                    all_keys = list(o.keys())
                    all_keys.sort()
                    o_choice = tuple([o.get(k, None) for k in all_keys])
                    return SearchSpaceObject(longName, all_keys, [o_choice])

            elif typ == "string":
                pass
            elif typ == "operator":
                # TODO: If there is a default, we could use it
                vals = schema.get("enum", None)
                if vals is None:
                    logger.error(
                        "An operator is required by the schema but was not provided"
                    )
                    return None

                sub_schemas: List[SearchSpace] = [
                    accept(op, self)
                    if isinstance(op, Operator) else SearchSpaceConstant(op)
                    for op in vals
                ]
                combined_sub_schema: SearchSpace
                if len(sub_schemas) == 1:
                    combined_sub_schema = sub_schemas[0]
                    if isinstance(combined_sub_schema, SearchSpaceConstant):
                        return combined_sub_schema
                else:
                    combined_sub_schema = SearchSpaceSum(sub_schemas)
                    if all((isinstance(x, SearchSpaceConstant)
                            for x in sub_schemas)):
                        return combined_sub_schema
                return SearchSpaceOperator(combined_sub_schema)

            elif typ == "Any":
                raise OperatorSchemaError(
                    path,
                    f"A search space was found with laleType ({typ}), which is not searchable.  Please mark the relevant hyperparameter as not relevant for the optimizer.  schema: {schema}",
                )
            else:
                raise OperatorSchemaError(
                    path,
                    f"An unknown type ({typ}) was found in the schema {schema}"
                )

        if "anyOf" in schema:
            objs = []
            for s_obj in schema["anyOf"]:
                if "type" in s_obj and s_obj["type"] == "object":
                    o = self.JsonSchemaToSearchSpaceHelper(
                        longName,
                        path,
                        s_obj,
                        relevantFields,
                        pgo_freqs=pgo_freqs,
                        sub_space=sub_space,
                    )
                    if o:
                        objs.append(o)
            if objs:
                # First, gather a list of all the properties
                keys_list = [set(o.keys()) for o in objs]
                # make sure the iterator is deterministic
                all_keys = list(set.union(*keys_list))
                # and we might as well make it sorted
                all_keys.sort()

                def as_str(k, c):
                    if c is None:
                        return "None"
                    else:
                        return search_space_to_str_for_comparison(
                            c, path + "_" + k)

                anys: Dict[str, Any] = {}
                for o in objs:
                    o_choice = tuple([o.get(k, None) for k in all_keys])
                    k = str([
                        as_str(all_keys[idx], c)
                        for idx, c in enumerate(o_choice)
                    ])
                    if k in anys:
                        logger.info(
                            f"Ignoring Duplicate SearchSpace entry {k}")
                    anys[k] = o_choice
                return SearchSpaceObject(longName, all_keys, anys.values())
            else:
                return SearchSpaceObject(longName, [], [])

        if "allOf" in schema:
            # if all but one are negated constraints, we will just ignore them
            pos_sub_schema: List[JsonSchema] = []
            for sub_schema in schema["allOf"]:
                if "not" not in sub_schema:
                    pos_sub_schema.append(sub_schema)

            if len(pos_sub_schema) > 1:
                raise OperatorSchemaError(
                    path,
                    f"schemaToSearchSpaceHelper does not yet know how to compile the given schema {schema}, because it is an allOf with more than one non-negated schemas ({pos_sub_schema})",
                )
            if len(pos_sub_schema) == 0:
                raise OperatorSchemaError(
                    path,
                    f"schemaToSearchSpaceHelper does not yet know how to compile the given schema {schema}, because it is an allOf with only negated schemas",
                )

            logger.debug(
                f"[{path}]: schemaToSearchSpaceHelper: ignoring negated schemas in the conjunction {schema}"
            )
            return self.schemaToSearchSpaceHelper_(
                longName,
                path,
                pos_sub_schema[0],
                relevantFields,
                pgo_freqs=pgo_freqs,
                sub_space=sub_space,
            )
        # TODO: handle degenerate cases
        raise OperatorSchemaError(
            path,
            f"schemaToSearchSpaceHelper does not yet know how to compile the given schema {schema}",
        )
示例#4
0
def schemaToSearchSpaceHelper_(
        longName,
        path: str,
        schema: Schema,
        relevantFields: Optional[Set[str]],
        pgo_freqs: pgo_part = None) -> Optional[SearchSpace]:
    # TODO: handle degenerate cases
    # right now, this handles only a very fixed form

    if is_false_schema(schema):
        return None

    if 'enum' in schema:
        vals = schema['enum']
        return SearchSpaceEnum(vals,
                               pgo=asFreqs(pgo_freqs),
                               default=get_default(schema))

    if 'type' in schema:
        typ = schema['type']
        if typ == "boolean":
            return SearchSpaceBool(pgo=asFreqs(pgo_freqs),
                                   default=get_default(schema))
        elif typ == "number" or typ == "integer":
            exclusive_minimum = False
            minimum = schema.get('minimumForOptimizer', None)
            if minimum is not None:
                exclusive_minimum = schema.get('exclusiveMinimumForOptimizer',
                                               False)
            else:
                minimum = schema.get('minimum', None)
                if minimum is not None:
                    exclusive_minimum = schema.get('exclusiveMinimum', False)

            exclusive_maximum = False
            maximum = schema.get('maximumForOptimizer', None)
            if maximum is not None:
                exclusive_maximum = schema.get('exclusiveMaximumForOptimizer',
                                               False)
            else:
                maximum = schema.get('maximum', None)
                if maximum is not None:
                    exclusive_maximum = schema.get('exclusiveMaximum', False)

            distribution = schema.get('distribution', None)

            typeForOptimizer = schema.get('typeForOptimizer', None)
            if typeForOptimizer is None:
                typeForOptimizer = typ

            if typeForOptimizer == "number":
                discrete = False
            elif typeForOptimizer == "integer":
                discrete = True
            else:
                raise NotImplementedError()

            pgo: Freqs

            return SearchSpaceNumber(minimum=minimum,
                                     exclusiveMinimum=exclusive_minimum,
                                     maximum=maximum,
                                     exclusiveMaximum=exclusive_maximum,
                                     discrete=discrete,
                                     distribution=distribution,
                                     pgo=asFreqs(pgo_freqs),
                                     default=get_default(schema))
        elif typ == "array" or typ == "tuple":
            typeForOptimizer = schema.get('typeForOptimizer', None)
            if typeForOptimizer is None:
                typeForOptimizer = typ

            is_tuple: bool = typeForOptimizer == "tuple"

            items_schema = schema.get('itemsForOptimizer', None)
            if items_schema is None:
                items_schema = schema.get('items', None)
                if items_schema is None:
                    raise ValueError(
                        f"an array type was found without a provided schema for the items in the schema {schema}.  Please provide a schema for the items (consider using itemsForOptimizer)"
                    )

            if isinstance(items_schema, list):
                contents = []
                for i, sub_schema in enumerate(items_schema):
                    sub = schemaToSearchSpaceHelper_(longName,
                                                     path + "_" + str(i),
                                                     sub_schema,
                                                     relevantFields)
                    if sub is None:
                        return None
                    else:
                        contents.append(sub)
                return SearchSpaceList(contents=contents, is_tuple=is_tuple)

            min_items = schema.get('minItemsForOptimizer', None)
            if min_items is None:
                min_items = schema.get('minItems', None)
                if min_items is None:
                    min_items = 0
            max_items = schema.get('maxItemsForOptimizer', None)
            if max_items is None:
                max_items = schema.get('maxItems', None)
                if max_items is None:
                    raise ValueError(
                        f"an array type was found without a provided maximum number of items in the schema {schema}.  Please provide a maximum (consider using maxItemsForOptimizer)"
                    )

            sub_opt = schemaToSearchSpaceHelper_(longName, path + "-",
                                                 items_schema, relevantFields)
            is_tuple = typeForOptimizer == "tuple"
            if sub_opt is None:
                if min_items <= 0 and max_items > 0:
                    return SearchSpaceConstant([])
                else:
                    return None
            else:
                return SearchSpaceArray(minimum=min_items,
                                        maximum=max_items,
                                        contents=sub_opt,
                                        is_tuple=is_tuple)

        elif typ == "object":
            if 'properties' not in schema:
                return SearchSpaceObject(longName, [], [])
            o = schemaObjToSearchSpaceHelper(longName,
                                             path,
                                             schema,
                                             relevantFields,
                                             pgo_freqs=pgo_freqs)
            all_keys = list(o.keys())
            all_keys.sort()
            o_choice = tuple([o.get(k, None) for k in all_keys])
            return SearchSpaceObject(longName, all_keys, [o_choice])
        elif typ == "string":
            pass
        else:
            raise ValueError(
                f"An unknown type ({typ}) was found in the schema {schema}")

    if 'anyOf' in schema:
        objs = []
        for s_obj in schema['anyOf']:
            if 'type' in s_obj and s_obj['type'] == "object":
                o = schemaObjToSearchSpaceHelper(longName,
                                                 path,
                                                 s_obj,
                                                 relevantFields,
                                                 pgo_freqs=pgo_freqs)
                if o: objs.append(o)
        if objs:
            # First, gather a list of all the properties
            keys_list = [set(o.keys()) for o in objs]
            # make sure the iterator is deterministic
            all_keys = list(set.union(*keys_list))
            # and we might as well make it sorted
            all_keys.sort()

            def as_str(k, c):
                if c is None:
                    return "None"
                else:
                    return search_space_to_str_for_comparison(
                        c, path + "_" + k)

            anys: Dict[str, Any] = {}
            for o in objs:
                o_choice = tuple([o.get(k, None) for k in all_keys])
                k = str([
                    as_str(all_keys[idx], c) for idx, c in enumerate(o_choice)
                ])
                if k in anys:
                    logger.info(f"Ignoring Duplicate SearchSpace entry {k}")
                anys[k] = o_choice
            return SearchSpaceObject(longName, all_keys, anys.values())
        else:
            return SearchSpaceObject(longName, [], [])

    if 'allOf' in schema:
        # if all but one are negated constraints, we will just ignore them
        pos_sub_schema: List[Schema] = []
        for sub_schema in schema['allOf']:
            if 'not' not in sub_schema:
                pos_sub_schema.append(sub_schema)

        if len(pos_sub_schema) > 1:
            raise ValueError(
                f"schemaToSearchSpaceHelper does not yet know how to compile the given schema {schema} for {longName}, because it is an allOf with more than one non-negated schemas ({pos_sub_schema})"
            )
        if len(pos_sub_schema) == 0:
            raise ValueError(
                f"schemaToSearchSpaceHelper does not yet know how to compile the given schema {schema} for {longName}, because it is an allOf with only negated schemas"
            )

        logger.debug(
            f"schemaToSearchSpaceHelper: ignoring negated schemas in the conjunction {schema} for {longName}"
        )
        return schemaToSearchSpaceHelper_(longName,
                                          path,
                                          pos_sub_schema[0],
                                          relevantFields,
                                          pgo_freqs=pgo_freqs)
    # TODO: handle degenerate cases
    raise ValueError(
        f"schemaToSearchSpaceHelper does not yet know how to compile the given schema {schema} for {longName}"
    )