
    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Z%dZ&d Z'dId Z(dJd!Z) ejT                  d"       ejT                  d#      d$               Z+d% Z,	 	 	 dKd&e-d'e-fd(Z.d) Z/d* Z0d+ Z1d, Z2d- Z3d. Z4d/ Z5d0 Z6d1 Z7d2 Z8d3 Z9d4 Z:d5 Z;d6 Z<d7 Z=d8 Z>d9 Z?d: Z@d; ZAd< ZBd= ZCd> ZDd? ZEd@ ZF G dA dBej                        ZH	 	 dLdCZI ejT                  dD       ejT                  dE      dF               ZJ	 	 dMdGZKdH ZLy)Nzcond_v2 and gradient.

This is a version of cond that emits a single If op, as well as the gradient
function for If ops produced by cond_v2. This will eventually replace the
current tf.cond implementation once it reaches feature and performance parity.
    N)	types_pb2)backprop_util)context)auto_control_deps)auto_control_deps_utils)constant_op)dtypes)errors_impl
func_graph)indexed_slices)none_tensor)opstensor)tensor_shape)tensor_util)	type_spec)	array_ops)control_flow_util)control_flow_util_v2)default_gradient)gen_functional_ops)gen_optional_ops)gradients_util)handle_data_util)math_ops)nest      c                     t        j                  |       } t        j                  |       rA| j                  j
                  | j                  j
                  rt        j                  |       } | S )z+Normalize the predicate to a scalar tensor.)r   convert_to_tensorr   
is_tf_typeshapedimsr   
squeeze_v2)preds    M/home/dcms/DCMS/lib/python3.12/site-packages/tensorflow/python/ops/cond_v2.py_normalize_predr)   ?   sM    			t	$$D!
jjoo%D	+    c                    t        | t              rt        d|       |sd}t        j                  |      5 }t        j                  |d      }t        j                  |d      }t        j                         j                  }t        |       } t        j                  ||g i t        j                  |t        j                         j                        ||       }t        j                  ||g i t        j                  |t        j                         j                        ||       }	t        t        ||	g       t!        | ||	|j"                  |	j"                  d|      cd	d	d	       S # 1 sw Y   y	xY w)
z*Like tf.cond, except emits a single If op.pred must not be a Python boolcondtruefalsecollectionsr   add_control_dependenciesop_return_valueF)building_gradientnameN)
isinstancebool	TypeErrorr   
name_scopeutilunique_fn_nameget_default_graph_add_control_dependenciesr)   func_graph_modulefunc_graph_from_py_funcCondBranchFuncGraph_collectionsverify_captures_COND_build_condexternal_captures)
r'   true_fnfalse_fnr6   scope	true_name
false_namer3   
true_graphfalse_graphs
             r(   cond_v2rN   I   sL   d
4d
;;	D
~~d !u##E62I$$UG4J  #446PP4 D"::R++3#8#8#:#G#GI!9J $;;"b++C$9$9$;$H$HJ!9K EJ45$$%%3! ! !s   D'E''E0c                    t        | t              rt        d|       |sd}t        j                  |      5 }t        j                  |d      }t        j                  |d      }t        |       } t        j                  ||g i t        j                  |t        j                         j                        d|       }t        j                  ||g i t        j                  |t        j                         j                        d|       }t        t        ||g       t        | |||j                   |j                   ddd|		      cd
d
d
       S # 1 sw Y   y
xY w)a  Like cond_v2, except emits an If op and applies various optimizations.

  This function is intended to be used for cases where the cond is used to
  implement a simple conditional control flow operator. It makes the following
  assumptions:

  1. The conditional is never differentiated.
  2. The caller does not rely on V1 control flow semantics, i.e. for cross
     device execution, pruning subgraphs of the true or false branches, or
     non-strict evaluation order.
  3. The caller manually configures any control dependencies within the graphs.

  In this case, the cond will be lowered to a single If (or StatelessIf) op and
  the true and false graphs will be executed as TF functions.

  Args:
    pred: boolean Tensor
    true_fn: function to execute if pred is true
    false_fn: function to execute if pred is false
    name: the name for the If op.
    
  Returns:
    A list of Tensors which are the outputs of the If op. Does not include 
    intermediate outputs.
  r,   	fast_condr.   r/   r0   Fr2   T)r5   add_identitiesprevent_loweringr6   N)r7   r8   r9   r   r:   r;   r<   r)   r?   r@   rA   r=   rB   rC   rD   rE   rF   )	r'   rG   rH   r6   rI   rJ   rK   rL   rM   s	            r(   fast_cond_v2rS   u   sC   4 d
4d
;;	D
~~d 'u##E62I$$UG4J4 D"::

++3#8#8#:#G#G
 "'
J $;;

++C$9$9$;$H$H
 "'
K EJ45$$%%
;' ' 's   DEEStatelessIfIfc                    | j                   d   j                  }t        |      \  }}|j                  |j                  k(  sJ |j                  |j                  k(  sJ t        ||t        j                  |j                              }t        ||t        j                  |j                              }t        ||g||g       |j                  s|j                  rt        j                         r't        j                  t        j                                r,|j"                  }|j"                  }t%        ||g||g      \  }	}
n+|j&                  }|j&                  }t)        ||g||g      \  }	}
|j                   j+                  |	       |j                   j+                  |
       t-        t.        ||g       |xj                  dz  c_        |xj                  dz  c_        |j1                  dt        j2                  |             |j1                  dt        j2                  |             |j5                  d|j6                         |j9                  d|j:                         |j=                  |	D cg c]  }|j>                   c}|	D cg c]  }|j@                   c}       tC        ||      }tC        ||      }tE        t.        ||g       tG        |jH                  d   ||||d      }d	g|z   S c c}w c c}w )
z-The gradient of an If op produced by cond_v2.r   
_rewrittenthen_branchelse_branchToutoutput_shapesT)r5   N)%outputsopget_func_graphsouter_graphgraph_create_grad_funcr;   unique_grad_fn_namer6   _create_zeros_for_none_gradsop_needs_rewriter   optionals_in_gradients_enabledr   GraphOrParentsInXlaContextr   r=   xla_intermediates_make_intermediates_match_xlawrapped_intermediates_make_intermediates_matchextend_check_same_outputsrD   _set_func_attrcreate_new_tf_function_set_type_list_attroutput_types_set_shape_list_attrr[   _add_outputsdtyper$   _resolve_grad_inputs$_make_output_composite_tensors_matchrE   inputs)r]   gradsif_oprL   rM   true_grad_graphfalse_grad_graphtrue_intermediatesfalse_intermediatesextra_true_outputsextra_false_outputsttrue_grad_inputsfalse_grad_inputsr\   s                  r(   _IfGradr      s   
 **Q-

%+E2*k 
		5;;	..	.		 	 EKK	//	/
 &%11*//BD/&5$22;3C3CDF
 
K8 /1ABD &&*:*K*K 224778M8M8OP
 +<<,>>0M{
#&8:M%N1P-- +@@,BB0I{
#&8:M%N1P-- 0123
K89OO|#O$	(C(CJ(OP	44[AC	fj&=&=>	
0H0HI	,-Q-,-Q-/ **oF*;8HI 'u(79I'JL ll1o' '	- 	.-s   0K1	K6
c                     | j                   dk(  ry| j                   dk(  ry| j                   dk(  r| j                  d      ry| j                   dk(  r| j                  d      ry| j                  S )a  Check whether an op is stateful.

  This helper function handles two special cases to make the stateful analysis
  consistent with the mlir side effect analysis.
  1. GlobalIterIdOp should be stateless.
  2. CollectiveGatherV2 with attribute is_stateless to be True should be
     stateless.

  Args:
   op: Operation

  Returns:
    Boolean indicates whether the operation is stateless or not.
  GlobalIterIdF&UpdateFdoWithGlobalMinibatchStatisticsCollectiveGatherV2is_statelessCollectiveAllToAllV2)typeget_attr_is_stateful)r]   s    r(   _is_op_statefulr     sc    " WWWW88WW$$^)DWW&&2;;~+F	r*   rQ   rR   c	                 B    t        t        g       t        t        g       t        g||g      }	|st	        j
                         rt              }
t              }t        |
      }t        |      }t        g||g      \  }}j                  j                  |       j                  j                  |       t        t        g       t        j                  t        j                  j                        t        j                  j                        z         5  j!                         D cg c]  }t#        |      r| }}j!                         D cg c]  }t#        |      r| }}|s|rt$        j&                  nt$        j(                   fd}t	        j*                  ||	      }ddd       |r"D cg c]  }t-        j.                  |       }}t1              }t3        |      S c c}w c c}w # 1 sw Y   OxY wc c}w )a  Creates an If op from the specified predicate, branch functions and inputs.

  Note that this modifies true_graph and false_graph to make the inputs match,
  and to output all intermediates values so they're available for the gradient
  computation.

  true_graph and false_graph need not have the same input types, but they must
  have the same output types.

  Args:
    pred: boolean Tensor
    true_graph: FuncGraph
    false_graph: FuncGraph
    true_inputs: a list of Tensors to be passed to true_graph as input.
    false_inputs: a list of Tensors to be passed to false_graph as input.
    building_gradient: Whether this is a gradient If op.
    add_identities: If `True`, adds an identity op for each output of the If op.
      This is useful for pruning, but can be disabled if the caller does not
      want to rely on pruning and wants to avoid the overhead of extra identity
      ops in the graph.
    prevent_lowering: If `True`, prevents the If op from being lowered to
      V1 `Switch` and `Merge` ops.
    name: the name for the If op.

  Returns:
    A list of Tensors which are the outputs of the If op. Does not include added
    intermediate outputs.
  c                    t        j                   | 	j                  D cg c]  }|j                   c}t        j                  	      t        j                        t        	j                  j                                    \  }}t        |	j                  j                         |t        j                         	_	        t        j                         _	        	|_
        |_        t        j                  |rdnd        t        j                  |       t        |	g       s|j                  j!                  |       |S c c}w )Nr[   r6   F)r;   get_op_and_outputsr\   rs   rn   _get_output_shapes_copy_handle_datar   r=   r_   _true_graph_false_graphmaybe_set_lowering_attr*maybe_propagate_compile_time_consts_in_xla#_set_read_only_resource_inputs_attrr`   prevent_fetching)
rv   r   rx   tensorsrM   r6   op_fnr'   rR   rL   s
       r(   _make_opz_build_cond.<locals>._make_op  s   ..u

J$6$67q1777

%
%j
1

%
%k
2*:+=+=+6+>+>@0 neW !3!3[5H5HI 
	 "%!6!6!8
"%"7"7"9&($$U5EE4P77>+EJ3LM
++
&
&u
-n3 8s   EN)(_make_indexed_slices_indices_types_matchrD   rl   _make_inputs_matchr;   output_all_intermediates_get_intermediates_wrap_intermediatesrj   r\   rk   r   control_dependencieslistfunction_capturescontrolget_operationsr   r   _ifstateless_if"run_as_function_for_tape_gradientsr   identity'_get_compatible_structured_output_specs_pack_sequence_as)r'   rL   rM   true_inputsfalse_inputsr5   rQ   rR   r6   cond_inputsr{   r|   wrapped_true_intermediateswrapped_false_intermediatesr}   r~   r]   true_stateful_opsfalse_stateful_opsr   r   r   structured_output_specsr   s   ```    ``              @r(   rE   rE   5  s7   N +5:{2KLej+67 #J#<$/#>@+ 
t<<> ,J7,[9 "5Z5G"I"5k6I#K /H	[!	#%@A/C++ 0123
K89 
:''//04

'
'
/
/41 12 /M
 ++-2 	  ,,.2 	 
 	/ $$e --e : 55hLG_/Mv .56y!!!$6G6CJDOQ	2G	<<{
/M /Mx 7s1   ,H?HH'H;AHH
HHc           
          d fd	} j                   dv r0 | j                  d      d       | j                  d      d      fS  j                   dv rCt         j                  d            D cg c]  \  }} ||d	j                  |             c}}S t	        d
j                   j                               c c}}w )zReturns `FuncGraph`s for the input op branches.

  Args:
    op: The If or Case Operation.

  Returns:
    A tuple of the `FuncGraph`s of the then_branch and else_branch (all branches
    for Case).
  c                    d}|t        |d      }j                  dd }|:|D cg c]  }|j                   }}t        j                  || j
                        }t        ||j                        D ]  \  }}t        j                  ||        |j                  j                  ||j                         |_        |S c c}w )z7Generates and returns a FuncGraph for the given branch.Nr   )getattrrv   r$   r;   get_func_graphr6   zipr   copy_handle_datar   reset_captures_forward_cond)	name_attr_listcached_attr_namer   rv   r   input_shapes
external_t
internal_tr]   s	           r(   _get_func_graph_for_branchz3get_func_graphs.<locals>._get_func_graph_for_branch  s    J#2/6jYYqr]F'-.!agg.l.&&r<9L9LMj"%fj.?.?"@ @
J''
J?@  //
8I8IJ!J /s   C)rU   rT   rX   r   rY   r   )CaseStatelessCasebranches_branch_graph_{}zUnsupported op type: {}N)r   r   	enumerateformat
ValueError)r]   r   i	branch_fns   `   r(   r^   r^     s      WW%%&
M"M3&M*N<= = 
ww++ )"++j*A BD9 'y2D2K2KA2NO D D .55bgg>
??Ds   1"B;c                 `    t        j                  t        | j                  |j                        S )zGReturns the most specific compatible specs of graph structured outputs.)r   map_structure_get_compatible_specstructured_outputs)rL   rM   s     r(   r   r     s*    			0&99'::
< <r*   c                     t        |       }t        |      }|j                         j                  |j                         g      }|t        d| d| d      |S )a_  Returns the most specific compatible spec.

  Args:
    value_or_spec1: A TypeSpecs or a value that has a defined TypeSpec.
    value_or_spec2: A TypeSpecs or a value that has a defined TypeSpec.

  Returns:
    The most specific compatible TypeSpecs of the input.

  Raises:
    ValueError: If value_or_spec1 is not compatible with value_or_spec2.
  zNo common supertype of  and .)_get_spec_for_without_tensor_namesmost_specific_common_supertyper9   )value_or_spec1value_or_spec2spec1spec2commons        r(   r   r     sg     
'%

'% &&(GG""$%'&^
-eWE%B
CC	-r*   c                 d    t        | t        j                        r| S t        j                  |       S )zBReturns TypeSpec of a value or itself if it is a TypeSpec already.)r7   r   TypeSpectype_spec_from_value)value_or_specs    r(   r   r     s)    y112		'	'	66r*   c                 F   t        | j                        t        |      k(  sJ g }g }t        | j                  |      D ]=  \  }}t        j                  |      s|j                  |       |j                  |       ? t        j                  || j                  ||       }|S )a  The gradient function for each conditional branch.

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

  Args:
    func_graph: FuncGraph. The corresponding forward-pass function.
    grads: The list of input gradient Tensors.

  Returns:
    The output gradient Tensors.
  )grad_ys	src_graph)	lenr\   r   r   IsTrainableappendr   _GradientsHelperrv   )r   rw   ysr   ygrad_yresults          r(   _grad_fnr     s    $ 
Z	 CJ	..	.	"'z))51 ia$$Q'IIaLNN6	 ***

W& 
-r*   c           
      V     t        j                  | fdg i t        |             S )z1Returns the FuncGraph representation of _grad_fn.c                      t               S r   )r   )r   rw   s   r(   <lambda>z#_create_grad_func.<locals>.<lambda>8  s    hz5) r*   r   )r?   r@   _CondGradFuncGraph)r   rw   r6   s   `` r(   ra   ra   4  s*    		2	2
)2r#D*5
7 7r*   c                 >   g }|j                   D ]
  }|j                  |j                  k7  r|j                  | k(  sJ t        |j                  j                        D ].  \  }}||u s|j                  j
                  j                  |   } nb t        |j                  j                        D ]$  \  }}||u s|j                  j                   |   } n t        dj                  |            |j                  | j                  k(  sJ |j                  |        |S )a  Returns the tensors to pass as inputs to `grad_graph`.

  The `grad_graph` may have external references to
  1. Its outer graph containing the input gradients. These references are kept
     as is.
  2. Tensors in the forward pass graph. These tensors may not be "live"
     when the gradient is being computed. We replace such references by their
     corresponding tensor in `cond_graph.outer_graph`. In the case of nested
     control flow or functions, the gradient logic handling
     `grad_graph.outer_graph` will make sure the tensor from
     `cond_graph.outer_graph` is also correctly captured.

  Args:
    cond_graph: FuncGraph. The forward-pass function.
    grad_graph: FuncGraph. The gradients function.

  Returns:
    A list of inputs tensors to be passed to grad_graph.
  zFCould not find external tensor capture {tensor} in captures or outputsr   )
rF   r`   r_   r   r\   r   internal_capturesr   r   r   )
cond_graph
grad_graph
new_inputsr   r   outputs         r(   rt   rt   <  s"   ( *'' a 	ww*(((WW
""" !1 C)!VQ;gg##++A.!
C
 #177#<#<= 	CIAvq[))!,A	C
  117q1AC C WW
.....a36 
r*   c                    g }| j                         D ]o  }|j                  D ]^  }|| j                  v r|| j                  v r!|j                  t        j
                  u r>|j                  dk(  rN|j                  |       ` q |S )zFReturns intermediate tensors of `func_graph` for gradient computation.	MutexLock)r   r\   rv   rs   r	   resourcer   r   )r   intermediatesr]   r   s       r(   r   r   p  s    -%%' 	bZZ 	
j		
j  	 (	
FOO	#	K	1	 
r*   c           	          g }t        d |D              }t        |       D ]7  \  }}t        ||t        ||         z
        }|j	                  ||   |z          9 |S )a  Returns new optionals lists that have matching signatures.

  This is done by mirroring each list in the other using none optionals.
  There is no merging of like optionals.

  Args:
    branch_graphs: `list` of `FuncGraph`.
    branch_optionals: `list` of `list`s of optional `Tensor`s from other
      branch_graphs

  Returns:
    A `list` of `list`s of `Tensor`s for each branch_graph. Each list has the
    same number of `Tensor`s, all of which will be optionals of the same
    shape/type.
  c              3   2   K   | ]  }t        |        y wr   r   ).0os     r(   	<genexpr>z,_make_intermediates_match.<locals>.<genexpr>  s     <a3q6<   )maxr   _create_none_optionalsr   r   )branch_graphsbranch_optionalsnew_branch_optionalsintermediates_sizer   branch_graphother_optionalss          r(   rj   rj     sz       <+;<<"=1 Goa,(3/?/B+CCEO 0 3o EFG 
r*   c                     g }t        |       D ]Z  \  }t        |t        fdD        g             }t        d d D              }|j                  |d|    z   ||d z          \ |S )z4Like _make_intermediates_match but for the XLA case.c              3   0   K   | ]  }|   ur|  y wr    )r   bibranch_intermediatesr   s     r(   r   z0_make_intermediates_match_xla.<locals>.<genexpr>  s&      3B.q11  3s   c              3   2   K   | ]  }t        |        y wr   r   )r   r  s     r(   r   z0_make_intermediates_match_xla.<locals>.<genexpr>  s     CBBCr   N)r   _create_fakeparamssumr   )r  r  new_branch_intermediatesr  other_fakeparamsnum_precedingr   s    `    @r(   rh   rh     s    "=1 Foa) 3. 346	89 C*>r*BCCM##$4^m$D$8$;%<$4]^$D%E FF 
"!r*   c                    t        |       t        |      k(  sJ t               }g }|D ]E  }|D ]>  }t        j                  |      }||vs|j	                  |       |j                  |       @ G t        | |      D ]  \  }}|D cg c]  }t        j                  |       }	}t        t        |	|j                              }
g }|D ]E  }|
j                  t        j                  |            }|t        ||      }|j                  |       G ||_        |j                  j                  ||j                          |S c c}w )a  Modifies branch_graphs so they have the same input signature.

  This method reorders and/or adds parameters to each graph in branch_graphs so
  they have the same input signature, and updates the 'inputs' and 'captured'
  fields of each graph accordingly. It uses the input tensors from the outer
  graph to avoid duplicating shared arguments.

  Args:
    branch_graphs: a `list` of `FuncGraph`
    branch_inputs: a `list` of `list`s of `Tensor`s in the outer graph. The
      inputs for the corresponding graph in `branch_graphs`.

  Returns:
    A new list of Tensors from the outer graph that are the new inputs for each
    branch_graph. This is a deduped version of `sum(branch_inputs)`.
  )r   setr   	tensor_idaddr   r   dictrv   get_create_dummy_inputr   r   )r  branch_inputsadded_inputsr   	branch_inr   r  r  r   	input_idsbranch_input_to_param
input_listin_tparams                 r(   r   r     sM   " 
]	s=1	11	1,*  "i "--'i	,	&#&!	"" "%]M!B )lI+45aq!5I5 Y0C0C!DEJ #''d(;<e	#L$7	 %L ""11L''))  
 6s   E c                    t        |       t        |      k(  sJ |D cg c]  }|j                   }}|D cg c]  }t        |       }}t        t        |            dk(  sJ |       t        t	        |       D ]  \  }}t        d |D              st        d |D              s,t        |      D ][  \  }}	|		||   j                         5  t        j                  | |   j                  |         }
|
||   j                  |<   ddd       ]  |D ]6  }t        j                  |j                        D 	cg c]  }	|	|	 c}	|_        8 yc c}w c c}w # 1 sw Y   xY wc c}	w )zCreates zeros for None out grads if at least one branch has non-None grad.

  Args:
    forward_graphs: List of forward FuncGraphs.
    grad_graphs: List of grad FuncGraphs.
  r   c              3   $   K   | ]  }|d u  
 y wr   r
  r   r   s     r(   r   z/_create_zeros_for_none_grads.<locals>.<genexpr>  s     +!AI+   c              3   $   K   | ]  }|d u 
 y wr   r
  r$  s     r(   r   z/_create_zeros_for_none_grads.<locals>.<genexpr>  s     /aATM/r%  N)r   r   r  r   r   any
as_defaultr   
zeros_likerv   r?   flattenr\   )forward_graphsgrad_graphsgbranch_outputsoutsnum_outputs_per_branch
output_idxbranch_outsbranch_indexr   zerosr   s               r(   rc   rc     s~    
^	K 0	00	02=>QA((>.>2@A$CIAA	S'(	)Q	.F0FF	.!*3+?!@ Mj++{++/;//&{3 M/,9<(335 M$//|,33J?AEGLK%88DM MMM   j$,,Z-J-JK= 	
J ?AM Ms   EE8E7E#E c           	      :   |sJ |D cg c]  }|j                    }}t        d |D              }t        t        |            dk(  sJ |       t	        t        |       D ]  \  }}t        t        d |D                    dk(  r%t        d |D              s8t	        |      D ]  \  }}t        |t        j                        r!t        |t        j                        r8||   j                         5  t        j                  |      ||   |<   ddd       st        dj!                  | t"        k(  rdnd||	              t        ||      D ]7  \  }	}||	_         t%        j&                  |      D 
cg c]  }
|
|
	 c}
|	_        9 yc c}w # 1 sw Y   xY wc c}
w )
a  Modifies each branch_graph's outputs to have the same output signature.

  Currently the only transformation implemented is turning a Tensor into an
  equivalent IndexedSlices if the other branch returns an IndexedSlices.
  Updates branch_graph.{outputs,structured_outputs} for each branch_graph in
  branch_graphs.

  Args:
    op_type: _COND or _CASE
    branch_graphs: `list` of `FuncGraph`

  Raises:
    TypeError: if a set of outputs cannot be rewritten.
  c              3   2   K   | ]  }t        |        y wr   r   )r   r/  s     r(   r   z7_make_output_composite_tensors_match.<locals>.<genexpr>  s     A$CIAr   r   c              3   2   K   | ]  }t        |        y wr   )r   r   outs     r(   r   z7_make_output_composite_tensors_match.<locals>.<genexpr>  s     0StCy0r   c              3   P   K   | ]  }t        |t        j                           y wr   r7   r   IndexedSlicesr8  s     r(   r   z7_make_output_composite_tensors_match.<locals>.<genexpr>  s$      N:=
3445N   $&NzZCannot reconcile {op_name} {output_idx}-th outputs:
  outputs from all branches: {outputs}tf.condtf.switch_caseop_namer1  r\   )r   r   r   r  r   r   r'  r7   r   r<  
tensor_libTensorr(  r   _as_indexed_slicesr9   r   rD   r?   r*  r\   )op_typer  r-  r.  outputs_per_branchr1  r2  
branch_idx
branch_outr  r   s              r(   ru   ru     s   $ 
2?@QA((@.@A.AA	S#$	%	*>,>>	*!*3+?!@ &j+
30K001Q6 NALN N"+K"8 &
J	J < <	=j*"3"34:&113 	3;3N3N4.
$Z
0	 	 55;V%,%5	;K%# 6< 6%& 	&&&* $'}n#E lK&1L#$,,[9Q]L3 A	 	s   F0F0F8FFc                    |sJ g }d}|D cg c]#  }t        j                  |j                  d      % }}|D cg c]  }t        |       }}t        t	        |            dk(  sJ |       t        t        |       D ]  \  }}	t        t	        d |	D                    dk7  r(t        dj                  | t        k(  rdnd||		            t        |	d   t        j                        r|j                  |dz          t        j                  |	d         r'|t        t        j                  |	d   d
            z  }|	d   |dz  } |sy|t        |d   j                        k7  r&t!        d|t        |d   j                        fz        |D ]  t#        fd|D              r<t        dt%        |D 
cg c]  }
|
j                     j&                   c}
      z        t        t	        fd|D                    dk7  st|D ]  }|j                     j&                  t(        j*                  k(  s.|j-                         5  t/        j0                  |j                     t(        j2                        |j                  <   ddd         |D ]'  }t5        |j                  |j                        |_        ) yc c}w c c}w c c}
w # 1 sw Y   xY w)zAMatch dtype of IndexedSlices.indices in outputs of branch_graphs.r   Fexpand_compositesr   c              3   P   K   | ]  }t        |t        j                           y wr   r;  r8  s     r(   r   z;_make_indexed_slices_indices_types_match.<locals>.<genexpr>:  s%      $ sN889$r=  zUCannot reconcile tf.{op_name} {output_idx}-th outputs:
  branches returned: {outputs}r-   switch_caser@  TNzJInsufficient elements in branch_graphs[0].outputs.
Expected: %i
Actual: %ic              3      K   | ]=  }|j                      j                  t        j                  t        j                  fv ? y wr   )r\   rs   r	   int32int64r   bgindexs     r(   r   z;_make_indexed_slices_indices_types_match.<locals>.<genexpr>Y  s:      $ ::e""6<<*FF $s   AAz?Type of IndexedSlices.indices must be int32 or int64. Found: %sc              3   P   K   | ]  }|j                      j                    y wr   )r\   rs   rQ  s     r(   r   z;_make_indexed_slices_indices_types_match.<locals>.<genexpr>^  s      ?2rzz% &&?s   #&)r   r*  r   r   r  r   r   r9   r   rD   r7   r   r<  r   is_nested_or_compositer\   r   r'  strrs   r	   rO  r(  r   castrP  r   )rE  r  indexed_slice_indicescurrent_indexr  #branch_outputs_flat_with_compositesr/  outs_per_branchr1  r2  rR  rS  s              @r(   r   r   '  s   	- ()
 ll<22eL)% ) ,OO4SYO/O	S!	"a	'88	'!*	./"1 j+
 $"$ 	$% )**  77=v,3u,<&-%/"- 8> 8/0 0
 +a..">">?""=1#45"";q>2s4<<A$OPPm	Q	# qm'* 

 c-*2233
 " $Sq)9)A)A%BCD E E % ;e
 $"$ $ "]Kr2::e,22KLM N N 3???@AE' ;,&,,<&&( ;*2--$$U+V\\+;L  '; ;;; $ ?l&7'')=)='?L#?k) PR L; ;s   (J:J?4 K?K		Kc                     g }d}t        j                  | d      D ]/  }||j                  d       |j                  ||          |dz  }1 t        j                  | |      S )a  Packs the outputs of the gradient If/Case op.

  The branch functions may contain None's in the list of `structured_outputs`.
  `op_outputs` has those outputs missing. So we need to add those Nones to the
  list of `op_outputs` and then pack it in the same structure as
  `structured_outputs`.

  Args:
    structured_outputs: structured_outputs from one of the branch functions.
    op_outputs: List of output tensors of the op.

  Returns:
    `op_outputs` packed like `structured_outputs`.
  r   TrJ  Nr   )r   r*  r   r?   pack_sequence_as)r   
op_outputsoutputs_with_nonescounterr   s        r(   r   r   j  sv     '/4H f~%
7 34lg 
	+	+,>,>
@ @r*   c                     | j                         5  |D cg c]  }t        j                  |g       c}cd d d        S c c}w # 1 sw Y   y xY wr   )r(  r   optional_from_value)r   r   r   s      r(   r   r     sL     N?LM!00!5MN NMN Ns   A?AAAc                     | j                         5  t        j                  |j                  |j                        cddd       S # 1 sw Y   yxY w)zCreates tensors in func_graph to represent template_tensors.

  Args:
    func_graph: FuncGraph.
    template_tensor: a tensor in the outer graph.

  Returns:
    A tensor in func_graph.
  )r$   N)r(  r   placeholderrs   r$   )r   template_tensors     r(   r  r    sD      <  _%:%:<< < <s   +AAc                     | j                         5  t        |      D cg c]  }t        j                          c}cddd       S c c}w # 1 sw Y   yxY w)zCreates `n` `None` optionals in func_graph.

  Args:
    func_graph: FuncGraph.
    n: `int` the number of `None` optionals to make.

  Returns:
    A list of tensors in func_graph.
  N)r(  ranger   optional_none)r   n_s      r(   r  r    sN      @6;Ah?**,?@ @?@ @s   AAAAAc                     | j                   | S t        j                  | j                         D cg c]  }|dn|
 c}      S c c}w )a  Converts dynamic dimensions in `shape` to zero.

  The fake params created to match the intermediates captured in other branches
  could have dynamic dimensions. But the XLA shape is not able to handle
  dynamic dimensions in TF TensorShape. Setting the dynamic dimensions to
  size zero will help avoid failing safety checks in bridge. When XLA
  DynamicConditional op reconciles branch differences, XLA will replace the
  dimension size 0 with a bounded dimension determined from the shape of
  real argument in the other branch.

  Note: Rank unknown shapes are returned as they are.

  Args:
    shape: The TensorShape of fake param.

  Returns:
    The new TensorShape with dynamic dimensions set to zero.
  r   )rankr   TensorShapeas_list)r$   ds     r(   "_convert_dynamic_dimension_to_zerorp    sF    & ZZL		!	!&+mmo6AIq16
 6s   Ac           
          | j                         5  |D cg c]6  }t        j                  |j                  t	        |j
                              8 c}cddd       S c c}w # 1 sw Y   yxY w)z$Creates FakeParams for the XLA case.)rs   r$   N)r(  r   
fake_paramrs   rp  r$   )r   template_tensorsr   s      r(   r  r    sf     # "#  	%%''!CAGG!L	N## ### #s   A";AA"A""A+c                      fd}t        dt                    D ]  }	 t        j                  d   j                  |   j                  d        t        k(  rdnd}t        d   j                        t        |   j                        k7  rJt        d	j                  |t        d   j                        |t        |   j                        
            t        d   j                  |   j                        D ].  \  }}|j                  |j                  k7  s  |||d|d       0  y# t
        t        f$ r} ||t        |             Y d}~
d}~ww xY w)z3Raises an error if `graphs` have different outputs.c           
          t        dj                  t        k(  rdndt        k(  rdndj                  |       t        k(  rdndd   j                  |    j                  |	            )
Nz{b0_name} and {bn_name} arguments to {op_name} must have the same number, type, and overall structure of return values.

{b0_name} output: {b0_out}
{bn_name} output: {bn_out}

Error details:
{detail}rG   zbranches[0]rH   zbranches[{}]r>  r?  r   )b0_namebn_namerA  b0_outbn_outdetail)r9   r   rD   r   )rG  error_detailgraphsrE  s     r(   errorz"_check_same_outputs.<locals>.error  su    
	 6!(E!1I}#*e#3Z#**:6!(E!1I7G!9//*%88  !" "r*   r   r   TrJ  Nr-   casezuLengths of branch outputs of {op_type} must match.
len(graphs[0].outputs): {len_0}
len(graphs[{b}].outputs): {len_b}
)rE  len_0blen_br   z have different types)rg  r   r   assert_same_structurer   r   r9   rV  rD   r\   r   r   rs   )rE  r|  r}  r  eop_type_strrx  ry  s   ``      r(   rl   rl     sQ   "$ CK  Fa
  
)
&
&
)
&
& " $u,&&K
6!9VAY%6%6!77 ==CV#.!$VAY%6%6!7!$VAY%6%6!7	 >D >9: : fQi//1B1BC F		%aVVDEF%F 	" As1vs   2D88E$EE$c                      g }t        |  D ]G  }|d   j                  }|dd  D ]  }|j                  |j                        } |j                  |       I |S )Nr   r   )r   r$   most_specific_compatible_shaper   )branch_graph_outputsr[   out_by_branchr$   	other_outs        r(   r   r     sn    -01  m!""E"12& D	229??CeD	 
 
r*   c                    t        | g| D ]k  }|d   }|dd }g }|D ]N  }t        j                  |      }|j                  rt	        |j
                        dk7  r P|j                  |       P t        j                  d      }d}	|D ]  }t        j                  |j
                  d   j                        }
|j                  |
      }|	|j
                  d   j                  }	\|j
                  d   j                  |	k7  syt        j                  }	 |d   }|j
                  d   j                  j                  |j                                |	|j
                  d   _        t        j                   ||       n y)zGCombines shapes in handle data and sets metadata on `external_tensors`.r   r   N)r   r   get_resource_handle_datais_setr   shape_and_typer   r   rm  r$   r  rs   r   
DT_INVALIDCopyFromas_protoset_handle_data)external_tensorsr  r   externalinternalinternal_handle_datar   handle_datacombined_shapecombined_dtypehandle_shapecombined_handle_datas               r(   r   r     s   %=(<= GgqzHqr{H G$==fEk 3{'A'A#Ba#G!!+.G $//5nn- 
0+#//&&q)//1'FF!&55a8>>.''*00NB %//.
0 2!4))!,22;;

!
!
#%5C))!,2&&x1EF;Gr*   c           
         t        |      D ci c]  \  }}||
 }}}t        |      D ]  \  }}|j                  D ]  }t        |t        j                        r|j
                  |v s-| t        k(  rddgn0t        t        |            D cg c]  }dj                  |       c}}t        dj                  |j                  |||j
                        ||                 yc c}}w c c}w )zCVerify that a branch's tensor is not accessed in another branch fn.rG   rH   z	branch {}z5Tensor {tname} in {b0name} is accessed from {b1name}.)tnameb0nameb1nameN)r   rF   r7   r   EagerTensorr`   rD   rg  r   r   r   r6   )	rE  r  r   r-  other_branch_graphsr  r   r  branch_namess	            r(   rC   rC   %  s     +4M*BC$!QACC"=1 	)oa++ )3??+;N0N29U2B	:.-23}3E-FIH')Kr"IHCJJff#$7$@A#A K () 	)	)	) DIHs   C%C+c                   L     e Zd ZdZ fdZed        Zed        Z fdZ xZ	S )r   a]  FuncGraph for the gradient function of the branch of an If op.

  Handles wrapping and unwrapping intermediate values that are captured by the
  gradient computation in optionals.

  Attributes:
    op_needs_rewrite: True if any intermediates were captured, meaning the
      forward If op needs to be written to output the wrapped intermediates.
  c                     t         t        |   |t        j                         j
                         d| _        || _        i | _        t        j                         | _        g | _        i | _        y )Nr0   F)superr   __init__r   r=   rB   rd   _forward_graph_indirect_capturesr1   OrderedDict_wrapped_intermediates_xla_intermediates_captured_constants)selfr6   forward_graph	__class__s      r(   r  z_CondGradFuncGraph.__init__C  sn    	
d,#//1>> - @!D'D !D #."9"9";D !D  "Dr*   c                 H    t        | j                  j                               S )zCThe optional-wrapped intermediates captured from the forward graph.)r   r  valuesr  s    r(   ri   z(_CondGradFuncGraph.wrapped_intermediatesU  s     ++22455r*   c                     | j                   S )zDRaw intermediates captured from the forward graph if XLA is enabled.)r  r  s    r(   rg   z$_CondGradFuncGraph.xla_intermediatesZ  s     """r*   c           	        
 j                   | j                  usPt        fd| j                  j                  D              s(t        fd| j                  j                  D              rt
        t        |   |      S t        j                        }|| j                  v r| j                  |   S t        j                        rPt        j                  t        j                        j                         | j                  |<   | j                  |   S t#        j$                         r't'        j(                  t        j*                               rTt-        fd| j.                  D              r"| j0                  j3                         d| _        t
        t        |   |      S | j6                  j9                  |      }||S j                   t:        j<                  k(  rt?        j@                  jB                  | j                  j                  D cg c]  }|jB                   c}| j                  jE                         D ci c]  }|jB                  |jF                   c}| j                  jH                        }t
        t        |   | j                  j                  |   |      }n|| jJ                  vrjM                         D ]K  

jN                  dk(  st        
fd| j                  j                  D              s<
j                  d   } nA | j                  jQ                         5  tS        jT                  g      }d d d        d| _        | jJ                  |<   | jJ                  |   }t
        t        |   ||      }	tS        jV                  |	j                   gjX                  g      d   }|| j6                  |<   |S c c}w c c}w # 1 sw Y   xY w)	Nc              3   &   K   | ]  }|u  
 y wr   r
  r   r   r   s     r(   r   z5_CondGradFuncGraph._capture_helper.<locals>.<genexpr>a  s     <AFaK<   c              3   &   K   | ]  }|u  
 y wr   r
  r  s     r(   r   z5_CondGradFuncGraph._capture_helper.<locals>.<genexpr>b  s     =AFaK=r  )rs   c              3   &   K   | ]  }|u 
 y wr   r
  )r   capturer   s     r(   r   z5_CondGradFuncGraph._capture_helper.<locals>.<genexpr>v  s     IwV7"Ir  TOptionalFromValuec              3   @   K   | ]  }j                   d    |u   yw)r   N)r\   )r   r   consumers     r(   r   z5_CondGradFuncGraph._capture_helper.<locals>.<genexpr>  s)      = ""1%/ =s   r   )-r`   r  r'  rv   r\   r  r   _capture_helperr   r  r  r   is_constantconstantr   constant_valuers   r   re   r   rf   r=   allrF   rg   r   rd   r  r  r	   r   r;   resource_input_indexr6   r   node_def
_functionsr  	consumersr   r(  r   rb  optional_get_valuer$   )r  r   r6   r  captured_tensorr   r]   rS  optionalcaptured_optionalr  r  s    `        @r(   r  z"_CondGradFuncGraph._capture_helper_  sM   D///<!4!4!;!;<<=!4!4!<!<==%t<VTJJf%I D,,,%%i00		 	 	(,7,@,@

$
$V
,FLL-Bdy)%%i00 224778M8M8OP 
I$2H2HI	I%%f- $%t<VTJJ--11)<O" ||v&''
++(;(;(B(BC1C*.*=*=*L*L*N
OB277BKK
O



(
(*e 0$G



$
$U
+T3o 
$55	5 ((* 
	'Hmm22 = $ 3 3 ; ;= =''*H
	' ""--/ F';;VHEHF"&$
19##I.,,Y7h 2 $66>&E (;;
fll^fll^	o *9DI&A D
O$F Fs   O
O2OO)
__name__
__module____qualname____doc__r  propertyri   rg   r  __classcell__)r  s   @r(   r   r   8  sA    "$ 6 6 # #J Jr*   r   c                    t        | t              rt        d|       t        j                  |      5 }t        t        |            D cg c]'  }t        j                  |dj                  |            ) }}t        j                         j                  }t        j                  | d      } g }t        ||      D ]a  \  }	}
|j                  t        j                   |	|
g i t        j"                  |	t        j                         j$                        ||              c t'        t(        |       t+        | ||D cg c]  }|j,                   c}||      cddd       S c c}w c c}w # 1 sw Y   yxY w)	z6Like conv_v2, except emits a Case op instead of an If.z%branch_index must not be a Python intzbranch{}r3  )r6   r0   r2   r6   lower_using_switch_mergeN)r7   intr9   r   r:   rg  r   r;   r<   r   r=   r>   r"   r   r   r?   r@   rA   rB   rC   _CASE_build_caserF   )r3  
branch_fnsr6   r  rI   r  r  r3   r  branch_namer   r-  s               r(   indexed_caser    s`   
 c"
;\
JJ
~~d ;u s:' 	E:#4#4Q#78L   #446PP((NKLM"%lJ"? -Y

3
311!335BBD (@*	,
-- E=)]C++C!9	;5; ;6 D9; ;s*   E)	,E5CE)9E$	E)
E))E2r   r   c           
         | j                   d   j                  }t        |      }|sJ |D ]  }|j                  |j                  k(  rJ  g }|D ];  }|j                  t        ||t        j                  |j                                     = t        ||       t        d |D              rt        j                         r't        j                  t!        j"                               r&|D cg c]  }|j$                   }}t'        ||      }n%|D 	cg c]  }	|	j(                   }
}	t+        ||
      }t-        ||      D ]   \  }}|j                   j/                  |       " t1        t2        |       |D ]  }|xj                  dz  c_	         |j5                  d|D cg c]  }t        j6                  |       c}       |j9                  d|d   j:                         |j=                  d|d   j>                         |jA                  |d   D cg c]  }|jB                   c}|d   D cg c]  }|jD                   c}       t-        ||      D cg c]  \  }}tG        ||       }}}tI        t2        |       	 |jK                  d      }tQ        |jR                  d   ||d	|
      }dg|z   S c c}w c c}	w c c}w c c}w c c}w c c}}w # tL        jN                  $ r d}Y Yw xY w)z5The gradient of a Case op produced by tf.switch_case.r   c              3   4   K   | ]  }|j                     y wr   )rd   )r   r-  s     r(   r   z_CaseGrad.<locals>.<genexpr>  s     8		8s   rW   r   rZ   r[   _lower_using_switch_mergeNgradientr  )*r\   r]   r^   r_   r`   r   ra   r;   rb   r6   rc   r'  r   re   r   rf   r   r=   rg   rh   ri   rj   r   rk   rl   r  _set_func_list_attrrn   ro   rp   rq   r[   rr   rs   r$   rt   ru   _get_attr_boolr
   NotFoundErrorr  rv   )r]   rw   case_opr  r  branch_grad_graphsbranch_grad_graphbranches_intermediatesextra_branch_outputsr-  r  extra_outputsr   branches_grad_inputsloweringr\   s                   r(   	_CaseGradr    s   
 JJqM'!'*-	 $ 5l##w}}4445 # Hl,22<3D3DE	GHH }.@A8%788 224778M8M8OP $6  
-
-    ;
/1 ,>&'!
!
!  7}7KM (+=:N'O 1#m!!-01 }-% (<'( 
)- 	##L1-  a(8(E(EF  !.q!1!?!?A+?+BCa!''C+?+BCa!''CE }.@AA <):;  'u.@A%%&ABH nnQ')' '	o - DC 
	"	" Hs6   +J3J8J=
K,K
K?K K*)K*c           	          t        t               t        t               t        |      }g }D ]E  }|j	                  |j                         D cg c]  }t        j                  |      s| c}       G |rt        j                  nt        j                  t        j                  t        d D        g             5   fd}	t        j                  |	|      }
ddd       
D cg c]  }t!        j"                  |       }
}t%        d   j&                  |
      S c c}w # 1 sw Y   IxY wc c}w )a  Creates an `Case` op from `branch_index`, branch graphs and inputs.

  Note that this modifies `branch_graphs` to make the inputs match, and to
  output all intermediates values so they're available for the gradient
  computation.

  `branch_graphs` need not have the same input types, but they must
  have the same output types.

  Args:
    branch_index: integer Tensor
    branch_graphs: List of FuncGraph
    branch_inputs: List of lists of Tensors to be passed to corresponding
      branch_graph as input.
    name: the name for the Case op.
    lower_using_switch_merge: Lower this op using switch merge ops (optional).

  Returns:
    A list of Tensors which are the outputs of the Case op. Does not include
    added intermediate outputs.
  c              3   Z   K   | ]#  }t        |j                  j                         % y wr   )r   r   r   )r   rR  s     r(   r   z_build_case.<locals>.<genexpr>e  s!     
F"4$$,,-
Fs   )+c                    t        j                   | d   j                  D cg c]  }|j                   c}D cg c]  }t        j                  |       c}t        D cg c]  }|j                   c} 
            \  }}t        |gD cg c]  }|j                   c}  |t        j                  |	       t        j                  |       t        |       |j                  j                  |       t              D ]:  \  }}t        j                         |_        t!        |dj#                  |      |       < |S c c}w c c}w c c}w c c}w )Nr   r   r   )r;   r   r\   rs   rn   r   r   r   r   r   r`   r   r   r   r=   r_   setattrr   )rv   r   r-  r  r   r   rR  r  r3  r  r6   r   s          r(   r   z_build_case.<locals>._make_opg  s*   00

M!$4$<$<=q177=3@
Aa4&&q)
A*,N1QYY,NO2 gw Em"D199"DE		$$W.FG77@+G]C&&w/ }- 	=EAr002".
'-44Q7
<	= n% >
A,N"Ds   EE&EE
Nr   )r   r  rl   r   rk   r   r   op_is_statefulr   r~  stateless_caser   r   r  r;   r   r   r   r   r   )r3  r  r  r6   r  case_inputsstateful_opsrR  r]   r   r   r   r   s   `` ``       @r(   r  r  7  s*   4 +5-@e]+ #=-@+, b&&(,=,L,LR,P 
 ##E--E 	
F
FKM M , 55hLG3MF -44qY"4'4	=+>>	HH_M MF 5s   D*
1D*
 D/3D;/D8c                    t        t        t        | j                        dz
              }|D ]a  }t        |j                        t        | j                        dz
  k(  sJ d       |s n(t	        j
                  |      }|j                  |      }c |D cg c]  }|dz   	 }}t        j                  | t        j                  t        |             yc c}w )zSets the list of resource inputs which are read-only.

  This is used by AutomaticControlDependencies.

  Args:
    op: If or Case Operation.
    branch_graphs: List of branch FuncGraphs.
  r   zshould never happenN)r  rg  r   rv   acd*get_read_only_resource_input_indices_graphintersectionr   set_int_list_attrREAD_ONLY_RESOURCE_INPUTS_ATTRsorted)r]   r  read_only_indicesr  branch_read_only_indicesr   s         r(   r   r     s     %BII 234# Ql|""#s299~'99P;PP9"MM )667OPQ '88q1u88C>>013 9s   C)r-   r   )TFN)r  N)NN)Mr  r1   tensorflow.core.frameworkr   tensorflow.python.eagerr   r   tensorflow.python.frameworkr   r   r  r   r	   r
   r   r?   r   r   r   r   rB  r   r   r   tensorflow.python.opsr   r   r   r;   r   r   r   r   r   r   tensorflow.python.utilr   rD   r  r)   rN   rS   RegisterGradientr   r   r8   rE   r^   r   r   r   r   ra   rt   r   rj   rh   r   rc   ru   r   r   r   r  r  rp  r  rl   r   r   rC   rA   r   r  r  r  r   r
  r*   r(   <module>r      s    / 1 + 9 F 3 . 3 G 6 3 + < 4 3 1 + 3 > 2 4 2 0 2 * ' 	
	)XGT m$dU  %UpF  "	I= I= I=X$@N<07#L71h 6"+\80f@?F@6N
<@ 6#)FXGD)&q11 ql %*.&;R fo&] ' ]F )-	RIj3r*   