// Copyright (c) 2017, Apple Inc. All rights reserved.
//
// Use of this source code is governed by a BSD-3-clause license that can be
// found in LICENSE.txt or at https://opensource.org/licenses/BSD-3-Clause

syntax = "proto3";
option optimize_for = LITE_RUNTIME;

package CoreML.Specification;

/*
 * The 64-bit integer feature type.
 */
message Int64FeatureType {}

/*
 * The double-precision floating point number feature type.
 */
message DoubleFeatureType {}

/*
 * The string feature type.
 */
message StringFeatureType {}


message SizeRange {
    uint64 lowerBound = 1;
    int64 upperBound = 2; // negative value means unbound otherwise upperbound is included in range
}

/*
 * The image feature type.
 */
message ImageFeatureType {
    // Assumes raw (decompressed) format
    enum ColorSpace {
        INVALID_COLOR_SPACE = 0;
        GRAYSCALE = 10;         //  8 bits per pixel
        RGB = 20;               // 32 bits per pixel: RGBA with A channel ignored
        BGR = 30;               // 32 bits per pixel: BGRA with A channel ignored
        GRAYSCALE_FLOAT16 = 40; // 16 bits float per pixel
    }

    message ImageSize {
        uint64 width = 1;
        uint64 height = 2;
    }

    message EnumeratedImageSizes {
        repeated ImageSize sizes = 1;
    }

    message ImageSizeRange {
        SizeRange widthRange = 1;
        SizeRange heightRange = 2;
    }

    // The required or default image size is width x height
    //
    // If specificationVersion <= 2 or SizeFlexibility is empty,
    // width x height is the required fixed image size
    //
    // If SizeFlexibility is present, width x height indicate a "default"
    // image size which must be consistent with the flexibility specified

    int64 width = 1;
    int64 height = 2;

    // For specification version >= 3 you can specify image size flexibility.

    oneof SizeFlexibility {

        // Use enumeratedSizes for a set of distinct fixed sizes
        // e.g. portrait or landscape: [80 x 100, 100 x 8]
        //
        // If the width x height fields above are specified then they must be
        // one of the sizes listed.
        //
        // If width and height are not specified above then the default width
        // and height will be enumeratedSizes[0]
        //
        // Must be non-empty

        EnumeratedImageSizes enumeratedSizes = 21;

        // Use imageSizeRange to allow for ranges of values
        // e.g. any image greater than 10 x 20: [10..<max] x [20..<max]
        //
        // If width and height are specified above they must fall in the range
        // specified in imageSizeRange. They will be treated as the default size.
        //
        // If width and height are not specified above then the default width
        // and height will be imageSizeRange.widthRange.lowerBound x imageSizeRange.heightRange.lowerBound

        ImageSizeRange imageSizeRange = 31;
    }

    ColorSpace colorSpace = 3;
}

/*
 * The array feature type.
 */
message ArrayFeatureType {

    enum ArrayDataType {
        INVALID_ARRAY_DATA_TYPE = 0;
        FLOAT32 = 65568; // 0x10000 | 32
        DOUBLE = 65600;  // 0x10000 | 64
        INT32 = 131104;  // 0x20000 | 32
        INT8  = 131080;  // 0x20000 |  8
        FLOAT16 = 65552; // 0x10000 | 16
    }

    // The required or default shape
    //
    // If specificationVersion <= 2 or ShapeFlexibility is empty,
    // shape is the required fixed shape
    //
    // If ShapeFlexibility is present, shape indicate a "default"
    // shape which must be consistent with the flexibility specified

    repeated int64 shape = 1;

    ArrayDataType dataType = 2;

    message Shape {
        repeated int64 shape = 1;
    }

    message EnumeratedShapes {
        repeated Shape shapes = 1;
    }

    message ShapeRange {
        // sizeRanges.size() must be length 1 or 3
        // sizeRanges[d] specifies the allowed range for dimension d
        repeated SizeRange sizeRanges = 1;
    }

    // For specification version >= 3 you can specify image size flexibility.

    oneof ShapeFlexibility {

        // Use enumeratedShapes for a set of distinct fixed shapes
        //
        // If the shape field is specified then it must be
        // one of the enumerated shapes.
        //
        // If shape is not specified, the "default" shape will be considered
        // enumeratedShapes[0]
        //
        // Must be non-empty

        EnumeratedShapes enumeratedShapes = 21;

        // Use shapeRange to allow the size of each dimension vary within
        // independently specified ranges
        //
        // If you specify shape above it must fall in the range
        // specified in shapeRanges. It will be treated as the default shape.
        //
        // If you don't specify shape above then the default shape will
        // have shape[d] = shapeRange.sizeRanges[d].lowerBound

        ShapeRange shapeRange = 31;

    }

    oneof defaultOptionalValue {
        int32 intDefaultValue = 41;
        float floatDefaultValue = 51;
        double doubleDefaultValue = 61;
    }

}

/*
 * The dictionary feature type.
 */
message DictionaryFeatureType {
    /*
     *  Key/value type tags, with the following restrictions:
     *  - ``keyType`` must be a hashable type
     *  - ``valueType`` is assumed to be a ``double``
     */
    oneof KeyType {
        Int64FeatureType int64KeyType = 1;
        StringFeatureType stringKeyType = 2;
    }
}

/*
 * The Sequence feature type.
 */
message SequenceFeatureType {

    /*
     * Currently only categorical int64 and String sequences are supported
     */
    oneof Type {
        Int64FeatureType int64Type = 1;
        StringFeatureType stringType = 3;
    }

    // Range of allowed size/length/count of sequence
    SizeRange sizeRange = 101;
}

message StateFeatureType {
    oneof Type {
        ArrayFeatureType arrayType = 1;
    }
}

/*
 * A feature, which may be optional.
 */
message FeatureType {
    oneof Type {
        Int64FeatureType int64Type = 1;
        DoubleFeatureType doubleType = 2;
        StringFeatureType stringType = 3;
        ImageFeatureType imageType = 4;
        ArrayFeatureType multiArrayType = 5;
        DictionaryFeatureType dictionaryType = 6;
        SequenceFeatureType sequenceType = 7;
        StateFeatureType stateType = 8;
    }

    bool isOptional = 1000;
}
