o
    ?eR%                     @   s2  d 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T dd Zede ede eddd Zeddd Zeddd Zede eddd Zeddd Zedd d! Zed"d#d$ Zed%d&d' Zd(S ))z7Gradients for operators defined in control_flow_ops.py.    )dtypes)indexed_slices)ops)sparse_tensor)tensor)control_flow_ops)control_flow_util)math_ops)*c           	      G   sJ  t  }|  }| }t|trN|jj| }|dur.|d dur,tj	||d dd dS |d durLt
|d |d gddd }||jj| < |dfS dS t|tr|d|j  }|du ry| jd jtjkrwt
||j gd	 d
dd dfS dS t
|ddd dfS t|d | jd d }t|d | jd d }t
||gd dfS )a  Gradients for a Switch op is calculated using a Merge op.

  If the switch is a loop switch, it will be visited twice. We create
  the merge on the first visit, and update the other input of the merge
  on the second visit. A next_iteration is also added on second visit.
  N   F)Zenforce_shape_invariant)NNr   Zb_switchname   Zcond_resource_grad	cond_grad)r   get_default_graph_get_control_flow_context
isinstanceWhileContext
grad_stateZ
switch_mapgetr   Z_AddNextAndBackEdgemergeCondContextbranchinputsZdtyper   resourceswitch)	opgradgraphop_ctxt	grad_ctxtZ
merge_gradZ	zero_gradZ
false_gradZ	true_grad r!   h/home/www/facesmatcher.com/pyenv/lib/python3.10/site-packages/tensorflow/python/ops/control_flow_grad.py_SwitchGrad    s@   

r#   ZSwitchZ	RefSwitchZMergec                    s   j d j}t }t|}| }t|trt	
|jS t|tr`|j}|rX|jrX|j}|j|j}	|	du rV|j}|  ||}
|  ||
|}	|	|j|j< |	}t	j
|ddS tj }fddt|D   fddt|D S )z:Gradients for a Merge op are calculated using a Switch op.r   Nr   r   c                    s   g | ]}t  jd  |qS r   )r	   equalZoutputs.0i)r   r!   r"   
<listcomp>   s    z_MergeGrad.<locals>.<listcomp>c                    s    g | ]}t  | d  qS r$   )r   _SwitchRefOrTensorr&   )condr   r!   r"   r)      s    )r   r   r   r   r   ZGetOutputContextr   r   r   r   r*   Zpivotr   predr   Zhistory_mapr   r   Zgrad_contextExitZAddForwardAccumulatorEnterZAddBackpropAccumulatedValuelenrange)r   r   _Zinput_opr   r   r    r,   r   Z	real_predZhistory_predZ
num_inputsr!   )r+   r   r   r"   
_MergeGrad\   s2   





r2   ZRefMergec                 C   s   t | ||S N)r2   )r   r   r1   r!   r!   r"   _RefMergeGrad   s   r4   r-   c                 C   s   t  }|  }| }|jsdS |jrtdt|tjr%|	|j
 n.t|tjtjfs8tdt| d|	|jj
 |	|jj
 |j}|durS|	|j
 |  tj||j
d|jdd}|j| |  |S )z:Gradients for an exit op are calculated using an Enter op.Nz4Second-order gradient for while loops not supported.Type zO not supported, must be either`indexed_slices.IndexedSlices` or `SparseTensor`.FZb_exit)is_constantparallel_iterationsr   )r   r   r   	back_propr   	TypeErrorr   r   TensorZAddNamer   r   IndexedSlicesr   ZSparseTensortypevaluesindicesdense_shaper.   r   Z_Enterr7   Zloop_entersappendr-   )r   r   r   r   r    r?   resultr!   r!   r"   	_ExitGrad   s6   rB   ZRefExitZNextIterationc                 C   s   |S )zA forward next_iteration is translated into a backprop identity.

  Note that the backprop next_iteration is added in switch grad.
  r!   r1   r   r!   r!   r"   _NextIterationGrad   s   rD   ZRefNextIterationc                 C   
   t | |S r3   )rD   rC   r!   r!   r"   _RefNextIterationGrad      
rF   r.   c                 C   s   t  }| }|du r|S |js|S |jdu r|S | drEt|tjr-|	| |}|S t|t
jr;|| |}|S tdt| dt|}|j| ||g |S )zGradients for an Enter are calculated using an Exit op.

  For loop variables, grad is the gradient so just add an exit.
  For loop invariants, we need to add an accumulator loop.
  Nr6   r5   z/ not supported,must be Tensor or Indexed Slices)r   r   r   r8   r   Zget_attrr   r   r:   ZAddBackpropAccumulatorr   r;   Z#AddBackpropIndexedSlicesAccumulatorr9   r<   exitZ
loop_exitsr@   Z
ExitResult)r   r   r   r    rA   r!   r!   r"   
_EnterGrad   s(   

	rI   ZRefEnterc                 C   rE   r3   )rI   )r   r   r!   r!   r"   _RefEnterGrad   rG   rJ   ZLoopCondc                 C   s   dS )z0Stop backprop for the predicate of a while loop.Nr!   )r1   r!   r!   r"   _LoopCondGrad   s   rK   N)__doc__Ztensorflow.python.frameworkr   r   r   r   r   Ztensorflow.python.opsr   r   r	   Z&tensorflow.python.ops.control_flow_opsr#   ZRegisterGradientr2   r4   rB   rD   rF   rI   rJ   rK   r!   r!   r!   r"   <module>   s<   8
/

(


#
