
    BVh                         d Z ddl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 Zd Zd Z G d de      Z G d de      Zy)z;Helper library for handling infeed between hosts and TPUs.
    N)xla_sharding)dtypes)ops)tensor_shape)	array_ops)tpu_name_util)tpu_sharding)tpu_ops)nestc           
         |t        j                  |       S t        j                  |      }| g}t        j                  | j                  j                               }t        j                  ||      \  }}t        t        ||||            D ]  \  }\  }}}	}
|	dk  r|dkD  r~|dz   }t        j                  |
|      \  }}|g|z  |gz   }t        |      |	k  r|dg|	t        |      z
  z  z  }g }|D ])  }|j                  t        j                  |||             + |}n.|D cg c]#  }t        j                  |t        |	      |      % }}t        j                  |      } |S c c}w )aO  Partitions or replicates the input tensor.

    The ops inside this function are placed on the host side.

  Args:
    tensor: The input tensor which will be partitioned or replicated.
    dims: A list of integer describes how to partition the input tensor.

  Returns:
    An iterator of `Tensor`s or a list of partitioned tensors.
     r   )num_or_size_splitsaxis)r   )	itertoolsrepeatnparrayshapeas_listdivmod	enumerateziplenappendr   splitintr   flatten)tensordimsoutput
shape_list	quotients
remaindersr   quotient	remainderdimoriginal_size
ceil_rationum_full_slots	left_overr   
new_outputxs                    N/home/dcms/DCMS/lib/python3.12/site-packages/tensorflow/python/tpu/tpu_feed.pypartition_or_replicate_on_hostr.   #   s~    
\F##	$$8&xx,,./*))J5)Z9B	)Zz2:4 "5d5Xy#}
ax1} a<j"$))M:"Fni&<.8I;F		 3	&qcS3/A+B%BCCj F!OO&8tE	FF fAGHA	3s8$7HfH\\&!F1"2 
- Is   %(E(c                 2   |t        j                  | d      S t        j                  |      dk(  rt        j                  | dd      S t        j
                  t        j                  |            j                  |      }t        j                  | |d      S )a;  Tags appropriate XLA sharding attribute to the dequeued tensor.

  The sharding attribute of the dequeued tensor will be a tuple.

  Args:
    tensor: The dequeued tensor on TPU.
    dims: A list of integer describes how the tensor is partitioned.

  Returns:
    The same tensor with the xla_sharding attribute.
  T)assign_tuple_shardingr   r   )r   tile_assignmentr0   )r   	replicater   prodassign_devicearangereshapetile)r   r   r1   s      r-   +_tag_sharding_attribute_for_dequeued_tensorr8   Q   s~     
\!!&EE	wwt}%%fatLLii.66t<O'"$ $    c                 f    t        j                  | |       t        j                  | t        | |      S )a  Tags appropriate XLA sharding attribute to the dequeued tensors.

  Args:
    dequeues: A list of dequeued tensors on TPU.
    dims: A list of integer describes how the tensor is partitioned.

  Returns:
    The same dequeues with appropriate xla_sharding attribute.
  )r   assert_shallow_structuremap_structure_up_tor8   )dequeuesr   s     r-   +tag_sharding_attribute_for_dequeued_tensorsr>   i   s3     $/		!	!;Xt
M Mr9   c                       e Zd ZdZ	 	 	 	 	 	 ddZd Zed        Zed        Zd Z	ed        Z
d	 Zed
        Zed        Zd Zed        Zd Zd Zd Zd ZddZ	 	 ddZ	 	 ddZd Zd Z	 	 	 ddZy)InfeedQueuezA helper object to build a device infeed queue.

  The InfeedQueue builds the host-side and device-side Ops to enqueue and
  dequeue elements, respectively, and ensures that their types and
  shapes match.
  Nc                    d| _         d| _        d| _        |dn|| _        |d| _        n|| _        |5|t        |      }n'|t        |      }n|t        |      }nt        d      |dk  rt        d| d      t        |      D cg c]  }t        j                          c}| _
        || j                  |       nd| _        || j                  |       nd| _        || j                  |       | j!                          yc c}w )	a  Creates a new InfeedQueue with the given configuration.

    The configuration need not be fully specified at creation since it
    can be modified subsequently by methods that set the values
    explicitly or infer them from the shapes of inputs.

    Args:
      number_of_tuple_elements: the number of Tensors fed atomically through the
        queue, must be present unless it can be inferred from other arguments.
      tuple_types: if not None, a list of types of the elements of the queue.
      tuple_shapes: if not None, a list of shapes of the elements of the queue.
      shard_dimensions: if not None, a list of dimensions on which the
        elements of the queue should be sharded during automatic
        parallelization.
      number_of_partitions: if > 1, the infeed dequeue shape will contain
        the full shape that includes all partitions and add corresponding XLA
        annotation on the infeed dequeue op. In this case, the infeed is still
        data parallel that feeds per-core batch size to each core while the XLA
        computation may be partitioned. As XLA requires infeed dequeue shape to
        be per-replica shape, thus we need number_of_partitions here to
        calculate the per-replica unpartitioned shape.
      name: the name of the queue.

    Raises:
      ValueError: if number_of_tuple_elements <= 0; or
        number_of_tuple_arguments, tuple_types, tuple_shapes, and
        shard_dimensions are all None; or the length of tuple_types,
        tuple_shapes, or shard_dimensions is not equal to
        number_of_tuple_elements; or any element of shard_dimensions
        can't be converted to a Dimension.
      TypeError: if any element of tuple_types or tuple_shapes can't
        be converted to a dtype or TensorShape, respectively.
    FNr@   r   zHnumber of tuple elements cannot be inferred from InfeedQueue constructorr   znumber_of_tuple_elements z must be > 0)_frozen_generated_enqueue_ops_generated_dequeue_op_name_number_of_partitionsr   
ValueErrorranger	   ShardingPolicy_sharding_policiesset_tuple_types_tuple_typesset_tuple_shapes_tuple_shapesset_shard_dimensions	_validate)selfnumber_of_tuple_elementstuple_typestuple_shapesshard_dimensionsnumber_of_partitionsname_s           r-   __init__zInfeedQueue.__init__   s=   P DL"'D!&D"&,DDJ##$d #7d '		 #&{#3 ##&|#4 '#&'7#8  	  1$23K2L M% % & & 055M/N*+##%D 
;'d
L)d#
 01NNs   
Dc                     | j                   :t        | j                  | j                        D ]  \  }}|j	                  |      } yy)zChecks that the configuration is self-consistent.

    Raises:
      ValueError: if the shapes and sharding policies don't match.
    N)rT   r   rJ   rN   get_sharded_shape)rQ   policyr   rX   s       r-   rP   zInfeedQueue._validate   sK     $ !8!8$:L:LM ,/65$$U+, %r9   c                 ,    t        | j                        S )z1Returns the number of InfeedQueue tuple elements.)r   rJ   rQ   s    r-   rR   z$InfeedQueue.number_of_tuple_elements   s     t&&''r9   c                     | j                   S )z4Returns the types of the InfeedQueue tuple elements.)rL   r^   s    r-   rS   zInfeedQueue.tuple_types   s     r9   c           	         t        |      | j                  k7  r$t        dt        |       d| j                         | j                  rQt        | j                  |      D ]7  \  }}||k7  st        dt        | j                         dt        |              y	 |D cg c]  }t        j                  |       c}| _        yc c}w # t        $ r)}t        dt        |       dt        |             |d}~ww xY w)a  Sets the type of each element of the queue.

    tuple_types must be a list of length
    self.number_of_tuple_elements, and each element must be
    convertible to a dtype.

    Args:
      tuple_types: the types of each queue element.

    Raises:
      ValueError: if tuple_types is not of length
        self.number_of_tuple_elements.
      TypeError: if an element of tuple_types cannot be converted to a
        dtype.
    ztuple_types is , but must be a list of length zcTrying to update InfeedQueue with frozen configuration with an incompatible type. Frozen types are z, updated types are zF, but must be a list of elements each convertible to dtype: got error N)
r   rR   rG   strrB   r   rL   r   as_dtype	TypeError)rQ   rS   frozenupdatedtes         r-   rK   zInfeedQueue.set_tuple_types   s     ;4888C,- .1124  ||"4#4#4kB 7
67W5589J9J5K4L M##&{#3"467 77N9DEAV__Q/EE Nc+./ 0==@VHFGLM	NNs*   C	 C;C	 C	 		C;$C66C;c                     | j                   S )z5Returns the shapes of the InfeedQueue tuple elements.)rN   r^   s    r-   rT   zInfeedQueue.tuple_shapes  s     r9   c           	      *   t        |      | j                  k7  r$t        dt        |       d| j                         	 |D cg c]  }t	        j
                  |       }}| j                  rQt        | j                  |      D ]7  \  }}||k7  st        dt        | j                         dt        |              n|| _	        | j                          yc c}w # t        t        f$ r)}t        dt        |       dt        |             |d}~ww xY w)a  Sets the shape of each element of the queue.

    tuple_shapes must be a list of length
    self.number_of_tuple_elements, and each element must be
    convertible to a TensorShape.

    Args:
      tuple_shapes: the shapes of each queue element.

    Raises:
      ValueError: if tuple_shapes is not of length
        self.number_of_tuple_elements.
      TypeError: if an element of tuple_shapes cannot be converted to
        a TensorShape.
    ztuple_shapes is ra   zL, but must be a list of elements each convertible to TensorShape: got error NzeTrying to update InfeedQueue with frozen configuration with an incompatible shape. Frozen shapes are z, updated shapes are )r   rR   rG   rb   r   as_shaperd   rB   r   rN   rP   )rQ   rT   r   rh   re   rf   s         r-   rM   zInfeedQueue.set_tuple_shapes  s4     <D999S./ 01124 @LMul++E2MlM ||"4#5#5|D &
67W7T''())>\"#%& && (dNN# N	" S./ 0AVH s)   C CC C D)$DDc                     | j                   S )z@Returns the sharding policies of the InfeedQueue tuple elements.)rJ   r^   s    r-   sharding_policieszInfeedQueue.sharding_policies5  s     """r9   c                 T    | j                   D cg c]  }|j                   c}S c c}w )zGets the shard dimension of each tuple element.

    Returns:
      A list of length number_of_tuple_elements, where each list entry
      is the shard dimension of that tuple element or None if the
      shard dimension has not been set.
    )rJ   shard_dimension)rQ   r\   s     r-   rU   zInfeedQueue.shard_dimensions:  s$     261H1HIvF""IIIs   %c                     t        |      | j                  k7  r$t        dt        |       d| j                         t	        | j
                  |      D ]  \  }}|j                  |        | j                          y)ak  Sets the shard_dimension of each element of the queue.

    shard_dimensions must be a list of length
    self.number_of_tuple_elements, and each element must be
    convertible to a Dimension compatible with self.tuple_shapes.

    Args:
      shard_dimensions: the dimensions of each queue element.

    Raises:
      ValueError: if shard_dimensions is not of length
        self.number_of_tuple_elements; or an element of
        shard_dimensions cannot be converted to a Dimension; or an
        element of shard_dimensions is a Dimension that is out of
        range for the corresponding tuple element shape.
    zshard_dimensions is ra   N)r   rR   rG   rb   r   rJ   set_shard_dimensionrP   )rQ   rU   r\   	dimensions       r-   rO   z InfeedQueue.set_shard_dimensionsF  s    "  = ==-c2B.C-D E..2.K.K-LN O O"4#:#:<LM ,  +,NNr9   c                 4    | j                   d   j                  S )zGets the number of shards to use for the InfeedQueue.

    Returns:
      Number of shards or None if the number of shards has not been set.
    r   )rJ   number_of_shardsr^   s    r-   rt   zInfeedQueue.number_of_shards^  s     ""1%666r9   c                     | j                   D ].  }|j                  |       |j                  | j                         0 | j	                          y)a.  Sets the number of shards to use for the InfeedQueue.

    Args:
      number_of_shards: number of ways to shard the InfeedQueue.

    Raises:
      ValueError: if number_of_shards is not > 0; or the policies have
        been frozen and number_of_shards was already set to something
        else.
    N)rJ   set_number_of_shardsset_number_of_partitionsrF   rP   )rQ   rt   r\   s      r-   rv   z InfeedQueue.set_number_of_shardsh  sJ     )) B!!"23%%d&@&@AB 	NNr9   c                 6   t        |      | j                  k7  r%t        dt        |       d| j                   d      | j	                  |D cg c]  }|j
                   c}       | j                  |D cg c]  }|j                   c}       yc c}w c c}w )a  Sets the shapes and types of the queue tuple elements.

    input_tensors is a list of Tensors whose types and shapes are used
    to set the queue configuration.

    Args:
      input_tensors: list of Tensors of the same types and shapes as
        the desired queue Tuple.

    Raises:
      ValueError: if input_tensors is not a list of length
        self.number_of_tuple_elements
    input_tensors is z, but should be a list of z TensorsN)r   rR   rG   rb   rM   r   rK   dtype)rQ   input_tensorsrg   s      r-   $set_configuration_from_input_tensorsz0InfeedQueue.set_configuration_from_input_tensorsx  s     =T:::*3}+=*> ?$$($A$A#B(L M MM:q177:;=9a!''9: ;9s   B6Bc           	      F   | j                   sd| _        t        |      }| j                  |       |D ]>  }t        |      | j                  k7  st        dt        |       d| j                          t        | j                        D cg c]  }|D cg c]  }||   j                   c}! }}}t        | j                  |      D cg c]  \  }}|j                  |       }}}| j                  |       t        d| j                        D ]M  }t        |d   ||         D ]6  \  }	}
|	j                  |
j                  k7  s t        dt        |       d       O | j!                  |d   D cg c]  }|j                   c}       yc c}w c c}}w c c}}w c c}w )a  Sets the shapes and types of the queue tuple elements.

    input_tensors is a list of lists of Tensors whose types and shapes are used
    to set the queue configuration. The length of the outer list is the number
    of shards required, and each inner list is the tuple of Tensors to use to
    determine the types and shapes of the corresponding shard. This method
    depends on the shard dimension, and calling it freezes the shard policy.

    Args:
      input_tensors: list of lists of Tensors. The outer list length corresponds
        to the desired number of shards, and each inner list is the size
        and shape of the desired configuration of the corresponding shard.

    Raises:
      ValueError: if any inner list is not a list of length
        self.number_of_tuple_elements; or the inner lists do not combine to
        form a consistent unsharded shape.
      TypeError: if the types of the Tensors in the inner lists do not match.
    Nry   zX but must be a list of lists, where each inner list has length number_of_tuple_elements=r   r   z-types of the tuple elements of input_tensors z are not consistent)rB   rN   r   rv   rR   rG   rb   rH   r   r   rJ   get_unsharded_shaperM   rt   rz   rd   rK   )rQ   r{   rt   rg   isharded_shapesr\   sunsharded_shapest1t2s              r-   ,set_configuration_from_sharded_input_tensorsz8InfeedQueue.set_configuration_from_sharded_input_tensors  s   ( <<  d=)./ I	Q400	0M 23 4((,(E(E'FHI 	II  %T%B%BCE !./ tzz / EN E t66GVQ 	""1%  	*+1d++, :-*M!,<= :(2r88rxx=]#$$79: ::: 	=+;<a!''<=/ E =s$   	FF*FF2FFc                     d| _         | j                  t        d      | j                  t        d      | j                  D ]  }|j                  t        d       | j
                  D ]  }|j                           | j                          y)ap  Freezes the InfeedQueue so it can no longer be modified.

    The configuration is implicitly frozen before any host-side or
    device-side Ops are generated. The configuration cannot be frozen
    until the types and shapes of the tuple elements have been set.

    Raises:
      ValueError: if the types or shapes of the tuple elements have not been
      set.
    TNz<Can't freeze an InfeedQueue without setting all tuple types.z=Can't freeze an InfeedQueue without setting all tuple shapes.)rB   rL   rG   rN   r   rJ   freezerP   )rQ   r   r\   s      r-   r   zInfeedQueue.freeze  s     DL 
HJ J!
IK K## M		KM 	MM )) mmoNNr9   c           	      X   | j                          | j                  rt        j                         st	        d      d| _        d| j
                  z  }t        | j                  | j                        D cg c]%  \  }}|j                  |j                  |            ' }}}|Tt        j                  t        j                  |            5  t        j                  | j                   ||      }ddd       n"t        j                  | j                   ||      }| j"                  dk  rS t        | j                  | j                        D cg c]2  \  }}|j                  dg|j$                  z        j'                         4 }}}t)        |      S c c}}w # 1 sw Y   xY wc c}}w )ab  Generates the device-side Op to dequeue a tuple from the queue.

    Implicitly freezes the queue configuration if it is not already
    frozen, which will raise errors if the shapes and types have not
    been fully specified.

    Args:
      tpu_device: The TPU device ordinal where the infeed instruction should be
        placed. If None, no explicit placement will be performed, and it is up
        to the user to call this API from within a proper TPU device scope.
        The XLA code will fail if the TPU dequeue instruction is not bound to
        any device.

    Returns:
      A list of Outputs corresponding to a shard of infeed dequeued
      into XLA, suitable for use within a replicated block.

    Raises:
      ValueError: if the types or shapes of the tuple elements have not been
      set; or if a dequeue op has already been generated.
    2Can't generate two dequeue Ops from the same queueT
%s/dequeueNr   shapesrW   r   )r   rD   r   inside_functionrG   rE   r   rN   rJ   get_unpartitioned_shaper[   devicer   corer
   infeed_dequeue_tuplerL   rF   ndimsr   r>   )rQ   
tpu_device	full_namer   r\   r   
dequeue_op
partitionss           r-   generate_dequeue_opzInfeedQueue.generate_dequeue_op  s   , 	KKM!!#*=*=*?KLL!%Dtzz)I  #4#5#5t7N7NOUF 	&&v'?'?'FGN  ::m((45 M11$$^)M
M M //"">	Kj!!Q&  #4#5#5t7N7NOUF 	&&sU[['89AACJ  7z:NN#
M Ms   5*F#F7F&F#c           	      $   d||fz  }|D cg c]  }|j                    }}||D cg c]  }|j                   }	}t        d| j                        D ](  }
|	d   |	|
   k7  st	        d| dt        |	       d       t        j                  |d         5  t        j                  ||||      cddd       S t        j                  |      5  t        j                  ||||      cddd       S c c}w c c}w # 1 sw Y   yxY w# 1 sw Y   yxY w)	a  Generate a host-side Op to enqueue a tuple to the queue.

    If device is None the inputs are all required to have the same
    device specification, and the enqueue Op is colocated with
    inputs[0]. Otherwise the enqueue Op is placed on 'device'.

    Args:
      inputs: a list of Tensors with the types and shapes of the tuple elements.
      name_prefix: the base name for the Op.
      index: the shard index, used to uniquify the Op name.
      device: device to place the Op on, or None if it should be
        colocated with the inputs.
      tpu_ordinal: ordinal of the TPU device on the host to use for
      infeed if device is a CPU device. Should be set to -1 if device
      is a TPU device.

    Returns:
      An Op corresponding to a shard of infeed enqueued at the host,
      suitable for use within a replicated block.

    Raises:
      ValueError: if device is None and inputs do not all have the
        same device specification.
    %s/%dNr   r   zinput devices for shard z are z, but should all be the sameinputsr   rW   device_ordinal)
r   r   rH   rR   rG   rb   r   colocate_withr
   infeed_enqueue_tuple)rQ   r   name_prefixindexr   tpu_ordinalr   rg   r   devicesr   s              r-   _generate_enqueue_opz InfeedQueue._generate_enqueue_op  s-   < ;..I%&!agg&F&~#)*a*g*Q556 !!1:#(uS\N C   ! !!
 VAY' (++&	(( ( ::f (++&	(( ( '*( (( (s"   C0C5C:D:DDc                    | j                  |       | j                          | j                  rt        j                         st        d      d| _        |d }d| j                  z  }t        |t        | j                              D cg c]+  \  }}| j                  ||| ||      |r ||      nd      - c}}S c c}}w )a  Generates the host-side Ops to enqueue the shards of a tuple.

    sharded_inputs is a list, one for each shard, of lists of
    Tensors. sharded_inputs[i] is the tuple of Tensors to use to feed
    shard i of the queue. Returns the host-side Ops that must be run to
    enqueue the sharded tuple. The Op for shard i is colocated with the inputs
    for shard i.

    Implicitly freezes the queue configuration if it is not already
    frozen. If the configuration has already been frozen, and is not
    compatible with the types and shapes of sharded_inputs, an error
    will be raised.

    Args:
      sharded_inputs: a list of lists of Tensors. The length of the outer list
        determines the number of shards. Each inner list indicates the types
        and shapes of the tuples in the corresponding shard.
      tpu_ordinal_function: if not None, a function that takes the
        shard index as input and returns the ordinal of the TPU device
        the shard's infeed should be placed on. tpu_ordinal_function must be
        set if the inputs are placed on CPU devices.
      placement_function: if not None, a function that takes the shard index as
        input and returns the host device where the enqueue op should be placed
        on.

    Returns:
      A list of host-side Ops, one for each shard, that when executed together
      will enqueue a full-size element of infeed.

    Raises:
      ValueError: if the queue configuration has previously been frozen and the
        shapes of the elements of sharded_inputs are not compatible with the
        frozen configuration; or if the shapes of the elements of sharded_inputs
        don't form a consistent unsharded tuple; or if the elements of a tuple
        have different device constraints.
      TypeError: if the queue configuration has previously been frozen and the
        types of the elements of sharded_inputs are not compatible with the
        frozen configuration; or if the types of the elements of sharded_inputs
        don't form a consistent unsharded tuple.
    2Can't generate two enqueue Ops from the same queueTNc                      yN )r   s    r-   <lambda>z2InfeedQueue.generate_enqueue_ops.<locals>.<lambda>n  s    r9   
%s/enqueue)r   r   )r   r   rC   r   r   rG   rE   r   rH   rt   r   )rQ   sharded_inputstpu_ordinal_functionplacement_functionr   shardr   s          r-   generate_enqueue_opsz InfeedQueue.generate_enqueue_ops<  s    X 	55nEKKM""3+>+>+@KLL"&D#-+K ".%8M8M2NO UE 	!!,U30B%e, 	" 	N  s   
0B>c                     d|dz  z  S )Nz/task:%d/device:CPU:0   r   rQ   r   s     r-   _default_placement_functionz'InfeedQueue._default_placement_function}  s    "eai00r9   c                     |dz  S )Nr   r   r   s     r-   _default_ordinal_functionz%InfeedQueue._default_ordinal_function  s    19r9   c                    || j                   }|| j                  }nfd}fd}||}||}| j                  |       | j                          | j                  rt        j                         st        d      d| _        d| j                  z  }| j                  dk(  r|D cg c]  }|g }	}ned }
t        || j                  t        | j                              D cg c]+  \  }}} |
|| j                  |j                  d||fz  	      - }	}}}t        | j                        D cg c]  }|	D cg c]  }||   	 c} }}}d
| j                  z  }t        |t        | j                              D cg c]'  \  }}| j                  ||| ||       ||            ) c}}S c c}w c c}}}w c c}w c c}}w c c}}w )a|	  POORLY-PERFORMING ON MULTI-HOST SYSTEMS.

    Generates the host-side Ops to enqueue a tuple.

    This method performs poorly because it takes an entire input on a single
    host, splits it, and distributes it to all of the cores. It is present only
    to simplify tutorial examples.

    inputs is a list of Tensors to use to feed the queue. Each input is split
    into self.number_of_shards shards. Returns an Op for each shard to enqueue
    the shard. The Op for shard i is placed on device placement_function(i).

    Implicitly freezes the queue configuration if it is not already
    frozen. If the configuration has already been frozen, and is not
    compatible with the types and shapes of inputs, an error
    will be raised.

    Args:
      inputs: a list of Tensors which indicates the types and shapes of the
        queue tuple.
     device_assignment: if not `None`, a TPU `DeviceAssignment`. If
        device_assignment is not `None`, but `placement_function` and
        `ordinal_function` are None, then `device_assignment` will be used to
        place infeeds on the first k TPU shards, where k is the number of shards
        in the queue. If all three are `None`, then default placement and
        ordinal functions are used.
      placement_function: if not None, a function that takes the shard
        index as input and returns a device string indicating which
        device the shard's infeed should be placed on. If placement_function
        and tpu_ordinal_function are None, inputs are sharded round-robin
        across the devices in the system.
      tpu_ordinal_function: if not None, a function that takes the
        shard index as input and returns the ordinal of the TPU device
        the shard's infeed should be placed on. If placement_function
        and tpu_ordinal_function are None, inputs are sharded round-robin
        across the devices in the system.

    Returns:
      A list of host-side Ops, one for each shard, that when executed together
      will enqueue a full-size element of infeed.

    Raises:
      ValueError: if the queue configuration has previously been frozen and the
        shapes of the elements of inputs are not compatible with the frozen
        configuration.
      TypeError: if the queue configuration has previously been frozen and the
        types of the elements of inputs are not compatible with the frozen
        configuration.
    c                 (    j                  |       S N)replica)host_devicer   device_assignments    r-   _placement_function_from_mapzWInfeedQueue.split_inputs_and_generate_enqueue_ops.<locals>._placement_function_from_map       ,,U,;;r9   c                 (    j                  |       S r   )r   r   s    r-   _ordinal_function_from_mapzUInfeedQueue.split_inputs_and_generate_enqueue_ops.<locals>._ordinal_function_from_map  r   r9   r   Tz%s/splitr   c                     t        j                  |       5  t        j                  | |||      cd d d        S # 1 sw Y   y xY w)Nr   rW   )r   r   r   r   )inp
num_shardsr   rW   s       r-   split_fnzCInfeedQueue.split_inputs_and_generate_enqueue_ops.<locals>.split_fn  s;    s# 	Hjt$G	H 	H 	Hs	   9Ar   r   r   )r   r   )r   r   r|   r   rC   r   r   rG   rE   rt   r   rJ   rH   rR   ro   r   )rQ   r   r   r   r   r   r   split_name_prefixr   transposed_sharded_inputsr   r\   r   r   r   r   r   s     `              r-   %split_inputs_and_generate_enqueue_opsz1InfeedQueue.split_inputs_and_generate_enqueue_ops  s   l  		#!==		%#==<< 
	#9		%9--f5KKM""3+>+>+@KLL"&D"TZZ/!4:";SC5";";H '*&$2I2I*/0M0M*N'P# # #sFE ##))/77	9# #  %T%:%:;= %>?  Qx ? =N = +K ".%8M8M2NO UE 	!!%e,,U3 	" 	5 ) #<#? =s*   (
F0&0F52	G;F<G ,G<G)NNNNNNr   r   )NN)NNN)__name__
__module____qualname____doc__rY   rP   propertyrR   rS   rK   rT   rM   rm   rU   rO   rt   rv   r|   r   r   r   r   r   r   r   r   r   r9   r-   r@   r@   x   s    )-  $$(L\	, ( (  "NH  'R # # 	J 	J0 7 7 ;(1>f4,Od #'')3(n 15.2<B1 ?C?CAE	jr9   r@   c                   F     e Zd ZdZ	 	 	 	 d fd	ZddZd Zd Zd Z xZ	S )	_PartitionedInfeedQueuea  A helper object to build a device infeed queue with input partition.

  Args:
    number_of_tuple_elements: the number of Tensors fed atomically through the
      queue, must be present unless it can be inferred from other arguments.
    device_assignment: A TPU `DeviceAssignment` which is used to place all the
      partitions to different TPU infeed queues.
    host_id: The id of the host machine.
    input_partition_dims: A nested list/tuple of integers. Each inner
      list/tuple describes how to partition the corresponding input tensor.
    tuple_types: If not None, a list of types of the elements of the queue.
    tuple_shapes: If not None, a list of shapes of the elements of the queue.
    name: The name of the queue.
  c                 h    t         t        |   ||d d |dn|       || _        || _        || _        y )NPartitionedInfeedQueue)rR   rS   rT   rU   rW   )superr   rY   _input_partition_dims_host_id_device_assignment)	rQ   rR   r   host_idinput_partition_dimsrS   rT   rW   	__class__s	           r-   rY   z _PartitionedInfeedQueue.__init__  sJ     

!41!9)-%4 2 A "6DDM/Dr9   c                    | j                          | j                  rt        j                         st	        d      d| _        d| j
                  z  }t        | j                  | j                        D cg c]  \  }}|j                  |       }}}t        j                  t        j                  |            5  t        j                  | j                  ||      }ddd       t!        | j"                        S c c}}w # 1 sw Y   %xY w)a  Generate TPU dequeue ops.

    Args:
      tpu_device: The TPU device ordinal where the infeed instruction should be
        placed.

    Returns:
      A list of Outputs corresponding to a partition of infeed dequeued
      into XLA, suitable for use within a replicated block.

    Raises:
      ValueError: if the types or shapes of the tuple elements have not been
      set; or if a dequeue op has already been generated.
    r   Tr   r   N)r   rD   r   r   rG   rE   r   rN   rJ   r[   r   r   r   r
   r   rL   r>   r   )rQ   r   r   r   r\   r   valuess          r-   r   z+_PartitionedInfeedQueue.generate_dequeue_op  s     	KKM!!#*=*=*?KLL!%Dtzz)I  #4#5#5t7N7NOUF 	  'N  
M&&z2	3 K++"">	KfK 7**, ,K Ks   5C<;#DDc                    | j                  |       t        |      }t        |d         }t        | j                        |k(  sJ g }t        |      D ]  }||   }t	        j
                  || j                        }t        ||   |      D 	cg c]   \  }}	t        | j                  ||	            " }
}}	| j                  j                  | j                  d      |   }t        | j                  j                        D ]  }| j                  j                  ||      }t        j                  |      5  | j                  j!                  ||      }g }|
D ]"  }t#        |d      }||j%                  |       $ |rP|j%                  t'        j(                  ||D cg c]  }|j*                   c}dj-                  ||      |             ddd         |S c c}	}w c c}w # 1 sw Y   xY w)a  Generates the host-side Ops to enqueue the partitioned inputs.

    sharded_inputs is a list, one for each replica, of lists of
    Tensors. sharded_inputs[i] is the tuple of Tensors to use to feed
    replica i.
    sharded_inputs[i][j] is partitioned by self._input_partition_dims[j].

    For example, if sharded_inputs[i][j] is a 2-D Tensor:
    [[A, B, C, D],
     [E ,F, G, H]]
    self._input_partition_dims[j] is [2, 4].

    sharded_inputs[i][j] will be partitioned and flattened into:
    [A, B, C, D, E, F, G, H] and fed into the logical core ids:
    [0, 1, 2, 3, 4, 5, 6, 7] respectively.

    Args:
      sharded_inputs: a list of lists of Tensors. The length of the
        outer list determines the number of shards. Each inner list indicates
        the types and shapes of the tuples in the corresponding shard.

    Returns:
      A list of host-side Ops, one for each shard, that when executed together
      will enqueue a full-size element of infeed.

    Raises:
      ValueError: if the queue configuration has previously been frozen and the
        shapes of the elements of sharded_inputs are not compatible with the
        frozen configuration; or if the shapes of the elements of sharded_inputs
        don't form a consistent unsharded tuple; or if the elements of a tuple
        have different device constraints; or if the partition dims are invalid.
      TypeError: if the queue configuration has previously been frozen and the
        types of the elements of sharded_inputs are not compatible with the
        frozen configuration; or if the types of the elements of sharded_inputs
        don't form a consistent unsharded tuple.
    r   )task_idlogical_core)r   r   Nzenqueue/replica_{0}/input_{1}r   )r   r   r   rH   r   flatten_up_tor   iter._check_dims_and_partition_or_replicate_on_hostr   lookup_replicasr   num_cores_per_replicar   r   r   r   nextr   r
   r   r   format)rQ   r   number_of_replicasrR   enqueue_opsreplica_indexflattened_inputsinputs_part_dims_flatr,   r   inputs_parted_iters
replica_idr   r   ordinalinfeed_inputsitinput_for_devices                     r-   r   z,_PartitionedInfeedQueue.generate_enqueue_ops2  s   J 	55nE^,">!#45t))*.FFFFK12 (-'6"001A151K1KM ^M:24a tBB1dK
L  **::--a ; 11>@j 7 7 M MN -, ((44\ 5 ; ZZ 	-++77 | 8 ='-' 5b#B~+""#345
 ,,(-:;AGG;8??%|5#*,-	- 	--#(-R KB <	- 	-s*   %G33G&'4G&G!.G&!G&&G/c                 *   |yt        j                  |      }|dk  j                         rt        d      |j	                         dk(  ry|j	                         | j
                  j                  k7  r/t        dj                  || j
                  j                              |j                  d   |j                  j                  k7  r3t        dj                  |j                  j                         |            |j                  j                          y)ap  Checks that input partition dims are valid for the `Tensor`.

    Args:
      tensor: Input tensor for partitioning.
      dims: A list of integer describes how to partition the input tensor.

    Raises:
      ValueError: If the tensor can't be partitioned by dims or the
        num_cores_per_replica doesn't match the number of
        partitions(dims.prod()).
    Nr   z&All input partition dims must be >= 1.zuThe product of each input partition dim should equal to num_cores_per_replica. (dim = {}, num_cores_per_replica = {})r   zInput partition dims must have the same number of dimensions as the `Tensor` to be partitioned. (tensor shape = {}, input partition dims = {}).)r   r   anyrG   r3   r   r   r   r   r   r   assert_is_fully_definedrQ   r   r   s      r-   _check_input_partition_dimsz3_PartitionedInfeedQueue._check_input_partition_dims  s     |88D>Dq~~?@@ yy{ayy{d--CCC&t66LLMO O zz!}***""(&)=)=)?"FH H
 LL((*r9   c                 >    | j                  ||       t        ||      S )am  Checks dims and partitions or replicates the input tensor.

      The ops inside this function are placed on the host side.

    Args:
      tensor: The input tensor which will be partitioned or replicated.
      dims: A list of integer describes how to partition the input tensor.

    Returns:
      An iterator of `Tensor`s or a list of partitioned tensors.
    )r   r.   r   s      r-   r   zF_PartitionedInfeedQueue._check_dims_and_partition_or_replicate_on_host  s!     	$$VT2)&$77r9   )NNNNr   )
r   r   r   r   rY   r   r   r   r   __classcell__)r   s   @r-   r   r     s2    & %) 0$,<Un$+L8r9   r   )r   r   numpyr   +tensorflow.python.compiler.xla.experimentalr   tensorflow.python.frameworkr   r   r   tensorflow.python.opsr   tensorflow.python.tpur   r	   tensorflow.python.tpu.opsr
   tensorflow.python.utilr   r.   r8   r>   objectr@   r   r   r9   r-   <module>r     s[       D . + 4 + / . - '+\$0Mw	& w	tJ8k J8r9   