
    Vhl                     4   d dl Z d dlZd dlZd dlmZmZmZmZ d dlZd dl	Zd dl
mc mZ d dlmZ d dlmZmZmZmZ d dlmZ d dlmZ d dlmZmZmZmZmZmZm Z m!Z!m"Z"m#Z# d dl$m%Z% d d	l&m'Z'm(Z( d d
l	m)Z) d dl*m+Z+m,Z,m-Z-m.Z.m/Z/ d dl0m1Z1 ddlm2Z2m3Z3m4Z4  ejj                  e6      Z7	  G d de%      Z8 e8       Z9 ed      	 d,dee:e;e<ejz                  f   dededee>e?f   def
d       Z@d ZAd ZBe9j                  ej                        d        ZE G d dej                  j                        ZHe9j                  ej                        d        ZJe9j                  e.      d        ZKe9j                  e(      d        ZLd ejz                  d!ejz                  d"e>eMd#f   d$eMddf
d%ZNd&eejz                     d'eejz                     d(e(fd)ZOe9j                  d*        ZQe9j                  ej                  j                  j                  j                        d+        ZVy)-    N)AnyCallableOptionalUnion)DispatchKey)_add_batch_dimget_unwrappedis_batchedtensormaybe_get_bdim)suspend_functionalization)
exposed_in)
!_has_potential_branch_input_alias$_has_potential_branch_input_mutation_maybe_run_with_interpreter_set_compilation_envreenter_make_fx%save_tensors_and_symints_for_backwardsaved_tensors_and_symintsunique_graph_id!UnsupportedAliasMutationExceptionvalidate_subgraph_args_types)HigherOrderOperator)
FakeTensorFakeTensorMode)disable_functional_mode))_temp_remove_metadata_torch_function_mode-_temp_remove_pre_dispatch_torch_function_modedisable_proxy_modes_tracingProxyTorchDispatchModetrack_tensor_tree)_get_current_dispatch_mode   )	_from_fun _maybe_fake_prop_ignore_unbackedcreate_fw_bw_graphc                   (     e Zd Z fdZ fdZ xZS )CondOpc                 $    t         |   d       y )Ncond)super__init__)self	__class__s    L/home/dcms/DCMS/lib/python3.12/site-packages/torch/_higher_order_ops/cond.pyr+   zCondOp.__init__8   s         c                 >    t        |       t        | 	  ||||      S N)r   r*   __call__)r,   predtrue_fnfalse_fnoperandsr-   s        r.   r2   zCondOp.__call__;   s!    $X.wgxBBr/   )__name__
__module____qualname__r+   r2   __classcell__)r-   s   @r.   r'   r'   7   s    !C Cr/   r'   torchr3   r4   r5   r6   returnc           
      h   t         j                  j                         rt        | |||      S ddlm} t        | t        t        t        f      rDt         j                  j                         rt        j                  dt               | r || S  || S d } || |||       t         j                  j                         st!        d      d }t#               5  t         j                  j$                  j'                         5  t)               5  t+               5 }|r	 ||      }nd} t        j,                  ||d	      | |||      cd
d
d
       cd
d
d
       cd
d
d
       cd
d
d
       S # 1 sw Y   nxY w	 d
d
d
       n# 1 sw Y   nxY wd
d
d
       n# 1 sw Y   nxY wd
d
d
       y
# 1 sw Y   y
xY w)a
  
    Conditionally applies `true_fn` or `false_fn`.

    .. warning::
        `torch.cond` is a prototype feature in PyTorch. It has limited support for input and output types and
        doesn't support training currently. Please look forward to a more stable implementation in a future version of PyTorch.
        Read more about feature classification at: https://pytorch.org/blog/pytorch-feature-classification-changes/#prototype

    `cond` is structured control flow operator. That is, it is like a Python if-statement,
    but has restrictions on `true_fn`, `false_fn`, and `operands` that enable it to be
    capturable using torch.compile and torch.export.

    Assuming the constraints on `cond`'s arguments are met, `cond` is equivalent to the following::

        def cond(pred, true_branch, false_branch, operands):
            if pred:
                return true_branch(*operands)
            else:
                return false_branch(*operands)

    Args:
        pred (Union[bool, torch.Tensor]): A boolean expression or a tensor with one element,
          indicating which branch function to apply.

        true_fn (Callable): A callable function (a -> b) that is within the
          scope that is being traced.

        false_fn (Callable): A callable function (a -> b) that is within the
          scope that is being traced. The true branch and false branch must
          have consistent input and outputs, meaning the inputs have to be
          the same, and the outputs have to be the same type and shape.

        operands (Tuple of possibly nested dict/list/tuple of torch.Tensor): A tuple of inputs to the
          true/false functions. It can be empty if true_fn/false_fn doesn't require input. Defaults to ().

    Example::

        def true_fn(x: torch.Tensor):
            return x.cos()
        def false_fn(x: torch.Tensor):
            return x.sin()
        return cond(x.shape[0] > 4, true_fn, false_fn, (x,))

    Restrictions:
        - The conditional statement (aka `pred`) must meet one of the following constraints:

          - It's a `torch.Tensor` with only one element, and torch.bool dtype

          - It's a boolean expression, e.g. `x.shape[0] > 10` or `x.dim() > 1 and x.shape[1] > 10`

        - The branch function (aka `true_fn`/`false_fn`) must meet all of the following constraints:

          - The function signature must match with operands.

          - The function must return a tensor with the same metadata, e.g. shape,
            dtype, etc.

          - The function cannot have in-place mutations on inputs or global variables.
            (Note: in-place tensor operations such as `add_` for intermediate results
            are allowed in a branch)

    r   )+make_eager_backend_with_torch_function_modezPred is a Python constant. When used with torch.cond, it specializes on one of the branches. If you want torch.cond to preserve two branches, please make the predicate a boolean tensor or a SymBool.c                    t        | t        t        j                  t        j                  f      st        d|  d      t        | t        j                        r"| j                         dk7  rt        d|  d      t        |      rt        |      st        d      t        |t        t        f      rt        j                  d |      rt        d| d      y )Nz,Expected pred to be bool or tensor, but got .r"   z;Expected pred to be bool or single-element tensor, but got z$Expect both branches to be callable.c                 8    t        | t        j                         S r1   
isinstancer;   Tensorts    r.   <lambda>z/cond.<locals>._validate_input.<locals>.<lambda>   s    *Q55 r/   znExpect operands to be a tuple of possibly nested dict/list/tuple that only consists of tensor leaves, but got )rC   boolr;   rD   SymBoolRuntimeErrornumelcallabletuplelistpytreetree_any)r3   r4   r5   r6   s       r.   _validate_inputzcond.<locals>._validate_input   s    $u||U]] CD!MdVSTUVVdELL)djjla.?MdVSTU   (:EFF(UDM2foo5x7
 66>ZqB 7
r/   z#torch.cond requires dynamo support.c                      t        | i |S r1   )cond_op)argskwargss     r.   _cond_op_wrapperzcond.<locals>._cond_op_wrapper   s    '''r/   eagerT)backend	fullgraphN)r;   compileris_dynamo_compilingrS    torch._dynamo.backends.debuggingr>   rC   rH   intfloatis_compilingwarningswarnUserWarning_dynamois_dynamo_supportedrJ   r   utilsdisable_cache_limitr   r   compile)	r3   r4   r5   r6   r>   rQ   rV   metadata_moderX   s	            r.   r)   r)   C   s   J ~~))+tWh99 $sE*+ >>&&(MM} H%%X&&( D'8X6==,,.@AA( 
	 !4!4!H!H!J LyL{ 68 	MEmT!S5==!17dSgx	 	   	 	 	        s`   )F(?F
E>.E(		E>	F	F((E1-E>5	F>FF
	F(F	F((F1c                    t               5  t               5  t               5  t        j                  t
        |      }t        j                  t
        t        | |            }t        d |D              r&t        d|D cg c]  }t        |       c} d      t        j                  t
        t        ||            }t        d |D              r&t        d|D cg c]  }t        |       c} d      t        | d||      \  }}t        |d||      \  }	}
d d d        	
fcd d d        cd d d        S c c}w c c}w # 1 sw Y   +xY w# 1 sw Y   nxY wd d d        y # 1 sw Y   y xY w)Nc              3   V   K   | ]!  }|t        |t        j                          # y wr1   rB   .0outs     r.   	<genexpr>z.create_fw_bw_graph_branches.<locals>.<genexpr>   +      ? sELL11   ')zFExpect outputs of true_fn to only contains tensors or None. Got types r@   c              3   V   K   | ]!  }|t        |t        j                          # y wr1   rB   rk   s     r.   rn   z.create_fw_bw_graph_branches.<locals>.<genexpr>   ro   rp   zGExpect outputs of false_fn to only contains tensors or None. Got types F)r   r   r   rO   tree_mapr#   r$   anyrJ   typer%   )r4   r5   r6   	fw_inputsfw_outputs_truerm   fw_outputs_falsefw_true_graphjoint_true_graphfw_false_graphjoint_false_graphs              r.   create_fw_bw_graph_branchesr|      s    
#	$ 'R&=&? 'R(* $		8<I$oo;GYOO  * 
 #!7F!G$s)!G HK   &;HiP   + 
 #!7G!H$s)!H IL  /A	?/+M+ 1C%,<1-N-E$	L n.>@QQO'R 'R 'R "H "I3$	 $	'R 'R 'R 'R 'RsY   E!EAE <D6A
E D;*,E E#	E!6
E  E	EE	E!!E*c                 ~   t        |t        t        f      s
J d|         t        |      | } t        |      | }g }g }	|j                  j
                  D ]-  }
|
j                  dk(  s|j                  |
j                         / |j                  j
                  D ]-  }
|
j                  dk(  s|	j                  |
j                         / t        j                  | }t        j                  |	 }t        |      t        |      k7  rBt        j                  j                  j                  dt        |       dt        |       d      t!        | d      \  }}d| }t#        | j$                  j&                  |      rJ | j$                  j&                  j)                  ||       | j$                  j&                  j)                  ||       ||||f}t        j*                  | j$                  j,                  |      }| j$                  j/                  d	||i       } |||||      }t1        ||d | j$                  
      S )Nz=Cond operands must be a list or tuple of tensors and SymInts outputzIExpected to return same number of outputs but got:
  true branch returns z  item(s)
  false branch returns z item(s)
true_graph)prefixfalse_graph_call_function)constanttracer)rC   rN   rM   r   graphnodesopextendrT   rO   arg_tree_leaveslenr;   rc   excCondOpArgsMismatchErrorr   hasattrr   rootregister_modulerr   unwrap_proxycreate_proxyr    )
proxy_modefunc_overloadr3   r4   r5   r6   r   false_graph	true_outs
false_outsnodeflat_true_outsflat_false_outsi	true_name
false_namerT   
proxy_args	out_proxyrm   s                       r.   
trace_condr      s-   4- R	FxjQR  *)84J+/(+X6KIJ  && (77hTYY'( !!'' )77hdii() ++Y7N,,j9O
>c/22mm77''*>':&; <((+O(<'=XG
 	
 #:lCLAys#Jz((--z:::**9jA**:{C*k84D!2!2!?!?FJ!!..
BI j+x
@CS)d:CTCTUUr/   c                 x    t        d |D              s
J d|        t               }|J d       | r || S  || S )Nc              3   \   K   | ]$  }t        |t        j                  t        f       & y wr1   )rC   r;   rD   r]   )rl   os     r.   rn   z cond_op_dense.<locals>.<genexpr>&  s%      /0
1u||S)*s   *,zADense implementation operands must be a list of tensors and ints z-Mode should never be enabled for CPU/CUDA key)allr!   )r3   r4   r5   r6   modes        r.   cond_op_denser   $  se     4<  V	J8*UV  &'D<HHH<!!""r/   c                   ,    e Zd Zed        Zed        Zy)CondAutogradOpc                     || _         || _        || _        t        | |       t        j
                  j                         5  t        ||||      cd d d        S # 1 sw Y   y xY wr1   )_pred_joint_true_graph_joint_false_graphr   r;   _C_AutoDispatchBelowAutogradrS   )ctxr3   rx   rz   ry   r{   r6   s          r.   forwardzCondAutogradOp.forward2  s\     	 0!2-c8<XX002 	J4I	J 	J 	Js    AA!c                     t        |       }t        | j                  | j                  | j                  ||z         }d d d d d g|S r1   )r   rS   r   r   r   )r   
flat_gradsr6   gradss       r.   backwardzCondAutogradOp.backwardD  sO    ,S1II!!""!	
 T4t3e33r/   N)r7   r8   r9   staticmethodr   r    r/   r.   r   r   1  s*    J J" 	4 	4r/   r   c                 2   t        j                  t        j                  d | |f      r6t        j                  j                         5  t        | |||      cd d d        S t        ||g| \  }}}}t        j                  | ||||g| }|S # 1 sw Y   7xY w)Nc                     | j                    S r1   )requires_gradrE   s    r.   rG   zcond_autograd.<locals>.<lambda>W  s    aoo% r/   )
rO   tree_all_onlyr;   rD   r   r   rS   r|   r   apply)	r3   r4   r5   r6   rx   rz   ry   r{   flat_outs	            r.   cond_autogradr   Q  s     %	x
 XX002 	>4(H=	> 	> 	$GXAA## 
H O#	> 	>s   BBc                 *    t        | t        ||||      S r1   )r   rS   )r   r3   r4   r5   r6   s        r.   innerr   n  s    dGT7HhGGr/   c           	         t        j                         }| j                  r| j                  j                         }| 5  |5  t	        j
                   ||       \  }}t	        j
                   ||       \  }}	||	k7  rt        d| d|	 d      	 d d d        d d d        g }
t              D ]!  \  }}|
j                  t        |||              # t	        j                  |
      S # 1 sw Y   YxY w# 1 sw Y   ]xY w)NzFUnmatched output spec from torch.cond branches: true branch tree_spec z vs false branch tree_spec r@   )
contextlibnullcontext	shape_envignore_fresh_unbacked_symbolsrO   tree_flattenrJ   zipappend_merge_tensorstree_unflatten)r   r3   r4   r5   r6   ignore_fresh_unbackedr   true_out_specr   false_out_specmerged_outstrue_out	false_outs                r.   cond_fake_tensor_moder   s  s    '224~~ $ L L N	 $ (.(;(;GX<N(O%*0*=*=h>Q*R'N*))67RSaRbbce  +  K">?C F)>(ItDEF  m<<   s$   C3 AC'C3'C0	,C33C<t1t2
attr_names.
msg_prefixc                     dt         j                  dt        dt        fd}|D ]3   ||        ||      t        j                  k(  fd       5 y )NrF   	attr_namer<   c                 B    t        | |      }t        |      r |       S |S r1   )getattrrL   )rF   r   attrs      r.   _get_attr_maybe_callz5check_tensor_meta_match.<locals>._get_attr_maybe_call  s!    q)$D>6Mr/   c                        d  d d dS )Nz expected same z	 but got z and r@   r   )r   lattrr   rattrs   r.   rG   z)check_tensor_meta_match.<locals>.<lambda>  s#    zl/)IeWERWQXXYZ r/   )r;   rD   strr   _check)r   r   r   r   r   r   r   r   s      ` @@@r.   check_tensor_meta_matchr     s`          
	$R3$R3UNZ	

r/   abr   c                 Z   ddl m} | || |	J | |f       y t        |       t        u rt        |      t        u sJ | t        |       |t        |      f       h d}t	        | |t        |      d       | j                  s|j                  rJ | j                  s|j                  rJ | j                         s|j                         rJ 	 g }t        | j                         |j                               D ]  \  }} ||       ||      k(  r|j                  |       )fd}j                  J j                  j                         }	 j                  j                  |	j                  j                   g |||        |j                  |	        	 dt"        j$                  dt"        j$                  d	t
        t&        d
f   dt
        t&        d
f   dt(        t*        t&        t"        j,                  f      dt(        t*        t&        t"        j,                  f      ffd}
 |
| j                         |j                         | j/                         |j/                         |      }5  t#        j0                  ||| j2                  | j4                        cd d d        S # 1 sw Y   y xY w)Nr   )SymIntEqByExpr>   dimdtypedevicelayoutis_conj	is_sparseis_quantizedstorage_offsetz1When merging two branches' output in torch.cond, )r   c                     dt         ffd}t         || d       ||d            t         || d       ||d            fS )Nlower_boundc                 D   t        | t              r| S j                  j                  j	                  | j
                  j                  t        j                  j                  j                  j                  j                               }|r|j                  S |j                  S r1   )rC   r]   r   var_to_rangegetr   exprr;   re   _sympyvalue_rangesValueRangesunknownlowerupper)s0r   rr   s      r.   _boundz/_merge_tensors.<locals>.min_max.<locals>._bound  sp    !"c*!	3377**77CCKKMA '2177>qww>r/   TF)rH   minmax)r   s1r   r   s      r.   min_maxz_merge_tensors.<locals>.min_max  sN    ?D ? 6"d+VB-=>2u%vb%'8A  r/   	a_ex_size	b_ex_sizea_ex_stride.b_ex_stridemerged_sizer<   c                    ddl m}  ||j                        } ||j                        }d gt        |      z  }d gt        |      z  }	t	        |      D ]  \  }
}||
   |
 f||<    t	        |      D ]  \  }
}||
   |
 f|	|<    t        ||	      D ],  \  }}||J |\  }}|\  }}||k7  st        d| d| d       dt        t        t        j                  f   fd}i }i }d gt        |      z  }t        ||	      D ]  \  }}||J |\  }}|\  }}| }
|dk(  r|dk(  s	J ||f       d||
<   2 ||      |v r,| ||         }| ||         |k(  sJ d| d	|        |||
<   n@|d
k(  r#|d
k(  sJ d
| ||      <   d
| ||      <   d
||
<   nt        d|  d| d| d| d	      ||
   ||
   z  }|| ||| |
   z        <   || ||||
   z        <    |S )Nr   )get_stride_orderzThe sorted order of strides of the two branches' output doesn't match.this indicates the contiguousness of the two branches are different. True branch has stride z but false branch has stride zS.Consider using contiguous() to make the two branches have the same contiguousness.sc                 R    t        | t              r| S | j                  j                  S r1   )rC   r]   r   r   )r  s    r.   _maybe_exprz:_merge_tensors.<locals>._bound_stride.<locals>._maybe_expr9  s    !S!66;;r/   za_stride_expr:z, b_stride_expr:r"   zIt seems one of cond's output stride is not a simple accumulative multiplication of sizes. This could be because cond returns a slice of a tensor, which is not dense in memory. True branch has size z	, stride z and false branch has size z stride z!. Hint: can call t.contiguous(). )torch._inductor.irr  r   r   	enumerater   rJ   r   r]   r;   SymInt)r   r   r  r  r  r  a_sorted_stride_idxb_sorted_stride_idxa_stride_lib_stride_lir   idxa_pairb_pair_a_idxb_idxr  a_stride_exprb_stride_exprmerged_stridesa_valneg_ib_vala_exprnxt_merged_stride_exprr   s                             r.   _bound_stridez%_merge_tensors.<locals>._bound_stride  s    	8.{DNNK.{DNNK M
M M
M   34 	4FAs +A3K	4 34 	4FAs +A3K	4 "+{; 	NFF%&*<<<HAuHAu~"..9]:WXcWd eij 		5ell!23 	
 >@=?:>#kBR9R!+{; $	VNFF%&*<<<!LE5HE1Azz1E5>1z$%q!5!]2&{5'9:!+e"45?S#M?2B=/RS?$*q!A: A:%:89M+e"4589M+e"45()N1% '009{)K=Pklukv w""-.OQ  &4A%6Q%G"?UM+eil&:;<?UM+eil&:;<I$	VJ r/   )r   r   )%torch.fx.experimental.symbolic_shapesr   rt   r   r   rM   r   r   r   r   sizer   r   create_unbacked_symintconstrain_symbol_ranger   r   r;   Sizer]   rN   r   r  strideempty_stridedr   r   )r   r   r   r   _meta_to_checkr  r   r   r   new_sizer  merged_strides     `         r.   r   r     sg    EyAIyQY.A.&7j T!W
%:TQQDQRG<TT:	N 		nF	 ~~ann44{{1;;..yy{199;..
 35Kaffh) )B"!33r" >>---~~<<>H1DNN11(--2D2DWwrSUWx(-)0/bQ::Q::Q 38_Q 38_	Q
 %U\\ 123Q 
eC%&	'Qf 5B	!&&(AHHJ
K5M 
 
""aggahh

 
 
s   *-J!!J*c                    | j                  |      }| j                  |      }| j                         5  | j                  t        |            }| j                  t        |            }t	        | d      xr | j
                  j                  }	||fD ]  }
t        |
||	      st        d       ||fD ]  }
t        |
||	      st        d       t        ||||      }| j                  |      cd d d        S # 1 sw Y   y xY w)Nr   )pre_dispatchzgOne of torch.cond branch might be modifying the input! Consider cloning the input before modifying it. z~One of torch.cond branch might be aliasing the input! If you are returning a view of the input, please make sure to clone it. )unwrap_tensorsredispatch_to_nextfunctionalizer   r   r   r*  r   r   r   rS   wrap_tensors)r   r3   r4   r5   inputsunwrapped_inputsunwrapped_predfunctional_truefunctional_falser*  branchcond_returns               r.   	cond_funcr6  r  s&   ))&1''-N				! -++,G,PQ,,-H-RSsF+E0E0E) 	F3(| 8G 		 ) 	F0(| 8$ 		 O-=?O
 ,3- - -s   A.C8"!C8*C88Dc           
      `   t        |t        t        f      sJ d       t        d |D              sJ d       t        |t        j
                        xr t        |      }|rt        |      n|}t        |D cg c]'  }t        |      rt        |      t        |      fn|d f) c} \  }}	|rE|f|z   }d|	z   }	fd}
| j                         5   t	        j                  |
|	      | }d d d        nUt	        j                  |	      t	        j                  |	      | j                         5  t        ||      }d d d        t        t              s|f}| j                         }t        |D cg c]  }t        |d|       c}      S c c}w # 1 sw Y   UxY w# 1 sw Y   axY wc c}w )Nz.Cond inputs must be a list or tuple of tensorsc              3   P   K   | ]  }t        |t        j                           y wr1   rB   )rl   r   s     r.   rn   z"cond_batch_rule.<locals>.<genexpr>  s       ()
1ell#s   $&z%Cond inputs must be a list of tensors)r   c                 R     | } | }t        j                  | |d   |d         S )Nr   )r;   where)prT   rF   fr5   r4   s       r.   fnzcond_batch_rule.<locals>.fn  s0    A$A;;q!A$!--r/   )in_dimsr   )rC   rN   rM   r   r;   rD   r
   r	   r   r   r   vmaprS   levelr   )interpreterr3   r4   r5   r/  pred_is_batchedpred_rF   tensorsr>  r=  resultlvlr   s     ``          r.   cond_batch_rulerG    s   u 878   -3  /./  !u||4O9I$9OO#2M$E  

 6Fa5H]1~a01qRViW

GW (W$.	.
   	?4UZZG4g>F	? 	? **Wg6::h8  	?T7Hg>F	? fe$



CV<.As+<==?

 	? 	?	? 	? =s$   8,FF0F3F+FF()r   )Wr   loggingr`   typingr   r   r   r   r;   #torch._subclasses.functional_tensortorch.utils._pytreere   _pytreerO   torch._Cr   torch._C._functorchr   r	   r
   r   torch._dispatch.pythonr   torch._functorch.utilsr   torch._higher_order_ops.utilsr   r   r   r   r   r   r   r   r   r   
torch._opsr   torch._subclasses.fake_tensorr   r   r   "torch.fx.experimental.proxy_tensorr   r   r   r   r    torch.utils._python_dispatchr!   r#   r$   r%   	getLoggerr7   logr'   rS   rH   r]   r^   rD   rM   rN   r)   r|   r   py_implCompositeExplicitAutogradr   autogradFunctionr   Autogradr   r   r   r   r   r   py_functionalize_implr6  r   
_functorchTransformTypeVmaprG  r   r/   r.   <module>ra     sm      1 1  * $ $    = -   + D G  D R R g!C  C ( G
 $&	@
c5%,,.
/@@ @ E4K 	@
 	@ @F*RZ-V` 	667	# 8	#4U^^,, 4@ 	%%& '8 	'(H )H 	 = !=0

,,
49#s(O
QT
	
$Q
Q
"*5<<"8Q
@NQ
h 	- -> 	$$22778,> 9,>r/   