
    ukiG                    x   d Z ddlmZ ddlmZmZ ddlmZ ddlZddl	Z	ddl
mZmZ ddlmZ ddl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mZmZ ddlmZmZmZ  ej8                  e        G d de      Z G d d      Z  e        Z! G d d      Z" G d d      Z# G d d      Z$ed,d       Z%ed,d       Z&ed,d       Z'edd	 	 	 	 	 d-d       Z( G d d      Z) e)       Z* G d d e      Z+ ejX                  d!      Z-d.d"Z.d/d0d#Z/ ejX                  d$      Z0d1d%Z1d2d&Z2d3d'Z3dd(	 d4d)Z4e%d*        Z5d+ Z6y)5a  
Utilities for defining functions composed with transformations.

For example,

   from jax._src import linear_util as lu

   # Produce a WrappedFun for applying transformations on `f`
   wf = lu.wrap_init(f, debug_info=api_util.debug_info("test", f, (), {}))

A `WrappedFun` object represents a function `f`, together with a sequence of
nested transformations that are to be applied to the positional and keyword
arguments at call time and function return values at return time.
A transformation can take some static positional arguments that are given
at the wrapping time, and may also return some auxiliary output:

    wf, aux_out_thunk = trans1(wf, static_arg)

We can call the transformed function. First, the transformation is applied
to the dynamic args and keyword args to produce new dynamic and keyword args.
Then the underlying function is called and the transformation is applied to
the results.
If there are multiple transformations, they form a stack. The arguments are
transformed first with the last applied transformation; the results are
transformed first with the first applied transformation.

    res = wf.call_wrapped(dynamic_args, kwargs)
    # Now `aux_out_thunk()` is the auxiliary output.

A transformation is written as a generator function that takes zero or more
static positional arguments (given when the transformation is instantiated),
along with positional and keyword arguments to be transformed.
The generator will yield twice:

    @lu.transformation_with_aux
    def trans1(static_arg, *dynamic_args, **kwargs):
      ...
      # First yield: pair of transformed (args, kwargs). Get back the results.
      results = yield (new_dynamic_args, new_kwargs)
      ...
      # Second yield: pair of (transformed results, and auxiliary output)
      yield new_results, auxiliary_output


`WrappedFun` objects explicitly represent the set of transformations so that
they can be used as dictionary keys for memoization. `WrappedFun` objects
compare as equal only if they compute the same function. The static and the
dynamic positional arguments for the generators, and also the auxiliary output
data must be immutable, because it will be stored in function memoization tables.
    )annotations)CallableSequence)partialN)Any
NamedTuple)Hashable)config)core)traceback_util)KeyPathgenerate_key_pathskeystr)curryfun_nameregister_cachec                      e Zd Zy)StoreExceptionN__name__
__module____qualname__     O/home/cdr/jupyterlab/.venv/lib/python3.12/site-packages/jax/_src/linear_util.pyr   r   V       r   r   c                      e Zd Zy)EmptyStoreValueNr   r   r   r   r   r   Y   r   r   r   c                  @    e Zd ZdZdZd Zd Zd Zed        Z	d Z
e
Zy)	StorezHStorage for a value, with checks for overwriting or reading empty store.)_valc                    t         | _        y N_EMPTY_STORE_VALUEr!   selfs    r   __init__zStore.__init__`   s	    "DIr   c                L    | j                   t        urt        d      || _         y )NzStore occupied)r!   r%   r   )r'   vals     r   storezStore.storec   s"    yy**+,,DIr   c                    t         | _        y r#   r$   r&   s    r   resetzStore.reseth   s	    "DIr   c                4    | st        d      | j                  S )NzStore empty)r   r!   r&   s    r   r*   z	Store.vall   s    =))99r   c                &    | j                   t        uS r#   )r!   r%   r&   s    r   __nonzero__zStore.__nonzero__r   s    99...r   N)r   r   r   __doc__	__slots__r(   r+   r-   propertyr*   r0   __bool__r   r   r   r    r    \   s9    P)#
#  
/ (r   r    c                  2    e Zd ZdZd Zed        Zd Zd Zy)
EqualStore)_storec                "    t               | _        y r#   )r    r7   r&   s    r   r(   zEqualStore.__init__z   s    'DKr   c                .    | j                   j                  S r#   )r7   r*   r&   s    r   r*   zEqualStore.val}   s    ;;??r   c                    	 | j                   j                  |       y # t        $ rC}	 t        | j                   j                  |k(        }|st        d      d #  |d xY wY d }~y d }~ww xY w)Nz#Store occupied with not-equal value)r7   r+   r   boolr!   )r'   r*   eokays       r   r+   zEqualStore.store   sp    	P
kk PPDKK$$+, DE4
O	TPs&    	A*"A
A%AA%%A*c                8    | j                   j                          y r#   )r7   r-   r&   s    r   r-   zEqualStore.reset   s    KKr   N)	r   r   r   r2   r(   r3   r*   r+   r-   r   r   r   r6   r6   w   s+    )  
Pr   r6   c                      e Zd ZU dZdZded<   ded<   ded<   ded	<   d
ed<   ded<   ded<   	 	 	 	 	 	 	 	 	 	 	 	 ddZed        Z 	 	 	 	 ddZd Z	d Z
d Zd Zd ZddZddZy)
WrappedFuna=  Represents a function `f` to which `transforms` are to be applied.

  Args:
    f: the function to be transformed.
    f_transformed: transformed function.
    transforms: a tuple of `(gen, gen_static_args)` tuples representing
      transformations to apply to `f.` Here `gen` is a generator function and
      `gen_static_args` is a tuple of static arguments for the generator. See
      description at the start of this module for the expected behavior of the
      generator.
    stores: a list of out_store for the auxiliary output of the `transforms`.
    params: a tuple of `(name, param)` tuples representing extra parameters to
      pass as keyword arguments to `f`, along with the transformed keyword
      arguments.
    in_type: optional input type
    debug_info: debugging info about the function being wrapped.
  ff_transformed
transformsstoresparamsin_type
debug_infor   rB   rC   1tuple[tuple[Callable, tuple[Hashable, ...]], ...]rD   %tuple[Store | EqualStore | None, ...]rE   ztuple[tuple[str, Any], ...]rF   core.InputType | NonerG   	DebugInforH   c                f    || _         || _        || _        || _        || _        || _        || _        y r#   rA   )r'   rB   rC   rD   rE   rF   rG   rH   s           r   r(   zWrappedFun.__init__   s6     DF&D DODKDKDL DOr   c                .    t        | j                  d      S )Nz<unnamed wrapped function>)r   rB   r&   s    r   r   zWrappedFun.__name__   s    DFF899r   c           	        |bt        | j                  t        || j                  g| ||ff| j                  z   |f| j
                  z   | j                  d| j                        S t        | j                  t        || j                  |g| ||ff| j                  z   |f| j
                  z   | j                  d| j                        S )z$Add another transform and its store.N)r@   rB   r   rC   rD   rE   rF   rH   )r'   gengen_static_args	out_stores       r   wrapzWrappedFun.wrap   s     T-?-? R/ R/1DOOC"t{{2DKKtX X T-?-? ]_ ]/1DOOC"t{{2DKKtX Xr   c                |    t        | j                  |      D ]#  \  }}|	|j                  |j                         % y)z5Copy the values from the `stores` into `self.stores`.N)ziprE   r+   r*   )r'   rE   
self_storeother_stores       r   populate_storeszWrappedFun.populate_stores   s9    #&t{{F#; *
K		)*r   c                &     | j                   |i |S )zCalls the transformed function)rC   )r'   argskwargss      r   call_wrappedzWrappedFun.call_wrapped   s    4t.v..r   c                    d }t        |t        | j                              }ddj                  |      z   dz   t	        | j
                        z   dz   S )Nc                J    | \  }\  }}| dt        |       dt        |       S )Nz   : z   )r   )xirP   rZ   s       r   transform_to_strz-WrappedFun.__repr__.<locals>.transform_to_str   s/    na#ts%c(4.)9::r   zWrapped function:

z
Core: )map	enumeraterD   joinr   rB   )r'   ra   transformation_stacks      r   __repr__zWrappedFun.__repr__   sR    ; /4??1KL 499-A#BBZORZ[_[a[aRbbeiiir   c                    t        | j                  | j                  | j                  | j                  | j
                  f      S r#   )hashrB   rD   rF   rG   rH   r&   s    r   __hash__zWrappedFun.__hash__   s3    $++t||" # #r   c                   | j                   |j                   k(  xrj | j                  |j                  k(  xrO | j                  |j                  k(  xr4 | j                  |j                  k(  xr | j                  |j                  k(  S r#   )rB   rD   rF   rG   rH   )r'   others     r   __eq__zWrappedFun.__eq__   sn    FFegg 0$//U5E5E"E 0KK5<<'0,0LLEMM,I0OOu///1r   c           	         t        | j                  | j                  | j                  | j                  | j
                  | j                  |      S r#   )r@   rB   rC   rD   rE   rF   rG   )r'   dbgs     r   replace_debug_infozWrappedFun.replace_debug_info   s9    dffd00$//kk4;; r   c                T    | j                  | j                  j                               S r#   )rp   rH   with_unknown_namesr&   s    r   rr   zWrappedFun.with_unknown_names   s     ""4??#E#E#GHHr   N)rB   r   rC   r   rD   rI   rE   rJ   rF   z tuple[tuple[str, Hashable], ...]rG   rK   rH   rL   )rR   zStore | EqualStore | Nonereturnr@   )ro   zcore.DebugInfors   r@   )rs   r@   )r   r   r   r1   r2   __annotations__r(   r3   rS   rX   r\   rg   rj   rm   rp   rr   r   r   r   r@   r@      s    " `)+??
//
%%  !&!L! =! 8	!
 .! %! : :
X/
X4>
X*/j#1

Ir   r@   c                (    |j                  | |d      S )zAdds one more transformation to a WrappedFun.

  Args:
    gen: the transformation generator function
    fun: a WrappedFun on which to apply the transformation
    gen_static_args: static args for the generator function
  N)rS   )rP   funrQ   s      r   transformation2rw      s     
#	--r   c                2      fd} t        ||g|        S )Nc                ^     |i |}t        |      \  }}|j                   | |i |      S r#   )nextsend)rB   rZ   r[   gen_instargs_kwargs_rP   s         r   gen2ztransformation.<locals>.gen2   s8    D#F#H(^NE7==E-W-..r   )rw   rP   rv   rQ   r   s   `   r   transformationr      s!    / 
6s	5_	5	77r   c                2      fd} t        ||g|        S )Nc                     	|i |}t        |      \  }}|j                   | |i |      \  }}|j                  |       |S r#   )rz   r{   r+   )
rB   r+   rZ   r[   r|   r}   r~   ansauxrP   s
            r   r   z%transformation_with_aux.<locals>.gen2  sL    D#F#H(^NE7}}Q112HC	KKJr   )transformation_with_aux2r   s   `   r   transformation_with_auxr     s"     
?	!$	>o	>	@@r   F)use_eq_storec               d    |s
t               n	t               fd}|j                  | |      |fS )zCAdds one more transformation with auxiliary output to a WrappedFun.c                      j                   S r#   )r*   )rR   s   r   <lambda>z*transformation_with_aux2.<locals>.<lambda>  s    imm r   )r    r6   rS   )rP   rv   r   rQ   	out_thunkrR   s        @r   r   r     s/    
 *egz|)#)	#		2I	==r   c                      e Zd Zy)InitialResultPathsNr   r   r   r   r   r     s    r   r   c                      e Zd ZU dZded<   ded<   	 ded<   	 ded<   	 dd	Zedd
       ZddZd Z	edd       Z
edd       ZddZddZddZddZddZddZddZy)rL   z8Debugging info about a func, its arguments, and results.str
traced_forfunc_src_infotuple[str, ...] | None	arg_nameszKtuple[str, ...] | InitialResultPaths | Callable[[], tuple[str, ...]] | Noneresult_pathsc                    | j                   t        usJ t        | j                         r+t        | j                               }| j	                  |      S | S )z/Return a debug info with resolved result paths.r   )r   initial_result_pathscallabletuple_replace)r'   pathss     r   resolve_result_pathszDebugInfo.resolve_result_paths?  sN    $8888!!"D%%'(e]]]..Kr   c                >    | j                   j                  d      d   S )N r   )r   splitr&   s    r   	func_namezDebugInfo.func_nameG  s    ##C(++r   c                    | j                   j                  d      }||d<   | j                  dj                  |            S )Nr   r   )r   )r   r   r   re   )r'   namefunc_src_compss      r   replace_func_namezDebugInfo.replace_func_nameK  s<    ''--c2NN1==sxx'?=@@r   c                \    t        d t        |      D              }| j                  |      S )Nc              3  >   K   | ]  \  }}d t        |         yw)resultN)_clean_keystr_arg_names).0path_s      r   	<genexpr>z-DebugInfo.set_result_paths.<locals>.<genexpr>Q  s,      A$T1 ""9$"?!@A As   r   )r   r   r   )r'   r   r   s      r   set_result_pathszDebugInfo.set_result_pathsP  s2     A(:3(?A AL==l=33r   c                h    t         j                  | j                        }|sy |j                  d      S )N   )_re_func_src_infomatchr   groupr'   ms     r   func_filenamezDebugInfo.func_filenameU  s+     2 23AT771:r   c                    t         j                  | j                        }|r|j                  d      y t	        |j                  d            S )N   )r   r   r   r   intr   s     r   func_linenozDebugInfo.func_lineno[  s<     2 23A
"4qwwqz?r   c                ^    | j                  |       | j                  | j                  S d|z  S )z&Get the arg_names with a safety check. )assert_arg_namesr   r'   expected_counts     r   safe_arg_nameszDebugInfo.safe_arg_namesa  s/    .)~~!^^>!!r   c                `    | j                   "t        | j                         |k(  s	J || f       y y r#   )r   lenr   s     r   r   zDebugInfo.assert_arg_namesh  s:    >>!S%8N%J M J%J!r   c           
         | j                   yt        d t        | j                  t	        |            |      D              S )z1Keep only the arg_names for which `keep` is True.Nc              3  ,   K   | ]  \  }}|s	|  y wr#   r   r   vbs      r   r   z-DebugInfo.filter_arg_names.<locals>.<genexpr>p  s     Ntq!AN   
)r   r   rU   r   r   r'   keeps     r   filter_arg_nameszDebugInfo.filter_arg_namesl  s6    ~~Ns4#6#6s4y#A4HNNNr   c                    | j                   t        urt        | j                         rJ |        | j                  |       | j                   | j                   S d|z  S )zCGet the result paths with a safety check. Empty paths mean unknown.r   )r   r   r   assert_result_pathsr   s     r   safe_result_pathszDebugInfo.safe_result_pathsr  s[    $88$J[J[A\b^bb\^,$>!!r   c                `    | j                   "t        | j                         |k(  s	J || f       y y r#   )r   r   r   s     r   r   zDebugInfo.assert_result_paths{  s>    $D,=,=(>.(P S P(P$r   c                    | j                   t        urt        | j                         rJ |        | j                   yt        d t	        | j                   |      D              S )z4Keep only the result_paths for which `keep` is True.Nc              3  ,   K   | ]  \  }}|s	|  y wr#   r   r   s      r   r   z0DebugInfo.filter_result_paths.<locals>.<genexpr>  s     Atq!qAr   )r   r   r   r   rU   r   s     r   filter_result_pathszDebugInfo.filter_result_paths  sV    $88$J[J[A\b^bb\ As4#4#4d;AAAr   c                (    | j                  d d       S )N)r   r   )r   r&   s    r   rr   zDebugInfo.with_unknown_names  s    ==4d=;;r   N)rs   rL   )rs   r   )r   r   rs   rL   )rs   z
str | None)rs   z
int | None)r   r   rs   ztuple[str, ...])r   r   )r   zSequence[bool]rs   r   )r   r   r   r1   rt   r   r3   r   r   r   r   r   r   r   r   r   r   r   rr   r   r   r   rL   rL     s    @/
 $#	 \[ , ,A
4
  
  
"O"B<r   rL   z([^ ]+)( at (.+):(\d+))?$c                \    t        j                  |  dt        d       t        ddd d       S )Nz is missing a DebugInfo object. This behavior is deprecated, use api_util.debug_info() to construct a proper DebugInfo object and propagate it to this function. See https://github.com/jax-ml/jax/issues/26480 for more details.   )
stacklevelmissing_debug_infoz<missing_debug_info>)warningswarnDeprecationWarningrL   )for_whats    r   _missing_debug_infor     s;    
--	
 I I Q( 
')?t	LLr   c          	         |i n|}|dn!t        t        |j                                     }|j                  d      }t	        | t        | fi |dd|d|      }|S )zBWraps function `f` as a `WrappedFun`, suitable for transformation.Nr   r   )r   sorteditemsr   r@   r   )rB   rF   rH   params_dictrv   s        r   	wrap_initr     s`    n&+2U6&,,.+A%B&"""5*1ga/;/RzR#	*r   z<flat index ([^>]+)>c                D    t        |       }t        j                  d|      S )Nz\1)r   _re_clean_keystr_arg_namessub)kress     r   r   r     s    q	#	#	'	's	33r   c           	         | j                   J || S t        |       t        | j                  | j                  | j
                  | j                  | j                  || j                        S r#   )	rG   _check_input_typer@   rB   rC   rD   rE   rF   rH   )rB   rG   s     r   annotater     sX    	
		_HG	ACC!,,!((Q\\
+ +r   c                R    t        |       t        u sJ t        d | D              sJ y )Nc              3  P   K   | ]  }t        |t        j                           y wr#   )
isinstancer   AbstractValue)r   as     r   r   z$_check_input_type.<locals>.<genexpr>  s     @1Z4--.@s   $&)typer   all)rG   s    r   r   r     s(    	g%			@@	@@	@r   )explainc                    t        j                         d fd}fd}j                  |_        ||_        t        |t                      |S )a  Memoization decorator for functions taking a WrappedFun as first argument.

  Args:
    call: a Python callable that takes a WrappedFun as its first argument. The
      underlying transforms and params on the WrappedFun are used as part of the
      memoization cache key.

    explain: a function that is invoked upon cache misses to log an explanation
      of the miss.
      Invoked with `(fun, is_cache_first_use, cache, key, elapsed_sec)`.

  Returns:
     A memoized version of ``call``.
  c                   j                  | j                  i x}      }| j                  | j                  | j                  |t        j                         f}|j                  |d       }||\  }}| j                  |       |S xr t
        j                  j                  x}rt        j                         }	 
| g| }|r# | ||u ||t        j                         	z
         || j                  f||<   |S r#   )
setdefaultrB   rD   rF   rG   r
   trace_contextgetrX   explain_cache_missesvaluetimerE   )rv   rZ   	new_cachecachekeyr   r   rE   
do_explainstartcallr   
fun_cachess             r   memoized_funzcache.<locals>.memoized_fun  s    !!#%%b9E>>3::s{{D&:N:N:P
QCYYsD!Fkc6	&! J D6#>#>#D#D	D	D		tc	Ui'TYY[55HI$eCjJr   c                *    j                  | d        y r#   )pop)rB   r  s    r   _evict_functionzcache.<locals>._evict_function  s    NN1dr   )rv   r@   )weakrefWeakKeyDictionaryclearcache_clearevict_functionr   r   )r   r   r  r  r  s   ``  @r   r   r     sI      +2*C*C*E*" (--, /,s4y)	r   c                     | | S r#   r   )rB   rZ   s     r   hashable_partialr    s    	
D/r   c                    	  |        }	  |       }t        d      # t         $ r d|fcY S w xY w# t         $ r( 	  |       }d|fcY S # t         $ r t        d      d w xY ww xY w)Nzboth stores occupiedTFzneither store occupied)r   )aux1aux2out1out2s       r   merge_linear_auxr    s    36D3Vd 122  4Z 
 Vd D[  ?34$>?	s,   /  ,,	A A A AA )rv   r@   rs   r@   )rv   r@   r   r;   rs   z$tuple[WrappedFun, Callable[[], Any]])r   r   rs   rL   r#   )rB   r   rH   rL   rs   r@   )r   r   rs   r   )rB   r@   rG   rK   rs   r@   )rG   zcore.InputTypers   None)r   r   r   z=Callable[[WrappedFun, bool, dict, tuple, float], None] | None)7r1   
__future__r   collections.abcr   r   	functoolsr   rer   typingr   r   r	   r   r  jax._srcr
   r   r   jax._src.tree_utilr   r   r   jax._src.utilr   r   r   register_exclusion__file__	Exceptionr   r   r%   r    r6   r@   rw   r   r   r   r   r   rL   compiler   r   r   r   r   r   r   r   r  r  r   r   r   <module>r      s  1d # .  	  " $     # B B 9 9 " ! !( + &Y %  $&  6 4[I [Iz . . 8 8 A A AF>>:>>)> > )+ l<
 l<^ BJJ;< M (RZZ(?@ 4+A TX)P)V  3r   