
    uki;                    T   d dl mZ d dl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 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mZmZm Z m!Z!  ejD                  e#        ejD                  e#       ejH                  e%cZ%Z&ejN                  e(cZ(Z)ejT                   G d d             Z+ G d d      Z,d Z-d Z.d Z/d Z0d Z1d)dZ2d Z3d  Z4d! Z5	 	 	 	 	 	 	 	 d*d"Z6 e
jn                  d#      Z8d$e8_9        e8ju                  e3       e8jw                  e5       e4ejx                  e8<   e6ejz                  e8<    ej|                  e8        ej~                  e8 ej                  e3d$%             d& ZAd' ZBd( ZCy)+    )annotations)Callable)AnyN)api)core)custom_api_util)linear_util)source_info_util)traceback_util)	tree_util)util)api_util)ad)batching)
not_mapped)mlir)partial_eval)pxla)tree_flattentree_maptree_structuretree_unflattentreedef_tuplec                  z    e Zd ZU dZded<   ded<   d
dZej                  Z	 	 	 	 ddZ	e
j                  d        Zy	)custom_vmapa  Customize the vmap behavior of a JAX-transformable function.

  This decorator is used to customize the behavior of a JAX function under the
  :func:`jax.vmap` transformation. A ``custom_vmap``-decorated function will
  mostly (see below for caveats) have the same behavior as the underlying
  function, except when batched using :py:func:`jax.vmap`. When batched, the
  rule defined using :py:func:`~jax.custom_batching.custom_vmap.def_vmap` will
  be used.

  For example:

    >>> @jax.custom_batching.custom_vmap
    ... def f(x, y):
    ...   return x + y
    ...
    >>> @f.def_vmap
    ... def f_vmap_rule(axis_size, in_batched, xs, ys):
    ...   assert all(in_batched)
    ...   assert xs.shape[0] == axis_size
    ...   assert ys.shape[0] == axis_size
    ...   out_batched = True
    ...   return xs * ys, out_batched
    ...
    >>> xs = jnp.arange(3)
    >>> ys = jnp.arange(1, 4)
    >>> jax.vmap(f)(xs, ys)  # prints xs * ys instead of xs + ys
    Array([0, 2, 6], dtype=int32)

  Of note, ``custom_vmap`` functions do not support reverse-mode autodiff. To
  customize both vmap and reverse-mode autodiff, combine ``custom_vmap`` with
  :py:class:`jax.custom_vjp`. For example:

    >>> @jax.custom_vjp
    ... @jax.custom_batching.custom_vmap
    ... def f(x, y):
    ...   return jnp.sin(x) * y
    ...
    >>> @f.def_vmap
    ... def f_vmap_rule(axis_size, in_batched, xs, ys):
    ...   return jnp.cos(xs) * ys, True
    ...
    >>> def f_fwd(x, y):
    ...   return f(x, y), (jnp.cos(x), jnp.sin(x), y)
    ...
    >>> def f_bwd(res, g):
    ...   cos_x, sin_x, y = res
    ...   return (cos_x * g * y, sin_x * g)
    ...
    >>> f.defvjp(f_fwd, f_bwd)
    >>> jax.vmap(f)(jnp.zeros(3), jnp.ones(3))
    Array([1., 1., 1.], dtype=float32)
    >>> jax.grad(f)(jnp.zeros(()), jnp.ones(()))
    Array(1., dtype=float32)

  Note that the :py:class:`jax.custom_vjp` must be on the outside, wrapping the
  ``custom_vmap``-decorated function.
  Callable[..., Any]funz%Callable[..., tuple[Any, Any]] | None	vmap_rulec                L    t        j                  | |       || _        d | _        y N)	functoolsupdate_wrapperr   r   )selfr   s     S/home/cdr/jupyterlab/.venv/lib/python3.12/site-packages/jax/_src/custom_batching.py__init__zcustom_vmap.__init__p   s     T3'DHDN    c                    || _         |S )a  Define the vmap rule for this custom_vmap function.

    Args:
      vmap_rule: A function that implements the vmap rule. This function should
        accept the following arguments: (1) an integer ``axis_size`` as its
        first argument, (2) a pytree of booleans with the same structure as the
        inputs to the function, specifying whether each argument is batched,
        and (3) the batched arguments. It should return a tuple of the batched
        output and a pytree of booleans with the same structure as the output,
        specifying whether each output element is batched. See the documentation
        for :py:func:`jax.custom_batching.custom_vmap` for some examples.

    Returns:
      This method passes the rule through, returning ``vmap_rule`` unchanged.
    )r   )r#   r   s     r$   def_vmapzcustom_vmap.def_vmapw   s    & DNr&   c                   t        j                  d| j                  ||      }	 t        j                  | j                  ||      }| j                  st        d|j
                   d      t        |      \  }}t        j                  t        j                  | j                  |      |      \  }}|D 	cg c]  }	t        j                  |	       }
}	t        j                  ||
      \  }}}t        j                   t        j"                  |      d      }t%        t'        |      |f      }| j                  J t        j                  d| j                  d	||fi       }t)        j*                  g |||t-        | j                  |      | |       d
}t/         |       |      S # t        $ r!}t	        d|j
                   d|       |d }~ww xY wc c}	w )Nzcustom_vmap funz:The input arguments to the custom_vmap-decorated function zT could not be resolved to positional-only arguments. Binding failed with the error:
z2No batching rule defined for custom_vmap function z using def_vmap.
debug_info zcustom_vmap ruler   callrulein_treeout_tree)r   r+   r   resolve_kwargs	TypeError	func_namer   AttributeErrorr   flatten_fun_nokwargslu	wrap_initr   get_avalpetrace_to_jaxpr_dynamicClosedJaxprconvert_constvars_jaxprr   r   custom_vmap_pbind
ClosedRuler   )r#   argskwargs	debug_fune	args_flatr0   flat_funr1   xin_avalsjaxpr_constsclosed_call
debug_ruleout_flats                    r$   __call__zcustom_vmap.__call__   s   ##$5txx$(&2I$$TXXtV<d >>>y?R?R>S T   &d+Iw!66
TXX)4Hh +44Qa 4H4008DE1f""2#=#=e#DbIK^F3W=>G>>%%%$$%7&'t_b:J!! 76 7I 7'2'1$..2<(>*1+3:7H (*h//9  
F  ! "889s< 	 5s   !F% 4G%	G.G

GN)r   r   )r   Callable[..., tuple[Any, Any]]returnrP   )__name__
__module____qualname____doc____annotations__r%   r   forward_attr__getattr__r(   r   api_boundaryrO   r,   r&   r$   r   r   1   sY    8t 22
  ,,+/ &, !0 !0r&   r   c                       e Zd ZddZd Zd Zy)r@   c                L    t        j                  | |       || _        || _        y r    )r!   r"   r/   debug)r#   r/   r\   s      r$   r%   zClosedRule.__init__   s     T4(DIDJr&   c                    |\  }}|\  }}t        t        j                  |            rJ |       t        | j                  |||      S r    )anyr   tree_leaves	call_ruler/   )r#   	axis_sizeall_in_batchedall_argsrJ   rA   consts_batched
in_batcheds           r$   rO   zClosedRule.__call__   sH    GAt!/NJ9((89I>I9TYY	:t<<r&   c                ,    t        | j                        S r    )strr/   )r#   s    r$   __str__zClosedRule.__str__   s    tyy>r&   N)r/   r   r\   zcore.DebugInfo)rR   rS   rT   r%   rO   rh   r,   r&   r$   r@   r@      s    
=r&   r@   c                >    t        |       t        u r| S t        |       S r    )typelist)xss    r$   ensure_listrm      s    Bx4-T"X-r&   c                    t        | dd      S )NrR   z<unnamed rule>)getattr)r/   s    r$   	rule_namerp      s    	z#3	44r&   c                (     | |t        |      g| S r    )rm   )r/   ra   re   rA   s       r$   r`   r`      s    	iZ0	84	88r&   c                    ||k7  rt        dt        |        d| d|       ||k7  rt        dt        |        d| d|       y )NzZstructure of output value and output batching specification returned by custom vmap rule (z) do not match.
Output values: z
Batching spec: z2structure of output returned by custom vmap rule (zL) does not match that of original custom-vmapped function.
Original output: z
Rule output: )
ValueErrorrp   )r/   original_out_treer1   out_batched_trees       r$   check_vmap_rule_treesrv      s    !!
	  )$0 1" $*+	-. .
 ""

<Yt_<M N-. / z	#$ $ #r&   c                D    |t         u r| S t        j                  | |d      S Nr   )r   r   moveaxis)rG   bdims     r$   maybe_bdim_at_frontr{      s"    	ZH==D!$$r&   c                   t        j                  ||d d       }t        j                         }t        j                  | |||      \  } } | j
                  | }| |       fS r    )r   AxisDatar   TraceTagbatch_subtracecall_wrapped)	fin_axes	axis_namera   rA   	axis_datatagout_axesoutss	            r$   vmap_unrestrictedr      sZ    	9dDA)#''3	7C+!X		$	xz	r&   c                8    ~~~ t        j                  |       | S r    )r   jaxpr_as_fun)r.   r/   r0   r1   rA   s        r$   custom_vmap_implr      s!    
GX	 		4	 $	''r&   c                  ~t        | |      D ch c]  \  }}|	|j                  |    c}}\  }t        t        | |      } |D cg c]
  }|t        u }	}t        ||       }
t        ||	      }t        ||||
      \  }}t        |      \  }}t        |      \  }}t        ||||       |D cg c]  }|rdnt         }}||fS c c}}w c c}w c c}w rx   )	zipshapemapr{   r   r   r`   r   rv   )rE   dimsr.   r/   r0   r1   rG   dra   flat_in_batchedrA   re   outout_batched	flat_outstree1flat_out_batchedtree2bflat_out_dimss                       r$   custom_vmap_batchingr      s    
'*9d';Mtq!q}
M*)%y$7)267QQj(7/7		+$g7*tY
DA#{!#&)U(5Ehu53CDa1z)D-D	M	!! N7 Es   
CCC0Cc                4    ~| j                   | j                  fS r    )	out_avalseffects)r.   rH   rJ   s      r$   custom_vmap_abstract_evalr     s    		%%r&   c                  dfd}t        t        j                  |      }t        j                  dgt	        |       z  d      \  }}t        ||f      }	t        f      }
t        j                  g | ||||	|
d}t	        |      dz  dk(  sJ t	        |             t        j                  |t	        |      dz  g      \  }}||fS )Nc                J    !" |\  }}t        t        j                  ||       t        d ||      }t        d ||      }t        j                         !t        ||f      \  }}	t        ||fd       \  }
}|	|k(  sJ ~  !$%fd"t        j                  "#j                  j                         "fd}t        j                  t        j                  |#j                  j                        |	      \  }}t        |g||
t        j                   d\  }}t        t!        |      d	      \  }}|rJ |d | ||d  }}|d | ||d  }}t#        t$        ||      }|D cg c]
  }|t&        u }}t#        t$        ||      }|D cg c]
  }|t&        u }}t)         |       g ||      \  }}t)         |       g ||      \  }}t        t        j*                  !j,                  |      }t        t        j*                  !j,                  |      }||f||ffS c c}w c c}w )
Nc                    | r|sdS d S rx   r,   pbtbs     r$   <lambda>z;custom_vmap_jvp.<locals>.jvp_of_rule_rule.<locals>.<lambda>      Brq t r&   c                    |r| sdS d S rx   r,   r   s     r$   r   z;custom_vmap_jvp.<locals>.jvp_of_rule_rule.<locals>.<lambda>  r   r&   c                
    | d u S r    r,   )rG   s    r$   r   z;custom_vmap_jvp.<locals>.jvp_of_rule_rule.<locals>.<lambda>  s
    !t) r&   )is_leafc                     t        |       \  }}t        t        |      t        |             j                  |       |S r    )r`   rv   r   store)primalsr   r   ra   mutually_batchedout_mutually_batchedr1   r/   s      r$   to_jvpz9custom_vmap_jvp.<locals>.jvp_of_rule_rule.<locals>.to_jvp$  sH    "44DgNc;
.-~k/JL  -jr&   c                2    t        j                  | |      S r    )r   jvp)r   tangentsr   s     r$   to_vmap_over_extra_batched_dimszRcustom_vmap_jvp.<locals>.jvp_of_rule_rule.<locals>.to_vmap_over_extra_batched_dims,  s    WWVWh//r&   r*   )r   r   ra      )r   operatorand_r7   Storer   r   save_wrapped_fun_debug_inforI   r+   r6   r8   r   r   no_axis_namedivmodlenr   r{   r   r   or_val)&ra   re   r   r   in_batched_psin_batched_tsextra_batched_psextra_batched_ts
flat_ps_ts
tree_ps_tsflat_extra_batched_ps_tstree_ps_ts2r   $to_vmap_over_extra_batched_dims_flat	out_tree2flat_out_ps_tsflat_out_axesnraggedflat_out_psflat_out_tsflat_out_axes_pflat_out_axes_tr   flat_out_extra_batched_psflat_out_extra_batched_tsout_psout_tsout_extra_batched_psout_extra_batched_tsout_batched_psout_batched_tsr   r   r   r.   r1   r/   s&   `                               @@@r$   jvp_of_rule_rulez)custom_vmap_jvp.<locals>.jvp_of_rule_rule  sk   #- M=}mL K -}> K -}> 88:)7H*=>J
,8	+,#-%)k $$$  ((1F1FG0 7?6S6S
4 $

 5 5	7 		73() %6,%:/9%:(##y%:!NM
 s>*A.IAv:-bq1>!"3EK'4Ra'8-:K_O);HK>M N*!4 N N);HK>M N*!4 N N#1{1[13NFF1?M0M3LM2O.. *..0DFN*..0DFN Fnn=== !O Ns   "HH Tr-   r   r   )ra   int)
r   r   instantiate_zeros	jvp_jaxprr   r   r>   r?   r   
split_list)r   r   r.   r/   r0   r1   r   jvp_callrJ   jvp_in_treejvp_out_treer   out_primalsout_tangentss     `` `        r$   custom_vmap_jvpr     s    >>@ %%x0(TD6CL#8$?+(Aw01+(34,			 
2
2
2*L
2$ 
TQ!	&SY&	"oodSY!^4DE+|	l	""r&   custom_vmap_callT)multiple_resultsc                B    t        d | |      }t        d | |      }||fS )Nc                    | r|S d S r    r,   lrG   s     r$   r   ztree_split.<locals>.<lambda>k  s    1a $ r&   c                    | rd S |S r    r,   r   s     r$   r   ztree_split.<locals>.<lambda>l  s    ad Q r&   r   )masktreelhsrhss       r$   
tree_splitr   j  s)    .d;#.d;#	c/r&   c                     t        d | ||      S )Nc                    | r|S |S r    r,   )r   x_lx_rs      r$   r   ztree_merge.<locals>.<lambda>p  s    Qc C r&   r   )r   lhs_treerhs_trees      r$   
tree_merger   o  s    	7(
, ,r&   c                V     ddl m t                 j                   fd       } S )a  A special case of ``custom_vmap`` that uses a loop.

  A function decorated with ``sequential_vmap`` will be called sequentially
  within a loop when batched. This is useful for functions that don't natively
  support batch dimensions.

  For example:

    >>> @jax.custom_batching.sequential_vmap
    ... def f(x):
    ...   jax.debug.print("{}", x)
    ...   return x + 1
    ...
    >>> jax.vmap(f)(jnp.arange(3))
    0
    1
    2
    Array([1, 2, 3], dtype=int32)

  Where the print statements demonstrate that this :py:func:`~jax.vmap` is being
  generated using a loop.

  See the documentation for :py:class:`~jax.custom_batching.custom_vmap` for
  more details.
  r   )control_flowc                    ~ 	fd}t        t        |            \  }j                  ||      }t        d |      }||fS )Nc                (    t        |       } | S r    )r   )mapped_argsrA   
bcast_argsr   re   s     r$   to_mapz-sequential_vmap.<locals>.rule.<locals>.to_map  s    
K<dXor&   c                     y)NTr,   )rJ   s    r$   r   z/sequential_vmap.<locals>.rule.<locals>.<lambda>  s    r&   )r   rk   r   r   )
ra   re   rA   r   r   r   r   r   r   r   s
    `     @r$   r/   zsequential_vmap.<locals>.rule  sK     )T$Z@K


6;
/C>3/Kr&   )jax._src.laxr   r   r(   )r   r/   r   s   ` @r$   sequential_vmapr  s  s.    4 (!n!::
 
 
(r&   )r   zlu.WrappedFun)r.   zcore.ClosedJaxprr/   r@   r0   tree_util.PyTreeDefr1   r  )D
__future__r   collections.abcr   typingr   r!   r   jax._srcr   r   r   r	   r7   r
   r   r   r   r   jax._src.interpretersr   r   jax._src.interpreters.batchingr   r   r   r:   r   jax._src.tree_utilr   r   r   r   r   register_exclusion__file__safe_mapr   
unsafe_mapsafe_zipr   
unsafe_zipregister_custom_decorator_typer   r@   rm   rp   r`   rv   r{   r   r   r   r   r   	Primitiver>   r   def_impldef_effectful_abstract_evalprimitive_batchersprimitive_jvps register_initial_style_primitiveregister_lowering	lower_funr   r   r  r,   r&   r$   <module>r     s   # $      $ & % #    $ * 5 & 4 &? ? $  # #H - ! ! !( + --Z--Z //}0 }0 0}0H .59$%(
" &
N#*N#$N# 1N# =PN#b 12!%    ' (  ) )*C D-A  M *#2  -   % % %m 4   }ndnnt'- .
,+r&   