
    AVh                       d Z ddlZddlmZmZmZmZmZmZm	Z	m
Z
 ddlZddlmZ ddlmZ ddlmZ ddlmZ ddlmZ dd	lmZ dd
lmZ ddlmZ ddlmZ ddlmZ ddlmZ ddlmZ ddlmZ ddlmZ ddlmZ ddl m!Z! ddl m"Z" ddl#m$Z$ e
ejJ                  ejL                  dejN                  f   Z(ee(ge(f   Z) e$d       G d dejT                               Z+ ejX                  d      Z-d Z.dee/e(f   deejJ                     deee      dej`                  fdZ1d  Z2d! Z3d" Z4d# Z5d$ Z6d% Z7d& Z8d' Z9d( Z:d) Z;d* Z<d+ Z=d, Z> e?       Z@d-e
ej                  j                  ej                  e+j                  ej                  f   dej                  j                  fd.ZEd/d0dee/   fd1ZFd2 ZGd3 ZH	 dAdej                  fd4ZId5eej                     d6eej                     deej                     fd7ZJd8eKd9ej`                  deej                     fd:ZLd;e(deej`                     fd<ZMd;e(d9ej`                  de(fd=ZNdee/e(f   d9ej`                  dee/e(f   fd>ZOd? ZPd@ ZQy)BzStructured Tensors.    N)CallableDictListMappingOptionalSequenceTupleUnion)constant_op)dtypes)extension_type)ops)tensor)tensor_shape)	type_spec)	array_ops)	check_ops)control_flow_ops)math_ops)dynamic_ragged_shape)ragged_factory_ops)ragged_tensor)RowPartition)compat)nest)	tf_exportStructuredTensorzexperimental.StructuredTensorc                      e Zd ZU dZeeef   ed<   ej                  ed<   dZ e
eee   f   Zdeeef   dej                  fdZed1d       Zedej                  d	d fd
       Ze	 	 	 	 d2d       Ze	 	 d3deeef   dededeej,                     d	d f
d       Z	 d1deee
eedf   f   ded	d fdZdeedf   deeee
eef   f      ded	d fdZd Zd Ze d        Z!e d        Z"e d        Z#e d        Z$d Z%dej,                  d	d fdZ&d Z'd Z(d  Z)d! Z*d" Z+d# Z,d$ Z-d% Z.ed4d&       Z/ed'        Z0ed(        Z1ed)        Z2ed*        Z3ed+        Z4ed,        Z5d- Z6d. Z7 G d/ d0      Z8y)5r   a  A multidimensional collection of structures with the same schema.

  A **`StructuredTensor`** is a multi-dimensional collection of ***structures***
  with the same ***schema***, where:

  * A ***schema*** is a collection of fields, each of which has a name and type.
  * A ***structure*** maps each field in the schema to a tensor value (which
    could be a nested StructuredTensor).

  As an important special case, a 1D `StructuredTensor` encodes a 2D table,
  where columns are heterogeneous `Tensor`s, and rows are the aligned elements
  in each of those `Tensor`s.

  Internally, StructuredTensors use a "field-major" encoding: for each leaf
  field, there is a single tensor that stores the value of that field for all
  structures in the `StructuredTensor`.

  ### Examples

  >>> # A scalar StructuredTensor describing a single person.
  >>> s1 = tf.experimental.StructuredTensor.from_pyval(
  ...     {"age": 82, "nicknames": ["Bob", "Bobby"]})
  >>> s1.shape
  TensorShape([])
  >>> s1["age"]
  <tf.Tensor: shape=(), dtype=int32, numpy=82>

  >>> # A vector StructuredTensor describing three people.
  >>> s2 = tf.experimental.StructuredTensor.from_pyval([
  ...     {"age": 12, "nicknames": ["Josaphine"]},
  ...     {"age": 82, "nicknames": ["Bob", "Bobby"]},
  ...     {"age": 42, "nicknames": ["Elmo"]}])
  >>> s2.shape
  TensorShape([3])
  >>> s2[0]["age"]
  <tf.Tensor: shape=(), dtype=int32, numpy=12>


  ### Field Paths

  A *field path* is a tuple of field names, specifying the path to a nested
  field.
  _fields_ragged_shapeztf.StructuredTensorfieldsragged_shapec                      || _         || _        y N)r   r    )selfr!   r"   s      b/home/dcms/DCMS/lib/python3.12/site-packages/tensorflow/python/ops/structured/structured_tensor.py__init__zStructuredTensor.__init__s   s    DL%D    c           	         t        |t              sJ |       t        |t        j                        sJ |       |!t        |t        j
                        sJ |       |t        |t              sJ |       t        |t        ||||            S )a  Private constructor -- use factory methods to create StructuredTensors.

    This constructor builds a `StructuredTensor` from the given attributes,
    performing minimal validation.

    Args:
      fields: A dictionary mapping from string to `Tensor`, `RaggedTensor`, or
        `StructuredTensor`.  (This dict is not copied, so the caller must ensure
        that it does not get mutated via leaked references.)
      shape: `tf.TensorShape` with statically known rank.
      nrows: scalar integer `tf.Tensor`, or `None` if `shape.rank==0`.
      row_partitions: tuple of `RowPartition`s, with length `shape.rank-1`.
      internal: ignored argument.

    Returns:
      a StructuredTensor.
    r!   r"   )	
isinstancedictr   TensorShaper   Tensortupler   _dynamic_ragged_shape_init)clsr!   shapenrowsrow_partitionsinternals         r&   	_old_initzStructuredTensor._old_initx   s    & fd#+V+#e\556==6=Jufmm<CeC<!Z05&7 G8FG 7/u0>@A Ar(   returnc                     t        i |      S )zCreates a `StructuredTensor` with no fields and ragged_shape.

    Args:
      ragged_shape: the shape of the structured tensor.

    Returns:
      a StructuredTensor with no fields and ragged_shape.
    r*   )r   )r1   r"   s     r&   
from_shapezStructuredTensor.from_shape   s     2LAAr(   Nc                    t        j                  |      }|j                  }|t        d      t	        |t
              s!t        dt        |      j                  z        |dk  r|rt        d      |dk(  r|t        d      |1t        |      }t        |      t        d|dz
        k7  rt        d	      |dk  rd
}t        |      }t        j                  dd|j                               5  t        ||||      }|j                  dkD  r|j!                  |j                  dz
        }|j#                         D ]  \  }}t	        |t$              st        d|       t&        j)                  |      st        d|z        t+        |      ||<   t        |j#                         D 	
cg c]  \  }	}
|	t-        |
|      f c}
}	      }  | ||      cddd       S c c}
}	w # 1 sw Y   yxY w)a  Creates a `StructuredTensor` from a dictionary of fields.

    Args:
      fields: A dictionary mapping from string to `Tensor`, `RaggedTensor`, or
        `StructuredTensor`, providing the values for individual fields in each
        structure.  If `shape.rank > 0`, then every tensor in `fields` must have
        the same shape in the first `shape.rank` dimensions; and that shape must
        be compatible with `shape`; and `result[i1...iN][key] =
        fields[key][i1...iN]` (where `N==shape.rank`).
      shape: A `TensorShape`: static information about the shape of the
        `StructuredTensor`.  Must have a known `rank`.  Defaults to scalar shape
        (i.e. `rank=0`).
      nrows: scalar integer tensor containing the number of rows in this
        `StructuredTensor`.  Should only be specified if `shape.rank > 0`.
        Default value is inferred from the `fields` values.  If `fields` is
        empty, then this must be specified.
      row_partitions: A list of `RowPartition`s describing the (possibly ragged)
        shape of this `StructuredTensor`.  Should only be specified if
        `shape.rank > 1`.  Default value is inferred from the `fields` values.
        If `fields` is empty, then this must be specified.
      validate: If true, then add runtime validation ops that check that the
        field values all have compatible shapes in the outer `shape.rank`
        dimensions.

    Returns:
      A `StructuredTensor`.

    Examples:

      >>> tf.experimental.StructuredTensor.from_fields({'x': 1, 'y': [1, 2, 3]})
      <StructuredTensor(
        fields={
          "x": tf.Tensor(1, shape=(), dtype=int32),
          "y": tf.Tensor([1 2 3], shape=(3,), dtype=int32)},
        shape=())>

      >>> tf.experimental.StructuredTensor.from_fields(
      ...     {'foo': [1, 2], 'bar': [3, 4]}, shape=[2])
      <StructuredTensor(
        fields={
          "bar": tf.Tensor([3 4], shape=(2,), dtype=int32),
          "foo": tf.Tensor([1 2], shape=(2,), dtype=int32)},
        shape=(2,))>
    N.StructuredTensor's shape must have known rank.z#fields must be a dictionary, got %s   z1row_partitions must be None or [] if shape.rank<2r   z#nrows must be None if shape.rank==0   z(len(row_partitions) must be shape.rank-1 r   z%Unexpected type for key in `fields`: z'Field name %r is not currently allowed.r*   )r   as_shaperank
ValueErrorr+   r,   	TypeErrortype__name__r/   lenmaxr   
name_scopevaluesr0   _with_num_row_partitionsitemsstr_FIELD_NAME_REmatch"_convert_to_structured_field_value_replace_row_partitions)r1   r!   r2   r3   r4   validater@   keyvaluekvs              r&   from_fieldszStructuredTensor.from_fields   s   f !!%(E::D|GHHfd#;6l++, - -axNJKKqyU&<==!^,n	^	Atax 0	0CDD	n&\F	0&--/	B 4(~Ne 
a..uzzA~>  6*#u#s#A#GH
H##C(DsJK
K8?s%+\\^5!Aq 21nEF 5 66 U3%4 4 5!4 4s   .B9G"'G?G"G""G+r@   rP   dtypec           	         |st        d      t        |t              st        d      |dk  rt        d      |j                         D ci c]  \  }}|t	        |       }}}|t        |dd      }t        ||      }t        |||      }|dkD  r|j                  |dz
        }|j                  }|j                         D ci c]  \  }}|t        ||       }}}t        ||      S c c}}w c c}}w )a  Creates a `StructuredTensor` from a nonempty dictionary of fields.

    Note that if the shape dtype is not specified, the shape dtype will be
    inferred from any fields that have a shape dtype. If fields differ, then
    int64 will be preferred to int32, because coercing from int32 to int64 is
    safer than coercing from int64 to int32.

    If there are no ragged fields, then it will be int64 by default, but this
    will be changed to int32 in the future.

    Args:
      fields: A dictionary mapping from string to `Tensor`, `RaggedTensor`, or
        `StructuredTensor`, providing the values for individual fields in each
        structure.  If `rank > 0`, then every tensor in `fields` must have the
        same shape in the first `rank` dimensions. Cannot be empty.
      rank: The rank of the resulting structured tensor.
      validate: If true, then add runtime validation ops that check that the
        field values all have compatible shapes in the outer `rank` dimensions.
      dtype: If specified, then forces dtype of the shape to be this.

    Returns:
      A `StructuredTensor`.
    Examples:
      >>> tf.experimental.StructuredTensor.from_fields_and_rank(
      ...     {'x': 1, 'y': [1, 2, 3]}, 0)
      <StructuredTensor(
        fields={
          "x": tf.Tensor(1, shape=(), dtype=int32),
          "y": tf.Tensor([1 2 3], shape=(3,), dtype=int32)},
        shape=())>
      >>> StructuredTensor.from_fields_and_rank({'foo': [1, 2], 'bar': [3, 4]},
      ...                              1)
      <StructuredTensor(
        fields={
          "bar": tf.Tensor([3 4], shape=(2,), dtype=int32),
          "foo": tf.Tensor([1 2], shape=(2,), dtype=int32)},
        shape=(2,))>
    zMust provide at least one fieldzrank must be an integerr   zrank must be nonnegativeNr=   r*   )rA   r+   intrJ   rN   _find_shape_dtype_fields_with_dtype_shape_from_fieldsrI   _row_partitionsrO   r   )	r1   r!   r@   rP   rV   rS   rT   r2   new_rps	            r&   from_fields_and_rankz%StructuredTensor.from_fields_and_rank   s   Z 899dC 011ax122?E||~5;a-a00F  }d3e.FvtU3Eax,,TAX6e""F<BLLN281a"1f--F  6>>s   C,C2updatesc                 V   |j                         D cg c]  \  }}t        |      |f }}}t        |      }t        dt	        |            D ]A  }||   d   }||dz
     d   }|dt	        |       |k(  s(t        dj                  ||             | j                  d||      S c c}}w )a  Creates a new `StructuredTensor` with the updated fields.

    If this `StructuredTensor` is a scalar, and `k` is the `FieldName` being
    updated and `v` the new value, then:

    ```
    result[k] = v              # If (k, v) is in updates and v is a FieldValue
    result[k] = f(self[k])     # If (k, f) is in updates and f is a FieldFn
    result[k] = self[k]        # If k is in self.field_names but not in updates
    ```

    If this `StructuredTensor` has rank `N` and shape `[D1...DN]`, then each
    FieldValue `v` in `updates` must have shape `[D1...DN, ...]`, that is,
    prefixed with the same shape as the `StructuredTensor`. Then the resulting
    `StructuredTensor` will have:

    ```
    result[i1...iN][k] = v[i1...iN]                        # (k, v) in updates
    result[i1...iN][k] = f(self.field_value(k))[i1...iN]   # (k, f) in updates
    result[i1...iN][k] = self[i1...iN][k]                  # k not in updates
    ```

    Note that `result.shape` is always equal to `self.shape` (but the shapes
    of nested StructuredTensors may be changed if they are updated with new
    values).

    Args:
      updates: A dictionary mapping `FieldName` to either a `FieldValue` to be
        used to update, or a `FieldFn` that will transform the value for the
        given `FieldName`. `FieldName` can be a string for a direct field, or a
        sequence of strings to refer to a nested sub-field. `FieldFn` is a
        function that takes a `FieldValue` as input and should return a
        `FieldValue`. All other fields are copied over to the new
        `StructuredTensor`. New `FieldName` can be given (to add new fields),
        but only to existing `StructuredTensor`, it won't automatically create
        new nested structures -- but one can create a whole `StructureTensor`
        sub-structure and set that into an existing structure. If the new value
        is set to `None`, it is removed.
      validate: If true, then add runtime validation ops that check that the
        field values all have compatible shapes in the outer `shape.rank`
        dimensions.

    Returns:
      A `StructuredTensor`.

    Raises:
      `ValueError`: If the any of the `FieldName` keys points to non-existent
        sub-structures, if parent and child nodes are updated, if shapes
        change, if a delete update is given for a non-existent field, or if a
        `FieldFn` transforming function is given for a `FieldName` that doesn't
        yet exist.

    Examples:

    >>> shoes_us = tf.experimental.StructuredTensor.from_pyval([
    ...    {"age": 12, "nicknames": ["Josaphine"],
    ...       "shoes": {"sizes": [8.0, 7.5, 7.5]}},
    ...    {"age": 82, "nicknames": ["Bob", "Bobby"],
    ...        "shoes": {"sizes": [11.0, 11.5, 12.0]}},
    ...    {"age": 42, "nicknames": ["Elmo"],
    ...        "shoes": {"sizes": [9.0, 9.5, 10.0]}}])
    >>> def us_to_europe(t):
    ...   return tf.round(t * 2.54 + 17.0)  # Rough approximation.
    >>> shoe_sizes_key = ("shoes", "sizes")
    >>> shoes_eu = shoes_us.with_updates({shoe_sizes_key: us_to_europe})
    >>> shoes_eu.field_value(shoe_sizes_key)
    <tf.RaggedTensor [[37.0, 36.0, 36.0], [45.0, 46.0, 47.0],
    [40.0, 41.0, 42.0]]>
    r=   r   Nz`StructuredTensor.with_updates` does not allow both parent and child nodes to be updated: parent={}, child={}. If needed you can update child nodes in the parent update value.r>   )rJ   _normalize_field_name_to_tuplesortedrangerE   rA   format_with_updates_impl)r%   r_   rP   namerR   updates_itemsi	prev_names           r&   with_updateszStructuredTensor.with_updates@  s    R )09$u 5T:EB 9M 9 =)M1c-() 	"1a dA&q)i	os9~	)	+==CV4>!" 	"	" ""2}h??9s   B%error_prefix.c           
         t        | j                        dt        t           dt        ffddt        dt        t
        t        f   dt
        ffd}|D ]-  \  }}|r|d   s t        dj                   |                  t        |      dk(  rJ|d   }|6|vr t        d
j                   |                  j                  |       y |||      |<   |d   }|dd	 }|vr-t        dj                  t        |      z    |                  |   }	t        |	t              s7t        dj                  t        |      z    |      t        |	                  ||fg}
|	j                  |fz   |
|      }||<   0 	 t        j!                  | j"                  | j$                  | j'                         |      S # t        $ r'}d}rdj                  |      }t        |      |d	}~ww xY w)z0Recursive part of `with_updates` implementation.rf   r7   c                 "    t        | fz         S r$   )rK   )rf   rk   s    r&   name_fullpathz:StructuredTensor._with_updates_impl.<locals>.name_fullpath  s    '((r(   rR   c                 |    t        |      r/| vr t        dj                   |                    ||          }|S )Nz`StructuredTensor.with_updates` cannot update the field {} because a transforming function was given, but that field does not already exist.)callablerA   rd   )rf   rR   rn   
new_fieldss     r&   apply_valuez8StructuredTensor._with_updates_impl.<locals>.apply_value  sK    	%z!((.}T/B(CE E j&'lr(   r   z>`StructuredTensor.with_updates` does not allow empty names {}.r=   NzQ`StructuredTensor.with_updates` cannot delete field {} because it is not present.z]`StructuredTensor.with_updates` cannot create new sub-field {} if parent field {} is not set.z`StructuredTensor.with_updates` cannot create new sub-field {} if parent structure {} is not a `StructuredTensor` that can contain sub-structures -- it is a `{}`.)r2   r4   r3   rP   z&`StructuredTensor.with_updates` failedz{} for field {})r,   r   r   rK   r
   _FieldValue_FieldFnrA   rd   rE   popr/   r+   r   rC   re   rU   r2   r4   r3   )r%   rk   r_   rP   rr   rf   rR   prefixsuffixcurrent_value
one_updateemsgrn   rq   s    `           @@r&   re   z#StructuredTensor._with_updates_impl  sG    dll#J)HSM )c )
# 
eK,4-5 '6 
:E
  *#ea&t,-/ 	/ 
TaAw=#006}T7J0KM M ..
(u5*T
 aab#228&t,mF.C3EF F #6*-)9:<<BFt,mF.C}%='( ( uo&
 00	1I1;XG #
6U*#Z#))


,,

 *    #4c	&&sL9sO"	#s   ;G 	G8"G33G8c                 0   | j                  |      }| j                  |      j                  }| j                  |dd       j                  }||k(  r|S |j                  j                  }|t        d      t	        ||dz
        }||k  r|S t        |||      S )a  Creates a promoted field without adding it to the structure.

    Args:
      source_path: the source path in the structured tensor.
      new_parent_path: the new parent path. Must be a prefix of source_path.

    Returns:
      a composite tensor of source_path promoted.
    Raises:
      ValueError: if the shape of the field is unknown and the right strategy
      cannot be determined.
    Nz0Cannot determine if dimensions should be merged.r=   )field_valuer@   r2   rA   min_merge_dims_generic)r%   source_pathnew_parent_pathcurrent_fieldnew_parent_rankparent_rankcurrent_field_rank	inner_dims           r&   _promote_helperz StructuredTensor._promote_helper  s     $$[1M&&7<<O"";s#3499K+%&,,11!IJJK!3a!78IO#}oyIIr(   c                    t        |t              st        d      t        |t        t        f      st        d      t        |      dk  rt        d      |dd }| j                  ||      }||fz   }| j                  ||i      S )a  Promotes a field, merging dimensions between grandparent and parent.

    >>> d = [
    ...  {'docs': [{'tokens':[1, 2]}, {'tokens':[3]}]},
    ...  {'docs': [{'tokens':[7]}]}]
    >>> st = tf.experimental.StructuredTensor.from_pyval(d)
    >>> st2 =st.promote(('docs','tokens'), 'docs_tokens')
    >>> st2[0]['docs_tokens']
    <tf.Tensor: shape=(3,), dtype=int32, numpy=array([1, 2, 3], dtype=int32)>
    >>> st2[1]['docs_tokens']
    <tf.Tensor: shape=(1,), dtype=int32, numpy=array([7], dtype=int32)>

    Args:
      source_path: the path of the field or substructure to promote; must have
        length at least 2.
      new_name: the name of the new field (must be a string).

    Returns:
      a modified structured tensor with the new field as a child of the
      grandparent of the source_path.

    Raises:
      ValueError: if source_path is not a list or a tuple or has a length
        less than two, or new_name is not a string, or the rank
        of source_path is unknown and it is needed.
    znew_name is not a stringz#source_path must be a list or tupler<   z)source_path must have length at least twoN)r+   rK   rA   listr/   rE   r   rj   )r%   r   new_namegrandparent_path	new_fieldnew_paths         r&   promotezStructuredTensor.promote  s    6 h$122kD%=1<==
;!BCC"3B'$$[2BCI8+-Hh	233r(   c                 .    | j                   j                  S )z@The rank of this StructuredTensor.  Guaranteed not to be `None`.r    r@   r%   s    r&   r@   zStructuredTensor.rank4  s     """r(   c                 6    | j                   j                         S )zThe static shape of this StructuredTensor.

    The returned `TensorShape` is guaranteed to have a known rank, but the
    individual dimension sizes may be unknown.

    Returns:
      `tf.TensorShape`
    r    _to_tensor_shaper   s    r&   r2   zStructuredTensor.shape9  s     ..00r(   c                     | j                   S )z"Deprecated form of row_partitions.)r4   r   s    r&   r\   z StructuredTensor._row_partitionsF  s     r(   c                 V    | j                   dk  ry| j                  j                         S )a	  A tuple of `RowPartition`s defining the shape of this `StructuredTensor`.

    When `self.rank <= 1`, this tuple will be empty.

    When `self.rank > 1`, these `RowPartitions` define the shape of the
    `StructuredTensor` by describing how a flat (1D) list of structures can be
    repeatedly partitioned to form a higher-dimensional object.  In particular,
    the flat list is first partitioned into sublists using `row_partitions[-1]`,
    and then those sublists are further partitioned using `row_partitions[-2]`,
    etc.  The following examples show the row partitions used to describe
    several different `StructuredTensor`, each of which contains 8 copies of
    the same structure (`x`):

    >>> x = {'a': 1, 'b': ['foo', 'bar', 'baz']}       # shape = [] (scalar)

    >>> s1 = [[x, x, x, x], [x, x, x, x]]              # shape = [2, 4]
    >>> tf.experimental.StructuredTensor.from_pyval(s1).row_partitions
    (tf.RowPartition(row_splits=[0 4 8]),)

    >>> s2 = [[x, x], [x, x], [x, x], [x, x]]          # shape = [4, 2]
    >>> tf.experimental.StructuredTensor.from_pyval(s2).row_partitions
    (tf.RowPartition(row_splits=[0 2 4 6 8]),)

    >>> s3 = [[x, x, x], [], [x, x, x, x], [x]]        # shape = [2, None]
    >>> tf.experimental.StructuredTensor.from_pyval(s3).row_partitions
    (tf.RowPartition(row_splits=[0 3 3 7 8]),)

    >>> s4 = [[[x, x], [x, x]], [[x, x], [x, x]]]      # shape = [2, 2, 2]
    >>> tf.experimental.StructuredTensor.from_pyval(s4).row_partitions
    (tf.RowPartition(row_splits=[0 2 4]),
     tf.RowPartition(row_splits=[0 2 4 6 8]))


    >>> s5 = [[[x, x], [x]], [[x, x]], [[x, x], [x]]]  # shape = [3, None, None]
    >>> tf.experimental.StructuredTensor.from_pyval(s5).row_partitions
    (tf.RowPartition(row_splits=[0 2 3 5]),
     tf.RowPartition(row_splits=[0 2 3 5 7 8]))

    Note that shapes for nested fields (such as `x['b']` in the above example)
    are not considered part of the shape of a `StructuredTensor`, and are not
    included in `row_partitions`.

    If this `StructuredTensor` has a ragged shape (i.e., if any of the
    `row_partitions` is not uniform in size), then all fields will be encoded
    as either `RaggedTensor`s or `StructuredTensor`s with these `RowPartition`s
    used to define their outermost `self.rank` dimensions.

    Returns:
      A `tuple` of `RowPartition` objects with length `self.rank - 1`
      (or `0` if `self.rank < 2`)

    r<   r>   )r@   r    _as_row_partitionsr   s    r&   r4   zStructuredTensor.row_partitionsM  s(    l yy1}0022r(   c                 @    | j                   dk(  ry| j                  d   S )a  The number of rows in this StructuredTensor (if rank>0).

    This means the length of the outer-most dimension of the StructuredTensor.

    Notice that if `self.rank > 1`, then this equals the number of rows
    of the first row partition. That is,
    `self.nrows() == self.row_partitions[0].nrows()`.

    Otherwise `self.nrows()` will be the first dimension of the field values.

    Returns:
      A scalar integer `Tensor` (or `None` if `self.rank == 0`).
    r   N)r@   r    r   s    r&   r3   zStructuredTensor.nrows  s#     yyA~a  r(   c                     || j                   j                  k(  r| S t        t        | j                  |      | j                   j                  |            S )Nr*   )r    rV   r   rZ   r   
with_dtype)r%   rV   s     r&   with_shape_dtypez!StructuredTensor.with_shape_dtype  sJ    ""(((k!$,,6''2259; ;r(   c                 T    t        j                  | d      }t        d |D              S )z1True if all fields are composed of eager tensors.T)expand_compositesc              3   P   K   | ]  }t        |t        j                           y wr$   )r+   r   EagerTensor).0ts     r&   	<genexpr>z-StructuredTensor._is_eager.<locals>.<genexpr>  s     ?!z!S__-?s   $&)r   flattenall)r%   tensorss     r&   	_is_eagerzStructuredTensor._is_eager  s#    ll448G?w???r(   c                 H    t        | j                  j                               S )z;Returns the string field names for this `StructuredTensor`.)r/   r   keysr   s    r&   field_nameszStructuredTensor.field_names  s    ""$%%r(   c                     t        |t        t        f      rG| }|D ]>  }t        |t              st	        dj                  ||             |j                  |      }@ |S | j                  |   S )a  Returns the tensor value for the specified field or path.

    If `field_name` is a `string`, then it names a field directly owned by this
    `StructuredTensor`.  If this `StructuredTensor` has shape `[D1...DN]`, then
    the returned tensor will have shape `[D1...DN, V1...VM]`, where the slice
    `result[d1...dN]` contains the field value for the structure at
    `self[d1...dN]`.

    If `field_name` is a `tuple` of `string`, then it specifies a path to a
    field owned by nested `StructuredTensor`.  In particular,
    `struct.field_value((f1, f2, ..., fN))` is equivalent to
    `struct.field_value(f1).field_value(f2)....field_value(fN)`

    Args:
      field_name: `string` or `tuple` of `string`: The field whose values should
        be returned.

    Returns:
      `Tensor`, `StructuredTensor`, or `RaggedTensor`.

    Raises:
      KeyError: If the given field_name is not found.
    zField path {} not found in {})r+   r   r/   r   KeyErrorrd   r~   r   )r%   
field_namerR   fs       r&   r~   zStructuredTensor.field_value  sw    0 *tUm,e %!%!128??$  ! !!!!$	%
 l<<
##r(   c                     t        |t              rt        |      }nt        |t              s|f}|s| S | j                  dk(  r| j	                  |      S | j                  |      S )a<  Returns the specified piece of this StructuredTensor.

    * If `struct_tensor` is scalar (i.e., a single structure), then
      `struct_tensor[f]` returns the value of field `f` (where `f` must be a
      string).

    * If `struct_tensor` is non-scalar (i.e., a vector or higher-dimensional
      tensor of structures), `struct_tensor[i]` selects an element or slice of
      the tensor using standard Python semantics (e.g., negative values index
      from the end).  `i` may have any of the following types:

      * `int` constant
      * `string` constant
      * scalar integer `Tensor`
      * `slice` containing integer constants and/or scalar integer
        `Tensor`s

    #### Multidimensional indexing

    `StructuredTensor` supports multidimensional indexing.  I.e., `key` may be a
    `tuple` of values, indexing or slicing multiple dimensions at once.  For
    example, if `people` is a vector of structures, each of which has a vector-
    valued `names` field, then `people[3, 'names', 0]` is equivalent to
    `people[3]['names'][0]`; and `people[:, 'names', :]` will return a (possibly
    ragged) matrix of names, with shape `[num_people, num_names_per_person]`.

    Args:
      key: Indicates which piece of the StructuredTensor to return.

    Returns:
      A `Tensor`, `StructuredTensor`, or `RaggedTensor`.
    r   )r+   r   r/   r@   _scalar_getitem_tensor_getitem)r%   rQ   s     r&   __getitem__zStructuredTensor.__getitem__  s^    B #t#JcU#FckyyA~!!#&&!!#&&r(   c                    t        d   t              ryd   j                  jd   j                  [d   j                  Lt        fd| j                  j                         D              }t        j                  || j                        S t        d   t        j                        st        d      | j                  d      j                  dd        S )Nr   c              3   P   K   | ]  \  }}||j                  d d       f  yw)r=   Nr   r   r   r~   rQ   s      r&   r   z3StructuredTensor._scalar_getitem.<locals>.<genexpr>  s5      K1[  !8!8QR!AB Ks   #&zJKey for indexing a StructuredTensor must be a string or a full slice (':')r=   )r+   slicestartstopstepr,   r   rJ   r   rU   r2   r   bytes_or_text_typesrA   r   )r%   rQ   r!   s    ` r&   r   z StructuredTensor._scalar_getitem  s    3q65!c!fll&:AA 3 K59\\5G5G5IK Kf))&$**==A : :; 6 7 7 <<A++CG44r(   c                    | j                   }t              |k  rt        fd| j                  j	                         D              }| j
                  j                         }t              D ]  \  }}t        |t              r+|j                  |j                  |j                  ;d ||<   At        |t        t        j                  f      rd||<   g|t!        d      t!        d|z         |D cg c]
  }|dk7  s	| }}t"        j%                  ||      S t        |   t&        j(                        st!        d      | j                  |      j+                  d | |dz   d  z         S c c}w )Nc              3   J   K   | ]  \  }}||j                        f  y wr$   r   r   s      r&   r   z3StructuredTensor._tensor_getitem.<locals>.<genexpr>  s/      O5Z $[%<%<S%AB Os    #r}   z$Slicing not supported for tf.newaxiszSlicing not supported for %rz4Key for indexing a StructuredTensor must be a stringr=   )r@   rE   r,   r   rJ   r2   as_list	enumerater+   r   r   r   r   rX   r   r.   rA   r   rU   r   r   r   )r%   rQ   r@   rq   result_shapedrS   s    `     r&   r   z StructuredTensor._tensor_getitem  s\   99D
3x4 O9=9K9K9MO OjZZ'')lC. ?$!Qa''/affn"LOC/0,q/YAB
B 9A=>
>? ".9Aba9l9))*lCC D	6#=#=>OPP\\#d)$00Udc$()n1LMM :s   4
E0?E0c                     t        | j                  j                               }d |D        }d |D        }dj                  |      }d|d| j                  dS )Nc              3   \   K   | ]$  \  }}|t        |      j                  d d      f & yw)
z
            N)rK   replacer   rS   rT   s      r&   r   z,StructuredTensor.__repr__.<locals>.<genexpr>+  s)     Mdaq#a&..'789Ms   *,c              3   F   K   | ]  \  }}d j                  ||        yw)z"{}": {}N)rd   r   s      r&   r   z,StructuredTensor.__repr__.<locals>.<genexpr>,  s!     9$!Qj1%9s   !z
,
        z(<StructuredTensor(
    fields={
        z},
    shape=z)>)rb   r   rJ   joinr2   )r%   r!   	dict_reprs      r&   __repr__zStructuredTensor.__repr__)  sR    DLL&&()FMfMF9&9F""6*I !*4::7 8r(   c                    | j                         st        d      i }| j                  j                         D ]  \  }}t	        |t
        j                        r|j                         }t	        |t        j                        r|j                         }nKt	        |t        j                        r|j                         }n t	        |t              r|j                         }|||<    t!        | j"                        dkD  rk|s$t%        | j&                  | j)                               S t+        t-        |j/                               t-        |j1                               | j2                        S |S )a  Returns this StructuredTensor as a nested Python dict or list of dicts.

    Converts this `StructuredTensor` to a nested python value:

    * `StructTensors` with `rank=0` are converted into a dictionary, with an
      entry for each field.  Field names are used as keys and field values are
      converted to python values.  In particular:

      * Scalar Tensor fields are converted to simple values (such as
        `int` or `float` or `string`)
      * Non-scalar Tensor fields and RaggedTensor fields are converted to
        nested lists of simple values.
      * StructuredTensor fields are converted recursively using `to_pyval`.

    * `StructTensors` with `rank>0` are converted to nested python `list`s,
      containing one dictionary for each structure (where each structure's
      dictionary is defined as described above).

    Requires that all fields are Eager tensors.

    >>> tf.experimental.StructuredTensor.from_fields(
    ...     {'a': [1, 2, 3]}, [3]).to_pyval()
    [{'a': 1}, {'a': 2}, {'a': 3}]

    Note that `StructuredTensor.from_pyval(pyval).to_pyval() == pyval`.

    Returns:
      A nested Python dict or list of dicts.
    z<StructuredTensor.to_pyval() is only supported in eager mode.r   )r   rA   r   rJ   r+   r   r   numpynpndarraytolistr   RaggedTensorto_listr   to_pyvalrE   r2   &_empty_dict_pylist_from_row_partitionsr4   r3    _pyval_field_major_to_node_majorr   r   rH   r@   )r%   resultrQ   rR   s       r&   r   zStructuredTensor.to_pyval7  s    < >>
HJ J F**, 
e	E3??	+	E2::	&e]778e-. fSk
 4::5d6I6I6:jjlD 	D-
v{{}
tFMMO4diiA A mr(   c                 (    | j                  ||d      S )aZ  Constructs a StructuredTensor from a nested Python structure.

    >>> tf.experimental.StructuredTensor.from_pyval(
    ...     {'a': [1, 2, 3], 'b': [[4, 5], [6, 7]]})
    <StructuredTensor(
        fields={
          "a": tf.Tensor([1 2 3], shape=(3,), dtype=int32),
          "b": <tf.RaggedTensor [[4, 5], [6, 7]]>},
        shape=())>

    Note that `StructuredTensor.from_pyval(pyval).to_pyval() == pyval`.

    Args:
      pyval: The nested Python structure that should be used to create the new
        `StructuredTensor`.
      typespec: A `StructuredTensor.Spec` specifying the expected type for each
        field. If not specified, then all nested dictionaries are turned into
        StructuredTensors, and all nested lists are turned into Tensors (if
        rank<2) or RaggedTensors (if rank>=2).

    Returns:
      A `StructuredTensor`.
    r>   _from_pyval)r1   pyvaltypespecs      r&   
from_pyvalzStructuredTensor.from_pyvalq  s    2 ??5(B//r(   c                    t        |t              r| j                  |||      S t        |t        t        f      r@t               }t        ||      }|| j                  |||||      S | j                  |||      S | j                  |||      S )a(  Helper function for from_pyval.


    Args:
      pyval: The nested Python structure that should be used to create the new
        `StructuredTensor`.
      typespec: A `StructuredTensor.Spec` specifying the expected type for each
        field. If not specified, then all nested dictionaries are turned into
        StructuredTensors, and all nested lists are turned into Tensors (if
        rank<2) or RaggedTensors (if rank>=2).
      path_so_far: the path of fields that led here (for error messages).

    Returns:
      A `StructuredTensor`.
    )
r+   r,   _from_pydictr   r/   set!_pyval_find_struct_keys_and_depth_from_pylist_of_dict_from_pylist_of_value_from_pyscalar)r1   r   r   path_so_farr   r@   s         r&   r   zStructuredTensor._from_pyval  s    " %eX{;;	ED%=	)Ud.ud;d		''tT8(35 	5 ((+FFx==r(   c                     |$t         fd|j                         D              }n|j                  }|j                  t	        |t
        j                        r&|j                  dk(  rt        |      t              k(  st        dd|d|      t         fd|j                         D              }t
        j                  |dd	      S )
zEConverts python dictionary `pyval` to a StructuredTensor with rank=0.c              3   V   K   | ]   \  }}|j                  |d |fz         f " y wr$   r   )r   rS   rT   r1   r   s      r&   r   z0StructuredTensor._from_pydict.<locals>.<genexpr>  s6      1A 4t1CDE 1s   &)r   	Value at  does not match typespec:  vs c              3   \   K   | ]#  \  }}|j                  ||   |fz         f % y wr$   r   )r   rS   rT   r1   field_specsr   s      r&   r   z0StructuredTensor._from_pydict.<locals>.<genexpr>  s:      1A ;q>;!;MNO 1s   ),r>   Fr!   r2   rP   )r,   rJ   _shape_field_specsr+   r   Specr@   r   rA   rU   )r1   r   r   r   r!   
spec_shaper   s   `  `  @r&   r   zStructuredTensor._from_pydict  s      1"'++-1 1f ??j))k#3#8#89oo"s5zS5E'E%uh8 9 	9 1"'++-1 1f''vR%'PPr(   c                    t        d |D              }|D ]  }t        ||d        |Lt        j                  dg|z        }|j	                         D ]  \  }	}
| j                  |
d||	fz         ||	<   ! n|j                  }t        |t        j                        rt        |      t        |      z
  rt        d|d|d|      |j                  }|j                  |k  rt        d|d|d|      |j	                         D ]/  \  }	}| j                  |j                  |	g       |||	fz         ||	<   1 	 |s|t        j                  ||      S t        j!                  ||d	      S # t"        $ r}t        d
|      |d}~ww xY w)z?Converts python list `pyval` to a StructuredTensor with rank>1.c              3   $   K   | ]  }|g f 
 y wr$   r>   )r   rQ   s     r&   r   z8StructuredTensor._from_pylist_of_dict.<locals>.<genexpr>  s     ,3),   r=   Nr   r   r   z* does not match typespec (rank mismatch): Fr   Error parsing path )r,   _pyval_update_fieldsr   r-   rJ   r   r   r+   r   r   r   rA   r   r@   get_from_pylist_of_empty_dictrU   	Exception)r1   r   r   r@   r   r   r!   childr2   rQ   targetr   specexcs                 r&   r   z%StructuredTensor._from_pylist_of_dict  s    ,t,,F -5&!,-&&v}5e!<<> J-3oofdK3&4HIsJ $$k($4$9$9:v;[))%uh8 9 	9ooe	d	'2E8E F 	F$**, =+3ooJJsB{cV';=s=J(  ::5$GG))uu * 6 6 J+?@cIJs   8E* E* *	F3FFc                    |dk(  rt         j                  i dd      S |dk(  r&t        |      }|f}t         j                  i ||      S |dkD  rut        j                  t        |            }t        |      }t        j                  t        |      gdg|dz
  z  z         }t         j                  i ||j                  |      S y)	z=Converts a pylist of empty dictionaries to StructuredTensors.r   r>   Fr   r=   )r!   r2   r3   N)r!   r2   r4   r3   )	r   rU   rE   r   constant_dicts_to_zerosr   r-   _nested_row_partitions)r1   r   r@   r3   r2   ragged_zeross         r&   r   z+StructuredTensor._from_pylist_of_empty_dict  s     qy))2)NN	%jehe))5)NN	'001GHl%je&&E
|v7J'KLe))%<<	 *  	 
r(   c           	         |	 t        j                  |      S t	        |t
        j                        r\	 t        j                  ||j                        }|j                  j                  |j                        st        d|d|d|      |S t	        |t        j                        rS	 t        j                  ||j                  |j                  |j                  |j                   |j                  dz   d       S t	        |t"        j$                        r>t'        |      }|t        d|d|d|      | j)                  |t+               |||      S t        d|d|d|      # t        $ r}t        d|      |d}~ww xY w# t        $ r}t        d|      |d}~ww xY w# t        $ r}t        d|      |d}~ww xY w)zEConverts python list `pyval` to a Tensor or RaggedTensor with rank>1.Nr   r   r   r   r=   )rV   ragged_rankrow_splits_dtypeinner_shape)r   r   r   rA   r+   r   
TensorSpecr   rV   r2   is_compatible_withr   RaggedTensorSpec_dtype_ragged_rank_row_splits_dtyper   r   r   _pyval_empty_list_depthr   r   )r1   r   r   r   r   r   
empty_ranks          r&   r   z&StructuredTensor._from_pylist_of_value  s    L!**511 
Hf//	0L%%eX^^< ^^..v||<%x8 9 	9m	Hm<<	=L!**// --%77 (=(=(A(BCE 	E 
H.33	4*51j		%x8 9 	9 ''suj((35 	5 #Xu6 7 7?  LKABKL
  LKABKL  LKABKLsG   E(  F *AF( (	F1F  F	F%F  F%(	G1G  Gc                 @   |	 t        j                  |      S t	        |t
        j                        r|j                  j                  dk(  st        d|d|d|      t        j                  ||j                        S # t        $ r}t        d|      |d}~ww xY w)z1Converts python scalar value `pyval` to a Tensor.Nr   r   r   r   r   )
r   r   r   rA   r+   r   r  r2   r@   rV   )r1   r   r   r   r   s        r&   r   zStructuredTensor._from_pyscalar  s     L##E** 6#4#45nn!!Q&%x8 9 	9 !!%88  LKABKLs   B   	B	BBc                     t        |t              st        d      | j                  j                  dk(  rt        d| j                  z        t        | |      S )a  Partitions the outer dimension of this StructuredTensor.

    Returns a new `StructuredTensor` with the same values as `self`, where
    the outer dimension is partitioned into two (possibly ragged) dimensions.
    Requires that this StructuredTensor have an outer dimension (i.e.,
    `self.shape.rank > 0`).

    >>> st = tf.experimental.StructuredTensor.from_pyval(
    ...     [{'foo': 12}, {'foo': 33}, {'foo': 99}])
    >>> partition = RowPartition.from_row_lengths([2, 0, 1])
    >>> st.partition_outer_dimension(partition)
    <StructuredTensor(
      fields={
        "foo": <tf.RaggedTensor [[12, 33], [], [99]]>},
      shape=(3, None))>

    Args:
      row_partition: A `RowPartition`.

    Returns:
      A `StructuredTensor` with rank `values.rank + 1`.
    z%row_partition must be a RowPartition.r   z"Shape %s must have rank at least 1)r+   r   rB   r2   r@   rA   _partition_outer_dimension)r%   row_partitions     r&   partition_outer_dimensionz*StructuredTensor.partition_outer_dimension.  sL    . m\2=>>zz!;djjHII%dM::r(   c                     t        j                  || j                  j                  dd      }t        j                  || j                  j                  dd      }||k  st	        d||fz        t        | ||      S )a.  Merges outer_axis...inner_axis into a single dimension.

    Returns a copy of this RaggedTensor with the specified range of dimensions
    flattened into a single dimension, with elements in row-major order.

    >>> st = tf.experimental.StructuredTensor.from_pyval(
    ...     [[{'foo': 12}, {'foo': 33}], [], [{'foo': 99}]])
    >>> st.merge_dims(0, 1)
    <StructuredTensor(
      fields={
        "foo": tf.Tensor([12 33 99], shape=(3,), dtype=int32)},
      shape=(3,))>

    Args:
      outer_axis: `int`: The first dimension in the range of dimensions to
        merge. May be negative (to index from the last dimension).
      inner_axis: `int`: The last dimension in the range of dimensions to merge.
        May be negative (to index from the last dimension).

    Returns:
      A copy of this tensor, with the specified dimensions merged into a
      single dimension.  The shape of the returned tensor will be
      `self.shape[:outer_axis] + [N] + self.shape[inner_axis + 1:]`, where `N`
      is the total number of slices in the merged dimensions.
    
outer_axisz
rank(self))	axis_name
ndims_name
inner_axiszDExpected outer_axis (%d) to be less than or equal to inner_axis (%d))r   get_positive_axisr2   r@   rA   _merge_dims)r%   r  r  s      r&   
merge_dimszStructuredTensor.merge_dimsK  s    4 ,,

	!J
 ,,

	!J
 # ),6
+CD E EtZ44r(   c                       e Zd ZdZd Zed        Zedej                  dd fd       Z	e
dej                  fd       Ze
deeej"                  f   fd       Ze
dej                  fd	       Ze
d
        Zy)StructuredTensor.SpeczA spec for StructuredTensor.c                      | j                   J y r$   )r    r   s    r&   __validate__z"StructuredTensor.Spec.__validate__w  s    +++r(   c           
      :   d}|j                         D ]p  \  }}t        |      }|t        d| d      |j                  }|||k  rt        d| d| d| d      |j	                  |      }||}`|j                  |      }r t        j                  ||      S )z:Creates a spec of a StructuredTensor with fields and rank.NCannot convert spec of .Rank of field  is , but must be at least r    r   )rJ   $_dynamic_ragged_shape_spec_from_specrA   r@   	_truncate_merge_withr   r   )	r1   r!   r@   r2   rS   rT   field_shape_untruncateduntruncated_rankfield_shapes	            r&   _from_fields_and_rankz+StructuredTensor.Spec._from_fields_and_rankz  s     eLLN 1&1a"Fq"I"*4QCq9:
:277(-=-D^A3d3C2D E337&; < <-77==%##K0%1 """GGr(   r2   r7   c                 0    t         j                  |i       S )z.Creates the spec of an empty StructuredTensor.r%  )r   r   )r1   r2   s     r&   _from_shapez!StructuredTensor.Spec._from_shape  s    
 """CCr(   c                 6    | j                   j                         S r$   r   r   s    r&   r   zStructuredTensor.Spec._shape  s    0022r(   c                     | j                   S r$   )r   r   s    r&   r   z"StructuredTensor.Spec._field_specs  s    \\r(   c                     | j                   S r$   )r   r   s    r&   r2   zStructuredTensor.Spec.shape  s    [[r(   c                 .    | j                   j                  S r$   r   r   s    r&   r@   zStructuredTensor.Spec.rank  s    $$$r(   N)rD   
__module____qualname____doc__r  classmethodr,  r   DynamicRaggedShaper.  propertyr   r-   r   r   rK   r   TypeSpecr   r2   r@   r>   r(   r&   r   r  t  s    &, H H$ D(;;D	 D D 300 3 3 d3	(:(:#:;   |//   % %r(   r   )F)r>   NNF)FNr$   )9rD   r3  r4  r5  r   rK   rs   __annotations__r   r7  r
   r   	FieldNamer'   r6  r6   r9   rU   rX   boolr   r   DTyper^   r   rt   rj   r	   r   re   r   r   r8  r@   r2   r\   r4   r3   r   r   r   r~   r   r   r   r   r   r   r   r   r   r   r   r   r  r  r   r>   r(   r&   r   r   5   s#   *V 3#$$%888"( C#&')&WS+%56 &1DD&
 A A8 B-@@BB B  !% W4 W4r 
 &*@?c;&'@? @? 	@?
 fll#@?
 0B@? @?H %*W@ E+x2M,N!NOW@!W@.@W@rS#U38_ S#"&uYk>F?G 9H .H (I #JS# $(S# -?S#jJ4&4X # # 	1 	1   73 73r!$;FLL ;5G ;@& $N+'Z5N688t 0 04 > >: Q Q  J J@  $ %7 %7N 9 9,;:'5R2% 2%r(   z^[a-zA-Z][a-zA-Z0-9_]*$c                 h   t        | t        j                  t        j                  t
        f      r| S t        j                  |       rt        j                  |       S t        | t        j                        r| S 	 t        j                  |       S # t        t        f$ r}t        d| z        |d}~ww xY w)z@Converts `value` to a Tensor, RaggedTensor, or StructuredTensor.z)Unexpected type for value in `fields`: %rN)r+   r   r.   r   r   r   	is_ragged"convert_to_tensor_or_ragged_tensorr   ExtensionTyper   convert_to_tensorrA   rB   )rR   rz   s     r&   rN   rN     s     : :<LMOLu%;;EBB%556L$""5))	" $A "#$$s   9B B1B,,B1r!   r3   r4   r7   c                    | j                         D cg c]  }t        |       }}t        |t        j                        r|j
                  gng }|g n|D cg c]  }|j
                   c}}||z   |z   }t        j                  |v rt        j                  S t        j                  |v rt        j                  S t        j                  S c c}w c c}w )a  Return a consistent dtype for fields, nrows, & row_partitions.

  In the future, the default will switch from int64 to int32, but for now,
  we stick with int64.

  Args:
    fields: the fields of the StructuredTensor.
    nrows: the nrows of the StructuredTensor
    row_partitions: the row_partitions of the StructuredTensor.

  Returns:
    If anything requires int64, then return int64.
    If int32 is explicitly specified, return int32. Otherwise, return int64.
  )	rH   _field_shape_dtyper+   r   r.   rV   r   int64int32)	r!   r3   r4   rT   field_dtypesnrows_dtypesrp	rp_dtypes
all_dtypess	            r&   rY   rY     s    " 28AA$Q'A,A",UFMM"B%++,"*b'1bhh1) l*Y6*\\Z<<\\Z<< 
 B1s   C
Cc                    t        j                  |j                  d      }t        |t        j
                        rt        j                  ||      d   }n|j                         }| |} nf|j                  +|j                  |j                  |      st        d      |} n/|r-t        j                  t        j                  | |d      g|       } | |j                  |      fS )a  Merges `nrows` with `nrows(value)`.

  Checks that `value` has the expected number of rows (`nrows`), and returns
  `nrows`.  If `validate` is true, then add validation ops that check that
  the `nrows` values match.

  Args:
    nrows: scalar integer Tensor.
    static_nrows: tf.Dimension: static value of nrows, if known.
    value: Tensor or RaggedTensor or StructuredTensor
    dtype: dtype for `nrows`.
    validate: bool -- whether to add validation ops.

  Returns:
    A tuple `(nrows, static_nrows)`.
  r   out_typezfields have incompatible nrows)message)r   dimension_at_indexr2   r+   r   r.   r   r3   rR   r  rA   r   with_dependenciesr   assert_equalr(  )r3   static_nrowsrR   rV   rP   static_value_nrowsvalue_nrowss          r&   _merge_nrowsrV    s    " $66u{{AFv}}%//%%8;K++-K
]E  ,&00>788E..;(H	J0 E 
(();<	<<r(   c           
         t        |t        j                        rt        |||      }nZt        |t        j
                        rt        |||      }n2t        |t              sJ t        |             |j                  d|dz
   }t        |      |dz
  k(  sJ | t        |      S t        t        | |      D cg c]  \  }}|j                  ||       c}}      S c c}}w )z5Merges `row_partitions` with `row_partitions(value)`.Nr=   )r+   r   r.   _row_partitions_for_tensorr   r   !_row_partitions_for_ragged_tensorr   rC   r4   rE   r/   zip_merge_precomputed_encodings)r4   rR   r@   rV   rP   value_row_partitionsp1p2s           r&   _merge_row_partitionsr_    s    v}}%5eT5I%334<UD%P e-.;U;. //	:	!	"dQh	..	.%&&N,@AR 	''H5   s   7C
c                 H    t        j                  | |      }t        ||      S )z+Returns the row partitions for a tf.Tensor.rM  )r   r2   !_row_partitions_for_uniform_shape)rR   r@   rV   r2   s       r&   rX  rX  "  s    
//%%
0%	*5$	77r(   c                     |dkD  sJ | j                   d|dz
   }t        |      |dz
  k  r&|t        | j                  |t        |      z
  |      z  }t        |      |dz
  k(  sJ |S )z1Returns the row partitions for a tf.RaggedTensor.r=   N)r   rE   rX  flat_values)rR   r@   rV   r\  s       r&   rY  rY  (  s    	/55itax@	$(+64#&:";;UD D	!	"dQh	..	.	r(   c                     t        j                  | d|       }t        t        |dz
        D cg c])  }t	        j
                  | |dz      ||dz      ||         + c}      S c c}w )zReturns row partitions for the given shape Tensor.

  Args:
    shape: A vector describing a uniform shape.
    rank: The number of dimensions to generate row partitions for

  Returns:
    A list of (rank-1) `RowPartition`s with uniform row length.
  Nr=   )uniform_row_lengthnvalsr3   )r   cumprodr/   rc   r   from_uniform_row_length)r2   r@   shape_cumprodrh   s       r&   ra  ra  3  sx     ""5$<0-	 ,1?	 '( **"1q5\a!e$a " 
  s   .A#c           	         | sJ |dk(  rt        t        |             S t        d         t        fdt	        dt                    D              sJ t         D cg c]  }t        | ||dz
         c}S c c}w )aO  Regroup each field (k, v) from dict-of-list to list-of-dict.

  Given a "field-major" encoding of the StructuredTensor (which maps each key to
  a single nested list containing the values for all structs), return a
  corresponding "node-major" encoding, consisting of a nested list of dicts.

  Args:
    keys: The field names (list of string).  Must not be empty.
    values: The field values (list of python values).  Must have the same length
      as `keys`.
    depth: The list depth at which dictionaries should be created.

  Returns:
    A nested list of dict, with depth `depth`.
  r   c              3   @   K   | ]  }t        |         k(    y wr$   )rE   )r   rh   rf  rH   s     r&   r   z3_pyval_field_major_to_node_major.<locals>.<genexpr>[  s     DUc&)n$D   r=   )r,   rZ  rE   r   rc   r   )r   rH   depthvalue_slicerf  s    `  @r&   r   r   G  s      
+
aZD&!""
fQi.%	DeAs6{.CD	DD	D f

 't[%!)D
  
s   #A=c                    | st        |      D cg c]  }i  c}S t        | dd | d   j                         d         }| d   j                         }t        t        |      dz
        D cg c]  }|||   ||dz        c}S c c}w c c}w )a  Returns a python list of empty dicts from the given row partitions.

  Args:
    row_partitions: The row-partitions describing the ragged shape of the
      result.
    nrows: The number of rows in the outermost row-partition.  (Or if
      `len(row_partitions)==0`, then the number of empty dicts to return.)

  Returns:
    A nested python list whose leaves (if any) are empty python dicts.
  r=   Nr   r}   )rc   r   
row_splitsrE   )r4   r3   _rH   splitsrh   s         r&   r   r   b  s     
e%1B%%3qrN1-88:2>@FA))+F5:3v;?5KLF6!9VAE]+LL &
 Ms   	B+Bc                     t        | t              r |j                  | j                                yt        | t        t
        f      r5d}| D ],  }t        ||      }|||dz   }||dz   k7  s#t        d       |S y)a  Finds the keys & depth of nested dictionaries in `pyval`.

  Args:
    pyval: A nested structure of lists, tuples, and dictionaries.
    keys: (output parameter) A set, which will be updated with any keys that are
      found in the nested dictionaries.

  Returns:
    The nesting depth of dictionaries in `pyval`, or `None` if `pyval` does
    not contain any dictionaries.
  Raises:
    ValueError: If dictionaries have inconsistent depth.
  r   Nr=   z"Inconsistent depth of dictionaries)r+   r,   updater   r   r/   r   rA   )r   r   rm  r   child_depths        r&   r   r   w  s     tKK

%$'E A5eTBk		 =/%kAo%?@
@A Lr(   c                 T   t        | t        t        t        f      st	        d      |j                         D ]A  \  }}t        d|      D ]  }|d   }	 |j                  t        | t              r| |   ng        C t        | t        t        f      r| D ]  }t        |||dz           yy)a  Append the field values from `pyval` to `fields`.

  Args:
    pyval: A python `dict`, or nested list/tuple of `dict`, whose value(s)
      should be appended to `fields`.
    fields: A dictionary mapping string keys to field values.  Field values
      extracted from `pyval` are appended to this dictionary's values.
    depth: The depth at which `pyval` should be appended to the field values.
  z*Expected dict or nested list/tuple of dictr=   r}   N)	r+   r,   r   r/   rA   rJ   rc   appendr   )r   r!   rm  rQ   r   rq  r   s          r&   r   r     s     
ED$.	/
A
BB||~ AmsF1e_ bzf
MM
5$ 7%*R@A
 e}% 55&%!)45 &r(   c                     t        | t              r<| sy| D cg c]  }t        |       }}t        d |D              ryt	        |      dz   S yc c}w )zFind the max depth for nested empty lists.

  Args:
    pyval: A nested python list.

  Returns:
    The maximum depth of empty lists in `pyval`, or None if `pyval` contains
    anything other than nested empty lists.
  r=   c              3   $   K   | ]  }|d u  
 y wr$   r>   )r   rm  s     r&   r   z*_pyval_empty_list_depth.<locals>.<genexpr>  s     
-U5D=
-r   N)r+   r   r  anyrF   )r   rT   depthss      r&   r  r    sT     t278Q%a(8F8

-f
--[1_ 9s   Ac                    t        | t        j                        ss| S t        | t        j                        r;t        j                  j                  t        | j                  dd       d         S t        | t              sJ t        fd| j                  j                         D              }t        j                  || j                  | j                         t              t        | j                   t#              d       z         S )a  Updates `value` to use `new_partitions` as its (outer) row partitions.

  This is used to ensure that all fields in a `StructuredTensor` use identical
  `RowPartition` objects for the shared dimensions.  In particular,
  `StructuredTensor.from_fields` first merges all of the row partitions from
  any fields, and then replaces the outer row partitions of all fields with
  the merged row partitions (using this function).

  Args:
    value: A `Tensor`, `RaggedTensor`, or `StructuredTensor`.
    new_partitions: A list of row-partitions that should be used by `value`.
      Must be equivalent to `value`'s current row partitions.

  Returns:
    A value that is equivalent to `value`, where outer row partitions have been
    replaced by `new_partitions`.
  r=   Nr   )rH   r  c              3   @   K   | ]  \  }}|t        |      f  y wr$   )rO   )r   rS   rT   new_partitionss      r&   r   z*_replace_row_partitions.<locals>.<genexpr>  s*      ; 1a 1!^DE ;rl  )r!   r2   r3   r4   )r+   r   r.   r   r   _from_row_partitionrO   rH   r   r,   r   rJ   r6   r2   r3   r/   r4   rE   )rR   r~  rq   s    ` r&   rO   rO     s    $ v}}%^L%334%%99&u||^AB5GH$Q' : ) )
 e-... ;$)MM$7$7$9; ;J%%kkkkm^,e""3~#6#789:	 & ; ;r(   c                 L   j                         du }t        | t        j                        rq|sot	        j
                  j                         j                         gt	        j                  | j                        dd gd      }t	        j                  | |      S t        | t        j                  t        j                  f      r t        j                  j                  |       S t        | t              sJ j                  }j                  }t!        j"                  ||g      j%                  | j                  dd       }t'        fd| j(                  j+                         D              }t        j-                  ||j                         f| j.                  z         S )a  Partitions the outer dimension of `value` using `row_partitions`.

  Examples:

    >>> partition = RowPartition.from_row_lengths([2, 0, 1])
    >>> _partition_outer_dimension(tf.constant([1, 2, 3]), partition)
    <tf.RaggedTensor [[1, 2], [], [3]]>

    >>> struct_value = tf.experimental.StructuredTensor.from_pyval(
    ...     [{'x': 1}, {'x': 2}, {'x': 3}])
    >>> _partition_outer_dimension(struct_value, partition)
    <StructuredTensor(
      fields={
        "x": <tf.RaggedTensor [[1, 2], [], [3]]>},
      shape=(3, None))>

  Args:
    value: Tensor, RaggedTensor, or StructuredTensor
    row_partition: RowPartition

  Returns:
    A value with the same type as `value`, where
    `result.rank = value.rank + 1`.
  NrM  r=   r   )axisc              3   @   K   | ]  \  }}|t        |      f  y wr$   )r  )r   rS   rT   r  s      r&   r   z-_partition_outer_dimension.<locals>.<genexpr>  s*      7q! 0MBC 7rl  )re  r+   r   r.   r   concatr3   r2   rV   reshaper   r   r  r   rS  static_uniform_row_lengthr   r-   concatenater,   r   rJ   r6   r4   )rR   r  r?  	new_shaper3   ncolsr2   r!   s    `      r&   r  r    sy   2 ..0D8)v}}%i  





*
*
,
.	)<)<	=ab	A	C 	I
 UI..%&--)C)CDE%%99}  e-...&&E33E$$e&+&- ..9k%++ab/.J 
 7 % 3 3 57 7F%%}**,	5///1 1r(   c                 d   k  sJ t        | t        j                  t        j                  f      rt        j
                  |       S t        | t              sJ t        fd| j                  j                         D              }| j                  j                        }t        ||      S )zDMerges `outer_axis...inner_axis` of `value` into a single dimension.c              3   B   K   | ]  \  }}|t        |      f  y wr$   )r  )r   rS   rT   r  r  s      r&   r   z_merge_dims.<locals>.<genexpr>!  s+      7q! k!Z<= 7s   )r+   r   r.   r   r   r  r   r,   r   rJ   r    r  )rR   r  r  r!   r"   s    ``  r&   r  r    s    	j	  	 }'A'ABC##E:zBBe-... 7 % 3 3 57 7F&&22J LFL11r(   r   c                     t        | t        j                        r| j                  S t        j
                  j                  j                  |       S r$   )r+   r   r   r    r   r7  
_from_spec)r   s    r&   r&  r&  +  s>    
 &++,2277BB4HHr(   rf   r;  c                     t        | t              r| fS t        | t              rt        |       S t        | t              sJ | S )zEFieldName can be given also as string, this normalizes it to a tuple.)r+   rK   r   r/   )rf   s    r&   ra   ra   6  s<    c7Nd;	D%	  	 	+r(   c                 `    t        | t              ry| D cg c]  }t        |       c}S c c}w )z(Replaces dictionaries zeros in a pylist.r   )r+   r,   r   )r   xs     r&   r   r   @  s(    t&+	,/!
	,,	,s   +c                 t    t        | t              r| j                  ||      S t        j                  | ||      S )a)  Merges outer_axis...inner_axis into a single dimension.

  If outer == inner, this is a NOOP. If inner < outer, then this fials.
  If inner >= source.shape.rank, then the behavior is undefined.

  Args:
    source: a tensor, ragged tensor, or structured tensor.
    outer: a python int, indicating the first dimension to compress (must be
      nonnegative).
    inner: a python int, indicating the first dimension to keep (of the tail)
      (must be nonnegative).

  Returns:
    source with outer_axis...inner_axis merged into a single dimension.

  )r+   r   r  r   )sourceouterinners      r&   r   r   G  s7    " ()UE**##FE599r(   c                 &   t        | t              r| j                  S t        j                  | |      }t        |t
        j                        rt        j                  g |      S t        |t        j                        r|S t        d|  d| d      )zHExtension of DynamicRaggedShape.from_tensor to support StructuredTensor.rM  )r4   r  zExpected shape tf.shape(z<) to return a Tensor or a DynamicRaggedShape. Instead, got: r!  )
r+   r   r    r   shape_v2r   r.   r   r7  rB   )fieldrV   r2   s      r&   !_dynamic_ragged_shape_from_tensorr  ^  s     '(


UU
3%v}}%22u. .%-@@AL,UG 477<gQ@ 	A Ar(   abc                 4    | |S || S | j                  |      S r$   )r(  )r  r  s     r&   _merge_with_optionalr  o  s'     YHYH	
q	r(   r@   rV   c                     d}| j                         D ]$  \  }}	 t        ||      }|d| }t        ||      }& |S # t        $ r}t	        d|       |d}~ww xY w)z.Given fields, rank, and dtype, create a shape.NrV   zError in shape of )rJ   r  r  r   rA   )	r!   r@   rV   r+  rS   r  next_field_shape_rawnext_field_shapeerrs	            r&   r[   r[   z  s    
 +LLN :jq%:>
u-et4(6FGk: 
  :+A3/0c9:s   <	AAAr  c                     t        | t        j                        r| j                  j                  S t        | t
              r| j                  j                  S y r$   )r+   r   r   _row_partitionrV   r   r    )r  s    r&   rD  rD    sD    }112%%%'($$$	r(   c                     t        | t        j                        r| j                  |      S t        | t              r| j                  |      S | S r$   )r+   r   r   with_row_splits_dtyper   r   )r  rV   s     r&   _field_with_shape_dtyper    sD    }112&&u--'(!!%((	,r(   c           	      j    | j                         D ci c]  \  }}|t        ||       c}}S c c}}w r$   )rJ   r  )r!   rV   rS   rT   s       r&   rZ   rZ     s-    =C\\^	L6Aq!$Q.
.	LL	Ls   /c                    t        | t              sJ |        t        |t        j                        sJ |       |1t        |t        j
                        st        |t              sJ |       |t        |t              sJ |       |j                  }|t        d      t        | ||      }t        | |      } d}|j                         r/t        j                  j                  |j!                         |      }|dk(  r4t        j                  j                  t#        j$                  d|            S t'        |t)        | ||            }|dk(  rYt        j*                  |d         }||}|,t'        |t        j                  j                  |g|            }|t-        d      |S |r+t'        |t        j                  j/                  ||            }|t-        d      |S )	z2Produce a DynamicRaggedShape for StructuredTensor.Nr;   r  r   )r   r=   zMMust specify `nrows`, a fully specified `shape`, or have `fields` if `rank=1`zPMust specify row_partitions, a fully specified shape, or have fields if rank > 1)r+   r,   r   r-   r   r.   rX   r/   r@   rB   rY   rZ   is_fully_definedr   r7  _from_inner_shaper   r   zerosr  r[   dimension_valuerA   from_row_partitions)r!   r2   r3   r4   r@   rV   r   	alt_values           r&   r0   r0     s   	FD	!)6)	!	E<33	4;e;	4	*UFMM:jS?  
		:n.3$5 E6DE 
5	$	\
D
EE FE>
:%fe,&&
!44FFu G &F 
QY22DDE*, ,  (:64(OP&	QY,,U1X6Ie#


1
1
C
CgU D $%f ~ 7 8 8 M!//CC% 	D 	)*F
 ^
 2 3 3	-r(   c           
          t        |t              st        d      |j                         D ]  }t        |t              rt        d       |j                         D ]'  }t        |t        j                        rt        d       t        j                  j                  j                  t        j                  |       dt        j                        } | j                   }|t        d      |j#                         D ]k  \  }}t%        |      }|t'        d| d      |j                   }|||k  rt'        d| d	| d
| d      |j)                  |      }| j+                  |      } m t,        j                  | |      S )z/A placeholder for the old StructuredTensorSpec.z!field_specs must be a dictionary.z2field_specs must be a dictionary with string keys.z6field_specs must be a dictionary with TypeSpec values.r   r;   r   r!  r"  r#  r$  r%  )r+   r,   rB   r   rK   rH   r   r9  r   r7  r   _from_tensor_shaper   r?   r   rF  r@   rJ   r&  rA   r'  r(  r   )r2   r   rS   rT   r@   r)  r*  r+  s           r&   StructuredTensorSpecr    s   	K	&
7
88 LaaJKKL  Paa++,NOOP 
1
1
6
6
I
IE"Av||5%	$	\
D
EE!!# 	+fq!B1E&01566.33$)9D)@s$/?.@ A004vQ8 9 9)33D9Kk*E	+ 
		UK		HHr(   r$   )Rr5  retypingr   r   r   r   r   r   r	   r
   r   r   tensorflow.python.frameworkr   r   r   r   r   r   r   tensorflow.python.opsr   r   r   r   tensorflow.python.ops.raggedr   r   r   *tensorflow.python.ops.ragged.row_partitionr   tensorflow.python.utilr   r    tensorflow.python.util.tf_exportr   r.   r   rA  rs   rt   BatchableExtensionTyper   compilerL   rN   rK   r=  rY   rV  r_  rX  rY  ra  r   r   r   r   r  rO   r  r  object_structured_tensor_factory_keyr7  r   r  r  r&  ra   r   r   r  r  rX   r[   rD  r  rZ   r0   r  r>   r(   r&   <module>r     s    	 R R R  3 . 6 + . 4 1 + + 2 * = ; 6 C ) ' 6 
MM  ! [M;./ *+p%~<< p% ,p%l# 56$"C$%.6v}}.EXl349?D"=J,8(6M*>5.,#;L.1b2 "( I
$77<<..0@0E0E!!" #I ,,11	I # -:0 A.AAA"$778$778 "556<<$%9%L%LM$k hv||.D ; #)<<4?MwsK'78 M$llM/6sK7G/HM4pIr(   