
    uki;                      U d dl mZ d dlmZmZ d dlZd dlmZmZm	Z	m
Z
 d dlmZmZ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 d dlm Z m!Z!m"Z"m#Z#m$Z$m%Z%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/Z0 d dl+m1Z1 d dl2m3Z3 d dl4m5Z5m6Z6m7Z7m8Z8m9Z9m:Z:m;Z;m<Z<m=Z=m>Z>m?Z?m@Z@mAZA d dlBmCZCmDZDmEZEmFZFmGZGmHZH  ej                  eJ       eEZKeDZL	 	 	 	 djdZMdkdZNd ZOd ZP e	e7d       ZQej                  	 	 	 	 dld       ZS ed       ZTej                   G d! d"eeT                ZV e	ej                  d#$      d%        ZW G d& d'ej                        ZYdmd(ZZ eYd)      Z[d* Z\e\ej                  e[<   	 	 dnd+Z^ e.j                  e[e^       d, Z`e`e,j                  e[<   eH	 	 	 	 dod-       Zb	 	 	 	 	 	 dpd.Zcece0j                  e[<   	 	 	 	 	 	 dqd/Zeeeej                  e[<   ej                   G d0 d1eeT                Zgej                  	 	 	 	 	 	 drd2       Zi	 	 	 	 	 	 drd3Zjd4 Zkej                   G d5 d6             Zmd7 Znd8 Zo e	ej                  d#$      	 	 	 	 	 	 	 	 	 	 dsd9       Zpd: Zqej                  	 	 	 	 	 	 dtd;       Zrd< Zsdud=Zt G d> d?ej                        Zudvd@Zvej                  dA        Zw eudB      Zx e.j                  exe^dCD       dE Zyeyej                  ex<   	 	 	 	 	 	 dpdFZzeze0j                  ex<   	 	 	 	 	 	 dqdGZ{e{ej                  ex<   e,j                  e-j                  e,j                  <    e.j                  e,j                  e,j                  dCD       dH Ze: G dI dJ             ZdwdKZdxdLZ eC       	 	 dydM       ZdN Z	 	 dzdOZdP ZdQ ZdR ZdS Z ej                  dT      Zd#e_        ej                  e       ej                  e       ee,j                  e<   ee,j                  e<    e1j                   e        e.j                  e e.j"                  ed#U              ej                  dV      ZdWedX<   d#e_        dY Zej                  e        e.j                  ee       ej                  dZ        dedVd[d\Z e	eed]^      Zd_ Z ej                  d`      Z	 	 d{	 	 	 	 	 	 	 	 	 	 	 	 	 d|daZej                  db        Z	 	 	 	 	 	 	 	 d}dcZd~ddZ	 	 	 	 	 	 	 	 d}deZ	 	 	 	 	 	 	 	 d}dfZ	 	 	 	 	 	 	 	 d}dgZddhZ ej                  di      Zd#e_        ej                  e       ejG                  e        e1j                   e        e.j                  e e.j"                  ed#U             ee-jH                  e<   ee,j                  e<   ee,j                  e<   ee0j                  e<   y)    )annotations)CallableSequenceN)update_wrapperreducepartialwraps)AnyGenericTypeVar)config)core)custom_api_util)custom_transpose)dtypes)effects)linear_util)traceback_util)stop_gradient_pSymbolicZeroZerozeros_like_aval)argnums_partialflatten_fun_nokwargsresolve_kwargsprepend_static_args
debug_infofun_signatureinfer_argnums_and_argnames)UnexpectedTracerError)AbstractRef)ad)batching)mlir)partial_eval)pxla)
not_mapped)tree_flattentree_unflattentree_maptreedef_is_leaftreedef_tupleregister_pytree_node_classtree_leavestree_flatten_with_pathtree_leaves_with_pathkeystrtreedef_childrentree_structure	PyTreeDef)cachesafe_zipsafe_map
split_listunzip2weakref_lru_cachec                >    t        j                  | |      \  }}}||fS Npetrace_to_jaxpr_dynamic)funin_avalsjaxpr_constss        V/home/cdr/jupyterlab/.venv/lib/python3.12/site-packages/jax/_src/custom_derivatives.py_initial_style_jaxprrF   <   s'     ..sH=%F	    c                R    t        j                  t        j                  |             S r<   )r>   close_jaxprconvert_constvars_jaxpr)rB   s    rE   _close_jaxprrK   B   s    	2259	::rG   c                8    t        t        j                  ||      S r<   )r   r"   add_tangents)rC   xxss      rE   _sum_tangentsrP   E   s    	Q	''rG   c                6    t        t        j                  |       S r<   )r*   r   from_primal_valuerN   s    rE   _zeros_like_pytreerT   H   s    	$((!	,,rG   c                d    t        | t        j                        rt        j                  |       S | S r<   )
isinstancer   Tracerr   bindrS   s    rE   <lambda>rY   M   s"    At{{)Co""1%  rG   c                    t        ||      } | | }t        |      \  }}|D cg c]  }t        j                  |       }	}|j	                  ||	df       |S c c}w N )r)   r(   r   get_avalstore)
fr^   in_tree	args_flatpy_argsansans_flatans_treerN   	ans_avalss
             rE   _flatten_fun_nokwargsrg   R   sa     7I.'	7##C((H)12At}}Q2)2++xB'(	/ 3s   AReturnValuec                      e Zd ZU dZded<   ded<   ded<   dZd	ed
<   dZded<   	 	 d	 	 	 	 	 ddZej                  Z
	 d	 	 	 	 	 ddZddZ eej                  d      dd       Zy)
custom_jvpa  Set up a JAX-transformable function for a custom JVP rule definition.

  This class is meant to be used as a function decorator. Instances are
  callables that behave similarly to the underlying function to which the
  decorator was applied, except when a differentiation transformation (like
  :py:func:`jax.jvp` or :py:func:`jax.grad`) is applied, in which case a custom
  user-supplied JVP rule function is used instead of tracing into and
  performing automatic differentiation of the underlying function's
  implementation.

  There are two instance methods available for defining the custom JVP rule:
  :py:func:`~jax.custom_jvp.defjvp` for defining a *single* custom JVP rule for
  all the function's inputs, and for convenience
  :py:func:`~jax.custom_jvp.defjvps`, which wraps
  :py:func:`~jax.custom_jvp.defjvp`, and allows you to provide separate
  definitions for the partial derivatives of the function w.r.t. each of its
  arguments.

  For example::

    @jax.custom_jvp
    def f(x, y):
      return jnp.sin(x) * y

    @f.defjvp
    def f_jvp(primals, tangents):
      x, y = primals
      x_dot, y_dot = tangents
      primal_out = f(x, y)
      tangent_out = jnp.cos(x) * x_dot * y + jnp.sin(x) * y_dot
      return primal_out, tangent_out

  For a more detailed introduction, see the tutorial_.

  .. _tutorial: https://docs.jax.dev/en/latest/notebooks/Custom_derivative_rules_for_Python_code.html
  Callable[..., ReturnValue]r@   Sequence[int]nondiff_argnumsSequence[str]nondiff_argnamesNz5Callable[..., tuple[ReturnValue, ReturnValue]] | NonejvpFboolsymbolic_zerosc                   t        | |       || _        t               }|r:t        | j                        }|J t	        |d |      \  }}|j                  |       |r|j                  |       t        t        |            | _        y r<   )	r   r@   setr   r   updatetuplesortedrm   selfr@   rm   ro   nondiff_argnums_siginferred_nondiff_argnumsrC   s           rE   __init__zcustom_jvp.__init__   s    
 4DH!$$((#c__$>
t%%! 67o. (8!9:DrG   c                "    || _         || _        |S )a  Define a custom JVP rule for the function represented by this instance.

    Args:
      jvp: a Python callable representing the custom JVP rule. When there are no
        ``nondiff_argnums``, the ``jvp`` function should accept two arguments,
        where the first is a tuple of primal inputs and the second is a tuple of
        tangent inputs. The lengths of both tuples are equal to the number of
        parameters of the :class:`~jax.custom_jvp` function. The ``jvp`` function
        should produce as output a pair where the first element is the primal
        output and the second element is the tangent output. Elements of the
        input and output tuples may be arrays or any nested tuples/lists/dicts
        thereof.
      symbolic_zeros: boolean, indicating whether the rule should be passed
        objects representing static symbolic zeros in its tangent argument in
        correspondence with unperturbed values; otherwise, only standard JAX
        types (e.g. array-likes) are passed. Setting this option to ``True``
        allows a JVP rule to detect whether certain inputs are not involved in
        differentiation, but at the cost of needing special handling for these
        objects (which e.g. can't be passed into jax.numpy functions). Default
        ``False``.

    Returns:
      Returns ``jvp`` so that ``defjvp`` can be used as a decorator.

    Examples:

      >>> @jax.custom_jvp
      ... def f(x, y):
      ...   return jnp.sin(x) * y
      ...
      >>> @f.defjvp
      ... def f_jvp(primals, tangents):
      ...   x, y = primals
      ...   x_dot, y_dot = tangents
      ...   primal_out = f(x, y)
      ...   tangent_out = jnp.cos(x) * x_dot * y + jnp.sin(x) * y_dot
      ...   return primal_out, tangent_out

      >>> x = jnp.float32(1.0)
      >>> y = jnp.float32(2.0)
      >>> with jnp.printoptions(precision=2):
      ...   print(jax.value_and_grad(f)(x, y))
      (Array(1.68, dtype=float32), Array(1.08, dtype=float32))
    )rp   rr   )ry   rp   rr   s      rE   defjvpzcustom_jvp.defjvp   s    ` DH(DJrG   c                d      j                   rt        d       fd} j                  |       y)a  Convenience wrapper for defining JVPs for each argument separately.

    This convenience wrapper cannot be used together with ``nondiff_argnums``.

    Args:
      *jvps: a sequence of functions, one for each positional argument of the
        :class:`~jax.custom_jvp` function. Each function takes as arguments
        the tangent value for the corresponding primal input, the primal
        output, and the primal inputs. See the example below.

    Returns:
      None.

    Examples:

      >>> @jax.custom_jvp
      ... def f(x, y):
      ...   return jnp.sin(x) * y
      ...
      >>> f.defjvps(lambda x_dot, primal_out, x, y: jnp.cos(x) * x_dot * y,
      ...           lambda y_dot, primal_out, x, y: jnp.sin(x) * y_dot)

      >>> x = jnp.float32(1.0)
      >>> y = jnp.float32(2.0)
      >>> with jnp.printoptions(precision=2):
      ...   print(jax.value_and_grad(f)(x, y))
      (Array(1.68, dtype=float32), Array(1.08, dtype=float32))
    z/Can't use ``defjvps`` with ``nondiff_argnums``.c                     	|  }t        |      }t        |      D cg c]  \  }}|r
 |||g|  n| }}}t        t        |g| }||fS c c}}w r<   )rT   zipr*   rP   )
primalstangents
primal_outzerostrp   all_tangents_outtangent_outjvpsry   s
           rE   rp   zcustom_jvp.defjvps.<locals>.jvp   st    >j ,e(+Hd(;=$a ;>#a6g65H = =]JJ9IJk$$=s   AN)rm   	TypeErrorr   )ry   r   rp   s   `` rE   defjvpszcustom_jvp.defjvps   s-    : GHH% 	KKrG   zjax.custom_jvp.__call__repro_api_namec                x    t        d j                  || j                        }|j                  } j                  sd| d}t        |      	 t         j                  ||      } j                  r1t         fdt        |      D              }t        t        |            D cg c]  }| j                  vs| }}t        t        j                   j                  |      ||d	
      \  }	}
 j                  D cg c]  }||   	 }}t        |      D cg c]  \  }}| j                  vs||    }}}t        d j                  g |||i t        t        t        |                        }t        t        j                   j                  |      |      }n^t        j                   j                  |      |}
}	t        d j                  ||fi       }t        j                   j                  |      }t!        |
      \  }}t#        |	|      \  }}t%        |||j                  ||      \  }}t'        j(                  ||g|d j*                  i}t        j,                  ||      \  }\  }}}t/        ||      S # t        $ r}t        d| d|       |d }~ww xY wc c}w c c}w c c}}w )Nzcustom_jvp funstatic_argnumsz'No JVP defined for custom_jvp function z using defjvp.z9The input arguments to the custom_jvp-decorated function T could not be resolved to positional-only arguments. Binding failed with the error:
c              3  Z   K   | ]"  \  }}|j                   v rt        |      n| $ y wr<   )rm   _stop_gradient).0irN   ry   s      rE   	<genexpr>z&custom_jvp.__call__.<locals>.<genexpr>  s4      0q! )*T-A-A(A>!$qH 0s   (+r   Frequire_static_args_hashablezcustom_jvp jvprr   )r   r@   rm   	func_namerp   AttributeErrorr   r   rv   	enumeraterangelenr   lu	wrap_initr   r(   rg   _flatten_jvpcustom_jvp_call_prX   rr   merge_linear_auxr)   )ry   argskwargsdebugprimal_namemsger   diff_argnumsf_dyn_argsstatic_argsa	diff_args	debug_jvprp   ra   r`   flat_fun	out_type1flat_jvp	out_type2out_flatrC   out_trees   `                        rE   __call__zcustom_jvp.__call__  s    '4&*&:&:<E//K885k].Qc3DHHdF3d  0(0 0d!&s4y!1SAQd>R>R5RaSlS$R\\$((u%M%14BGIlb( '+&:&:;T!W;k;'0Xtq!!4CWCW:W47XiX-txxA{AIAyA,1%K8H2I,JLi  TXX8A!CDOQc \\$((u=t(b-txx"D\!i LLi8c%h/Iw/G<Hi&sK9L9L'.	;Hi %%h J9 J595H5HJH--iCA!Q(H--G  
EM --.C1 	 T <Xs6   J	 'J,;J, J1J63J6		J)J$$J)r\   r\   r@   rk   rm   rl   ro   rn   )F)rp   .Callable[..., tuple[ReturnValue, ReturnValue]]rr   rq   returnr   )r   z!Callable[..., ReturnValue] | Noner   Noner   r
   r   r
   r   rh   )__name__
__module____qualname____doc____annotations__rp   rr   r}   r   forward_attr__getattr__r   r   r   r   api_boundaryr   r\   rG   rE   rj   rj   a   s    #H "!  !!?C#<C.$ 1313;.; -; "/;,  ,,+ %*2@2!2 A2h(T >&&35-.5-.rG   rj   T)use_eq_storec                   t        |t        |      dz  g      \  }}t        ||      }	t        ||      }
 | |	|
      }t        |t        t
        f      rt        |      dk7  rd| d| d| d}t        |      |\  }}t        |      \  }}t        |      \  }}|D cg c]  }t        j                  |       }}||k7  rd| d| d| d| d	}t        |       |       }|#|\  }}\   t        ||D cg c]  }|j                          c}      }t        ||D cg c]  }|j                          c}      }||k7  rRd| d| d	| d
t        |      j                  dd       d| dt        |      j                  dd       d}t        |      t        t!        t        j"                  ||            sQd| d| d	| dt        |      j                  dd       d| dt        |      j                  dd       }t        |      |D cg c]%  }t        j                  |      j%                         ' }}|D cg c]3  }t        j                  |      j%                         j'                         5 }}|D cg c]P  }t)        |      t*        ur#t        j                  |      j%                         n|j,                  j%                         R }}t        t!        t        j"                  ||            st        |      dk(  rU|||c\  } \  }!\  }"d}t        |j/                  |!j                         | j                         |"j                                     d}d t1        |||      D        }#t        |j/                  dj3                  |#                  |j5                  ||df       ||z   S c c}w # t        j                  $ r d }Y w xY wc c}w c c}w c c}w c c}w c c}w )N   zCustom JVP rule  for function zd must produce a pair (list or tuple of length two) representing primal and tangent outputs, but got .z[ must produce primal and tangent outputs with equal container (pytree) structures, but got  and z respectively.z must produce a pair (list or tuple of length two) where the first element represents the primal output (equal in value to the output of the custom_jvp-decorated function z, and in particular of the same container/pytree structure), but instead the JVP rule output's first element had container/pytree structure:
    ' z)
while the custom_jvp-decorated function , had output container/pytree structure:
    z, and in particular with leaves of the same shape/dtype), but instead the JVP rule output's first element had shapes/dtypes of:
    " had output shapes/dtypes of:
       zCustom JVP rule must produce primal and tangent outputs with corresponding shapes and dtypes. Expected {} (tangent type of {}) but got {}.ziCustom JVP rule must produce primal and tangent outputs with corresponding shapes and dtypes, but got:
{}c              3  |   K   | ]4  \  }}}||k7  r)d |j                          d|j                          d|  6 yw)z	  primal z with tangent z, expecting tangent N)	str_short)r   av_pav_etav_ts       rE   r   z_flatten_jvp.<locals>.<genexpr>z  sK      dE4d] dnn&'~dnn6F5GG[\a[b
cs   :<
r\   )r8   r   r)   rV   listrv   r   r(   r   r]   r   StoreExceptionr   strreplaceallmap	typematchstrip_weak_typeto_tangent_avaltyper   avalformatr   joinr^   )$r_   r^   r   jvp_namer`   maybe_out_typer   
primals_intangents_in
py_primalspy_tangentspair_outr   py_primals_outpy_tangents_outprimals_outr   tangents_out	out_tree2rN   primal_avals	out_type_	out_tree_primal_avals_r   ty_treety_tree_mprimal_avals_outexpected_tangent_avals_outr   tangent_avals_outr   r   r   disagreementss$                                       rE   r   r   4  s    &tc$i1n-=>*kgz2*w4+z;'(	HtUm	,H0BhZ~k] C22:1>C C.$,!./&~6+x(9,	,78q$--"8,8hZ~k] C""*5>KC C.!#y#, I}bh)NA!++-)NOGi)OA!++-)OPHHhZ~k] CQ ]  M))#r23 466A] CM))#r2318a aLs4>><?@hZ~k] CQ ]  M))#r23 466A] CM))#r23
7a aLBMNQdmmA&668NN  	 	MM!$$&668   
 !-. q'5 }}Q'779;<66;Q;Q;ST . . 
S!;=NO	P
%&!+#35OQb gtx$]ccjj!2DNN4DdnnFVWXX=c#&'79SUf#gm cjj=!9:;;++xr*+	|	##} 9 
		,I, *O)O8 O .s7   N0N5 6O
O
*O<8O :AO%5OOc                  (    e Zd ZdZd Zd Zd Zd Zy)CustomJVPCallPrimitiveTc                &     | j                   |i |S r<   
_true_bindry   r   paramss      rE   rX   zCustomJVPCallPrimitive.bind      4??D+F++rG   c                L    |d   |d   |dd  }}} |j                   | |||fi |S )Nr   r   r   )process_custom_jvp_call)ry   tracer   r  r@   rp   tracerss          rE   bind_with_tracez&CustomJVPCallPrimitive.bind_with_trace  s;    Qa$qr(gC(5((sCKFKKrG   c                    t         r<   NotImplementedError)ry   r@   rC   r   s       rE   implzCustomJVPCallPrimitive.impl      
rG   c                   t        |      }|j                  d      }|j                  d      }|j                  d      }t        j                  t	        j
                  |      |j                  j                        }t        ||      }||g|fS )N
call_jaxpr
num_constsjvp_jaxpr_funr   )	dictpopr   r   r   jaxpr_as_funrB   r   lift_jvp)ry   r  
new_paramsr  r  r  r@   rp   s           rE   get_bind_paramsz&CustomJVPCallPrimitive.get_bind_params  sz    fJ#->>,#?J nn\2JNN?3M
,,t((4","2"2"="=?C
:}
-C:z!!rG   Nr   r   r   multiple_resultsrX   r  r  r  r\   rG   rE   r   r     s    ,L"rG   r   c                T      fd}t        j                  |j                        S )Nc            	     f   t        t        |       d      \  }}|rJ | | | |z   d  }}|D cg c]  }t        |      t        u  }} j                  | \  }}}	|D cg c]  }t        |      t        us| }
}t        j                  ||g||
 }t        |t        |	      g      \  }}t        |      }t        ||	      D cg c]>  \  }}|r,t        t        j                  |      j                               n
t        |      @ }}}t        |d       J g ||S c c}w c c}w c c}}w )Nr   )divmodr   r   r   call_wrappedr   
eval_jaxprr8   iterr   r]   r   next)rO   nraggedr   r   r   r   	jvp_jaxpr
jvp_consts	out_zerosnonzero_tangentsoutout_primalsnz_out_tangentsnz_out_tangents_pzout_tangentsr  r  s                     rE   rp   zlift_jvp.<locals>.jvp  sS   s2w"IAv::a("Qz\]*;XG.67T!W$7E7'A}'A'A5'I$Iz9#+KatAwl/JKK
//)Z
M'
M<L
MC#-cC	N3C#D KO, !$K ;=1  !q!1!A!A!CD"#345 =L =  $'///([(<(( 8K=s   D# D(7D(	AD-r   r   r   r   )r  r  rp   s   `` rE   r  r    s!    ) 
cm&>&>	??rG   custom_jvp_callc                   ~~~t         j                  j                  |j                         }|rt        d|       |j                  |j                   fS )Nz'Effects not supported in `custom_jvp`: r   "custom_derivatives_allowed_effectsfilter_not_inr  	out_avals)rC   r  r  r  rr   rA   disallowed_effectss          rE   _custom_jvp_call_typecheckr6    s^     zAAOOPZPbPbc

12D1EFH H			z11	11rG   c                  t        j                  |j                  |j                  j                  D cg c]  }|j
                   c}      }t        j                  | j                  |j                  | j                  | j                  |g|| j                  | j                  d\  }}| j                  |       |S c c}w )N)dim_var_valuesconst_lowering)r$   	ir_constsrD   rB   	constvarsr   jaxpr_subcompmodule_context
name_stack	tokens_inr8  r9  set_tokens_out)ctxr  r   rC   vrD   r'  tokenss           rE   _custom_jvp_vjp_call_loweringrD    s    >>**:*:*D*DEQ!&&EG&""3#5#5z7G7G#&>>3==&F$(F9<9K9K252D2DF+#v V	* Fs   B=
c                ^    ~ t        j                  |j                  d|j                  ||      S NF)r"   backward_pass3rB   rD   )r  rB   r   ctrC   s        rE    _custom_jvp_call_transpose_fancyrI    s&    			5;;u||T2	FFrG   c                    | j                   | j                  }}t        j                  |j	                  |j
                  j                               |d      \  }}t        j                  ||      |fS )Nr   T)	rB   rD   r>   	dce_jaxprr   r   with_unknown_namesr   ClosedJaxpr)jaxpr_used_outputsrB   rD   	new_jaxprused_inputss         rE   #_cached_closed_call_dce_instantiaterR    sd     ,,%<<mmu//BBDmED)[ 
		)V	,k	99rG   c           	         t               s0t        j                        sdgt        j                        z  d fS j
                  d   }j
                  d   t        |t                     \  }}t        |      sJ t        j                   fd       }t         j                        D cg c]
  \  }}|s	| }}}t        j
                  |t        j                  |j                              }	t        j                   j                  |j"                  |	|j$                  j&                  j(                        }
||
fS c c}}w )NFr  r  c                 4    j                   |  \  }}}j                  d   }|r"t        |      D cg c]
  \  }}|r	| c}}n}t        j                  |g |d      \  }}	t        |      D 
cg c]
  \  }
}|
s	| }}
}|||fS c c}}w c c}}
w )Nrr   T)r  r  r   r>   rK  )in_zerosr#  rD   r%  szur,  nz_used_outsdce_jvp_jaxprrC   usedrB  dce_out_zeroseqnr  	used_outss                rE   dce_jvp_jaxpr_thunkz1_custom_jvp_call_dce.<locals>.dce_jvp_jaxpr_thunk  s    #==#=#=x#H Ivy	$	%BIK#i";E$!Q1AEQZL||I/J/J\/JDQM1&))Y&?H744QHMH&-// FHs   
B B7
BBr   )r  r  )anyr>   has_effectsr   invarsr  rR  rv   r   _memoizer   outvarsr  r   r   r   new_jaxpr_eqn	primitiver   source_inforA  )r]  r\  r  dce_call_jaxprused_insr^  rZ  rB  rc  r  new_eqnr  s   ``         @rE   _custom_jvp_call_dcerj    s)    
Ys 37S_$d**zz,'***_-- A%	"$.(	X;;0 0 ")S[[9B74TQB'B	jjLL!4,9,D,DF* 	jj'3==*n6L6L	oosww ' 
7	 Cs   5
E Ec                d   t        | j                        }|d   s|j                  d       |j                  d      j                  j                  |d<   t        |      }|d   j                  j                  j                  |d<   t        j                  | j                  |      ||dg|z         S )Nr  r  rp   r  namer  
r  r  r  r   r   rw   rB   r   _pp_eqnr   r\  contextsettingsr  namess        rE   _custom_jvp_call_pp_rulert    s     

&		
JJ|**_-88BB&-
.%,'--88BB&.	ckkk0'8$X-
/ /rG   c                      e Zd ZdZ	 	 d	 	 	 	 	 d	dZej                  Z	 	 d
	 	 	 	 	 	 	 	 	 ddZ e	e
j                  d      dd       Zy)
custom_vjpa  Set up a JAX-transformable function for a custom VJP rule definition.

  This class is meant to be used as a function decorator. Instances are
  callables that behave similarly to the underlying function to which the
  decorator was applied, except when a reverse-mode differentiation
  transformation (like :py:func:`jax.grad`) is applied, in which case a custom
  user-supplied VJP rule function is used instead of tracing into and performing
  automatic differentiation of the underlying function's implementation. There
  is a single instance method, :py:func:`~jax.custom_vjp.defvjp`, which may be
  used to define the custom VJP rule.

  This decorator precludes the use of forward-mode automatic differentiation.

  For example::

    @jax.custom_vjp
    def f(x, y):
      return jnp.sin(x) * y

    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)

  For a more detailed introduction, see the tutorial_.

  .. _tutorial: https://docs.jax.dev/en/latest/notebooks/Custom_derivative_rules_for_Python_code.html
  c                F   t        | |       || _        t               }|r:t        | j                        }|J t	        |d |      \  }}|j                  |       |r|j                  |       t        t        |            | _        d | _	        d | _
        d| _        d| _        y rF  )r   r@   rt   r   r   ru   rv   rw   rm   fwdbwdrr   optimize_rematrx   s           rE   r}   zcustom_vjp.__init__,  s     4DH!$$((#c__$>
t%%! 67o. (8!9:D>BDH6:DHDDrG   c                    || _         || _        || _        || _        | j                  r| j                  rt	        d      yy)a  Define a custom VJP rule for the function represented by this instance.

    Args:
      fwd: a Python callable representing the forward pass of the custom VJP
        rule. When there are no ``nondiff_argnums``, the ``fwd`` function has
        the same input signature as the underlying primal function. It should
        return as output a pair, where the first element represents the primal
        output and the second element represents any "residual" values to store
        from the forward pass for use on the backward pass by the function
        ``bwd``. Input arguments and elements of the output pair may be arrays
        or nested tuples/lists/dicts thereof.
      bwd: a Python callable representing the backward pass of the custom VJP
        rule. When there are no ``nondiff_argnums``, the ``bwd`` function takes
        two arguments, where the first is the "residual" values produced on the
        forward pass by ``fwd``, and the second is the output cotangent with the
        same structure as the primal function output. The output of ``bwd`` must
        be a tuple of length equal to the number of arguments of the primal
        function, and the tuple elements may be arrays or nested
        tuples/lists/dicts thereof so as to match the structure of the primal
        input arguments.
      symbolic_zeros: boolean, determining whether to indicate symbolic zeros
        to the ``fwd`` and ``bwd`` rules. Enabling this option allows custom
        derivative rules to detect when certain inputs, and when certain
        output cotangents, are not involved in differentiation. If ``True``:

        * ``fwd`` must accept, in place of each leaf value ``x`` in
          the pytree comprising an argument to the original function,
          an object (of type
          ``jax.custom_derivatives.CustomVJPPrimal``) with two
          attributes instead: ``value`` and ``perturbed``. The
          ``value`` field is the original primal argument, and
          ``perturbed`` is a boolean.  The ``perturbed`` bit indicates
          whether the argument is involved in differentiation (i.e.,
          if it is ``False``, then the corresponding Jacobian "column"
          is zero).

        * ``bwd`` will be passed objects representing static symbolic zeros in
          its cotangent argument in correspondence with unperturbed values;
          otherwise, only standard JAX types (e.g. array-likes) are passed.

        Setting this option to ``True`` allows these rules to detect whether
        certain inputs and outputs are not involved in differentiation, but at
        the cost of special handling. For instance:

        * The signature of ``fwd`` changes, and the objects it is passed cannot
          be output from the rule directly.

        * The ``bwd`` rule is passed objects that are not entirely array-like,
          and that cannot be passed to most ``jax.numpy`` functions.

        * Any custom pytree nodes involved in the primal function's arguments
          must accept, in their unflattening functions, the two-field record
          objects that are given as input leaves to the ``fwd`` rule.

        Default ``False``.
      optimize_remat: boolean, an experimental flag to enable an automatic
        optimization when this function is used under :func:`jax.remat`. This
        will be most useful when the ``fwd`` rule is an opaque call such as a
        Pallas kernel or a custom call. Default ``False``.

    Returns:
      None.

    Examples:

      >>> @jax.custom_vjp
      ... def f(x, y):
      ...   return jnp.sin(x) * y
      ...
      >>> 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)

      >>> x = jnp.float32(1.0)
      >>> y = jnp.float32(2.0)
      >>> with jnp.printoptions(precision=2):
      ...   print(jax.value_and_grad(f)(x, y))
      (Array(1.68, dtype=float32), Array(1.08, dtype=float32))
    Aremat optimization for custom_vjp does not support symbolic zerosN)rx  ry  rr   rz  r  )ry   rx  ry  rr   rz  s        rE   defvjpzcustom_vjp.defvjpG  sN    t DHDH(D(Dt22
MO O  3rG   zjax.custom_vjp.__call__r   c           	        t        d| j                  ||| j                        }| j                  r| j                  sd|j
                   d}t        |      	 t        | j                  ||      }t        d| j                  ||| j                        }t        d| j                  |i       }| j                  r:t        | j                  || j                  || j                  | j                  	      }n| j                  }t        j                  j                  rE| j                  rt        d
       t!        | j                  | j                  | j                        | S | j                  r| j                  D ]  }	t#        ||	           t%        t'        |            D 	cg c]  }	|	| j                  vs|	 }
}	t)        t+        j,                  | j                  |      |
|d      \  }}| j                  D 	cg c]  }	||	   	 }}	t)        t+        j,                  ||      |
|d      \  }}t/        t+        j,                  | j                  |      |      }n[t+        j,                  | j                  |      |}}t+        j,                  ||      }t+        j,                  | j                  |      }t1        |      \  }}|D cg c]  }t3        j4                  |       }}t        j6                  j                  r!t9        || j                  |j                         }t;        ||      \  }}t=        || j                  | j                  ||||      \  }}t?        ||||      }tA        jB                  |||g||| j                  d}t+        jD                  ||      \  }\  }}}tG        ||      S # t        $ r!}t        d|j
                   d|       |d }~ww xY wc c}	w c c}	w c c}w )Nzcustom_vjp funr   z'No VJP defined for custom_vjp function z using defvjp.z9The input arguments to the custom_vjp-decorated function r   zcustom_vjp fwdzcustom_vjp bwd)rm   rr   z2nondiff_argnums not implemented for new custom_vjpr   Fr   )	out_treesrr   )$r   r@   rm   rx  ry  r   r   r   r   rz   optimize_remat_of_custom_vjp_fwdrr   r   %enable_custom_vjp_by_custom_transposevaluer  custom_vjp_by_custom_transpose_check_for_tracersr   r   r   r   r   r   r(   r   r]   mutable_array_checks_check_primal_refsrg   _flatten_fwd_flatten_bwdcustom_vjp_call_prX   r   r)   )ry   r   r   	debug_funr   r   	debug_fwd	debug_bwdrx  r   dyn_argnumsr   r   r   fwd_rC   ry  ra   r`   rN   rA   r   out_typeflat_fwdr  flat_bwdr   r   s                               rE   r   zcustom_vjp.__call__  s    +TXXtV*.*>*>@I884885i6I6I5J.Yc3DHHdF3d +TXXtV*.*>*>@I +TXXtR@I,
((Itxx..,,.c
 HHc3399			!@B 	BI+DHHdhhI4PP			%%BA'9$q''BB"'D	"2TQat?S?S6SqTT&LLi8+u6H )-(<(<=1tAw==!",,sy"I"-t?DFa "",,txxI"N"-/ ||DHHCTH||CI6ll488	:'1i,56q$--"6h6		$	$	*	*D$8$8"--H0W=h(
$$d&9&99
Wh(h	 c7Hi@h"''(H L)2L>G7;7J7JLh //)Da	(AqHh//k  
E  ! "889s< 	4 U > 7s0   N2 O2O7O$O)2	O;OONr   r   )FF)
rx  &Callable[..., tuple[ReturnValue, Any]]ry  zCallable[..., tuple[Any, ...]]rr   rq   rz  rq   r   r   r   )r   r   r   r   r}   r   r   r   r}  r   r   r   r   r\   rG   rE   rv  rv  	  s    F 1313 .  -  "/ 2  ,,+
 %*$)	`O8`O0`O "`O "	`O
 `OD >&&35>05>0rG   rv  c                J    t        | |||        | | }t        | |dg d       |S )Nprimalr   )_check_for_aliased_refs_check_for_returned_refs)r_   rm   r   r   r'  s        rE   r  r    s0     !_eT:	4#1c8R3	*rG   c                   t        |      }t        |      D cg c]%  \  }}|gt        |      j                  z  D ]  }| ' }}}}t	        |      }	i }
t        t        ||	            D ]  \  }\  }}||v rt        |t              r|j                  n|}t        t        j                  |      x}t              sR|
j                  t        t        j                  |            |      x}|k7  s|j                  t!        |	            }t#        d|  d|j%                          d||    d||    d	       y c c}}}w )Nzjonly one reference to a mutable array may be passed as an argument to a function, but custom_vjp function z. got the same mutable array reference of type z at r   r   )rt   r   r3   
num_leavesr.   r   rV   CustomVJPPrimalr  r   r]   r!   
setdefaultidget_referentsafe_arg_namesr   
ValueErrorr   )r_   rm   r   r   rz   r   argrN   argnumsleavesrefsargnumr   dup_idx	arg_namess                  rE   r  r    sL   )&t_ < <61ccN3/:::<  <Q <' <t&$!#gv"67 
na&! (a1qAq))AK8OOBt'8'8';$<a@	@QF&&s6{3i4453 7%%&[[]O4	'8J7K Ll^1 
	<s   *D9c                P   |D cg c]   }t        |t              r|j                  n|" }}|D ch c]1  }t        t        j                  |      t
              s't        |      3 }}t        |      }t        |      D ]  \  }\  }	}
t        t        j                  |
      x}t
              s/|	rdt        |	       nd}||k  r%t        d| d|  d|j                          | d      t        |
      |vsyt        d| d|  d|j                          | d       y c c}w c c}w )Nz at output tree path r   zcustom_vjp z
 function z, returned a mutable array reference of type z8, but mutable array references cannot be returned there.z that was not an argument.)rV   r  r  r   r]   r!   r  r0   r   r1   r  r   )r_   r'  kindr   	after_idxrN   idsr  r   pathleafr   locs                rE   r  r    s5   DH	IqZ?3!''
:	I$	IJ1
4==+;[ IAJ#J %&"6* 
6oa$d++1k:6:#F4L>2c	
Y;tfJqc :445KKM?3% HRR S 	S 
D	;tfJqc :445KKM?3% H55 6 	6
6 
JJs   %D(D#D#c                  &    e Zd ZU dZded<   ded<   y)r  zHPrimal to a ``custom_vjp``'s forward rule when ``symbolic_zeros`` is setr
   r  rq   	perturbedN)r   r   r   r   r   r\   rG   rE   r  r    s    P	*/rG   r  c                     d }t        ||       S )a	  Strips away perturbation information from forward rule arguments.

  This is a helper function for user with the ``symbolic_zeros`` option to
  the ``defvjp`` method of a ``custom_vjp``-decorated function.

  In ``symbolic_zeros`` mode, the custom forward rule receives arguments
  whose pytree leaves are records with a ``value`` attribute that carries
  the primal argument. This is a way to convert such argument trees back to
  their original form, replacing each such record with its carried value at
  each leaf.
  c                j    t        |       t        urt        dt        |              | j                  S )Nzunexpected leaf type )r   r  r   r  )r  s    rE   r  z,custom_vjp_primal_tree_values.<locals>.value(  s/    Dz(-d4j\:;;::rG   )r*   )treer  s     rE   custom_vjp_primal_tree_valuesr    s     
%	rG   c                r    t        |       D ])  }t        |t        j                        sd}t	        |       y )Na  Found a JAX Tracer object passed as an argument to a custom_vjp function in a position indicated by nondiff_argnums as non-differentiable. Tracers cannot be passed as non-differentiable arguments to custom_vjp functions; instead, nondiff_argnums should only be used for arguments that can't be or contain JAX tracers, e.g. function-valued arguments. In particular, array-valued arguments should typically not be indicated as nondiff_argnums.)r.   rV   r   rW   r    )rN   r  r   s      rE   r  r  .  s8    !n 	'd$$Nc "#&&	'rG   c                   |r|j                   n
t        |       }	|r|j                   nd}
|r)t        d t        |d d d   |dd d         D              }n|d d d   }t	        ||      }t
        j                  j                  rt        | |||        | | }t        |t        t        f      rt        |      dk7  rd|
 d|	 d|	 d|
 d	| d
}t        |      |\  }}t        |      \  }}t        |      \  }}t
        j                  j                  rt        | |d||j                         |D cg c]  }t!        j"                  |       }} |       }|#|\  }}\   t	        ||D cg c]  }|j)                          c}      }t	        ||D cg c]  }|j)                          c}      }||k7  rRd|
 d|	 d|	 dt        |      j+                  dd       d|	 dt        |      j+                  dd       d
}t        |      t-        t/        t         j0                  ||            sQd|
 d|	 d|	 dt        |      j+                  dd       d|	 dt        |      j+                  dd       }t        |      t3        ||      \  }}|j5                  |||f       g ||S c c}w # t$        j&                  $ r d }Y mw xY wc c}w c c}w )Nz	<unknown>c              3  :   K   | ]  \  }}t        ||        y wr<   )r  )r   rN   r,  s      rE   r   z_flatten_fwd.<locals>.<genexpr>D  s     N41aA&Ns   r   r   zCustom VJP fwd rule r   z must produce a pair (list or tuple of length two) where the first element represents the primal output (equal to those of the custom_vjp-decorated function z) and the second element represents residuals (i.e. values stored from the forward pass for use on the backward pass), but instead of a pair the fwd rule z
 produced r   rx  z must produce a pair (list or tuple of length two) where the first element represents the primal output (equal to the output of the custom_vjp-decorated function z) and the second element represents residuals (i.e. values stored from the forward pass for use on the backward pass), but instead the fwd rule output's first element had container/pytree structure:
    r   r   z)
while the custom_vjp-decorated function r   z) and the second element represents residuals (i.e. values stored from the forward pass for use on the backward pass), but instead the fwd rule output's first element had shapes/dtypes of:
    r   )r   r   rv   r   r)   r   r  r  r  rV   r   r   r   r(   r  r  r   r]   r   r   r   r   r   r   r   _filter_forwarded_inputsr^   )r_   r^   rm   rr   debug_primalr  r`   r   r   r   fwd_namerb   r   r   r   resr   r   res_treerN   r   r   r   r   r   r   r   r   
pruned_resinput_forwardss                                 rE   r  r  :  s    +7&&CF+$-Y  ;(N3tCaCy$qt!t*3MNND!9D7D)'  &&AgF[(	HtUm	,H0B!(>+ G, -8= 9- .6Jj
!MC C. .#&~6+xs#-#x  &&Q%x7J7JK,78q$--"8,8!#y#, I}bh)NA!++-)NOGi)OA!++-)OPHH!(>+ GH ] 
 M))#r23 466A] CM))#r2318a aLs4>><?@!(>+ GH ]  M))#r23 466A] CM))#r237a aL7TB*n++x>23	$:	$	$$O 9 
		,I, *O)Os$   /J$J) (K
K

)KKc           	         t        |      D ci c]  \  }}t        |      | }}}| D cg c]  }t        |      |vs| c}| D cg c]  }|j                  t        |             c}fS c c}}w c c}w c c}w r<   )r   r  get)outsinsr   rN   idxsos         rE   r  r    sh    /8~>tq!"Q%(>$>	/RU$.!	/41Pa$((2a5/1P	PP ?	/1Ps   A.A4A4	!A9c                ~    |       \  }}}t        |      |j                  |j                  z   k(  sJ t        ||j                  g      \  }}	t        ||      }
t        ||	      } | |
|      }t	        |t
              r+t        |      t        t        |            k(  rt        |      }t               t        |t               g|j                  z        }t        t        |      d         \  }}g fd}	 t	        |t              st        t        |||d        g }t!        ||      D ]  \  }}}|u s+t#        |j%                         d      t&        j(                  k(  r)|j+                  t-        |j%                                      `t/        |      t0        u rt3        j4                  |j7                         |j8                  x}      s<dt;        |       d|j=                          d	|j=                          d
}t        |      |j+                  t-        |j8                               t3        j4                  |j7                         t3        j>                  |      x}      stA        |j7                         |      sktC        |j7                         |      sQdt;        |       d|j=                          d|j=                          t3        jD                  ||       }t        |      |j+                  |        |S # t        $ r- t        |      \  }}d}t        |j                  ||            d w xY w)Nr   c                    t        t        |      d         }| |j                  g|z         | S | j                  | g|z         | S )Nr   )r   r(   extend)rN   dr  cts_in_flatzeros      rE   appendz_flatten_bwd.<locals>.append  s\    \!_Q'(JyQ]$*,- H 
!z)*HrG   c                
    | d u S r<   r\   rS   s    rE   rY   z_flatten_bwd.<locals>.<lambda>  s
    d rG   )is_leafa(  Custom VJP bwd rule must produce an output with the same container (pytree) structure as the args tuple of the primal function, and in particular must produce a tuple of length equal to the number of arguments to the primal function, but got bwd output structure {} for primal input structure {}.dtypezCustom VJP bwd rule produced a SymbolicZero with a shape/dtype that does not match the corresponding input tangent shape/dtype: at outputz" the SymbolicZero had shape/dtype z/ while the corresponding input had shape/dtype zG. Consider just returning a None here instead of a SymbolicZero object.zuCustom VJP bwd rule must produce an output with the same type as the args tuple of the primal function, but at outputz) the bwd rule produced an output of type z# corresponding to an input of type )#r   r  r8   r)   rV   r   r2   rv   objectr9   r/   r  r*   r(   r   r   r   getattrr   r   float0r  r   r   r   r   
typecompatto_cotangent_avalr   r1   r   r]   _ref_typecompat_temporary_dtype_exceptionaval_mismatch_extra)r_   r`   rA   r  r   r   r  rC   r  cts_outpy_res
py_cts_out	py_cts_indummykeypathsr  in_tree2r   resultskpr   rH  a_r  r  s                          @@rE   r  r    s    $+(Ha	Th))H,?,??	??	?D8#6#6"78,#w(C(&h0*
#)	4 S^s;KG;T7U%Ui I
 
$
68*w/A/A"A
B%-e4Q78+(A+=i'VY/BC 'x;7 ib!R	TzWQ..0':fmmKnnT!++-./	b\	!__Q002"''MBB!":,&H,,.! "667kkm_ E	 onnT"'']#ooa1134==;L5LRM!!"5"5"7<,Q-@-@-BBGr
| $||~& '&&'kkm_**1b124 onnR34 
.G 
 =y)KAx9C
 CJJx1
2<=s   :&L 6L<c                    t        | t              xr. t        j                  | j	                         j
                  |      S r<   )rV   r!   r   r  r  
inner_avalr   r  s     rE   r  r    s5    
Q
$ @
//!--/::B
?ArG   c                   t        | t        j                        rt        |t        j                        r| j                  |j                  k(  xr t        j                  | |d      xrh t        j                  |j                  t
        j                        xs8 t        j                  | j                  t
        j                  j                        S y)NT)only_shape_shd_checkF)rV   r   ShapedArrayshaper   r   
issubdtyper  extendednpinexactr  s     rE   r  r    s    4##$B8H8H)IGGrxx <NN1bt<<rxx9 ;qww		(9(9:= 
rG   c                  (    e Zd ZdZd Zd Zd Zd Zy)CustomVJPCallPrimitiveTc                &     | j                   |i |S r<   r   r  s      rE   rX   zCustomVJPCallPrimitive.bind  r  rG   c                ^    |d   |d   |d   |dd  f\  }}}} |j                   | ||||fi |S )Nr   r   r      )process_custom_vjp_call)ry   r  r   r  r@   rx  ry  r  s           rE   r  z&CustomVJPCallPrimitive.bind_with_trace  sK    !!Wd1gtAwQR@Cc7(5((sCgPPPrG   c                    t         r<   r
  )ry   r@   rx  ry  r   s        rE   r  zCustomVJPCallPrimitive.impl  r  rG   c                   t        |      }|j                  d      }|j                  d      }|j                  d      }t        j                  t	        j
                  |      |j                  j                        }t        ||      }t        |j                  |g      \  }}	t        |j                  d      |      }
|||
g|fS )Nr  r  fwd_jaxpr_thunkr   ry  )r  r  r   r   r   r  rB   r   lift_fwdr8   rA   _handle_consts_in_bwd)ry   r  r  r  r  r  r@   rx  const_avalsrC   ry  s              rE   r  z&CustomVJPCallPrimitive.get_bind_params  s    fJ#->>,#?J nn\2J nn%67O
,,t((4","2"2"="=?C
:
/C
 3 3j\BNK

u 5{
CCc?J&&rG   Nr  r\   rG   rE   r  r    s    ,Q
'rG   r  c                T      fd}t        j                  |j                        S )Nc                 &   | d d d   | dd d   }}t        |      t        |      k(  sJ t        |
g      \  }}t        |
g      \  }}t        |      rt        j                          	j
                  | \  }}t        j                  ||g| S )Nr   r   )r   r8   r_  r"   CustomVJPExceptionr  r   r  )r   valsnonzerosrC   r   const_nonzerosin_nonzeros	fwd_jaxpr
fwd_constsr  r  s            rE   rx  zlift_fwd.<locals>.fwd  s    #A#YQTT
(Dt9H%%%D:,/JAw",X
|"DNK
>""7"7"998O88+FIz??9j;7;;rG   r   r.  )r  r  rx  s   `` rE   r  r    s!    < 
co&@&@	AArG   c                \    |D cg c]  }t        |       c}t         | |       z   S c c}w r<   )r   r   )r_   r  r   r   s       rE   r  r    s'    &	'a$q'	'$q$x.	88	's   )custom_vjp_callF)	cacheablec                   ~~t         j                  j                  |j                         }|rt        d|       |j                  |j                   fS )Nz'Effects not supported in `custom_vjp`: r1  )rC   r  rA   r   r5  s        rE   _custom_vjp_call_typecheckr    s\    AAOO

12D1EFH H			z11	11rG   c           	         t               s0t        j                  |      sdgt        |j                        z  d fS |j
                  d   |j
                  d   |j
                  d   |j
                  d   |j
                  d   t        t                     \  }}t        |      sJ t        t        j                  j                        t        j                   fd              } fd	}t        j                  |j                        }t         |j                        D cg c]
  \  }}|s	| }	}}t!        |j
                  |||
      }
t        j"                  |j                  |	|j$                  |
|j&                  |j(                  |j*                        }t-        |      |fS c c}}w )NFr  r  ry  r  rr   r   c                    t        j                   j                  |   }        \  }}}|j                  t	        d |D              z
  }t        |d|z  t        	      z         \  }}|j                  |j                  fS )Nc              3  $   K   | ]  }|d u 
 y wr<   r\   r   r_   s     rE   r   zD_custom_vjp_call_dce.<locals>.dce_fwd_jaxpr_thunk.<locals>.<genexpr>&       +HaATM+H   )T)	r   rM  r  r  sumrR  rv   rB   rD   )
r   r  rC   r  fwdsnum_res_outdce_fwd_jaxprr  r  r]  s
          rE   dce_fwd_jaxpr_thunkz1_custom_vjp_call_dce.<locals>.dce_fwd_jaxpr_thunk!  s       ">/">">"FGI!Ax%%+H4+H(HHK:7[(5+;;=M1 4 444rG   c                            \  }}}t        | |j                  g      \  }}t        |      }g }t        j                        D ]i  \  }}|r|j                  t        |             #|j                         }	r|j                  t        |	             P|j                  t        |	             k t        |d       J  
j                  g || S r<   )r8   r  r  r   r4  r  r   r   r   r   r  )r   rC   r  r  ctscts_all_ctsrZ  r   ct_avalry  r  r  rr   r]  s             rE   dce_bwdz%_custom_vjp_call_dce.<locals>.dce_bwd+  s    [NAx$!4!4 56HC9DG)Z%9%9: 3
d	tDz"&&(
..g.
/
..1
23 d###3+S+7++rG   )r  r  ry  )r_  r>   r`  r   ra  r  rR  rv   r   r   r   r   r   rb  r   rc  r  rd  re  r   rf  rA  r   )r]  r\  rg  rh  r  r  dce_bwd_wrappedrZ  rB  rc  r  ri  ry  r  r  r  rr   s   `           @@@@@rE   _custom_vjp_call_dcer    s    
Ys 37S_$d**!$L!9*JJ01/zz%(#KN::VaKb)$45. A%	"$.(	X
2<<O$>$>?;;5  @5, ," LL,/NN</!)S[[9B74TQB'B	jj)
	* 	jj'3==*n6L6L	oosww ' 
h	   Cs   7
F<F<c                   t        | j                        }|d   s|j                  d       |j                  d       |j                  d      j                  j                  |d<   |j                  d      j                  j                  |d<   t        |      }|d   j                  j                  j                  |d<   t        j                  | j                  |      ||dg|z         S )	Nr  r  r  rx  ry  r  rl  rm  rn  rp  s        rE   _custom_vjp_call_pp_ruler  L  s     

&		
JJ|**[**./::DD&-**U#..88&-
.%,'--88BB&.	ckkk0'8$X-
/ /rG   c                X     t          fd       } fd}d }|j                  ||       |S )a
  Convenience function for defining custom VJP rules (aka custom gradients).

  While the canonical way to define custom VJP rules is via ``jax.custom_vjp``,
  the ``custom_gradient`` convenience wrapper follows TensorFlow's
  ``tf.custom_gradient`` API. The difference here is that ``custom_gradient``
  can be used as a decorator on one function that returns both the primal value
  (representing the output of the mathematical function to be differentiated)
  and the VJP (gradient) function. See
  https://www.tensorflow.org/api_docs/python/tf/custom_gradient.

  If the mathematical function to be differentiated has Haskell-like signature
  ``a -> b``, then the Python callable ``fun`` should have the signature
  ``a -> (b, CT b --o CT a)`` where we use ``CT x`` to denote a cotangent type
  for ``x`` and the ``--o`` arrow to denote a linear function. See the example
  below. That is, ``fun`` should return a pair where the first element
  represents the value of the mathematical function to be differentiated and the
  second element is a function to be called on the backward pass of reverse-mode
  automatic differentiation (i.e. the "custom gradient" function).

  The function returned as the second element of the output of ``fun`` can close
  over intermediate values computed when evaluating the function to be
  differentiated. That is, use lexical closure to share work between the forward
  pass and the backward pass of reverse-mode automatic differentiation. However,
  it cannot perform Python control flow which depends on the values of the
  closed-over intermediate values or its cotangent arguments; if the function
  includes such control flow, an error is raised.

  Args:
    fun: a Python callable specifying both the mathematical function to be
      differentiated and its reverse-mode differentiation rule. It should return
      a pair consisting of an output value and a Python callable that represents
      the custom gradient function.

  Returns:
    A Python callable that accepts the same arguments as ``fun`` and returns the
    output value specified by the first element of ``fun``'s output pair.

  For example:

  >>> @jax.custom_gradient
  ... def f(x):
  ...   return x ** 2, lambda g: (g * x,)
  ...
  >>> print(f(3.))
  9.0
  >>> print(jax.grad(f)(3.))
  3.0

  An example with a function on two arguments, so that the VJP function must
  return a tuple of length two:

  >>> @jax.custom_gradient
  ... def f(x, y):
  ...   return x * y, lambda g: (g * y, g * x)
  ...
  >>> print(f(3., 4.))
  12.0
  >>> print(jax.grad(f, argnums=(0, 1))(3., 4.))
  (Array(4., dtype=float32, weak_type=True), Array(3., dtype=float32, weak_type=True))
  c                      | i |\  }}|S r<   r\   )r   r   rc   rC   r@   s       rE   wrapped_funz$custom_gradient.<locals>.wrapped_fun  s    $!&!FCJrG   c                 f    | i |\  }}t        |f      \  }}t        d||fi       }t        t        j                  ||      |      \  }}|D cg c]%  }t        j                  |      j                         ' }	}t        j                  ||	      \  }
}}|t        |
 |       ||      fS c c}w )Nzcustom_gradient fwdr   )r(   r   r   r   r   r   r]   r   r>   r?   	Residuals)r   r   rc   rulerd   r   r  r`   rN   rf   rB   rC   rD   r@   s                rE   rx  zcustom_gradient.<locals>.fwd  s    T$V$IC%sf-Hh0$CI(dAJ*LMUWMD'=EFq!113FIF00yAE1f	%Hf=== Gs   *B.c                    | \  }}}}t        |f      \  }}||k7  rt        | d|       t        j                  ||g| }t	        ||      }t        |      r|f}|S )Nz
!=
)r(   r   r   r  r)   r+   )	r  r  rB   r`   r   rD   cts_flatr   r  s	            rE   ry  zcustom_gradient.<locals>.bwd  ss    '*$E7Hf&v.Hi9I
&.L$MMooeV7h7GWg.Gw
gNrG   )rv  r}  )r@   r  rx  ry  s   `   rE   custom_gradientr!  b  s:    z  > S#	rG   c                  .    e Zd Zd Zd Zd Zed        Zy)r  c                <    || _         || _        || _        || _        y r<   )rB   r`   r   rD   )ry   rB   r`   r   rD   s        rE   r}   zResiduals.__init__  s    DJDLDMDKrG   c                p    t        | j                  | j                  | j                  | j                  f      S r<   )r  rB   r`   r   rD   ry   s    rE   __iter__zResiduals.__iter__  s&    T\\4==$++FGGrG   c                `    | j                   | j                  | j                  | j                  ffS r<   )rD   rB   r`   r   r%  s    rE   r(   zResiduals.tree_flatten  s$    ;;T\\4==AAArG   c                $    |\  }}} | ||||      S r<   r\   )clsauxrD   rB   r`   r   s         rE   r)   zResiduals.tree_unflatten  s    "E7Hugx00rG   N)r   r   r   r}   r&  r(   classmethodr)   r\   rG   rE   r  r    s%    
HB1 1rG   r  c                    t        |      \  }}t        t        t        j                  |            }t        d| |i       }t        j                  j                  rt        j                  | |||      S t        | |||      S )a
  Closure conversion utility, for use with higher-order custom derivatives.

  To define custom derivatives such as with ``jax.custom_vjp(f)``, the target
  function ``f`` must take, as formal arguments, all values involved in
  differentiation. If ``f`` is a higher-order function, in that it accepts as an
  argument a Python function ``g``, then values stored away in ``g``'s closure
  will not be visible to the custom derivative rules, and attempts at AD
  involving these values will fail. One way around this is to convert the
  closure by extracting these values, and to pass them as explicit formal
  arguments across the custom derivative boundary. This utility carries out that
  conversion. More precisely, it closure-converts the function ``fun``
  specialized to the types of the arguments given in ``example_args``.

  When we refer here to "values in the closure" of ``fun``, we do not mean the
  values that are captured by Python directly when ``fun`` is defined (e.g. the
  Python objects in ``fun.__closure__``, if the attribute exists). Rather, we
  mean values encountered during the execution of ``fun`` on ``example_args``
  that determine its output. This may include, for instance, arrays captured
  transitively in Python closures, i.e. in the Python closure of functions
  called by ``fun``, the closures of the functions that they call, and so forth.

  The function ``fun`` must be a pure function.

  Example usage::

    def minimize(objective_fn, x0):
      converted_fn, aux_args = closure_convert(objective_fn, x0)
      return _minimize(converted_fn, x0, *aux_args)

    @partial(custom_vjp, nondiff_argnums=(0,))
    def _minimize(objective_fn, x0, *args):
      z = objective_fn(x0, *args)
      # ... find minimizer x_opt ...
      return x_opt

    def fwd(objective_fn, x0, *args):
      y = _minimize(objective_fn, x0, *args)
      return y, (y, args)

    def rev(objective_fn, res, g):
      y, args = res
      y_bar = g
      # ... custom reverse-mode AD ...
      return x0_bar, *args_bars

    _minimize.defvjp(fwd, rev)

  Args:
    fun: Python callable to be converted. Must be a pure function.
    example_args: Arrays, scalars, or (nested) standard Python
      containers (tuples, lists, dicts, namedtuples, i.e., pytrees)
      thereof, used to determine the types of the formal arguments to
      ``fun``. This type-specialized form of ``fun`` is the function
      that will be closure converted.

  Returns:
    A pair comprising (i) a Python callable, accepting the same
    arguments as ``fun`` followed by arguments corresponding to the
    values hoisted from its closure, and (ii) a list of values hoisted
    from the closure.
  closure_convert)r(   rv   r   r   r]   r   r   check_tracer_leaksr  _closure_convert_for_avals__wrapped__)r@   example_args	flat_argsr`   rA   r   s         rE   r-  r-    sq    | $L1)W3t}}i01(
&\2
>%$$%11#w%PP%c7HeDDrG   c                "   t        | t        j                        syt        | t        j                        r9t        | j
                  t        j                        rt        | j                        S t        | t        j                        rM| j                  j                         }|t        j                  u xs t        |dd       t        j                   k(   S t        | t        j                        s t#        d | j%                         D              S y)NFr  c              3  8   K   | ]  \  }}t        |        y wr<   )_maybe_perturbed)r   rl  attrs      rE   r   z#_maybe_perturbed.<locals>.<genexpr>#  s     F*$%Fs   T)rV   r   rW   r"   	JVPTracertangentr   r5  r  r>   DynamicJaxprTracerr   r   abstract_tokenr  r   r  r_  	_contents)rN   vspaces     rE   r5  r5    s     
At{{	#!R\\"z!))RWW'EAHH%%!R**+ VV##%F$--- @.&--?A Aa&FFFFrG   c                   	
 t        t        j                  | |            \  }t        j                  ||      \  
}}        t        t        |      \  \  	}t        |      	
fd}||fS )Nr   c                     t        |       z
  }t        | |g      \  }} 	|      }t        t        |            \  }}
|k7  rd
 d| }t	        |      t        j                  |g| }t        |      S )NzThe inputs to the closure produced by closure_convert must have the same Pytree structure as the example arguments passed when closure_convert was called. Expected z
, but got )r   r8   r(   rv   r   r   r  r)   )args_hconstsnum_argsr   
const_argsrD   all_argsr  r   r   closure_constsr`   rB   merger  r   s            rE   converted_funz1_closure_convert_for_avals.<locals>.converted_fun2  s    < :-H!,
;D*>:.F%eDk2Hh(55<IZzc cNuf8x8H(H--rG   )r   r   r   r>   r?   partition_listr5  r   )r@   r`   rA   r   r  	out_pvalsrD   rA  rE  rC  rB   rD  r  r   s    `       @@@@@rE   r/  r/  '  s{     /ll3:.9+x66{HM%FZ((67G(P%>::*. . 

	""rG   c                    g g f}|D cg c]&  }| | |         j                  |      xs  | |      ( c}fd}||fS c c}w )Nc                t    t        |       t        |      }}D cg c]  }t        |r|n|       c}S c c}w r<   )r  r   )l1l2i1i2sndwhichs        rE   rD  zpartition_list.<locals>.mergeE  s1    "XtBxB/45Ds#555s   5)r  )choicelstr'  eltrD  rO  s        @rE   rF  rF  B  sS    
B#BE
F33vc{""3'66#;6
F%6 
e	 Gs   +Ac                   t        |      \  }}t        |      \  }t        |f      }t        t        j                  | t        d| ||fi             |      \  }}	t        t        j                  |      t        t        j                  |      }
t        |g |
      \  }}t        |      }|j                  t        | |	       f      }t        t        j                  |t        d|||fi             |      \  t        j                  fd       }t        j                  g |||||t!        |      t!        |      d}t#         |	       |      S )a  Call a linear function, with a custom implementation for its transpose.

  The `Haskell-like type signatures`_ of ``fun`` and ``fun_transpose`` are:

  .. code-block:: haskell

    fun           :: r -> a -o b
    fun_transpose :: r -> b -o a

  where the ``-o`` arrow indicates a linear function, ``r`` is the
  residual input type and ``a`` is the linear input type.

  The functions ``fun`` and ``fun_transpose`` are coupled as
  transposes of one another. Specifically, the transpose of a
  ``linear_call`` primitive is another ``linear_call`` to
  ``fun_transpose``, with ``fun`` as its custom transposition.

  For example:

  >>> def f(r, x):
  ...   return x / r

  >>> def t(r, t):
  ...   return t / r

  >>> def div_add(x, denom):
  ...   return x + linear_call(f, t, denom, x)

  >>> def transpose(f, x_example):
  ...   def transposed(y):
  ...     x, = jax.linear_transpose(f, x_example)(y)
  ...     return x
  ...   return transposed

  >>> div_add(9., 3.)
  Array(12., dtype=float32, weak_type=True)

  >>> transpose(partial(div_add, denom=3.), 1.)(18.)  # custom
  Array(24., dtype=float32, weak_type=True)

  >>> transpose(lambda x: x + x / 3., 1.)(18.)  # reference
  Array(24., dtype=float32, weak_type=True)

  The above definition of ``f`` illustrates the purpose of a residual
  argument: division is linear in one of its inputs (the dividend
  ``x``) but not the other (the divisor ``r``).

  As another example:

  >>> def custom_id(x):
  ...   def f(_, x): return x
  ...   def t(_, t): return 7.
  ...   return linear_call(f, t, (), x)
  >>> custom_id(1.)
  1.0
  >>> transpose(custom_id, 1.)(1.)
  TypedFloat(7.0, dtype=float32)
  >>> transpose(transpose(custom_id, 1.), 1.)(1.)
  1.0
  >>> transpose(transpose(transpose(custom_id, 1.), 1.), 1.)(1.)
  TypedFloat(7.0, dtype=float32)

  Args:
    fun: a Python callable specifying a linear function. It should
      take two arguments: one of "residual" inputs (type ``r``),
      i.e. inputs in which the function is not necessarily linear, and
      one of "linear" inputs (type ``a``).  It should return output
      whose components are linear in the linear input (type ``b``).
    fun_transpose: a Python callable specifying a structurally linear
      function that is the transpose of ``fun`` with respect to its
      linear inputs. Its first argument is the same residual inputs
      (``r``) as ``fun``. Its second argument is of type
      ``b``. Finally, its output is of type ``a`` and each of its
      component are linear in its second argument (the ``b`` inputs).
    residual_args: Argument in which ``fun`` and ``fun_transpose`` are
      not necessarily linear. Not involved in transposition.
    linear_args: Argument in which ``fun`` and ``fun_transpose`` are
      linear and with respect to which the two are transposes.

  Returns:
    The call result, i.e. ``fun(residual_args, linear_args)``.

  .. _Haskell-like type signatures: https://wiki.haskell.org/Type_signature
  zlinear_call funr   zlinear_call fun_transposec                     t        j                         g       \  } }        k7  rt        d         d d      t        |       |fS )NzYtranspose output pytree structure must match that of linear inputs, got output structure z and input structure r   )rF   rL  r   rK   )t_jaxprt_constslin_treer4  	res_avalsr   
t_out_trees     rE   transpose_thunkz$linear_call.<locals>.transpose_thunk  sq    ,Q-A-A-C-Ey-E9-EGGX|x"",, 0!!)
!-. .  (**rG   calleerZ  num_callee_constsnum_res)r(   r,   r   r   r   r   r   r   r]   rF   rK   r4  r>   rb  linear_call_prX   r   r)   )r@   fun_transposeresidual_argslinear_argsoperands_resr  operands_lin	f_in_treer_   r   	lin_avalsf_jaxprf_constsf_jaxpr_closed	t_in_treerZ  r'  rW  r4  rX  r   rY  s                    @@@@@rE   linear_callrk  M  sw   n (6,'4,Xx01)$ll
 13!. <bBC +!X $--.)$--.)*1.F	.FI.FG'8(.&&)Xxz23)&ll
 ;]!. <bBC
 -!Z ;;+ + 	 	6H 	6| 	6l 	6"0+:-0]#&|#4		6# 

C	((rG   c                J    ~~~t        j                  | j                  dg| S r[   )r   r  rB   )r\  rZ  r]  r^  r   s        rE   _linear_call_implrm    s$    ('	r	1D	11rG   c                    t        | ||z   g      \  }} t        |||z   g      \  }}t        d |D              sJ t        j                  g || ||||d}t        j                  g ||||||d}	||	fS )Nc              3  >   K   | ]  }t        |      t        u   y wr<   )r   r   )r   r   s     rE   r   z(_linear_call_jvp_rule.<locals>.<genexpr>  s     5T!W_5s   r[  )r8   r   r_  rX   )
r   r   r\  rZ  r]  r^  consts_and_resconst_tangentsr   r   s
             rE   _linear_call_jvp_rulerr    s    &w1BW1L0MN.''3Dw3N2OP.(	5n5	55	5"" <<<(.)7<+ ## << <)/)7<, 
l	""rG   c          	         |       \  }}t        |||g      \  }}	t        |j                  t        |      |g      \  }
}
}t        d |	D              sJ t        d |D              sJ fd}t	        | |      D cg c]#  \  }}t        |      t        u rt        |      n|% } }}t        j                  g ||| ||t        |      t        |      d}d g||z   z  |z   S c c}}w )Nc              3  F   K   | ]  }t        j                  |        y wr<   r"   is_undefined_primalr   rN   s     rE   r   z._linear_call_transpose_rule.<locals>.<genexpr>  s     AqR##A&As   !c              3  H   K   | ]  }t        j                  |         y wr<   ru  rw  s     rE   r   z._linear_call_transpose_rule.<locals>.<genexpr>  s     Aq''**As    "c                      fS r<   r\   )r\  rh  s   rE   new_transpose_thunkz8_linear_call_transpose_rule.<locals>.new_transpose_thunk  s    8rG   r[  )
r8   rA   r   r   r   r   r   r   r_  rX   )r  r\  rZ  r]  r^  r   	transposerV  rc  rd  rC   	cts_avalsrz  rH  r   r  rh  s    `              @rE   _linear_call_transpose_ruler}    s   '))X)3
(**&(L,3x='24/!Q	 
ALA	AA	A	ALA	AA	A #y)	+R  $Bx4/	R	7 	+# 	+ : :< :# :&//B14X'*<'8	:' $w.	/'	99	+s   (C)c                      |d   j                   S )Nr\  r4  )r   r   s     rE   _linear_call_abstract_evalr    s    			#	##rG   rk  )r  unreachablezcore.Primitiveunreachable_pc                    ~  ||      r<   r\   )r4  exc_typemessagerC   s       rE   unreachable_implr    s    rG   c                    | S r<   r\   )r4  rC   __s      rE   rY   rY     s    I rG   r4  r  r  c                    | t        t        j                  |      } t        |      \  }}t        |       \  }}t	        j
                  ||||d}t        ||      S )a  Fail when evaluated concretely (but allow for staging).

  This function allows one to assert an impossibility of
  evaluation. It can be used to guarantee that evaluation does not
  "reach" a certain point in the sense that it does not execute, but
  it can nonetheless be staged out by JAX without error.

  Args:
    *args: The arbitrary pytree of arguments to the function.
    out_avals: Optional specification of the output types of this
     function invocation from the point of view of staging. If
     ``None``, these are chosen as equal to types of input arguments.
    exc_type: Optional constructor for the Python exception raised if
      evaluated.
    message: Optional string message for the Python exception raised
      if evaluated.

  r  )r*   r   r]   r(   r  rX   r)   )	r4  r  r  r   ra   r`   out_avals_flatr   r'  s	            rE   r  r    s^    ( -I#D))W))4.(I$,g	?#	#	&&rG   zAcan't apply forward-mode autodiff (jvp) to a custom_vjp function.)r  r  c                J    t        |       } | j                  fd       }| S )Nc                     |  \  }}t        d |      }t        t        t        |            }|j	                         | ||||      fS )Nc                H    t        j                  |       j                         S r<   )r   r]   r   )r  s    rE   rY   z=custom_vjp_by_custom_transpose.<locals>.jvp.<locals>.<lambda>G  s    t}}Q'7'G'G'I rG   r  )r*   r   r   disallow_jvpdef_transpose)r   r   r  	residualstan_out_typestan_fnry  rx  s         rE   rp   z+custom_vjp_by_custom_transpose.<locals>.jvpD  sP    7mOD)I4PMglmLMF
y(;;;rG   )rj   r   )r@   rx  ry  rp   s    `` rE   r  r  A  s)    3#::< < 
*rG   custom_jvp_call_jaxprc                Z     |rt        d      t              d fd       }|S )Nr|  c            	     <   t         | |      } "r"D ]  }t        | |           t        "      }t        t	        |             D cg c]	  }||vs| }}t        t        j                         || d      \  }}t        t        j                  !      || d      \  }}n0t        j                         | }}t        j                  !      }t        |      \  }	}
t        ||
      \  }t        |"d|
|      \  }}t        |      }|	D cg c]  }t        j                  |       c}t        j                  |j!                               \  }}}t        j"                  t        j$                  |            } |       \  }}}|j&                  t)        d |D              z
  }t*        j,                  j/                  |j*                        }|rt1        d|       t        j2                  fd       }t5        j6                  g ||	t	        |      |||d}t9        ||g      \  }}t;        |      }|D cg c]  }|t=        |      n|	|    }}t=        |d       J t?        ||f      }tA        |g ||      S c c}w c c}w c c}w )Nr   Fr   c              3  $   K   | ]  }|d u 
 y wr<   r\   r  s     rE   r   zHoptimize_remat_of_custom_vjp_fwd.<locals>.wrapped_fwd.<locals>.<genexpr>  r  r	  z^remat optimization for custom_vjp does not support forward functions with these side effects: c                 @    t        j                        \  } }}| |fS r<   r=   )rB   rC   rD   r   rA   s      rE   fun_jaxpr_thunkzNoptimize_remat_of_custom_vjp_fwd.<locals>.wrapped_fwd.<locals>.fun_jaxpr_thunk  s&    228XFeQF]rG   r  r^  r  r  )!r   r  rt   r   r   r   r   r   r(   rg   r  _fix_fwd_argsr   r]   r>   r?   rL  rI   rJ   r  r
  r   r2  r3  r  rb  remat_opt_prX   r8   r  r   r,   r)   )#r   r   r   rz   r  r   r   r  rC   ra   r`   r  r  r  rN   r  rD   	prim_treer  r  r  r5  r  r   r  res_r_   r   r   rA   r  r  r@   rx  rm   s#                               @@rE   wrapped_fwdz5optimize_remat_of_custom_vjp_fwd.<locals>.wrapped_fwdi  s    #tV,D;! 247 ;;_- %c$i 0N1A=M4MQNkN$R\\#)%L%0%)Olb(  SY G +T=BDgdA \\#)<d(b\\#)4d%h/Iw.r7;Hh&t_e'0)WhPHiX&H*34Qa 4H44X5P5P5R5=?Iq&r99)DEI )Ix%%+H4+H(HHK CCQQR[RcRcd00B/CEF F [[   A A) AF(3y0?AH x+7MC9D>B
C4:	!4
CC
Cd###i23H($5h$5$566U O  5. Ds   		JJJJ)r   ztuple[ReturnValue, Any])r  r	   )r@   r  rx  r  rm   rr   r  s   `````  rE   r  r  \  s@     
KM M 	:37 37 37j 
rG   c                t    |D cg c]  }|df }}|D cg c]  }|D ]  }|  }}} | | S c c}w c c}}w NTr\   )r_   r   rN   pairs       rE   r  r    sI    !	"1d)	"$	"	+d	+!	+!	+$	+	
D/ 
#	+s   /4c                8    ~ ~~ t        j                  |      | S r<   )r   r  )r  r^  r  r  r   s        rE   _remat_opt_implr    s#     '?	%		9	%t	,,rG   c                4    ~| j                   | j                  fS r<   )r4  r   )r  r   rC   s      rE   _remat_opt_abstract_evalr    s    
			i//	//rG   c          	     d    t        ||      D cg c]+  \  }}|t        ur|dk7  rt        j                  ||d      n|- }}}|D cg c]
  }|t        u }	}t        j                  | |	d      \  }
}|
j
                  }t        j                  t        j                  |
j                              }
|D cg c]  }|rdnt         }}t        |	|g      \  }t        j                   fd       }t        j                  g |||t        |      z   ||
|d}||fS c c}}w c c}w c c}w )Nr   Fc                     t        j                           } t        j                  | d      \  }}|j                  |j
                  fS rF  )r   rM  r#   batch_jaxprrB   rD   )	fun_jaxprbatched_fun_jaxprout_batched	axis_datar  prim_batcheds      rE   batched_fun_jaxpr_thunkz0_remat_opt_vmap.<locals>.batched_fun_jaxpr_thunk  sM      /"34I%-%9%99lE&3"{""$5$<$<<<rG   r  )r   r'   r#   moveaxisr  rD   r>   rI   rJ   rB   r8   rb  r  rX   r   )r  r   in_dimsr  r^  r  r  rN   r  
in_batchedbatched_fwd_jaxprr  extra_constsbout_dimsrC   r  batched_outsr  s   `     `           @rE   _remat_opt_vmapr    sR    !w/
1Q )*(;Q(

Aq!
$ 
1$ 
1-45#5*5#+#7#7J$/ [")),nn  !2!8!89;.9:1a*$:(:zJ<8/!\;;= = !! K< K$ K-7#l:K-K*1,=2I	K, 
x	3
15 ;s   0D"
D(8D-c               V    t         |g      \  } t        ||g      \  }}t        t        j                  |      }|D cg c]  }t	        |t
                }	}t        |	|      D 
cg c]
  \  }
}|
s	| }}
}|	dgt        |      z  z   }t        j                  ||d      \  }}t        |      |z
  }t        j                  ||t               gt        |      t        |      g||g||g      }t        j                  t        j                  |j                              } fd}t        |j                        |z   t        |      z   }t        j                   g |j                  || ||d|z  ||d}t        ||||g      \  }}}}g ||g ||fS c c}w c c}}
w )NTc                     t        j                           } dgt              z  }t        j                  | |d      \  }}|j
                  |j                  fS r  )r   rM  r   r"   r#  rB   rD   )r  in_nzfun_jvp_jaxprrC   r  r   s       rE   fun_jvp_jaxpr_thunkz+_remat_opt_jvp.<locals>.fun_jvp_jaxpr_thunk  sT      /"34IFS\!E||Iud;M1 4 444rG   r   r  )r8   r   r"   instantiate_zerosrV   r   r   r   r#  rearrange_bindersr>   rI   rJ   rB   rD   r  rX   )r   r   r  r^  r  r  rD   
consts_dotr   	consts_nznzcr  fwd_jaxpr_jvp_out_nznum_outfwd_jaxpr_jvpr  new_num_constsr  r  res_dotouts_dots   `    `                 rE   _remat_opt_jvpr    s    w5/&'#Hzl;*h%%x0(0:;1:a&&;);"9j9@eb!R@*@
tfs8},
,%<<	5$?.&K'!'''z3w<0
:H&'(:Wg<NP. ..!;!;N<P<P!QR-5 ~,,-
:S_L.			 
?>00 
?6 
?J 
?"
?%-
?:H"#g+*=
?$ ",D7GW2M!N#wh	3-'-H-	--/ <@s   F *
F%5F%c                   t        d      )NzBremat optimization for custom_vjp does not support higher-order ADr
  )r  r  r^  r  r  r   s         rE   _remat_opt_transposer    s     	J	L LrG   c           	     ,   t        |       s0t        j                  |      sdgt        |j                        z  d fS t        | |j                  d   g      \  }}t        | |j                        D cg c]
  \  }}|s	| }}}t        |      rSdg|j                  d   z  }|dgt        |j                        |j                  d   z
  z  z  }t        j                  |j                  d   j                  | |      \  }}	|j                  rJ t        j                  |      }
t        |	|j                        D cg c]
  \  }}|s	| }}}t        |j                        }t        t        |	|j                  d   g      d         }||d<   |
|d<   t        |      |d<   t        j                  ||t         ||
j"                  |j$                  |j&                        }|	|fS  |j                  d          \  }}t        j(                  ||      \  }}}	t        ||      D cg c]
  \  }}|s	| }}}t+        j,                  ||      }
t        |j                  |j                  d   g      \  }}t        |	|      D cg c]
  \  }}|s	| }}}t        j                  ||t*        j.                  t        |
	      |
j"                  |j$                  |j&                        }dg|j                  d   z  |	z   }	|	|fS c c}}w c c}}w c c}}w c c}}w )
NFr^  r  Tr  )instantiater   r  )r  )r_  r>   r`  r   ra  r8   r  r   rc  rK  rB   r;  rI   r  r
  rd  r  r   rf  rA  dce_jaxpr_constsr   rM  closed_call_p)r]  r\  used_res
used_primsrZ  rB  rc  r  rP  rh  closed_jaxprra  r  r  ri  r  rD   used_constsr  rC   s                       rE   _remat_opt_dcer  
  s   	Ys 37S_$d**#I

90E/FG(J!)S[[9B74TQB'B] 'CJJ|44KD6S_szz,/GGHHK,,szz+'>'D'Di3>@Ix"""">>),L"8SZZ8AGD!DaAFAcjj!JHszz,/G.HI!LMN-J|*J{MJyj,2F2F"G W 6

#457Iv')':':9j'Q$I{H";7@GD!4a@F@##Iv6L3::

<(@'ABIAv"8V4=GD!a=F=++T\-Jcoosww8G wL11H<HWI C B" A >s0   2
K>=K>=
LL#
L
.L

LL	remat_opt)r@   lu.WrappedFunrA   Sequence[core.AbstractValue]r   z tuple[core.Jaxpr, Sequence[Any]])rB   z
core.Jaxprr   core.ClosedJaxpr)r_   r   r^   zlu.Storer`   r4   )r  intr  r  r   r  )rA  zmlir.LoweringRuleContextr  r  )rN  r  rO  ztuple[bool, ...]r   z#tuple[core.ClosedJaxpr, list[bool]])r]  zSequence[bool]r\  core.JaxprEqnr   z'tuple[list[bool], core.JaxprEqn | None])r\  r  rq  zcore.JaxprPpContextrr  zcore.JaxprPpSettingsr   zcore.pp.Doc)r_   r   rm   rl   r   core.DebugInfo)r_   r   r^   zlu.EqualStorerm   rl   rr   rq   r  r  r  r  r`   r4   )r_   r   r`   r4   rA   r  r  z;Callable[[], tuple[PyTreeDef, PyTreeDef, list[int | None]]])r   rq   )r  r  r  r  r   r  )r@   r   r   ztuple[Callable, list[Any]])rN   r
   r   rq   )r   r  )r@   r   r`  r   )r\   F)r@   rk   r  r  rx  r  r  r  rm   rl   rr   rq   r   r  )r  r  r^  r  r  r  r  zCallable[[], core.ClosedJaxpr])r  r  )r]  z
list[bool]r\  r  )
__future__r   collections.abcr   r   dataclasses	functoolsr   r   r   r	   typingr
   r   r   jax._srcr   r   r   jax._src.custom_transposer   r   r   r   r   r   jax._src.ad_utilr   r   r   r   jax._src.api_utilr   r   r   r   r   r   r   jax._src.errorsr    jax._src.state.typesr!   jax._src.interpretersr"   r#   r$   r%   r>   r&   jax._src.interpreters.batchingr'   jax._src.tree_utilr(   r)   r*   r+   r,   r-   r.   r/   r0   r1   r2   r3   r4   jax._src.utilr5   r6   r7   r8   r9   r:   register_exclusion__file__r   r   rF   rK   rP   rT   r   transformation_with_aux2rg   rh   register_custom_decorator_typerj   r   	Primitiver   r  r   r6  custom_typechecksrD  register_loweringrI  fancy_transposesrR  rj  	dce_rulesrt  pp_eqn_rulesrv  transformation2r  r  r  	dataclassr  r  r  r  r  r  r  r  r  r  r  r  r  r  r  raise_custom_vjp_error_on_jvpprimitive_batcherscustom_lin_pr!  r  r-  r5  r/  rF  rk  rm  rr  r}  r  r_  r  def_impldef_abstract_evalprimitive_jvpsprimitive_transposes register_initial_style_primitive	lower_funr  r   r  r   r  r  r  custom_jvp_call_jaxpr_pr  r  r  r  r  r  r  r  r  def_effectful_abstract_evalfancy_primitive_batchersr\   rG   rE   <module>r     s%   # .  < < ( (   $ 6   & #: :   2 , $ * & 4 & 5P P P P. . " ! !( +
#?>;(- J !)4=  m$//P.% P. 0P.d 		$	$48K$ 9K$Z"T^^ ".@$ ++<= 2 -G  ( )	.>	   (*G HG *J  % &:6F:-P: :!!$1!,!D #7 
/&9
/';
/@K
/ (@  # $ //_0% _0 0_0B "/8F "/8F&6    
$
' 		$	$48E%"/E%!%E%  .E% +	E%
 $E% 9E%NQ C#C7C XC CJA
'T^^ '2	B 9 9 ++<=    (*G!&(2 -G  ( )7!7!$17!,7!p #7 /&9/';/@K/ (@  # $/1/O/O  BOO ,   r(H(H!&(Wr 1 1 1 DEL* #+9# 	#4B)'B)H2
#:0$ }-!%    ( )    : ;#8  -  )D   & % % %m 4   }ndnn'. /
 !/} =~ =!% 
   ' (   }&6 7    E F!%	%'< OQ )$..)@A " &( C	#CC 
0C 	C
 #C C ,CJ  
-- -  	-
 4-0!  !  	! 
  !  4! F$. 	$.
 $.  $. 4$.L
L
L 
L  	
L
 4
L(T dnn[)#    _ %  ' '(@ A % % %k 2   {NDNNd%, - 2A ! !+ .!/  + ';   $*[ rG   