
    AVhql                     f   d 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dg       ej@                  ddd      	 	 	 	 	 	 	 d)d              Z!d Z"d Z#d Z$d Z%d  Z&d! Z'd" Z( edg        ejR                  dd#dd$       ej@                  ddd      	 	 	 	 	 	 	 d)d%                     Z* ejV                  d&d'e!j                         e*_         d(e*j                   v sJ y)*zFunctional operations.    N)ag_ctx)api)context)composite_tensor)constant_op)ops)tensor_shape)tensor_spec)	type_spec)	array_ops)tensor_array_ops)variable_scope)
while_loop)
tf_logging)deprecation)nest)variable_utils)	tf_exportmap_fn)v1zUse fn_output_signature insteaddtypeTFc	                 b	   "#$%& |t               st        d j                   d      t        j                          }	|	r|sd}n5|	s|sd}n.|	s,|dkD  r't        j                  t
        j                  dd       d}t        j                        t        j                        }
t        |
      dk(  rt        dj                              |
D cg c]  }t        j                   |       c}#fd	$*|
D cg c]  }t#        |      j%                          c}&$}n1t        j                        D cg c]  }t'        |       c}&fd
}t)        j*                  |d|
      5  |	r6t-        j.                         }d}|j0                  |j3                  d        d}|
D cg c]  }t)        j4                  |d       }
}|
d   }t7        |d      r2|j8                  }|j:                  |j:                  dk  rt        d      t=        |
      }t?        j@                  t?        jB                  |d   jE                         jG                  d      d               }|dd D ]Y  }|jI                  t?        j@                  t?        jB                  |jE                         jG                  d      d                      [ |jJ                  xs tM        j8                  |d         d   %|D cg c]%  }tO        jP                  |jR                  %dd      ' c}"tU        "|      D cg c]  \  }}|jW                  |       c}}"tY        jZ                  d      }t]        &      }g }|D ]?  }|j_                  tO        jP                  |jR                  %d||j8                               A "#$ &fd}ta        j`                  %fd|||f|||%      \  }}|D cg c]  }|jc                          }}|D ]F  }|je                  t?        jf                  |      ji                  |jE                         dd              H |	rrj3                  d       tk        |&|      }  ||       }!|!cddd       S c c}w c c}w c c}w c c}w c c}w c c}}w c c}w # 1 sw Y   yxY w)a3-  Transforms `elems` by applying `fn` to each element unstacked on axis 0.

  See also `tf.scan`.

  `map_fn` unstacks `elems` on axis 0 to obtain a sequence of elements;
  calls `fn` to transform each element; and then stacks the transformed
  values back together.

  #### Mapping functions with single-Tensor inputs and outputs

  If `elems` is a single tensor and `fn`'s signature is `tf.Tensor->tf.Tensor`,
  then `map_fn(fn, elems)` is equivalent to
  `tf.stack([fn(elem) for elem in tf.unstack(elems)])`.  E.g.:

  >>> tf.map_fn(fn=lambda t: tf.range(t, t + 3), elems=tf.constant([3, 5, 2]))
  <tf.Tensor: shape=(3, 3), dtype=int32, numpy=
    array([[3, 4, 5],
           [5, 6, 7],
           [2, 3, 4]], dtype=int32)>

  `map_fn(fn, elems).shape = [elems.shape[0]] + fn(elems[0]).shape`.

  #### Mapping functions with multi-arity inputs and outputs

  `map_fn` also supports functions with multi-arity inputs and outputs:

  * If `elems` is a tuple (or nested structure) of tensors, then those tensors
    must all have the same outer-dimension size (`num_elems`); and `fn` is
    used to transform each tuple (or structure) of corresponding slices from
    `elems`.  E.g., if `elems` is a tuple `(t1, t2, t3)`, then `fn` is used to
    transform each tuple of slices `(t1[i], t2[i], t3[i])`
    (where `0 <= i < num_elems`).

  * If `fn` returns a tuple (or nested structure) of tensors, then the
    result is formed by stacking corresponding elements from those structures.

  #### Specifying `fn`'s output signature

  If `fn`'s input and output signatures are different, then the output
  signature must be specified using `fn_output_signature`.  (The input and
  output signatures are differ if their structures, dtypes, or tensor types do
  not match).  E.g.:

  >>> tf.map_fn(fn=tf.strings.length,  # input & output have different dtypes
  ...           elems=tf.constant(["hello", "moon"]),
  ...           fn_output_signature=tf.int32)
  <tf.Tensor: shape=(2,), dtype=int32, numpy=array([5, 4], dtype=int32)>
  >>> tf.map_fn(fn=tf.strings.join,  # input & output have different structures
  ...           elems=[tf.constant(['The', 'A']), tf.constant(['Dog', 'Cat'])],
  ...           fn_output_signature=tf.string)
  <tf.Tensor: shape=(2,), dtype=string,
   numpy=array([b'TheDog', b'ACat'], dtype=object)>

  `fn_output_signature` can be specified using any of the following:

  * A `tf.DType` or `tf.TensorSpec` (to describe a `tf.Tensor`)
  * A `tf.RaggedTensorSpec` (to describe a `tf.RaggedTensor`)
  * A `tf.SparseTensorSpec` (to describe a `tf.sparse.SparseTensor`)
  * A (possibly nested) tuple, list, or dict containing the above types.

  #### RaggedTensors

  `map_fn` supports `tf.RaggedTensor` inputs and outputs.  In particular:

  * If `elems` is a `RaggedTensor`, then `fn` will be called with each
    row of that ragged tensor.
    * If `elems` has only one ragged dimension, then the values passed to
      `fn` will be `tf.Tensor`s.
    * If `elems` has multiple ragged dimensions, then the values passed to
      `fn` will be `tf.RaggedTensor`s with one fewer ragged dimension.

  * If the result of `map_fn` should be a `RaggedTensor`, then use a
    `tf.RaggedTensorSpec` to specify `fn_output_signature`.
    * If `fn` returns `tf.Tensor`s with varying sizes, then use a
      `tf.RaggedTensorSpec` with `ragged_rank=0` to combine them into a
      single ragged tensor (which will have ragged_rank=1).
    * If `fn` returns `tf.RaggedTensor`s, then use a `tf.RaggedTensorSpec`
      with the same `ragged_rank`.

  >>> # Example: RaggedTensor input
  >>> rt = tf.ragged.constant([[1, 2, 3], [], [4, 5], [6]])
  >>> tf.map_fn(tf.reduce_sum, rt, fn_output_signature=tf.int32)
  <tf.Tensor: shape=(4,), dtype=int32, numpy=array([6, 0, 9, 6], dtype=int32)>

  >>> # Example: RaggedTensor output
  >>> elems = tf.constant([3, 5, 0, 2])
  >>> tf.map_fn(tf.range, elems,
  ...           fn_output_signature=tf.RaggedTensorSpec(shape=[None],
  ...                                                   dtype=tf.int32))
  <tf.RaggedTensor [[0, 1, 2], [0, 1, 2, 3, 4], [], [0, 1]]>

  Note: `map_fn` should only be used if you need to map a function over the
  *rows* of a `RaggedTensor`.  If you wish to map a function over the
  individual values, then you should use:

  * `tf.ragged.map_flat_values(fn, rt)`
    (if fn is expressible as TensorFlow ops)
  * `rt.with_flat_values(map_fn(fn, rt.flat_values))`
    (otherwise)

  E.g.:

  >>> rt = tf.ragged.constant([[1, 2, 3], [], [4, 5], [6]])
  >>> tf.ragged.map_flat_values(lambda x: x + 2, rt)
  <tf.RaggedTensor [[3, 4, 5], [], [6, 7], [8]]>

  #### SparseTensors

  `map_fn` supports `tf.sparse.SparseTensor` inputs and outputs.  In particular:

  * If `elems` is a `SparseTensor`, then `fn` will be called with each row
    of that sparse tensor. In particular, the value passed to `fn` will be a
    `tf.sparse.SparseTensor` with one fewer dimension than `elems`.

  * If the result of `map_fn` should be a `SparseTensor`, then use a
    `tf.SparseTensorSpec` to specify `fn_output_signature`.  The individual
    `SparseTensor`s returned by `fn` will be stacked into a single
    `SparseTensor` with one more dimension.

  >>> # Example: SparseTensor input
  >>> st = tf.sparse.SparseTensor([[0, 0], [2, 0], [2, 1]], [2, 3, 4], [4, 4])
  >>> tf.map_fn(tf.sparse.reduce_sum, st, fn_output_signature=tf.int32)
  <tf.Tensor: shape=(4,), dtype=int32, numpy=array([2, 0, 7, 0], dtype=int32)>

  >>> # Example: SparseTensor output
  >>> tf.sparse.to_dense(
  ...     tf.map_fn(tf.sparse.eye, tf.constant([2, 3]),
  ...               fn_output_signature=tf.SparseTensorSpec(None, tf.float32)))
  <tf.Tensor: shape=(2, 3, 3), dtype=float32, numpy=
    array([[[1., 0., 0.],
            [0., 1., 0.],
            [0., 0., 0.]],
           [[1., 0., 0.],
            [0., 1., 0.],
            [0., 0., 1.]]], dtype=float32)>

  Note: `map_fn` should only be used if you need to map a function over the
  *rows* of a `SparseTensor`.  If you wish to map a function over the nonzero
  values, then you should use:

  * If the function is expressible as TensorFlow ops, use:
    ```python
    tf.sparse.SparseTensor(st.indices, fn(st.values), st.dense_shape)
    ```
  * Otherwise, use:
    ```python
    tf.sparse.SparseTensor(st.indices, tf.map_fn(fn, st.values),
                           st.dense_shape)
    ```

  #### `map_fn` vs. vectorized operations

  `map_fn` will apply the operations used by `fn` to each element of `elems`,
  resulting in `O(elems.shape[0])` total operations.  This is somewhat
  mitigated by the fact that `map_fn` can process elements in parallel.
  However, a transform expressed using `map_fn` is still typically less
  efficient than an equivalent transform expressed using vectorized operations.

  `map_fn` should typically only be used if one of the following is true:

  * It is difficult or expensive to express the desired transform with
    vectorized operations.
  * `fn` creates large intermediate values, so an equivalent vectorized
    transform would take too much memory.
  * Processing elements in parallel is more efficient than an equivalent
    vectorized transform.
  * Efficiency of the transform is not critical, and using `map_fn` is
    more readable.

  E.g., the example given above that maps `fn=lambda t: tf.range(t, t + 3)`
  across `elems` could be rewritten more efficiently using vectorized ops:

  >>> elems = tf.constant([3, 5, 2])
  >>> tf.range(3) + tf.expand_dims(elems, 1)
  <tf.Tensor: shape=(3, 3), dtype=int32, numpy=
    array([[3, 4, 5],
           [5, 6, 7],
           [2, 3, 4]], dtype=int32)>

  In some cases, `tf.vectorized_map` can be used to automatically convert a
  function to a vectorized equivalent.

  #### Eager execution

  When executing eagerly, `map_fn` does not execute in parallel even if
  `parallel_iterations` is set to a value > 1. You can still get the
  performance benefits of running a function in parallel by using the
  `tf.function` decorator:

  >>> fn=lambda t: tf.range(t, t + 3)
  >>> @tf.function
  ... def func(elems):
  ...   return tf.map_fn(fn, elems, parallel_iterations=3)
  >>> func(tf.constant([3, 5, 2]))
  <tf.Tensor: shape=(3, 3), dtype=int32, numpy=
    array([[3, 4, 5],
           [5, 6, 7],
           [2, 3, 4]], dtype=int32)>


  Note: if you use the `tf.function` decorator, any non-TensorFlow Python
  code that you may have written in your function won't get executed. See
  `tf.function` for more  details. The recommendation would be to debug without
  `tf.function` but switch to it to get performance benefits of running `map_fn`
  in parallel.

  Args:
    fn: The callable to be performed.  It accepts one argument, which will have
      the same (possibly nested) structure as `elems`.  Its output must have the
      same structure as `fn_output_signature` if one is provided; otherwise it
      must have the same structure as `elems`.
    elems: A tensor or (possibly nested) sequence of tensors, each of which will
      be unstacked along their first dimension.  `fn` will be applied to the
      nested sequence of the resulting slices.  `elems` may include ragged and
      sparse tensors. `elems` must consist of at least one tensor.
    dtype: Deprecated: Equivalent to `fn_output_signature`.
    parallel_iterations: (optional) The number of iterations allowed to run in
      parallel. When graph building, the default value is 10. While executing
      eagerly, the default value is set to 1.
    back_prop: (optional) False disables support for back propagation.
    swap_memory: (optional) True enables GPU-CPU memory swapping.
    infer_shape: (optional) False disables tests for consistent output shapes.
    name: (optional) Name prefix for the returned tensors.
    fn_output_signature: The output signature of `fn`. Must be specified if
      `fn`'s input and output signatures are different (i.e., if their
      structures, dtypes, or tensor types do not match).
      `fn_output_signature` can be specified using any of the following:

      * A `tf.DType` or `tf.TensorSpec` (to describe a `tf.Tensor`)
      * A `tf.RaggedTensorSpec` (to describe a `tf.RaggedTensor`)
      * A `tf.SparseTensorSpec` (to describe a `tf.sparse.SparseTensor`)
      * A (possibly nested) tuple, list, or dict containing the above types.

  Returns:
    A tensor or (possibly nested) sequence of tensors.  Each tensor stacks the
    results of applying `fn` to tensors unstacked from `elems` along the first
    dimension, from first to last.  The result may include ragged and sparse
    tensors.

  Raises:
    TypeError: if `fn` is not callable or the structure of the output of
      `fn` and `fn_output_signature` do not match.
    ValueError: if the lengths of the output of `fn` and `fn_output_signature`
      do not match, or if the `elems` does not contain any tensor.

  Examples:

    >>> elems = np.array([1, 2, 3, 4, 5, 6])
    >>> tf.map_fn(lambda x: x * x, elems)
    <tf.Tensor: shape=(6,), dtype=int64, numpy=array([ 1,  4,  9, 16, 25, 36])>

    >>> elems = (np.array([1, 2, 3]), np.array([-1, 1, -1]))
    >>> tf.map_fn(lambda x: x[0] * x[1], elems, fn_output_signature=tf.int64)
    <tf.Tensor: shape=(3,), dtype=int64, numpy=array([-1,  2, -3])>

    >>> elems = np.array([1, 2, 3])
    >>> tf.map_fn(lambda x: (x, -x), elems,
    ...          fn_output_signature=(tf.int64, tf.int64))
    (<tf.Tensor: shape=(3,), dtype=int64, numpy=array([1, 2, 3])>,
     <tf.Tensor: shape=(3,), dtype=int64, numpy=array([-1, -2, -3])>)
  NzThe provided function z% is not callable.fn must be callable.
      zSetting parallel_iterations > 1 has no effect when executing eagerly. Consider calling map_fn with tf.function to execute fn in parallel.r   zlelems must be a Tensor or (possibly nested) sequence of Tensors. Got {}, which does not contain any Tensors.c                 0    t        j                  |       S Nr   pack_sequence_as)xelemss    L/home/dcms/DCMS/lib/python3.12/site-packages/tensorflow/python/ops/map_fn.py<lambda>zmap_fn.<locals>.<lambda>  s    d33E1=     c                 0    t        j                  |       S r   r   )r   fn_output_signatures    r!   r"   zmap_fn.<locals>.<lambda>  s    !6!67JA!N r#   mapFc                     | j                   S r   )device)ops    r!   r"   zmap_fn.<locals>.<lambda>  s
    ryy r#   Telem)nameshapez=Elements in elems must be 1+ dimensional Tensors, not scalars)r   sizedynamic_sizeinfer_shape)r   r-   r.   r/   element_shapec                    D cg c]  }|j                  |        }}t        |      } |      }t        j                         }t	        j
                  |      } ||      }t        j                  xs |       t        j                  |      }	t        |	      }
t        ||
      D cg c]  \  }}|j                  | |       }}}| dz   |fS c c}w c c}}w )a{  The loop body of map_fn.

      Args:
        i: the loop counter
        tas: the flat TensorArray accumulator list

      Returns:
        (i + 1, tas): the updated counter + updated TensorArrays

      Raises:
        TypeError: if fn_output_signature and result_value structure don't match
        ValueType: if fn_output_signature and result_value lengths don't match
      r   )read_elems_value_batchable_to_flatautograph_ctxcontrol_status_ctx	autograph
tf_convertr   assert_same_structureflatten_result_value_flat_to_batchablezipwrite)itastaelems_value_batchableelems_value_flatelems_valuer   autographed_fnresult_valueresult_value_flatresult_value_batchablevaluer    elems_batchable_taelems_flat_signatureelems_unflattenfnr%   result_flat_signatures               r!   computezmap_fn.<locals>.compute  s     5GGbrwwqzGG78M8LN#$45k//1f ++B7n#K0l
  !4!=|L,,|4>
2 4 14C9O0P!,"e"((1e
c  !eS\ Hs   C0Cc                     | k  S r    )r=   _ns     r!   r"   zmap_fn.<locals>.<lambda>  s    QU r#   )parallel_iterations	back_propswap_memorymaximum_iterations)6callable	TypeError__name__r   executing_eagerlylogginglog_first_nWARNr   convert_variables_to_tensorsr   r9   len
ValueErrorformatr   type_spec_from_value_most_general_type_spec_unbatch_dtype_to_specr   
name_scopevsget_variable_scopecaching_deviceset_caching_deviceconvert_to_tensor_or_compositehasattrr,   ndims_elems_flat_to_batchabler	   	Dimensiondimension_value	get_shapewith_rank_at_leastassert_is_compatible_withrG   r   r   TensorArrayr   r;   unstackr   constant/_result_flat_signature_to_batchable_tensor_specappendr   stack	set_shapeTensorShapeconcatenate_result_batchable_to_flat)'rK   r    r   rR   rS   rT   r/   r+   r%   in_graph_mode
elems_flateresult_unflattendvarscope varscope_caching_device_was_nonet
first_elemelems_static_shapeelems_batchablen_statictensorr?   r=   result_batchable_tensor_specresult_batchable_taspecrM   rP   r_arresult_batchableresult_flatresultrH   rI   rJ   rQ   rL   s'   ``      `                         @@@@@r!   r   r   )   s   n	  	"
,R[[M :+ + , , //11-.!4014  	
  
5
5e
<%||E"* 	_
	66<fUmE E FPP)88;P=/  
  	 "++- ' $(<<0C#Dq O
~~dE:. v  &&(h).&		 	 	( 	##$89+/( EO?@**16:J 
 AJz7#%++		!	!	-2D2J2JQ2NKM 	M /z:O %%$$A((*==a@C	EFH "!"% A((

 
 **""$77:1=?@AA
 	@)///!*<=a@A !  	$$''4	I &));_%M!2q

1 	QA
 	88MN !, B  

&
&JJQU%TZZABB < ""!()/FAs ,//a	//  kk,**84@@
++-
  9!!$'+,<,A,46K k*Fmv v% Q&8l 0Mv vsW   R R?R0=R%-RD)R%4*RR%0RBR%(R ?A8R%R%%R.c                 f    t        | t        j                        st        j                  d |       } | S r   )
isinstancer   TypeSpecr
   
TensorSpec)r   s    r!   rd   rd     s)    	Ay))	*tQ'A	
(r#   c                 p   t        | t        j                        r'	 | j                  t	        j
                  d            }|S t        j                  |       }t        |t        j                        r t        j                  d|j                        }|S # t        $ r t        j                  |       }Y |S w xY w)z+Returns the most general TypeSpec for elem.N)r   r   CompositeTensor_shape_invariant_to_type_specr	   rz   NotImplementedErrorr   ra   r
   r   r   )r*   r   s     r!   rb   rb     s    &6672//0H0H0NOd 
+ ))$/D$../##D$**5d	+  2++D1d
 
+2s   $B B54B5c                     g }| D ]F  }t        |t        j                        st        d|d      |j	                  |j
                         H |S )z@Converts result_flat_signature -> result_batchable_tensor_specs.zmap_fn can not generate z outputs)r   r   BatchableTypeSpecrW   extend_flat_tensor_specs)rL   tensor_specsr   s      r!   rv   rv     sP    ,# 1ddI778dDEE//01 
r#   c                     g }| D ]b  }t        j                  |      }t        |t         j                        st	        d|d|      |j                  |j                  |             d |S )z'Converts elems_flat -> elems_batchable.zmap_fn can not consume z inputs: got )r   ra   r   r   rW   r   _to_batched_tensor_list)r~   r   elems_tensorr   s       r!   rm   rm   )  sr    /  Gl)),7DdI778\+ , , 477EFG 
r#   c                     g }d}|D ][  }|j                         }| ||t        |j                        z    }|j                  |j	                  |             |t        |      z  }] |t        |       k(  sJ |S )z3Converts elems_value_batchable -> elems_value_flat.r   )rc   r^   r   rw   _from_compatible_tensor_list)r@   rI   rA   r=   r   tensor_lists         r!   r3   r3   6  s    !" d==?D'!c$2I2I.J*JKKD==kJK[	A 
c'(	((	(	r#   c           
      <   g }t        | |      D ]  \  }}t        |t        j                        r|j	                  |       2|j                  |      s(t        d|dt        j                  |      d|d      |j                  |j                  |              |S )z5Converts result_value_flat -> result_value_batchable.z2Error in map_fn:
  Expected `fn` to return a:
    z
  But it returned a:
    z
    (value=zO)
  To fix, update the `fn_output_signature` (or `dtype`) argument to `map_fn`.)r;   r   r
   r   rw   is_compatible_withr_   r   ra   r   _to_tensor_list)rE   rL   rF   r_valuer_specs        r!   r:   r:   D  s    02GH Ew&+001##G,&&w/
 Y33G<g	GH 	H ##F$:$:7$CDE 
 r#   c           	          g }d}|D ]Q  }t        |j                        }|j                  |j                  |      j	                  | |||z                 ||z  }S |t        |       k(  sJ |S )z)Converts result_batchable -> result_flat.r   )r^   r   rw   _batchr   )r   rL   
batch_sizer   r=   r   num_tensorss          r!   r|   r|   V  s     +!# dd--.KJ<<Qq;/	12 A 
c"#	##	#	r#   zback_prop=False is deprecated. Consider using tf.stop_gradient instead.
Instead of:
results = tf.map_fn(fn, elems, back_prop=False)
Use:
results = tf.nest.map_structure(tf.stop_gradient, tf.map_fn(fn, elems)))	warn_oncerS   c	           
      0    ||}t        | |||||||      S )zGTransform `elems` by applying `fn` to each element unstacked on axis 0.)rK   r    r%   rR   rS   rT   r/   r+   )r   )	rK   r    r   rR   rS   rT   r/   r+   r%   s	            r!   	map_fn_v2r   f  s5    *  		--
 r#   z (  back_prop: \(optional\) )(.*)z:\1Deprecated: prefer using `tf.stop_gradient` instead.  \2z'prefer using `tf.stop_gradient` instead)NNTFTNN),__doc__re tensorflow.python.autograph.corer   r4    tensorflow.python.autograph.implr   r6   tensorflow.python.eagerr   tensorflow.python.frameworkr   r   r   r	   r
   r   tensorflow.python.opsr   r   r   rf   r   tensorflow.python.platformr   rZ   tensorflow.python.utilr   r   r    tensorflow.python.util.tf_exportr   deprecated_argsr   rd   rb   rv   rm   r3   r:   r|   deprecated_arg_valuesr   subrO   r#   r!   <module>r      se     
 D = + 8 3 + 4 3 1 + 2 6 , < . ' 1 6 xjT#DgN ##] O ]@
 $  8"""K
  T#DgN "&"& O 0 BFF'A
NN	  1I4E4EE EEr#   