syntax = "proto3";

package tensorflow;

option cc_enable_arenas = true;
option java_outer_classname = "FullTypeProtos";
option java_multiple_files = true;
option java_package = "org.tensorflow.framework";
option go_package = "github.com/tensorflow/tensorflow/tensorflow/go/core/framework/full_type_go_proto";

// Experimental. Represents the complete type information of a TensorFlow value.
enum FullTypeId {
  // The default represents an uninitialized values.
  TFT_UNSET = 0;

  // Type symbols. Used to construct more complex type expressions like
  // algebraic data types.

  // Type variables may serve as placeholder for any other type ID in type
  // templates.
  //
  // Examples:
  //   TFT_DATASET[TFT_VAR["T"]] is a Dataset returning a type indicated by "T".
  //   TFT_TENSOR[TFT_VAR["T"]] is a Tensor of n element type indicated by "T".
  //   TFT_TENSOR[TFT_VAR["T"]], TFT_TENSOR[TFT_VAR["T"]] are two tensors of
  //     identical element types.
  //   TFT_TENSOR[TFT_VAR["P"]], TFT_TENSOR[TFT_VAR["Q"]] are two tensors of
  //     independent element types.
  //
  TFT_VAR = 1;

  // Wildcard type. Describes a parameter of unknown type. In TensorFlow, that
  // can mean either a "Top" type (accepts any type), or a dynamically typed
  // object whose type is unknown in context.
  // Important: "unknown" does not necessarily mean undeterminable!
  TFT_ANY = 2;

  // The algebraic product type. This is an algebraic type that may be used just
  // for logical grouping. Not to confused with TFT_TUPLE which describes a
  // concrete object of several elements.
  //
  // Example:
  //   TFT_DATASET[TFT_PRODUCT[TFT_TENSOR[TFT_INT32], TFT_TENSOR[TFT_FLOAT64]]]
  //     is a Dataset producing two tensors, an integer one and a float one.
  //
  TFT_PRODUCT = 3;

  // Represents a named field, with the name stored in the attribute.
  //
  // Parametrization:
  //   TFT_NAMED[<type>]{<name>}
  //   * <type> is the type of the field
  //   * <name> is the field name, as string (thpugh can theoretically be an int
  //     as well)
  //
  // Example:
  //   TFT_RECORD[
  //     TFT_NAMED[TFT_TENSOR[TFT_INT32]]{'foo'},
  //     TFT_NAMED[TFT_TENSOR[TFT_FLOAT32]]{'bar'},
  //   ]
  //     is a structure with two fields, an int tensor "foo" and a float tensor
  //     "bar".
  TFT_NAMED = 4;

  // Template definition. Expands the variables by repeating a template as
  // arguments of container.
  //
  // Parametrization:
  //   TFT_FOR_EACH[<container_type>, <template>, <expansions>]
  //   * <container_type> is the type of the container that the template will be
  //     expanded into
  //   * <template> is any type definition that potentially contains type
  //     variables
  //   * <expansions> is a TFT_VAR and may include more types in the future
  //
  // Example:
  //   TFT_FOR_EACH[
  //         TFT_PRODUCT,
  //         TFT_TENSOR[TFT_VAR["t"]],
  //         TFT_VAR["t"]
  //     ]
  //     will substitute a T = TFT_INT32 to TFT_PRODUCT[TFT_TENSOR[TFT_INT32]]
  //     and a T = (TFT_INT32, TFT_INT64) to
  //     TFT_PRODUCT[TFT_TENSOR[TFT_INT32], TFT_TENSOR[TFT_INT64]].
  TFT_FOR_EACH = 20;

  // Callable types describe functions and ops.
  //
  // Parametrization:
  //   TFT_CALLABLE[<arg type>, <return type>]
  //   * <arg type> is the type of the arguments; TFT_PRODUCT represents
  //   multiple
  //     arguments.
  //   * <return type> is the return type; TFT_PRODUCT represents multiple
  //     return values (that means that callables returning multiple things
  //     don't necessarily return a single tuple).
  //
  // Example:
  //   TFT_CALLABLE[
  //     TFT_ANY,
  //     TFT_PRODUCT[TFT_TENSOR[TFT_INT32], TFT_TENSOR[TFT_FLOAT64]],
  //   ]
  //     is a callable with unspecified (for now) input arguments, and
  //     two return values of type tensor.
  //
  TFT_CALLABLE = 100;

  // Concrete type IDs, representing "proper" data types that can describe
  // runtime TensorFlow objects.

  // The usual Tensor. This is a parametric type.
  //
  // Parametrization:
  //   TFT_TENSOR[<element type>, <shape type>]
  //   * <element type> is currently limited to one of the element types
  //     defined below.
  //   * <shape type> is not yet defined, and may only be TFT_UNKNOWN for now.
  //
  // A TFT_SHAPE type will be defined in the future.
  //
  // Example:
  //   TFT_TENSOR[TFT_INT32, TFT_UNKNOWN]
  //     is a Tensor of int32 element type and unknown shape.
  //
  // TODO: Define TFT_SHAPE and add more examples.
  TFT_TENSOR = 1000;

  // Array (or tensorflow::TensorList in the variant type registry).
  // Note: this is not to be confused with the deprecated `TensorArray*` ops
  // which are not supported by FullType.
  // This type represents a random-access list whose elements can be
  // described by a single type. Although immutable, Array is expected to
  // support efficient mutation semantics (i.e. element update) in the
  // user-facing API.
  // The element type may be generic or even TFT_ANY for a heterogenous list.
  //
  // Parametrization:
  //   TFT_ARRAY[<element type>]
  //   * <element type> may be any concrete type.
  //
  // Examples:
  //   TFT_ARRAY[TFT_TENSOR[TFT_INT32]] is a TensorArray holding int32 Tensors
  //     of any shape.
  //   TFT_ARRAY[TFT_TENSOR[TFT_UNKNOWN]] is a TensorArray holding Tensors of
  //     mixed element types.
  //   TFT_ARRAY[TFT_UNKNOWN] is a TensorArray holding any element type.
  //   TFT_ARRAY[] is equivalent to TFT_ARRAY[TFT_UNKNOWN].
  //   TFT_ARRAY[TFT_ARRAY[]] is an array or arrays (of unknown types).
  TFT_ARRAY = 1001;

  // Optional (or tensorflow::OptionalVariant in the variant type registry).
  // This type represents a value that may either hold an element of a single
  // specified type, or nothing at all.
  //
  // Parametrization:
  //   TFT_OPTIONAL[<element type>]
  //   * <element type> may be any concrete type.
  //
  // Examples:
  //   TFT_OPTIONAL[TFT_TENSOR[TFT_INT32]] is an Optional holding an int32
  //     Tensor of any shape.
  TFT_OPTIONAL = 1002;

  // Literal types describe compile-time constant values.
  // Literal types may also participate in dependent types.
  //
  // Parametrization:
  //   TFT_LITERAL[<value type>]{<value>}
  //   * <value type> may be any concrete type compatible that can hold <value>
  //   * <value> is the type's attribute, and holds the actual literal value
  //
  // Examples:
  //   TFT_LITERAL[TFT_INT32]{1} is the compile-time constant 1.
  TFT_LITERAL = 1003;

  // Type attributes. These always appear in the parametrization of a type,
  // never alone. For example, there is no such thing as a "bool" TensorFlow
  // object (for now).

  // The bool element type.
  // TODO
  TFT_BOOL = 200;
  // Integer element types.
  TFT_UINT8 = 201;
  TFT_UINT16 = 202;
  TFT_UINT32 = 203;
  TFT_UINT64 = 204;
  TFT_INT8 = 205;
  TFT_INT16 = 206;
  TFT_INT32 = 207;
  TFT_INT64 = 208;
  // Floating-point element types.
  TFT_HALF = 209;
  TFT_FLOAT = 210;
  TFT_DOUBLE = 211;
  TFT_BFLOAT16 = 215;
  // Complex element types.
  // TODO: Represent as TFT_COMPLEX[TFT_DOUBLE] instead?
  TFT_COMPLEX64 = 212;
  TFT_COMPLEX128 = 213;
  // The string element type.
  TFT_STRING = 214;

  // Other types that we don't know yet whether they will become part of the
  // core type system or be consisdered third-party (and consequently moved to
  // user-defined type mechanisms). Presently, they are effectively in the core
  // type system, because key compilation passes like Placer account for their
  // existence.

  // Datasets created by tf.data ops and APIs. Datasets have generator/iterable
  // semantics, that is, one can construct an iterator from them. Like
  // Array, they are considered to return elements that can be described
  // by a single type. Unlike Array, they do not support random access or
  // mutation, and can potentially produce an infinite number of elements.
  // A datasets can produce logical structures (e.g. multiple elements). This
  // is expressed using TFT_PRODUCT.
  //
  //
  // Parametrization: TFT_ARRAY[<element type>].
  //   * <element type> may be a concrete type or a type symbol. It represents
  //     the data type of the elements produced by the dataset.
  //
  // Examples:
  //   TFT_DATSET[TFT_TENSOR[TFT_INT32]] is a Dataset producing single int32
  //     Tensors of unknown shape.
  //   TFT_DATSET[TFT_PRODUCT[TFT_TENSOR[TFT_INT32], TFT_TENSOR[TFT_FLOAT32]] is
  //     a Dataset producing pairs of Tensors, one integer and one float.
  // Note: The high ID number is to prepare for the eventuality that Datasets
  // will be supported by user types in the future.
  TFT_DATASET = 10102;

  // A ragged tensor created by tf.ragged ops and APIs.
  //
  // Parametrization: TFT_RAGGED[<element_type>].
  TFT_RAGGED = 10103;

  // A mutex lock tensor, produced by tf.raw_ops.MutexLock.
  // Unlike strict execution models, where ownership of a lock is denoted by
  // "running after the lock has been acquired", in non-strict mode, lock
  // ownership is in the true sense: "the op argument representing the lock is
  // available".
  // Mutex locks are the dynamic counterpart of control dependencies.
  // TODO: Properly document this thing.
  //
  // Parametrization: TFT_MUTEX_LOCK[].
  TFT_MUTEX_LOCK = 10202;

  // The equivalent of a Tensor with DT_VARIANT dtype, kept here to simplify
  // translation. This type should not normally appear after type inference.
  // Note that LEGACY_VARIANT != ANY: TENSOR[INT32] is a subtype of ANY, but is
  // not a subtype of LEGACY_VARIANT.
  TFT_LEGACY_VARIANT = 10203;
}

// Highly experimental and very likely to change.
// This encoding uses tags instead of dedicated messages for regularity. In
// particular the encoding imposes no restrictions on what the parameters of any
// type should be, which in particular needs to be true for type symbols.
message FullTypeDef {
  // The principal type represented by this object. This may be a concrete type
  // (Tensor, Dataset) a type variable (used for dependent types) a type
  // symbol (Any, Union). See FullTypeId for details.
  FullTypeId type_id = 1;

  repeated FullTypeDef args = 2;

  // Literal values of this type object, if the the type admits one.
  // For example, a type variable admits a string attribute - its name.
  // Shape-related types may admit int attributes - their static shape values.
  // Fields for more data types to be added as needed.
  oneof attr {
    string s = 3;
    int64 i = 4;
    // TODO: list/tensor, map? Need to reconcile with TFT_RECORD, etc.
  }
}
