
    AVh                        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 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+ 	 	 	 	 	 	 dAd!Z, ejZ                  d"       ejZ                  d#      d$ej\                  fd%              Z/d& Z0d' Z1d( Z2d) Z3d* Z4d+ Z5d, Z6d- Z7d. Z8d/ Z9d0 Z: ejv                  d1g d2      Z< G d3 d4ejz                        Z>d5 Z?d6 Z@d7 ZAd8 ZBd9 ZCd: ZDd; ZEd< ZFd= ZGd> ZHd? ZId$ej\                  fd@ZJy)Ba  while_v2 and gradient.

This is a version of while_loop that emits a single While op, as well as the
gradient function for While ops produced by while_loop. This will eventually
replace the current tf.while_loop implementation once it reaches feature and
performance parity.
    N)attr_value_pb2)pywrap_tf_session)backprop_util)auto_control_deps_utils)constant_op)dtypes
func_graph)indexed_slices)opstensor)tensor_shape)tensor_spec)tensor_util)	array_ops)control_flow_ops)control_flow_util)control_flow_util_v2)default_gradient)gen_functional_ops)gen_resource_variable_ops)gradients_util)handle_data_util)list_ops)math_ops)tensor_array_ops) while_v2_indexed_slices_rewriter)compat)nest)object_identity)variable_utilsc	                 z   &'() t        j                        )t        j                  )d      't	        )      }	t              t        j                  t        j                  d      |&t        j                  t        j                  |      (n$t        j                  t        j                        (t        j                  d t        j                  (d            }
|sd}t        j                  |      5 }t        j                  d      5  t        j                  |d      }t        j                  |d      }ddd       t              }t!        j"                  d|j$                  ndd	
      }||gt'              z   t(        j*                  j-                  |      t(        j*                  j-                  |      gt'        (      z   }t        j.                         j0                  } '(fd}t3        j4                  |g i |t        j6                  |t        j.                         j8                        |      &&'()fd}t3        j4                  |g i |t        j:                  |t        j.                         j8                        |      }t        j                  |j<                  D cg c]	  } |        c}d      }|j>                  z   |z   |j@                  jC                  |jD                         |j@                  jC                  |jF                         &jI                         5  t	        &j>                        }&j>                  |j>                  d| k(  sJ tK        &|j>                  |d |z          ddd       t	        t        j                  )d            }d}tM        |j@                  |||z    |
t        j                  |||	z    d             t	        |j@                        }|rt        jN                         rtQ        |      }|D ]  }tS        jT                  |j$                  |jV                        }jY                  |       &jI                         5  &j[                  |       ddd       |jI                         5  tS        j\                  ||      }|j@                  jY                  |       ddd        t        j                  d      }t_        &|t	        |             ta        ||       t        jb                  t'        &jd                  jf                        t'        |jd                  jf                        z         5  |j@                  D  cg c]  } | jV                   }!} ti        |||z         }"|
|!|"<   tk        |&||!|||      }#ddd       t        j.                         jl                  sto        d #D              }#ddd       #|z    }$|s"|$D  cg c]  } tq        jr                  |        }$} tu        ('|$      }#|r|#S t        j                  |#d      }%t	        |%      dk(  r|%d   S |#S # 1 sw Y   xY wc c}w # 1 sw Y   xY w# 1 sw Y   xY w# 1 sw Y   jxY wc c} w # 1 sw Y   xY w# 1 sw Y   xY wc c} w )z3Like tf.while_loop, except emits a single While op.Texpand_compositesNc                     | j                   S N)shape)specs    N/home/dcms/DCMS/lib/python3.12/site-packages/tensorflow/python/ops/while_v2.py<lambda>zwhile_loop.<locals>.<lambda>a   s
    4::     whilecondbodyr   loop_counterdtypenamec                 
    t        |       }t        j                  |      rA|j                  j                  |j                  j                  rt        j                  |      }|S t        j                  | |k  |      S )z@Extra `cond` wrapper that can handle the extra counter loop_var.)	_pack_sequence_asr   
is_tf_typer(   dimsr   
squeeze_v2r   logical_and)r0   maximum_iterations_argargspredr.   flat_orig_loop_varsloop_vars_signaturemaximum_iterationss       r*   wrapped_condz while_loop.<locals>.wrapped_cond~   s}     02EtLNd

 
 
&::??"djjoo##D)		###1149 	9r,   )collections)	signaturer
   add_control_dependenciesc                 B   t        t        j                  
dd d      t        j                  |d             j                  D ]%  }t	        j
                         j                  |       '  t        	|       }t        j                  |      s|g}	 t        j                  |dd       t        |      }| dz   |gt        |      z   S # t        $ rF t        j                  |      }t        j                        }t        j                  ||dd       Y lw xY w)a)  Loop body augmented with counter update.

      Args:
        loop_counter: Loop counter which needs to be incremented in the body.
        maximum_iterations_arg: Maximum iterations of the loop.
        *args: List of args

      Returns:
        A list of tensors the same length as args.
         NTr$   F)check_typesr%      )_copy_handle_datar    flattenexternal_capturesr   get_default_graphcapturer5   	is_nestedassert_same_structure
ValueErrorr"   convert_variables_to_tensors_tensor_array_to_flowlist)r0   r:   r;   toutputsvars1vars2r/   
cond_graphr=   	loop_varsr>   orig_loop_varss          r*   wrapped_bodyz while_loop.<locals>.wrapped_body   s    Yqr]dKTTBD ++ +!''*+ 02EtLNg^^G$); 	""7N59	; &g.g Q 67$w-GG  ; ;;GD;;NK""5%U59	;;s   C ADDrE   )element_dtypeelement_shapemax_num_elementsoutput_shapesparallel_iterationsr3   num_original_outputsc              3   F   K   | ]  }t        j                  |        y wr'   )r   identity).0rS   s     r*   	<genexpr>zwhile_loop.<locals>.<genexpr>/  s     =i((+=   !rG   );r"   rP   r    rI   lenrQ   map_structurer   ,internal_convert_to_tensor_or_indexed_slicesr   _shape_invariant_to_type_specr   
name_scopeutilunique_fn_name"_build_maximum_iterations_loop_varr   constantr2   rR   r   
TensorSpecfrom_tensorrK   _add_control_dependenciesfunc_graph_modulefunc_graph_from_py_funcWhileCondFuncGraph_collectionsWhileBodyFuncGraphdeferred_external_capturesrJ   rT   extendinternal_capturesdeferred_internal_captures
as_default _duplicate_body_captures_in_cond_check_shapes_compatoutput_all_intermediates_get_intermediatesr   empty_tensor_listr(   appendrL   tensor_list_push_back_check_num_inputs_outputs!_check_inputs_outputs_types_matchcontrol_dependenciesfunction_capturescontrolslice_build_while_opbuilding_functiontupler   stop_gradientr5   )*r.   r/   rX   shape_invariantsr`   r?   r3   return_same_structure	back_proplen_orig_loop_varsflat_shape_invariantsscope	cond_name	body_namemaximum_iterations_loop_varr0   func_graph_signaturerC   r@   rZ   
body_graphcrx   num_cond_capturesnum_flattened_outputsfirst_loop_var_indexra   intermediate_tensorsintermediate_tensortensor_listappended_tensor_listflattened_loop_varsrS   r_   orig_loop_vars_rangerT   output_loop_varsflattened_outputsrW   r=   r>   rY   s*   ```  `                                @@@@r*   
while_loopr   :   s    99)D).^tL>*
 $I.)  AA) !,,66#% ,,66	C ,,
ll&$?A 
D
~~d H>u		 5%%eV4i%%eV4i5 #E#''	) *///3	L :;d9oMI 
			+	+L	9				+	+,G	H	J !	"   #446PP9& #::

&**3#8#8#:#G#GI!9;J-H -H^ #::

&**3#8#8#:#G#GI!9;J "& ;;<<"  	J0003MM  j::;jCCD 
			  &j::;****+=,=>? @ ?&
j223D3EF
$%&	&  ^?C!E F /0D011 	2Y34H152 3FJ	L	M z112T224 0
;!5 :
00-33-33/1 	%""$ 	* 

[
)	* ""$ 	: "*!?!?."0
 


#
#$8
9	: 	::$ ,,yDIj*!"568%j2EF		!	!Z))112T((0062 	2
3 5 )3(:(:;1qww;m;"#7#7:O#OQ,Am()


%135g5    "44 =W==gQH>T 12F233 4	<LMq	//2MM.0@B' Nll7dC	q QNo5 5` 	=& &F	* 	*	: 	:  <5 5aH> H>Z Ns   Z,-Y"E:Z,Y/
A5Z,AY4C*Z,>ZZ,(2ZBZ,/Z >Z(Z 98Z,Z8"Y,	'Z,4Y>	9Z,ZZ,ZZ,Z  Z)	%Z,,Z5StatelessWhileWhileopc                 D
   | j                   d   j                  }t        |dd      }t        |dd      }t        |j                         }| j                  d   }| j                  d      }	 |j                  d      }t        |j                         |z
  }	t        |d	| |j                   d	| |j                  d	| |j                   d	|       D 
cg c]  \  }
}}}t        |
|||       c}}}}
d	g|	z  z   }t        | d
d	      Gt        |j                        t        |j                        z
  }| j                  D ]  }||k\  s	d	||<    t        t        |j                   |j                  |      D 
cg c]  \  }}}
|
|||
f c}
}} \  }}}t        |||||t        j                  |j                        | |      \  }}|j                  r|xj                  dz  c_        |xj                  dz  c_        |j                   }|j                   |d	 }|j#                  dt        j$                  |             |j#                  dt        j$                  |             t        |j&                        t        |j                        t        |      z   k7  rDt)        dt        |j&                         dt        |j                         dt        |       d      |j+                  d|j&                         |j-                  d|j.                         |j1                  |       |j3                  |D cg c]  }|j4                   c}|D cg c]  }|j6                   c}       t9        ||j                   |d	        |j;                  dt=        j>                  t        |j                                      tA        |||      }||z   }tC        jD                  ||||j                        }d }t        j                  | j                  d      j                        }tG        jH                  |||i t        jJ                  |            }tM        ||t        |             tO        ||||j                   D cg c]  }|j6                   c}|d|j                  z  t        |j                               }|D cg c]  }tQ        jR                  |       }}tU        |||      S #  t        |j                         }Y xY wc c}}}}
w c c}
}}w c c}w c c}w c c}w c c}w )z2The gradient of a While op produced by while_loop.r   r.   _cond_graphr/   _body_graphrG   r`   _num_original_outputsNskip_input_indices
_rewrittenzjInputs and outputs constructed for the forward op of a While gradient don't match with 'output_types' at  z,'inputs' at length z, and 'new_inputs' at length z-. This doesn't make sense, please file a bug.Tr_   ic                     | |k  S r'    )counterunused_maximum_iterations_argforward_loop_itersunused_argss       r*   	grad_condz_WhileGrad.<locals>.grad_cond  s    '''r,   r	   z%s_gradr^   )+rT   r   
_get_graphrg   inputsget_attrzip_preprocess_gradgetattrrz   r   _create_grad_funcrl   unique_grad_fn_namer3   while_op_needs_rewriteextra_inputs_set_func_attrcreate_new_tf_functionoutput_typesAssertionError_set_type_list_attr_set_shape_list_attrr_   _add_while_inputs_add_outputsr2   r(   rH   	_set_attrr   	AttrValue_resolve_grad_capturesr   rewrite_grad_indexed_slicesrs   rt   ru   r   r   r   rc   _get_structured_grad_output) r   gradswhile_oprW   r   orig_num_paramsr?   r`   ra   num_intermediatesgradbody_outwhile_in	while_outcaptures_start_indexr   yxysxsnon_none_gradsbody_grad_graphr;   
new_inputsnew_outputsrS   captured_inputsrX   r   grad_cond_namecond_grad_graphrT   s                                    r*   
_WhileGradr   B  s    ZZ]((FM:*(FM:*
**+/yy|$9:1#,,-DE (**+.BB 25
%%
&


22
3
////
0


00
1	23 
-$(I tXx; f  !% R%t,8JZ%A%A!BB "" 	
"	"a #*++UC4 !I !I,1a7;7G #$Q !I J"b. ,"nj*
z/5GI/4 ++ OO|#OOO|#O !--J$$_%56KFD$?$?
$KLFD$?$?
$KL
:""#s8??';c*o'MM:(()**>!""?_J	LM M   j&=&=>!!/:3K3KLz*K8q1778,78q1778:k8#3#3O4D#EF ,#--H4D4D0EFH +:+35/_$) /JJ_i:)( ++BKK,?,D,DE.%==iB((8:/ O_c)nM&5&=&=>QWW>-x}}$6679' -44qY"4'4	$We_	EEC1x//0(!ID 98> ? 5s0   *S" S?
5T2TT
5T7T"S<c                 X   j                         D cg c]  }|j                  s| }}j                         D cg c]  }|j                  s| }	}|s|	rt        j                  nt        j                  fd}
t        j                  |
|       S c c}w c c}w )z.Builds the functional StatelessWhile/While op.c           
         t        j                   | t        j                        t        j                        	            \  }}t        j                  |       t        j
                  |       t        j                  |       t        |g       |j                  dt        j                               t        j                         _        t        j                         _        |_        |_        |S )N)r_   r`   r3   r   r   )rl   get_op_and_outputsr   rH   rT   maybe_set_lowering_attr*maybe_propagate_compile_time_consts_in_xla#_set_read_only_resource_inputs_attrr   r   r   r   rK   outer_graphr   r   )
r   r   tensorsr   rW   r3   ra   op_fnr_   r`   s
      r*   _make_opz!_build_while_op.<locals>._make_op  s    //##J/##J/#/1 Hg j(('2  *33H=':z2JK.%//2FGI
 !224J 224J%H%HNr,   )get_operations_is_statefulr   _whilestateless_whilerl   "run_as_function_for_tape_gradients)rX   rW   r   r_   r`   r3   ra   r   cond_stateful_opsbody_stateful_opsr   r   s    ``````    @r*   r   r     s     ,,."//b  ,,."//b  ,%%E..E . 
	0	09	EEEs   B"B"B'B'c                    g }t        d | j                  D              }| j                         D ]  }|j                  dk(  r|j                  dk(  r#|j                  D ]b  }|| j
                  d   us|j                  t        j                  k7  s3t        |      ?|j                         |vsR|j                  |       d  |S )z?Returns all tensors in `func_graph` that should be accumulated.c              3   F   K   | ]  \  }}|j                         |f  y wr'   ref)rd   kvs      r*   re   z%_get_intermediates.<locals>.<genexpr>  s     G41a1557A,Grf   Identity	MutexLockr   )dictcapturesr   typerT   r   r2   r   resource_get_accumulatorr   r   )r
   intermediatesreverse_capturesr   os        r*   r   r     s    0 -G:3F3FGG%%'  b	ww*	ww+ZZ  
:$$Q'
'
''V__
$
1

%
%%')
)Q   
r,   c                    t        |      sy|j                  t        j                  t        j                  fv r#t        j                  |      r| t        ||      S t        | t        j                        rt        j                  |       S | S )a  Returns the initial gradient to be used for a given output tensor.

  Args:
    grad: the original gradient Tensor passed to the gradient function.
    body_graph_output: the corresponding Tensor in the body graph.
    while_op_input: the corresponding Tensor input of the While op.
    while_op_output: the corresponding Tensor output of the While op.

  Returns:
    A Tensor or None.
  N)_is_trainabler2   r   r  variantr   supports_default_grad_zeros_like
isinstancer   IndexedSlicesr   convert_to_tensor)r   body_graph_outputwhile_op_inputwhile_op_outputs       r*   r   r     st    * 
(	) @@,,^<~77
 n223  &&	+r,   c                     |j                   t        j                  k(  r=t        j                  t        j                  |      t        j                  |             S t        j                  |      S )zBLike array_ops.zeros_like() but also accepts resource var handles.r2   )
r2   r   r  r   zerosr   variable_shaper   get_zeros_dtype
zeros_like)op_input	op_outputs     r*   r
  r
  ;  sT    __' ??!00;..x8: : 
		i	((r,   c                    t        j                  |       sy| j                  j                  dk(  r^| j                  dk(  rO| j
                  t        j                  k(  sJ | j                  j                  d      }t        j                  |      S y)z.Returns whether the given tensor is trainable.FTensorListPopBackr   r[   T)	r   IsTrainabler   r   value_indexr2   r   r  r   )r   element_types     r*   r  r  G  sq    		"	"6	* YY^^**v/A/AQ/F<<6>>)))99%%o6L$$\22	r,   c                    t        | |d      }|c| j                  d      D cg c]  }t        j                  |       }}| j                  |      j                  }t        j                  | ||      }| |_        |S c c}w )zReturns `FuncGraph` for the given function attribute.

  Args:
    while_op: The While Operation.
    func_attr_name: string
    attr_graph_name: cached forward graph name

  Returns:
    `FuncGraph`
  Nr_   )r   r   r   TensorShaper3   rl   get_func_graphr   )r   func_attr_nameattr_graph_namer
   sinput_shapes	func_names          r*   r   r   Y  s     x$7* .6->->-O()  #L  !!.166I$$X|YGJ*	s   A<c                     t               t        |      k(  sJ |j                  d   }t        j                  d|j                  d      }	t        j                  j                        }
t        j                  j                        }|	||gt        |      z   }t        j                  | fd|i t        |||||
|            }|j                  D ]  \  }}t        j                  |      |j                  v r#|j                  t        j                  |         }n$t!        dt#        |       dt#        |       d      |j                  j%                  |       |j&                  j%                  |        ||fS )	a  Builds and returns the gradient FuncGraph of `func_graph` and its args.

  The returned grad_func_graph must be called with the returned
  args + grad_func_graph.captures.

  Args:
    ys: A `Tensor` or list of tensors to be differentiated.
    xs: A `Tensor` or list of tensors to be used for differentiation.
    grads: The incoming grads for `ys`.
    cond_graph: FuncGraph for the forward cond function.
    body_graph: FuncGraph for the forward body function.
    name: Name of the returned gradient function.
    while_op: The forward While op.
    maximum_iterations: Tensor. The maximum number of iterations.

  Returns:
    2-tuple of (grad_func_graph, args).
  r   grad_counterr1   c                       t        |       S r'   )_grad_fn)r;   r   r   r   s    r*   r+   z#_create_grad_func.<locals>.<lambda>  s    HRT:6 r,   r	   zTensor z which captures zG is in list of internal_captures but not in internal_capture_to_output.)rg   rT   r   ro   r2   r!   ObjectIdentitySetr   rR   rs   rt   _WhileBodyGradFuncGraphr   r   	tensor_idinternal_capture_to_outputrO   strr   structured_outputs)r   r   r   rW   r   r3   r   r?   total_itersr   body_graph_inputsbody_graph_outputsr;   grad_func_graphexternal_captureinternal_capture
new_outputs   ``  `            r*   r   r   p  s   ( 
RCJ		  #+  {  ~7' &77
8I8IJ&889K9KL
%{	3d5k	A$ &==
6
B(z:);X):<NP	Q/ -<,D,D :((&'55	6"==cmm
? j C()**:!"# $EFG G "":.&&--j9: 
$	r,   c                     |dd }t        j                  | |||d      }t        d |D              sJ |d   }|d   }|d   }|dz   ||g|z   S )	a  Computes the gradient of `func_graph` in the current graph.

  This function builds the gradient graph of the corresponding forward-pass
  `func_graph` by differentiating `func_graph`'s outputs w.r.t. its inputs.

  Args:
    ys: A `Tensor` or list of tensors to be differentiated.
    xs: A `Tensor` or list of tensors to be used for differentiation.
    args: The input arguments.
      args[0] - Loop counter
      args[1] - Total number of iterations.
      args[2] - maximum_iterations.
      args[3:] - Incoming gradients for `ys`.
    func_graph: function.FuncGraph. The corresponding forward-pass function.

  Returns:
    The output gradient Tensors.
     Nzero)grad_ys	src_graphunconnected_gradientsc              3   $   K   | ]  }|d u 
 y wr'   r   )rd   gs     r*   re   z_grad_fn.<locals>.<genexpr>  s     .qQd].s   r   rG   rE   )r   _GradientsHelperall)	r   r   r;   r
   r:  	grad_outsr   r?   r0  s	            r*   r)  r)    sv    & H' --"g"$) 
.I.	..	.G'AwQ+
A+);	7)	CCr,   c                    g }|j                   D ]y  }|j                  | k(  rWt        |j                  j                        D ]  \  }}||u s|j                  |   } n |j                  | j                  k(  sJ |j                  |       { |S )a  Returns the tensors to pass as captured inputs to `body_grad_graph`.

  `body_grad_graph` may have external references to:
  1. Its outer graph containing the input gradients. These are left as-is.
  2. Accumulators captured from the forward-pass graph. These should have been
     added as `while_op` outputs after the gradient graph was built. We replace
     these with the corresponding output of `while_op`, i.e. a tensor in
     `body_graph.outer_graph`. In the case of nested control flow or functions,
     the gradient logic handling `body_grad_graph.outer_graph` will make sure
     the tensor from `body_graph.outer_graph` is also correctly captured.

  Args:
    body_graph: FuncGraph. The forward-pass body function.
    body_grad_graph: FuncGraph. The body gradients function.
    while_op: The forward-pass While Operation calling `body_graph`.

  Returns:
    A list of input tensors to be passed as the captured inputs to
    `body_grad_graph`.
  )rJ   graph	enumeraterT   r   r   )r   r   r   new_capture_inputsrS   r   outputs          r*   r   r     s    * ,, !a 	ww* 1 )!VQ;q!!
 WW
.....a !  
r,   c           
         g }d}d}|D ]  }||j                  d       |j                  |   }|dz  }t        |t        j                        r<|j                  t        j                  | |   | |dz      | |dz                   |dz  }t        |t
        j                        sJ |j                  | |          |dz  } |S )a3  Returns the values that should be returned from the while grad function.

  Args:
    outputs: the raw Tensor outputs of the grad While op.
    grads: the input gradients to the gradient function.
    body_grad_graph: _WhileBodyGradFuncGraph.

  Returns:
    A list of gradient values. May include Nones.
  r8  NrG   rE   )valuesindicesdense_shape)r   r/  r  r   r  
tensor_libTensor)rT   r   r   resultoutputs_idxstructured_outputs_idxr>  rF  s           r*   r   r     s     & + aymmD//0FGFa&.667 mmN00%+/*kAo.0 1 Qk
 1 1222mmGK()Qk%( 
-r,   c                     t         j                  t        j                        sJ  fd} j	                         D ]  }|j
                  dk7  rd}t         j                  j                        D ]  \  }}||j                  d   u s n P ||j                  d         }|ht         j                  j                        D ]  \  }}||u s||k(  r|c c S    y)a  Returns TensorList if any containing accumulated values of tensor.

  We try to find a pattern of the form:

     input_tl   tensor
        \        /
    (TensorListPushBack)
            |
        output_tl

  which satisfies the following conditions:

  1. input_tl must be in tensor.graph.inputs.
  2. output_tl or Identity(output_tl) must be in tensor.graph.outputs.
  3. tensor.graph.input_index(input_tl) == tensor.graph.output_index(output_t).

  output_tl or Identity(output_tl) (whichever is in tensor.graph.outputs) is
  returned if such a pattern is found else None is returned.

  Args:
    tensor: The Tensor to be accumulated.

  Returns:
    A variant tensor in the same graph as `tensor` or None if no accumulator is
    found.
  c                     j                   j                  D ]
  }|| u s| c S  | j                         d   j                  dk(  r7t	        fdj                   j                  D              rj                  d   S y)zEReturns t or Identity(t) whichever exists in graph outputs else None.r   r   c              3   @   K   | ]  }j                   d    |u   yw)r   N)rT   )rd   rS   identity_ops     r*   re   zB_get_accumulator.<locals>.get_func_graph_output.<locals>.<genexpr>S  s!     FAK"a'Fs   N)rC  rT   	consumersr   any)rS   rF  rS  r   s     @r*   get_func_graph_outputz/_get_accumulator.<locals>.get_func_graph_outputK  st    ,,&& 	1 ++-"KJ&F1E1EFF  ##r,   TensorListPushBackr   N)	r  rC  rs   	FuncGraphrT  r   rD  r   rT   )r   rV  consumeraccum_input_idxinprF  accum_output_idxouts   `       r*   r  r  .  s    6 
FLL"3"="=	>>	>
 ""$ h }},,O )&,,*=*= > 	"	" "8#3#3A#67F~ !*6<<+?+?!@ #	..-	'2 
r,   OptimizedReductionOpsCacheKey)op_typer   r   input_typesr3   attrsop_defcompute_devicec                        e Zd ZdZ fdZed        Z	 	 	 	 	 	 d	 fd	Z	 	 	 	 	 	 d	dZ	 	 	 	 	 	 d	dZ	 fdZ
d Z xZS )
r+  a	  FuncGraph for the gradient function of the body of a While op.

  Contains the logic for capturing the tensors from the body of the forward
  While op which is as follows:
  1. If the tensor is of resource type (these are not accumulated):
     a. Ensure that the tensor is a loop invariant, i.e., it exists in both loop
        inputs and outputs at the same index.
     b. Lookup the corresponding resource tensor in the forward outer graph and
        try to capture that.
  2. If the tensor is not of resource type:
     a. Create an accumulator for that tensor and output it from the forward
        pass. Note this also requires adding it as an input to the forward pass.
     b. Capture the accumulator from the forward pass in this FuncGraph. This
        will later be resolved to the correct output of the forward While op.
     c. Pop a value from the captured placeholder and use it as the captured
        value for the forward pass tensor.

  This only allows capturing tensors in the forward graph. A ValueError is
  raised if an attempt is made to capture a tensor not in the forward graph.
  To manually capture a tensor that is not in the forward graph, call `capture`
  with `allowlisted=True`.

  Note: The `captures` dict does not contain the forward tensor since it is not
  directly captured. It contains the accumulator corresponding to this forward
  tensor.

  Attributes:
    while_op_needs_rewrite: True if any non-resource intermediates were
      captured, meaning the forward While op needs to be rewritten to output the
      corresponding accumulators.
    extra_inputs: list of EmptyTensorList tensors to be used as initial input to
    the new accumulators in the forward graph. It may also contain external
    captures of the custom gradient function.
    internal_capture_to_output: dict from a tensor_id(captured placeholder) to
      the corresponding tensor that needs to be added to the list of outputs.
      For instance, when capturing an accumulator TensorList this contains the
      TensorList obtained after popping a tensor from the list. Other entries
      in this dict are expected, though not enforced, to be identities.
      This dict is needed because these output tensors need to be added to
      FuncGraph.outputs "after" the tensors returned from the gradient function.
  c                     t         t        |   |       g | _        i | _        || _        || _        || _        || _        i | _	        y r'   )
superr+  __init__r   r-  _forward_graph_forward_cond_graph_maximum_iterations_forward_while_op_indirect_captures)	selfr3   forward_cond_graphforward_body_graphr?   forward_while_opr1  r2  	__class__s	           r*   rh  z _WhileBodyGradFuncGraph.__init__  sO     

!41$7D&(D#,D1D1D-D !Dr,   c                     | j                   S r'   )r   )rn  s    r*   r   z._WhileBodyGradFuncGraph.while_op_needs_rewrite  s    r,   c	           
      n    h d}	||	v rt        j                         s}t         fd|D              rit        d |D              rWt        j                   j
                        s8t        j                   j
                        s j                  ||||||||      S t        t         +  ||||||||      S )N>   RankSizeShapeTensorListLengthTensorListElementShapec              3   N   K   | ]  }|j                   j                  u   y wr'   )rC  ri  )rd   inputrn  s     r*   re   z>_WhileBodyGradFuncGraph._create_op_internal.<locals>.<genexpr>  s      C5EKK4...Cs   "%c              3   6   K   | ]  }t        |      d u   y wr'   )r  )rd   r{  s     r*   re   z>_WhileBodyGradFuncGraph._create_op_internal.<locals>.<genexpr>  s     @U#t+@s   r   ra  r3   rb  rc  rd  )rl   r   r@  util_v1GraphOrParentsInXlaContextri  -graph_wrapped_for_higher_order_tape_gradients_move_op_to_forward_graphrg  r+  _create_op_internal)rn  r`  r   r   ra  r3   rb  rc  rd  optimized_reduction_opsrr  s   `         r*   r  z+_WhileBodyGradFuncGraph._create_op_internal  s    6 	**))+CFCC@@@..t/B/BC>>!++

!' , ) ) ($C% D ' 'r,   c	                    t        | j                  d      si | j                  _        | j                  ||||||||      }	| j                  j                  j	                  |	      }
|
|
S | j                  j                         5  t        j                  |      }| j                  j                  ||||||||      }|| j                  j                  |	<   |cd d d        S # 1 sw Y   y xY w)N_optimized_reduction_ops_cacher}  )	hasattrri  r  &_get_optimized_reduction_ops_cache_keygetr|   r   name_from_scope_namer  )rn  r`  r   r   ra  r3   rb  rc  rd  	cache_key	cached_oprM  s               r*   r  z1_WhileBodyGradFuncGraph._move_op_to_forward_graph  s     4&&(HI;=d8;;dE6I ##BBFFI 				'	'	)  %%d+d""66

!' 7 )f GMd88C)  s   AC  C)c	           
      L   t        t        d |            }|t        |      }|t        |      }|Og }	t        |j                               D ]&  \  }
}|	j	                  |
|j                         f       ( t        |	      }||j                         }t        ||||||||      S )Nc                 "    | j                         S r'   r   )rS   s    r*   r+   zP_WhileBodyGradFuncGraph._get_optimized_reduction_ops_cache_key.<locals>.<lambda>6  s     r,   )r   mapsorteditemsr   SerializeToStringr_  )rn  r`  r   r   ra  r3   rb  rc  rd  hashable_attrs	attr_name
attr_values               r*   r  z>_WhileBodyGradFuncGraph._get_optimized_reduction_ops_cache_key+  s     3(&12FV}f+&kn#)%++-#8 K
)Zy**F*F*HIJKN#e'')f(&&+)-ufnN Nr,   c           
         | j                   j                  t        j                  |            }||S |j                  | j
                  ur}t        |      | j                  j                  v }t        t        | /  ||      }|sD|| j                  t        j                  |      <   || j                   t        j                  |      <   |S |j                  j                  dk(  r3|j                  j                  d   }|j                  j                  dk(  r3| j                   j                  t        j                  |            }||S t!        || j
                  j                  | j
                  j"                        rZt        t        | /  ||      }|| j                  t        j                  |      <   || j                   t        j                  |      <   |S t%        j&                  |      rXt%        j(                  t+        j,                  |      |j.                        }|| j                   t        j                  |      <   |S |j.                  t0        j2                  k(  r| j5                  |      S t7        |      }|A| j
                  j8                  j;                         5  t=        j>                         5  tA        jB                  |j.                  |jD                  | jF                  tI        |            }ddd       ddd       | jJ                  jM                         | j
                  j;                         5  tA        jN                  ||      }ddd       | j
                  j"                  jM                  |       | jP                  j;                         5  | jP                  jS                  |       ddd       t        t        | /  ||      }tA        jT                  ||j.                        \  }	}|| j                   t        j                  |      <   |	| j                  t        j                  |      <   |S # 1 sw Y   GxY w# 1 sw Y   LxY w# 1 sw Y   xY w# 1 sw Y   xY w)z:Implements the capturing described in the class docstring.Nr   r   r  )r[   r\   r]   r3   )r[   )+rm  r  r   r,  rC  ri  idr   by_val_internalrg  r+  _capture_helperr-  r   r   r   _is_loop_invariantrT   r   is_constantro   r   constant_valuer2   r   r  _resource_capture_helperr  r   r|   rl   clear_control_inputsr   r   r(   rk  _build_accumulator_namer   r   r   rj  rL   tensor_list_pop_back)rn  r   r3   captured_tensoralready_captured
real_valueaccumulatorr   captured_accumulatornew_tensor_listrr  s             r*   r  z'_WhileBodyGradFuncGraph._capture_helperJ  s   --11#--2GHO"||4...Ft'='='M'MM5tL
$o !0 	'') 	9Hf 56
))..J
& yy"f ))..J
&
 --11#--2GHO"
 &$"5"5"<"<--5575"44:D$A 
 . %%cmm
' 7FdcmmF34 v&''

$
$V
,FLLBj7AdcmmF34 ||v&**622
 #6*K **557 4&&( 	4 22"LL"LL#77*62	4+	44 {+ ))+ J44[&IJ !!((5 ##..0 6  ((56 !!8$OT (0'D'DFLL(:$O_ 6EDCMM&12!0 	##CMM% E	4 	44 4J J6 6s=   #Q8AP>9Q>QQ%>Q	QQQ"%Q.c                    |j                   t        j                  k(  sJ | j                  j                  D cg c]  }|j
                   }}| j                  j                         D ci c]  }|j
                  |j                   }}t        j                  |j
                  ||| j                  j                        }| j                  j                  |   }| j                  j                  j                  |   }|j                   t        j                  k(  sJ |j                   t        j                  k(  sJ |t        j                  | j                  j                  |   j
                  ||| j                  j                        k7  rt        d|       | j                  |      | j                  t!        j"                  |      <   | j                  t!        j"                  |         S c c}w c c}w )a  Returns the captured resource tensor.

    Resource-type tensors are not accumulated. If a resource tensor exists in
    the loop body it must either be a loop input or an output of a nested While
    op inside the loop body which had captured the external resource.

    Args:
      tensor: the external resource Tensor to be captured.

    Returns:
      Tensor in this graph.
    z)Resource tensors must be loop invariants )r2   r   r  ri  r   r3   r   node_defrl   resource_input_index
_functionsr   rT   r   rL   rm  r   r,  )	rn  r   rS   forward_graph_input_namesr   forward_graph_name_to_opdefindexinput_placeholdertensor_in_outer_graphs	            r*   r  z0_WhileBodyGradFuncGraph._resource_capture_helper  s    <<6??***151D1D1K1K LA L L'+':':'I'I'K#M!##M #M%%.#&&(E
 ++2259 //66==eD""foo555 &&&//999
 ))##E*//1J#&&( ( 56K5L
MO O 6:\\6DCMM&12""3==#8995 !M#Ms   G*)G/)NNNNNT)__name__
__module____qualname____doc__rh  propertyr   r  r  r  r  r  __classcell__)rr  s   @r*   r+  r+    s|    (T!*   7'z ,d N>m^):r,   r+  c           
          t        | ||      D ]O  \  }}}t        j                  |j                  |      r(t	        d|j
                   d| d|j                   d       y )NzInput tensor `z` enters the loop with shape z, but has shape z after one iteration. To allow the shape to vary across iterations, use the `shape_invariants` argument of tf.while_loop to specify a less-specific shape.)r   r   _ShapeLessThanOrEqualr(   rO   r3   )flat_output_tensorsr   flat_input_tensorsrS   r(   input_ts         r*   r~   r~     sr     !46K!35 =q%11!''5A7<<.(EeW M77) $<<= ==r,   c                    t        | j                        |k(  sJ dt        | j                        |fz         t        | j                        dk(  sJ dt        | j                        z         t        |j                        |k(  sJ dt        |j                        |fz         t        |j                        |k(  sJ dt        |j                        |fz         y)zEChecks the number of inputs/outputs of `cond_graph` and `body_graph`.z(cond_graph takes %d inputs; Expected: %drG   z&cond_graph has %d outputs; Expected: 1z(body_graph takes %d inputs; Expected: %dz'body_graph has %d outputs; Expected: %dN)rg   r   rT   )rW   r   num_flattened_loop_varss      r*   r   r     s   	Z	#:	: N0C
8I8I4J4K4M MN	: 
Z	 A	% J.Z5G5G1HHJ	%	Z	#:	: N0C
8I8I4J4K4M MN	: 
Z	 $;	; M/3z7I7I3J3J3L LM	;r,   c                 
   t        | j                  | j                  |      D ]_  \  }}}|j                  |j                  k7  s!t	        d|j
                   d|j                   d|j                   d|j
                   d	       y )Nz	Loop var z enters the loop with type z but has type z after 1 iteration. z type should remain constant.)r   r   rT   r2   	TypeErrorr3   )r   r   r\  r^  loop_vars        r*   r   r      s    
 1 1:3E3E 35 %c3
yyCIIhmm_$?		{ K))$8 H$$% %%r,   c                 >    | j                  | j                  dz         S )N___redundant_placeholder)unique_namer3   )rW   s    r*   $_build_cond_placeholders_name_prefixr  
  s    			
2L L	MMr,   c           
         |D cg c]  }|j                   j                   }}| j                  j                         5 }t	        j
                  ||t        j                  t        |                   }ddd       D cg c],  }t        j                  j                  |j                  |       . }}g }|D ]   }	|j                  |	j                  d          " t        ||      }
|D cg c]  }t!        |       }}t        ||
      D ]*  \  }}| j"                  j%                  ||d   |d   d       , | j&                  j)                  |       yc c}w # 1 sw Y   xY wc c}w c c}w )zCreates placeholders for body captures in cond_graph.

  This is needed to match signatures of cond and body graphs.

  Args:
    cond_graph: cond branch graph
    body_graph_captures: Tensors which were captured when building the
      `body_graph`.
  Nr   rG   F)keyexternalinternal	is_by_ref)r2   as_datatype_enum_c_graphr  c_apiTF_CreatePlaceholdersr   as_strr  r   	Operation
_from_c_opoperr   rT   r   r  _function_capturesadd_or_replacer   ry   )rW   body_graph_capturesrS   typesc_graphplaceholdersphplaceholder_opsr   r   tupleskeysr   r   s                 r*   r}   r}     sg    .A
A177##
A%
A   IG..::FGILI
 ?K8:cmmrww
3/  ' "bNN2::a=!"
 "G,&,	-A"Q%	-$	-$ da!!0011	 1  7#= BI I 
.s   E4E>1E"(E'Ec                 X    t        | |      D ]  \  }}t        j                  ||        y r'   )r   r   copy_handle_data)src_tensorstgt_tensorssrc_ttgt_ts       r*   rH   rH   9  s,    +{3 4leU%%eU34r,   c                     d }t        t        j                  |d      |      D cg c]  } || 	 }}t        j                  | |d      S c c}w )zGLike `nest.pack_sequence_as` but also replaces flows with TensorArrays.c                 f    t        |t        j                        rt        j                  ||       S | S r'   )r  r   TensorArraybuild_ta_with_new_flow)flowtas     r*   flow_to_tensor_arrayz/_pack_sequence_as.<locals>.flow_to_tensor_arrayA  s4    AK
((B*33B= 5/35r,   Tr$   )r   r    rI   pack_sequence_as)r>   r=   rX   r  zr   s         r*   r5   r5   >  sd    5 4<<	TB&(
 A 
 
		24G15
7 7s   Ac                 8    d }t        j                  || d      S )Nc                 R    t        | t        j                        r| j                  S | S r'   )r  r   r  r  )maybe_tas    r*   fz _tensor_array_to_flow.<locals>.fP  s"    (,889]]Or,   Tr$   )r    rh   )rX   r  s     r*   rQ   rQ   N  s    
 
		AyD	AAr,   c                 V    | d} t        j                  | t        j                  d      S )NrX  r?   r1   )r   r  r   int32)r?   s    r*   rn   rn   X  s1     			3G
I Ir,   c                 X    dj                  | j                        j                  dd      S )Nz{}/accumulator:_)formatr3   replacer   s    r*   r  r  b  s$    		 	 	-	5	5c3	??r,   c                 X     t         fd|D              xr t         fd|D              S )Nc              3   &   K   | ]  }|u  
 y wr'   r   rd   rS   r   s     r*   re   z%_is_loop_invariant.<locals>.<genexpr>h  s     *afk*   c              3   &   K   | ]  }|u  
 y wr'   r   r  s     r*   re   z%_is_loop_invariant.<locals>.<genexpr>i  s     +afk+r  )rU  )r   r   rT   s   `  r*   r  r  g  s)    
*6*
* ,
+7+
+-r,   c                    t        t        t        | j                                    }|D ],  }|s n(t	        j
                  |      }|j                  |      }. t        j                  | t        j                  t        |             y)zSets the list of resource inputs which are read-only.

  This is used by AutomaticControlDependencies.

  Args:
    op: While Operation.
    branch_graphs: List of branch FuncGraphs.
  N)setrangerg   r   acd*get_read_only_resource_input_indices_graphintersectionr   set_int_list_attrREAD_ONLY_RESOURCE_INPUTS_ATTRr  )r   branch_graphsread_only_indicesbranch_graphbranch_read_only_indicess        r*   r   r   l  s|     %BII/0# Ql"MM )667OPQ C>>013r,   )N
   NNTT)Kr  rA   tensorflow.core.frameworkr   tensorflow.python.clientr   r  tensorflow.python.eagerr   tensorflow.python.frameworkr   r  r   r   r
   rs   r   r   r   rK  r   r   r   tensorflow.python.opsr   r   r   r~  r   rl   r   r   r   r   r   r   r   r   r   tensorflow.python.utilr   r    r!   r"   r   RegisterGradientr  r   r   r   r   r
  r  r   r   r)  r   r   r  
namedtupler_  rw   r+  r~   r   r   r  r}   rH   r5   rQ   rn   r  r  r   r   r,   r*   <module>r     s    4 ? 1 F 3 . G 6 + < 4 3 3 + 2 > > 2 4 ; 0 2 * * 2 B ) ' 2 1 !%#%"&%)EP &'gqF3== qF  (qFh%FP(V+`	)$.CL$DN&R%PBJ !7 6 6# 	&
! b:d55 b:J	=M%N($V4
7 BI@
-
3CMM 3r,   