o
    i e1                     @   s   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 Zdd Zdd Zdd Zdd Zdd Zdd Zdd Zedg dd"ddZd d! ZdS )#z|Gradient checker for functions.

The gradient checker verifies numerically that an function properly
computes the gradients
    N)backprop)context)dtypes)indexed_slices)ops)tensor)	array_ops)
tf_logging)	tf_exportc                 C   s(   t | tr| S d}| D ]}||9 }q|S )N   )
isinstanceint)tyx r   X/var/www/myenv/lib/python3.10/site-packages/tensorflow/python/ops/gradient_checker_v2.py_product!   s   

r   c                 C   sB   t | tjrt rtjdd | jD dd | jD | jdS | S )aY  Converts IndexedSlices to IndexedSlicesValue with numpy indices/values.

  When eager execution is enabled, converts IndexedSlices
  to IndexedSlicesValue with numpy indices/values.

  Args:
    a: any value.

  Returns:
    If a is IndexedSlices and eager execution is enabled, calls numpy() on a's
    fields. Otherwise returns a unchanged.
  c                 S      g | ]}|  qS r   numpy.0r   r   r   r   
<listcomp>;       z(_eval_indexed_slices.<locals>.<listcomp>c                 S   r   r   r   r   r   r   r   r   <   r   )indicesvaluesdense_shape)	r   r   IndexedSlicesr   executing_eagerlyIndexedSlicesValuer   r   r   )ar   r   r   _eval_indexed_slices+   s   r"   c                 C   s   t | tjr
|  S t | tjrt }|| S t | tj	ret
| j}t| jt| jks:J d| j| j| f t| j| jD ]!\}}d|  krQt|k sZn J d|| f ||  |7  < qA|S | S )a@  Converts Tensors, EagerTensors, and IndexedSlicesValue to numpy arrays.

  Args:
    a: any value.

  Returns:
    If a is EagerTensor or Tensor, returns the evaluation of a by calling
    numpy() or run(). If a is IndexedSlicesValue, constructs the corresponding
    dense numpy array. Otherwise returns a unchanged.
  z8IndexedSlicesValue has %s value slices but %s indices
%sr   z*IndexedSlicesValue has invalid index %s
%s)r   r   EagerTensorr   r   Tensorget_default_sessionrunr   r    npzerosr   lenr   r   zip)r!   sessarrvalues_sliceindexr   r   r   	_to_numpyA   s&   

r/   c                    sP   t  r fdd}|S dd t||D   t fdd}|S )a,  Return a function that executes 'f'.

    In TF 2.x, this is the same as `f`.
    In TF 1.x, returns a Python function that executes the graph defined by `f`
    in a Session.

  Args:
    f: the function.
    xs_dtypes: dtypes of f's arguments.
    xs_shapes: shapes of f's arguments.

  Returns:
  c                     s    t tj|  S N)mapr   convert_to_tensorxs_data)fr   r   decorated_eagern   s   z!_prepare.<locals>.decorated_eagerc                 S   s   g | ]\}}t j||d qS )shape)r   placeholder)r   x_dtypex_shaper   r   r   r   r   s    z_prepare.<locals>.<listcomp>c                     s&   dd | D }  j tt| dS )Nc                 S   s   g | ]}t |qS r   )r/   )r   r!   r   r   r   r   z   r   z5_prepare.<locals>.decorated_graph.<locals>.<listcomp>)	feed_dict)r&   dictr*   r3   )r+   xsr   r   r   decorated_graphy   s   z!_prepare.<locals>.decorated_graph)r   r   r*   r   r%   )r5   	xs_dtypes	xs_shapesr6   r?   r   )r5   r+   r>   r   r   _prepare^   s   rB   c                    s  || }|j jrt|jd n|j}|jrdnd}t|}t|dd }	t|| }
tj|
|f|j jjd}tj||jd}|	 
|jj}t| |g t fdd|gdd	 |D  dgd
d	 |D  }t|
D ]T}d||< t||g|R  d }t|}t|tjrt|j|jD ]\}}||	 }||	 }||||f  |j7  < qn|dur|	 
|j ||ddf< d||< qm|
dkrt||g|R  d }|j|jkrtd|j|jf t|rtdtdd| |S )aY  Computes the theoretical Jacobian for f regarding xs[param].

  One can think of the relation among f, xs and y as y = f(xs).

  Args:
    f: the function.
    y_shape: the shape of the result.
    y_dtype: the dtype of the result.
    xs: a list of tensors.
    param: the index of the target parameter.

  Returns:
    A 2-d numpy array representing the Jacobian. It has "y_size" rows
    and "x_size" columns where "x_size" is the number of elements in xs[param]
    and "y_size" is the number of elements in the result.

  Raises:
    ValueError: If result is empty but the gradient is nonzero.
  )   rC   r   Ndtypec                    s    |d| iS )Ndyr   )rF   r>   grad_fn_unprepr   r   <lambda>   s    z/_compute_theoretical_jacobian.<locals>.<lambda>c                 S      g | ]}|j qS r   rD   r   zr   r   r   r          z1_compute_theoretical_jacobian.<locals>.<listcomp>c                 S   rJ   r   r7   rK   r   r   r   r      rM   r   z3Empty gradient has wrong shape: expected %s, got %sz#Empty tensor with nonzero gradientszTheoretical Jacobian =
%s)rE   
is_complextupler8   r   r'   r(   
real_dtypeas_numpy_dtyperavelviewr   gradients_functionrB   ranger/   r"   r   r   r    r*   r   r   flat
ValueErroranyloggingvlog)r5   y_shapey_dtyper>   paramr   r;   y_factorx_size
x_val_sizey_sizejacobiandy_datady_data_flatgrad_fnrowgradivc_beginc_endr   rG   r   _compute_theoretical_jacobian   sJ   


rl   c                 C   sz  || j }|| j}t||jrdnd }||jrdnd }|jj}|jj}dd |D }	dd |D }
dd |D }|| }tjd| |dd }tj||f|d}t	| |	|
} t
|D ]V}| || }| ||  |7  < t| | }|| ||< | ||  |8  < t| | }|| ||< || | }| ||d	d	|f< q]tdd
| |S )aR  Computes the numeric Jacobian for f regarding xs[param].

  One can think of the relation among f, xs and y as y = f(xs).

  Args:
    f: the function.
    y_size: the number of elements of the result.
    y_dtype: the dtype of the result.
    xs: a list of tensors.
    param: the index of the target parameter.
    delta: the amount of perturbation we give to the input.

  Returns:
    A 2-d numpy array representing the Jacobian. It has "y_size" rows
    and "x_size" columns where "x_size" is the number of elements in xs[param]
    and "y_size" is the number of elements in the result.
  rC   r   c                 S   rJ   r   rD   r   r   r   r   r      rM   z-_compute_numeric_jacobian.<locals>.<listcomp>c                 S   rJ   r   r7   r   r   r   r   r      rM   c                 S   s   g | ]	}t t|qS r   )r'   asarrayr/   r   r   r   r   r      s    rD   r   NzNumeric Jacobian =
%s)r8   rE   r   rN   rP   rQ   r'   rm   r(   rB   rU   rR   rS   r/   rY   rZ   )r5   ra   r\   r>   r]   deltar;   r:   r_   r@   rA   r   scalerb   coloriginaly_posy_negdiffr   r   r   _compute_numeric_jacobian   s2   

ru   c                 C   s   || }|j }tjtjtjtjtjtjg}|j|v s#J d|j	|f |}	|	j|v s1J d|	j	 t
|}
t| ||||}t| |
||||}||fS )z0Computes the theoretical and numerical jacobian.z>Cannot compute gradient for unsupported type %s of argument %sz4Cannot compute gradient for unsupported type %s of y)rE   r   float16bfloat16float32float64	complex64
complex128
base_dtypenamer   rl   ru   )r5   r[   r\   r>   r]   rn   r   r   allowed_typest2ra   jacob_tjacob_nr   r   r   _compute_gradient  s    r   c                    sf   dd D dd D }dd D }t ||}| tt fddttD  S )z)Compute gradients for a list of x values.c                 S   s   g | ]}t |qS r   )r   r2   r   r   r   r   r     s    z*_compute_gradient_list.<locals>.<listcomp>c                 S   rJ   r   rD   r   r   r   r   r     rM   c                 S   rJ   r   r7   r   r   r   r   r     rM   c              	      s(   g | ]}t jtj| qS r   )r   r8   r   as_dtyperE   )r   rh   rn   r5   r>   r   r   r   r      s    )rB   rO   r*   rU   r)   )r5   r>   rn   r@   rA   f_tempr   r   r   _compute_gradient_list  s   
r   ztest.compute_gradient)v1c                 C   s6   t |ttfstdt| |du rd}t| ||S )a  Computes the theoretical and numeric Jacobian of `f`.

  With y = f(x), computes the theoretical and numeric Jacobian dy/dx.

  Args:
    f: the function.
    x: the arguments for the function as a list or tuple of values convertible
      to a Tensor.
    delta: (optional) perturbation used to compute numeric Jacobian.

  Returns:
    A pair of lists, where the first is a list of 2-d numpy arrays representing
    the theoretical Jacobians for each argument, and the second list is the
    numerical ones. Each 2-d array has "y_size" rows
    and "x_size" columns where "x_size" is the number of elements in the
    corresponding argument and "y_size" is the number of elements in f(x).

  Raises:
    ValueError: If result is empty but the gradient is nonzero.
    ValueError: If x is not list, but any other type.

  Example:

  >>> @tf.function
  ... def test_func(x):
  ...   return x*x
  ...
  >>>
  >>> class MyTest(tf.test.TestCase):
  ...
  ...   def test_gradient_of_test_func(self):
  ...     theoretical, numerical = tf.test.compute_gradient(test_func, [1.0])
  ...     # ((array([[2.]], dtype=float32),),
  ...     #  (array([[2.000004]], dtype=float32),))
  ...     self.assertAllClose(theoretical, numerical)

  zZ`x` must be a list or tuple of values convertible to a Tensor (arguments to `f`), not a %sNg      P?)r   listrO   rW   typer   )r5   r   rn   r   r   r   compute_gradient&  s   'r   c                 C   sB   d}t | |D ]\}}|js|jrt|t||  }q|S )a  Computes maximum elementwise gap.

  Computes the maximum elementwise gap between two lists of tensors of the same
  shape.

  Args:
    grad1: a lists of tensors.
    grad2: a lists of tensors with the same shape as grad1.

  Returns:
    The maximum elementwise gap between the two.
  r   )r*   sizer'   maximumfabsmax)grad1grad2errorj_tj_nr   r   r   	max_errorZ  s   r   r0   )__doc__r   r'   tensorflow.python.eagerr   r   tensorflow.python.frameworkr   r   r   r   tensorflow.python.opsr   tensorflow.python.platformr	   rY    tensorflow.python.util.tf_exportr
   r   r"   r/   rB   rl   ru   r   r   r   r   r   r   r   r   <module>   s,   
"H:
3