
    BVh%P                        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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 i Zd Zeed<   d Z e ed<    ejB                         Z"i Z#d Z$d Z% ejL                         Z' ejP                  e%dde'      Z) ejP                  e%dde'      Z*dZ+	 d#dZ, ejZ                  e,        edg         G d! d"             Z.y)$z5Utilities for forward-mode automatic differentiation.    N)function_cache)
pywrap_tfe)backprop)backprop_util)execute)forwardprop_util)tracing_compilation)ops)tensor_shape)	array_ops)control_flow_ops)UnconnectedGradients)
tf_logging)nest)	tf_exportc                 X    ~ ~~|D cg c]  }t        j                  |       c}S c c}w Nr   identity
attr_tupleinputsoutputstangentsts        S/home/dcms/DCMS/lib/python3.12/site-packages/tensorflow/python/eager/forwardprop.py_identity_jvpr   *   s*     &')1	2A)

Q
	22	2   'Identityc                 X    ~ ~~|D cg c]  }t        j                  |       c}S c c}w r   r   r   s        r   _read_variable_jvpr!   5   s*     &')1	2A)

Q
	22	2r   ReadVariableOpc           	         t         5  t        j                  | d      dz   t        | <   ddd       t        j                  | d      }| |||||      S |sg S t	        j
                         5  g }g }g }t        |      D ]Q  \  }	}
t        j                  |
      s|j                  |
       |j                  |	       |j                  ||	          S t        j                         5 }t        j                         5 }|j                  |       t        j                  | |||       ddd       g }g }g }t        |      D ]c  \  }}t        j                  |      s|j                  t        j                   |d             |j                  |       |j                  |       e |j                  |       j#                  |||t$        j&                        }ddd       j#                  |      }dgt)        |      z  }t+        |      D ]
  \  }}|||<    |cddd       S # 1 sw Y    xY w# 1 sw Y   xY w# 1 sw Y   jxY w# 1 sw Y   yxY w)a  Computes a Jacobian-vector product for an op.

  Note that this function would be wasteful if executed eagerly. It runs the
  backward gradient function and throws away the result just to record its
  operations on a GradientTape. These unused ops are pruned away when this
  function is traced.

  Args:
    op_name: A string, the type of operation being executed.
    attr_tuple: Attributes of the operation.
    inputs: A flat list of input Tensors to the operation.
    outputs: A flat list of output Tensors from the operation.
    tangents: A flat list of Tensors, same shape as `inputs`.

  Returns:
    A flat list of tangents corresponding to `outputs`.
  r      Nunused_forwardprop_aid)name)unconnected_gradients)output_gradients)_TRACE_COUNT_CONSISTENCY_LOCK_TRACE_COUNTget_SPECIAL_CASESr   push_forwardprop_state	enumerater   IsTrainableappendr   GradientTapewatchr   record_gradientr   	ones_likegradientr   ZEROlenzip)op_namer   r   r   r   special_casetrainable_inputstrainable_indicesnontrivial_tangentsinput_indextensortranspose_tapebackfunc_tapeforwardprop_aidstrainable_outputsnontrivial_output_indicesoutput_indexoutputgradsnontrivial_output_tangentsoutput_tangentsindextangents                          r   _jvp_helperrL   E   s{   $ % = ),,Wa81<L=
  ##GT2,
FGX>>	I ..0 %(0 :V		"	"6	*'  -""8K#89	: 
			  ;N  " Fm,-WEF "$"+G"4 9
,$$V,

!
!!!&/GHJ

"
"6
*
#
*
*<
89 +,$$


 4 9 9	 % ;e!;* "0!8!82E "9 "Gfs7|+O78: 'w&oe' K% %= =2F F; ;% %sV   !H&+-IAI%I :*H3$4I A>I AI&H03H=8I  I		IIc           	      h   |rt        ||      D ]b  \  }}|j                  j                  dg|j                  z         r0t        dj	                  |dg|j                  z   |j                               t        j                  t        j                  t        | |||      |      S t        | ||||      S )a  Computes a batch of Jacobian-vector product for an op.

  Args:
    op_name: A string, the type of operation being executed.
    attr_tuple: Attributes of the operation.
    inputs: A flat list of input Tensors to the operation.
    outputs: A flat list of output Tensors from the operation.
    tangents: A flat list of Tensors, compatible with shape `[None] +
      input_shape`.
    use_batch: A bool, True to vetorize over batch of tangents of shape `[None]
      + input_shape`.

  Returns:
    A flat list of tangents compatible with `outputs`
    or `[None] + output_shape`.

  Raises:
    ValueError: if tangent shapes are not compatible with input shapes.
  NzDTangent {} was expected to be of shape {} but is instead of shape {})
r8   shapeis_compatible_with
ValueErrorformatr   vectorized_map	functoolspartialrL   )r9   r   r   r   r   	use_batchprimalrK   s           r   _jvp_helper_wrapperrW      s    * vx0 M]]--tfv||.CD 99?$tfv||&;W]]:LM 	MM **+w
FGL  
Wj&'8	DD    _jvp_relaxed_shapesT)r&   reduce_retracingr   _jvp_exact_shapesF    c                     t         j                  | d      t        k  rt        }nt        }t        j                  | |||||f|      S )z-Determine which forwardprop function to call.r   )tracing_options)r*   r+   _TRACE_COUNT_LIMIT_jvp_exact_config_jvp_relaxed_configr	   call_function)r9   r   r   r   r   rU   configs          r   _jvp_dispatchrd      sJ     gq!$66F F		*	*
FGXyA
 rX   zautodiff.ForwardAccumulator)v1c                   n     e Zd ZdZd Zd Zd Zd Zd Zd Z	e
j                  fdZe fd	       Z xZS )
ForwardAccumulatora  Computes Jacobian-vector products ("JVP"s) using forward-mode autodiff.

  Compare to `tf.GradientTape` which computes vector-Jacobian products ("VJP"s)
  using reverse-mode autodiff (backprop). Reverse mode is more attractive when
  computing gradients of a scalar-valued function with respect to many inputs
  (e.g. a neural network with many parameters and a scalar loss). Forward mode
  works best on functions with many outputs and few inputs. Since it does not
  hold on to intermediate activations, it is much more memory efficient than
  backprop where it is applicable.

  Consider a simple linear regression:

  >>> x = tf.constant([[2.0, 3.0], [1.0, 4.0]])
  >>> targets = tf.constant([[1.], [-1.]])
  >>> dense = tf.keras.layers.Dense(1)
  >>> dense.build([None, 2])
  >>> with tf.autodiff.ForwardAccumulator(
  ...    primals=dense.kernel,
  ...    tangents=tf.constant([[1.], [0.]])) as acc:
  ...   loss = tf.reduce_sum((dense(x) - targets) ** 2.)
  >>> acc.jvp(loss)
  <tf.Tensor: shape=(), dtype=float32, numpy=...>

  The example has two variables containing parameters, `dense.kernel` (2
  parameters) and `dense.bias` (1 parameter). Considering the training data `x`
  as a constant, this means the Jacobian matrix for the function mapping from
  parameters to loss has one row and three columns.

  With forwardprop, we specify a length-three vector in advance which multiplies
  the Jacobian. The `primals` constructor argument is the parameter (a
  `tf.Tensor` or `tf.Variable`) we're specifying a vector for, and the
  `tangents` argument is the "vector" in Jacobian-vector product. If our goal is
  to compute the entire Jacobian matrix, forwardprop computes one column at a
  time while backprop computes one row at a time. Since the Jacobian in the
  linear regression example has only one row, backprop requires fewer
  invocations:

  >>> x = tf.constant([[2.0, 3.0], [1.0, 4.0]])
  >>> targets = tf.constant([[1.], [-1.]])
  >>> dense = tf.keras.layers.Dense(1)
  >>> dense.build([None, 2])
  >>> loss_fn = lambda: tf.reduce_sum((dense(x) - targets) ** 2.)
  >>> kernel_fprop = []
  >>> with tf.autodiff.ForwardAccumulator(
  ...     dense.kernel, tf.constant([[1.], [0.]])) as acc:
  ...   kernel_fprop.append(acc.jvp(loss_fn()))
  >>> with tf.autodiff.ForwardAccumulator(
  ...     dense.kernel, tf.constant([[0.], [1.]])) as acc:
  ...   kernel_fprop.append(acc.jvp(loss_fn()))
  >>> with tf.autodiff.ForwardAccumulator(dense.bias, tf.constant([1.])) as acc:
  ...   bias_fprop = acc.jvp(loss_fn())
  >>> with tf.GradientTape() as tape:
  ...   loss = loss_fn()
  >>> kernel_grad, bias_grad = tape.gradient(loss, (dense.kernel, dense.bias))
  >>> np.testing.assert_allclose(
  ...     kernel_grad, tf.stack(kernel_fprop)[:, tf.newaxis])
  >>> np.testing.assert_allclose(bias_grad, bias_fprop[tf.newaxis])

  Implicit in the `tape.gradient` call is a length-one vector which
  left-multiplies the Jacobian, a vector-Jacobian product.

  `ForwardAccumulator` maintains JVPs corresponding primal tensors it is
  watching, derived from the original `primals` specified in the constructor. As
  soon as a primal tensor is deleted, `ForwardAccumulator` deletes the
  corresponding JVP.

  `acc.jvp(x)` retrieves `acc`'s JVP corresponding to the primal tensor `x`. It
  does not perform any computation. `acc.jvp` calls can be repeated as long as
  `acc` is accessible, whether the context manager is active or not. New JVPs
  are only computed while the context manager is active.

  Note that `ForwardAccumulator`s are always applied in the order their context
  managers were entered, so inner accumulators will not see JVP computation from
  outer accumulators. Take higher-order JVPs from outer accumulators:

  >>> primal = tf.constant(1.1)
  >>> with tf.autodiff.ForwardAccumulator(primal, tf.constant(1.)) as outer:
  ...   with tf.autodiff.ForwardAccumulator(primal, tf.constant(1.)) as inner:
  ...     primal_out = primal ** tf.constant(3.5)
  >>> inner_jvp = inner.jvp(primal_out)
  >>> inner_jvp  # 3.5 * 1.1 ** 2.5
  <tf.Tensor: shape=(), dtype=float32, numpy=4.4417057>
  >>> outer.jvp(inner_jvp)  # 3.5 * 2.5 * 1.1 ** 1.5
  <tf.Tensor: shape=(), dtype=float32, numpy=10.094786>

  Reversing the collection in the last line to instead retrieve
  `inner.jvp(outer.jvp(primal_out))` will not work.

  Strict nesting also applies to combinations of `ForwardAccumulator` and
  `tf.GradientTape`. More deeply nested `GradientTape` objects will ignore the
  products of outer `ForwardAccumulator` objects. This allows (for example)
  memory-efficient forward-over-backward computation of Hessian-vector products,
  where the inner `GradientTape` would otherwise hold on to all intermediate
  JVPs:

  >>> v = tf.Variable([1., 2.])
  >>> with tf.autodiff.ForwardAccumulator(
  ...     v,
  ...     # The "vector" in Hessian-vector product.
  ...     tf.constant([1., 0.])) as acc:
  ...   with tf.GradientTape() as tape:
  ...     y = tf.reduce_sum(v ** 3.)
  ...   backward = tape.gradient(y, v)
  >>> backward  # gradient from backprop
  <tf.Tensor: shape=(2,), dtype=float32, numpy=array([ 3., 12.], dtype=float32)>
  >>> acc.jvp(backward)  # forward-over-backward Hessian-vector product
  <tf.Tensor: shape=(2,), dtype=float32, numpy=array([6., 0.], dtype=float32)>
  c                    t        j                  d      | _        d| _        t	               }t        j                  |      D ]4  }t        |      |v rt        d      |j                  t        |             6 | j                  ||       y)a  Specify tensors to watch and their Jacobian-vector products.

    Mathematically, `tangents` is a vector right-multiplying the Jacobian matrix
    (a Jacobian-vector product) for the function computed while this accumulator
    is active. Since JVPs are computed in forward mode as the computation
    happens, this vector must be supplied in advance.

    Listing a single tensor multiple times in `primals` raises an
    exception. Excluding a tensor from `primals` is equivalent to watching it
    with a tangent tensor of zeros.

    Args:
      primals: A tensor or nested structure of tensors to watch.
      tangents: A tensor or nested structure of tensors, with the same nesting
        structure as `primals`, with each element being a vector with the same
        size as the corresponding primal element.

    Raises:
      ValueError: If the same tensor or variable is specified multiple times in
        `primals`.
    FTensor {} was specified as a primal multiple times. This may indicate an error. If it was intended, please sum the corresponding tangents.N)r   TFE_Py_ForwardAccumulatorNew_accumulator
_recordingsetr   flattenidrP   add_watch)selfprimalsr   
primal_idsrV   s        r   __init__zForwardAccumulator.__init__T  s}    , #??FDDOJ,,w' !	Fz	!&' 	' nnRZ ! 	KK"rX   c                 &    | j                          | S r   )_push_accumulatorrr   s    r   	__enter__zForwardAccumulator.__enter__v  s    KrX   c                 >    | j                   r| j                          y y r   )rl   _pop_accumulator)rr   typvalue	tracebacks       r   __exit__zForwardAccumulator.__exit__z  s    
 rX   c                 ~    | j                   rt        d      t        j                  | j                         d| _         y )Nz!Accumulator is already recording.T)rl   rP   r   TFE_Py_ForwardAccumulatorSetAddrk   rx   s    r   rw   z$ForwardAccumulator._push_accumulator~  s0    :;;..t/@/@ADOrX   c                 ~    | j                   st        d      t        j                  | j                         d| _         y )NzAccumulator is not recording.F)rl   rP   r   "TFE_Py_ForwardAccumulatorSetRemoverk   rx   s    r   r{   z#ForwardAccumulator._pop_accumulator  s0    ??67711$2C2CDDOrX   c                 >      fd}t        j                  |||       y)aa  Ensures that `primals` are being traced by this accumulator.

    Mathematically, `tangents` is a vector right-multiplying the Jacobian matrix
    (a Jacobian-vector product) for the function computed while this accumulator
    is active. Since JVPs are computed in forward mode as the computation
    happens, this vector must be supplied in advance.

    Watching a single tensor multiple times sums each of its `tangents`. Any
    un-watched tensor has zeros for its tangent vector.

    Args:
      primals: A Tensor or list of Tensors.
      tangents: A Tensor or list of Tensors matching `primals`.
    c                 l   | j                   j                  s0t        j                  t        j                  dd| j                          t        j                  || j                         }t        | d      rt        j                  | j                        } t        j                  j                  | |       y )NzJThe dtype of the watched primal must be floating (e.g. tf.float32), got %r   )dtypehandle)r   is_floatinglogginglog_first_nWARNr
   convert_to_tensorhasattrr   r   TFE_Py_ForwardAccumulatorWatchrk   )rV   rK   rr   s     r   rq   z)ForwardAccumulator._watch.<locals>._watch  s    \\%%LL 123V\\	C %%gV\\Bg		" &&v}}5//0A0A6079rX   N)r   map_structure)rr   rs   r   rq   s   `   r   rq   zForwardAccumulator._watch  s     9 	vw1rX   c                      t               j                  t        d       fd}t        j                  ||      S )a   Fetches the Jacobian-vector product computed for `primals`.

    Note that this method performs no computation, and simply looks up a JVP
    that was already computed (unlike backprop using a `tf.GradientTape`, where
    the computation happens on the call to `tape.gradient`).

    Args:
      primals: A watched Tensor or structure of Tensors to fetch the JVPs for.
      unconnected_gradients: A value which can either hold 'none' or 'zero' and
        alters the value which will be returned if no JVP was computed for
        `primals`. The possible values and effects are detailed in
        'tf.UnconnectedGradients' and it defaults to 'none'.

    Returns:
      Tensors with the same shapes and dtypes as `primals`, or None if no JVP
      is available.
    z,Called jvp() without first tracing anything.c                     t        | d      r t        j                  | j                        }n| }t	        j
                  j                  |      }|(t        j                  k(  rt        j                  |       }|S )Nr   )r   r
   r   r   r   TFE_Py_ForwardAccumulatorJVPrk   r   r6   r   
zeros_like)r?   unwrapped_tensorresultrr   r'   s      r   
_fetch_jvpz*ForwardAccumulator.jvp.<locals>._fetch_jvp  sm    		"00?!66t7H7H7GIf	15I5N5NN%%f-mrX   )r   rk   rP   r   r   )rr   rs   r'   r   s   ` ` r   jvpzForwardAccumulator.jvp  sC    $ 11FG EFF	 j'22rX   c                    t         t        |   | ||      }d|_        t	        j
                  d      |_        t               }t        t        j                  |      t        j                  |            D ]s  \  }}|j                  j                  t        j                  dg      |j                  z          t        |      |v rt!        d      |j#                  t        |             u |j%                  ||       |S )a  Factory constructor to test accumulator on batches of tangents.

    Args:
      primals: A tensor or nested structure of tensors to watch.
      tangents: A tensor or nested structure of tensors, with the same nesting
        structure as `primals`, with each element being a vector with compatible
        shape `[None] + primal.shape` of the corresponding primal element.

    Returns:
      A batch accumulator object.
    FTNri   )superrg   __new__rl   r   rj   rk   rm   r8   r   rn   rN   assert_is_compatible_withr   TensorShapero   rP   rp   rq   )clsrs   r   accrt   rV   rK   	__class__s          r   _batch_accumulatorz%ForwardAccumulator._batch_accumulator  s     "C
0gx
HCCN!>>tDCJt||G4dll86LM !mm--

"
"D6
*V\\
9;	Fz	!&' 	' nnRZ ! JJw!JrX   )__name__
__module____qualname____doc__ru   ry   r   rw   r{   rq   r   NONEr   classmethodr   __classcell__)r   s   @r   rg   rg      sO    kZ #D2> 0D/H/H !3F  rX   rg   )F)/r   rS   	threading%tensorflow.core.function.polymorphismr   tensorflow.pythonr   tensorflow.python.eagerr   r   r   r   ,tensorflow.python.eager.polymorphic_functionr	   tensorflow.python.frameworkr
   r   tensorflow.python.opsr   "tensorflow.python.ops.parallel_forr   +tensorflow.python.ops.unconnected_gradientsr   tensorflow.python.platformr   r   tensorflow.python.utilr    tensorflow.python.util.tf_exportr   r,   r   r!   Lockr)   r*   rL   rW   FunctionCache_jvp_function_cacheTracingOptionsra   r`   r_   rd   TFE_Py_RegisterJVPFunctionrg    rX   r   <module>r      s*   <   @ ( , 1 + 4 L + 4 + ? L < ' 6
 3 +z 3 $6   !/	 0  EP E\ 3n224 8)88	&	  7'66	&	    "& &
 % %m 4 (R0A A 1ArX   